smbd: Make find_share_mode_lease() static
[kai/samba-autobuild/.git] / source3 / smbd / open.c
index 38aaa7d267b0e8c5f81e483676d17cf2c8fd5be8..9c242ddba35b42cc6db6ccb2a9b166c2fa2aacfc 100644 (file)
@@ -1863,15 +1863,25 @@ static bool delay_for_oplock(files_struct *fsp,
        for (i=0; i<d->num_share_modes; i++) {
                struct share_mode_entry *e = &d->share_modes[i];
                bool e_is_lease = (e->op_type == LEASE_OPLOCK);
-               struct share_mode_lease *l = NULL;
                uint32_t e_lease_type = get_lease_type(d, e);
                uint32_t break_to;
                uint32_t delay_mask = 0;
                bool lease_is_breaking = false;
 
                if (e_is_lease) {
-                       l = &d->leases[e->lease_idx];
-                       lease_is_breaking = l->breaking;
+                       NTSTATUS status;
+
+                       status = leases_db_get(
+                               &e->client_guid,
+                               &e->lease_key,
+                               &fsp->file_id,
+                               NULL, /* current_state */
+                               &lease_is_breaking,
+                               NULL, /* breaking_to_requested */
+                               NULL, /* breaking_to_required */
+                               NULL, /* lease_version */
+                               NULL); /* epoch */
+                       SMB_ASSERT(NT_STATUS_IS_OK(status));
                }
 
                if (have_sharing_violation) {
@@ -1900,8 +1910,8 @@ static bool delay_for_oplock(files_struct *fsp,
 
                        ign = smb2_lease_equal(fsp_client_guid(fsp),
                                               &lease->lease_key,
-                                              &l->client_guid,
-                                              &l->lease_key);
+                                              &e->client_guid,
+                                              &e->lease_key);
                        if (ign) {
                                continue;
                        }
@@ -1961,9 +1971,9 @@ static bool file_has_brlocks(files_struct *fsp)
        return (brl_num_locks(br_lck) > 0);
 }
 
-int find_share_mode_lease(struct share_mode_data *d,
-                         const struct GUID *client_guid,
-                         const struct smb2_lease_key *key)
+static int find_share_mode_lease(struct share_mode_data *d,
+                                const struct GUID *client_guid,
+                                const struct smb2_lease_key *key)
 {
        uint32_t i;
 
@@ -1981,9 +1991,66 @@ int find_share_mode_lease(struct share_mode_data *d,
        return -1;
 }
 
+NTSTATUS update_share_mode_lease_from_db(
+       struct share_mode_data *d,
+       const struct GUID *client_guid,
+       const struct smb2_lease_key *lease_key)
+{
+       int idx;
+       struct share_mode_lease *l;
+       uint32_t current_state, breaking_to_requested, breaking_to_required;
+       bool breaking;
+       uint16_t lease_version, epoch;
+       NTSTATUS status;
+
+       idx = find_share_mode_lease(d, client_guid, lease_key);
+       if (idx == -1) {
+               DBG_WARNING("find_share_mode_lease failed\n");
+               return NT_STATUS_NOT_FOUND;
+       }
+       l = &d->leases[idx];
+
+       status = leases_db_get(client_guid,
+                              lease_key,
+                              &d->id,
+                              &current_state,
+                              &breaking,
+                              &breaking_to_requested,
+                              &breaking_to_required,
+                              &lease_version,
+                              &epoch);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("leases_db_get returned %s\n",
+                           nt_errstr(status));
+               return status;
+       }
+
+       if ((l->current_state == current_state) &&
+           (l->breaking == breaking) &&
+           (l->breaking_to_requested == breaking_to_requested) &&
+           (l->breaking_to_required == breaking_to_required) &&
+           (l->lease_version == lease_version) &&
+           (l->epoch == epoch)) {
+               return NT_STATUS_OK;
+       }
+
+       l->current_state = current_state;
+       l->breaking = breaking;
+       l->breaking_to_requested = breaking_to_requested;
+       l->breaking_to_required = breaking_to_required;
+       l->lease_version = lease_version;
+       l->epoch = epoch;
+
+       d->modified = true;
+
+       return NT_STATUS_OK;
+}
+
 struct fsp_lease *find_fsp_lease(struct files_struct *new_fsp,
                                 const struct smb2_lease_key *key,
-                                const struct share_mode_lease *l)
+                                uint32_t current_state,
+                                uint16_t lease_version,
+                                uint16_t lease_epoch)
 {
        struct files_struct *fsp;
 
@@ -2016,90 +2083,134 @@ struct fsp_lease *find_fsp_lease(struct files_struct *new_fsp,
        new_fsp->lease->ref_count = 1;
        new_fsp->lease->sconn = new_fsp->conn->sconn;
        new_fsp->lease->lease.lease_key = *key;
-       new_fsp->lease->lease.lease_state = l->current_state;
+       new_fsp->lease->lease.lease_state = current_state;
        /*
         * We internally treat all leases as V2 and update
         * the epoch, but when sending breaks it matters if
         * the requesting lease was v1 or v2.
         */
-       new_fsp->lease->lease.lease_version = l->lease_version;
-       new_fsp->lease->lease.lease_epoch = l->epoch;
+       new_fsp->lease->lease.lease_version = lease_version;
+       new_fsp->lease->lease.lease_epoch = lease_epoch;
        return new_fsp->lease;
 }
 
-static NTSTATUS grant_fsp_lease(struct files_struct *fsp,
-                               struct share_mode_lock *lck,
-                               const struct smb2_lease *lease,
-                               uint32_t *p_lease_idx,
-                               uint32_t granted)
+static NTSTATUS try_lease_upgrade(struct files_struct *fsp,
+                                 struct share_mode_lock *lck,
+                                 const struct GUID *client_guid,
+                                 const struct smb2_lease *lease,
+                                 uint32_t granted)
 {
        struct share_mode_data *d = lck->data;
-       const struct GUID *client_guid = fsp_client_guid(fsp);
-       struct share_mode_lease *tmp;
+       bool do_upgrade;
+       uint32_t current_state, breaking_to_requested, breaking_to_required;
+       bool breaking;
+       uint16_t lease_version, epoch;
+       uint32_t existing, requested;
        NTSTATUS status;
-       int idx;
 
-       idx = find_share_mode_lease(d, client_guid, &lease->lease_key);
+       status = leases_db_get(
+               client_guid,
+               &lease->lease_key,
+               &fsp->file_id,
+               &current_state,
+               &breaking,
+               &breaking_to_requested,
+               &breaking_to_required,
+               &lease_version,
+               &epoch);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
-       if (idx != -1) {
-               struct share_mode_lease *l = &d->leases[idx];
-               bool do_upgrade;
-               uint32_t existing, requested;
+       fsp->lease = find_fsp_lease(
+               fsp,
+               &lease->lease_key,
+               current_state,
+               lease_version,
+               epoch);
+       if (fsp->lease == NULL) {
+               DEBUG(1, ("Did not find existing lease for file %s\n",
+                         fsp_str_dbg(fsp)));
+               return NT_STATUS_NO_MEMORY;
+       }
 
-               fsp->lease = find_fsp_lease(fsp, &lease->lease_key, l);
-               if (fsp->lease == NULL) {
-                       DEBUG(1, ("Did not find existing lease for file %s\n",
-                                 fsp_str_dbg(fsp)));
-                       return NT_STATUS_NO_MEMORY;
-               }
+       /*
+        * Upgrade only if the requested lease is a strict upgrade.
+        */
+       existing = current_state;
+       requested = lease->lease_state;
 
-               *p_lease_idx = idx;
+       /*
+        * Tricky: This test makes sure that "requested" is a
+        * strict bitwise superset of "existing".
+        */
+       do_upgrade = ((existing & requested) == existing);
 
-               /*
-                * Upgrade only if the requested lease is a strict upgrade.
-                */
-               existing = l->current_state;
-               requested = lease->lease_state;
+       /*
+        * Upgrade only if there's a change.
+        */
+       do_upgrade &= (granted != existing);
 
-               /*
-                * Tricky: This test makes sure that "requested" is a
-                * strict bitwise superset of "existing".
-                */
-               do_upgrade = ((existing & requested) == existing);
+       /*
+        * Upgrade only if other leases don't prevent what was asked
+        * for.
+        */
+       do_upgrade &= (granted == requested);
 
-               /*
-                * Upgrade only if there's a change.
-                */
-               do_upgrade &= (granted != existing);
+       /*
+        * only upgrade if we are not in breaking state
+        */
+       do_upgrade &= !breaking;
 
-               /*
-                * Upgrade only if other leases don't prevent what was asked
-                * for.
-                */
-               do_upgrade &= (granted == requested);
+       DEBUG(10, ("existing=%"PRIu32", requested=%"PRIu32", "
+                  "granted=%"PRIu32", do_upgrade=%d\n",
+                  existing, requested, granted, (int)do_upgrade));
 
-               /*
-                * only upgrade if we are not in breaking state
-                */
-               do_upgrade &= !l->breaking;
+       if (do_upgrade) {
+               NTSTATUS set_status;
 
-               DEBUG(10, ("existing=%"PRIu32", requested=%"PRIu32", "
-                          "granted=%"PRIu32", do_upgrade=%d\n",
-                          existing, requested, granted, (int)do_upgrade));
+               current_state = granted;
+               epoch += 1;
 
-               if (do_upgrade) {
-                       l->current_state = granted;
-                       l->epoch += 1;
+               set_status = leases_db_set(
+                       client_guid,
+                       &lease->lease_key,
+                       current_state,
+                       breaking,
+                       breaking_to_requested,
+                       breaking_to_required,
+                       lease_version,
+                       epoch);
+
+               if (!NT_STATUS_IS_OK(set_status)) {
+                       DBG_DEBUG("leases_db_set failed: %s\n",
+                                 nt_errstr(set_status));
+                       return set_status;
                }
+       }
 
-               /* Ensure we're in sync with current lease state. */
-               fsp_lease_update(lck, fsp_client_guid(fsp), fsp->lease);
-               return NT_STATUS_OK;
+       status = update_share_mode_lease_from_db(
+               d, client_guid, &lease->lease_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("update_share_mode_lease_from_db failed: %s\n",
+                           nt_errstr(status));
+               return status;
        }
 
-       /*
-        * Create new lease
-        */
+       fsp_lease_update(lck, fsp_client_guid(fsp), fsp->lease);
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS grant_new_fsp_lease(struct files_struct *fsp,
+                                   struct share_mode_lock *lck,
+                                   const struct GUID *client_guid,
+                                   const struct smb2_lease *lease,
+                                   uint32_t granted)
+{
+       struct share_mode_data *d = lck->data;
+       struct share_mode_lease *tmp;
+       NTSTATUS status;
 
        tmp = talloc_realloc(d, d->leases, struct share_mode_lease,
                             d->num_leases+1);
@@ -2122,8 +2233,6 @@ static NTSTATUS grant_fsp_lease(struct files_struct *fsp,
        fsp->lease->lease.lease_state = granted;
        fsp->lease->lease.lease_epoch = lease->lease_epoch + 1;
 
-       *p_lease_idx = d->num_leases;
-
        d->leases[d->num_leases] = (struct share_mode_lease) {
                .client_guid = *client_guid,
                .lease_key = fsp->lease->lease.lease_key,
@@ -2135,6 +2244,9 @@ static NTSTATUS grant_fsp_lease(struct files_struct *fsp,
        status = leases_db_add(client_guid,
                               &lease->lease_key,
                               &fsp->file_id,
+                              fsp->lease->lease.lease_state,
+                              fsp->lease->lease.lease_version,
+                              fsp->lease->lease.lease_epoch,
                               fsp->conn->connectpath,
                               fsp->fsp_name->base_name,
                               fsp->fsp_name->stream_name);
@@ -2151,6 +2263,24 @@ static NTSTATUS grant_fsp_lease(struct files_struct *fsp,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS grant_fsp_lease(struct files_struct *fsp,
+                               struct share_mode_lock *lck,
+                               const struct smb2_lease *lease,
+                               uint32_t granted)
+{
+       const struct GUID *client_guid = fsp_client_guid(fsp);
+       NTSTATUS status;
+
+       status = try_lease_upgrade(fsp, lck, client_guid, lease, granted);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+               status = grant_new_fsp_lease(
+                       fsp, lck, client_guid, lease, granted);
+       }
+
+       return status;
+}
+
 static bool is_same_lease(const files_struct *fsp,
                          const struct share_mode_data *d,
                          const struct share_mode_entry *e,
@@ -2165,8 +2295,8 @@ static bool is_same_lease(const files_struct *fsp,
 
        return smb2_lease_equal(fsp_client_guid(fsp),
                                &lease->lease_key,
-                               &d->leases[e->lease_idx].client_guid,
-                               &d->leases[e->lease_idx].lease_key);
+                               &e->client_guid,
+                               &e->lease_key);
 }
 
 static int map_lease_type_to_oplock(uint32_t lease_type)
@@ -2200,7 +2330,8 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
        bool got_oplock = false;
        uint32_t i;
        uint32_t granted;
-       uint32_t lease_idx = UINT32_MAX;
+       const struct GUID *client_guid = NULL;
+       const struct smb2_lease_key *lease_key = NULL;
        bool ok;
        NTSTATUS status;
 
@@ -2291,13 +2422,16 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
 
                fsp->oplock_type = LEASE_OPLOCK;
 
-               status = grant_fsp_lease(fsp, lck, lease, &lease_idx,
-                                        granted);
+               status = grant_fsp_lease(fsp, lck, lease, granted);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
 
                }
                *lease = fsp->lease->lease;
+
+               lease_key = &fsp->lease->lease.lease_key;
+               client_guid = fsp_client_guid(fsp);
+
                DEBUG(10, ("lease_state=%d\n", lease->lease_state));
        } else {
                if (got_handle_lease) {
@@ -2315,10 +2449,14 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
                }
        }
 
-       ok = set_share_mode(lck, fsp, get_current_uid(fsp->conn),
-                           req ? req->mid : 0,
-                           fsp->oplock_type,
-                           lease_idx);
+       ok = set_share_mode(
+               lck,
+               fsp,
+               get_current_uid(fsp->conn),
+               req ? req->mid : 0,
+               fsp->oplock_type,
+               client_guid,
+               lease_key);
        if (!ok) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -4283,9 +4421,14 @@ static NTSTATUS open_directory(connection_struct *conn,
                return status;
        }
 
-       ok = set_share_mode(lck, fsp, get_current_uid(conn),
-                           req ? req->mid : 0, NO_OPLOCK,
-                           UINT32_MAX);
+       ok = set_share_mode(
+               lck,
+               fsp,
+               get_current_uid(conn),
+               req ? req->mid : 0,
+               NO_OPLOCK,
+               NULL,
+               NULL);
        if (!ok) {
                TALLOC_FREE(lck);
                fd_close(fsp);
@@ -4998,7 +5141,7 @@ static NTSTATUS lease_match(connection_struct *conn,
                        if (e->op_type == LEASE_OPLOCK) {
                                struct share_mode_lease *l = NULL;
                                l = &lck->data->leases[e->lease_idx];
-                               if (!smb2_lease_key_equal(&l->lease_key,
+                               if (!smb2_lease_key_equal(&e->lease_key,
                                                          lease_key)) {
                                        continue;
                                }