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) {
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;
}
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;
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,
+ ¤t_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;
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,
+ ¤t_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);
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,
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);
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,
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)
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;
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) {
}
}
- 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;
}
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);
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;
}