summaryrefslogtreecommitdiff
path: root/source3/locking/locking.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2014-10-10 14:32:19 -0700
committerJeremy Allison <jra@samba.org>2014-12-04 05:45:09 +0100
commita504b84ec147f64c428095519099104a2cb6ff1f (patch)
tree4c649cc3a1350bbb85616255880b266718f816bd /source3/locking/locking.c
parent6b2f19a5e6e8b3eb2a44cd24408ba4f27cfb8745 (diff)
downloadsamba-a504b84ec147f64c428095519099104a2cb6ff1f.tar.gz
s3:locking: ensure all share mode removal functions go through a common lease refcount manager.
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> Signed-off-by: Jeremy Allison <jra@samba.org> Signed-off-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'source3/locking/locking.c')
-rw-r--r--source3/locking/locking.c91
1 files changed, 88 insertions, 3 deletions
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index 9194dd388e6..f96887e6832 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -46,6 +46,7 @@
#include "messages.h"
#include "util_tdb.h"
#include "../librpc/gen_ndr/ndr_open_files.h"
+#include "locking/leases_db.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_LOCKING
@@ -617,6 +618,86 @@ bool is_valid_share_mode_entry(const struct share_mode_entry *e)
}
/*
+ * See if we need to remove a lease being referred to by a
+ * share mode that is being marked stale or deleted.
+ */
+
+static void remove_share_mode_lease(struct share_mode_data *d,
+ struct share_mode_entry *e)
+{
+ struct GUID client_guid;
+ struct smb2_lease_key lease_key;
+ uint16_t op_type;
+ uint32_t lease_idx;
+ uint32_t i;
+
+ op_type = e->op_type;
+ e->op_type = NO_OPLOCK;
+
+ d->modified = true;
+
+ if (op_type != LEASE_OPLOCK) {
+ return;
+ }
+
+ /*
+ * This used to reference a lease. If there's no other one referencing
+ * it, remove it.
+ */
+
+ lease_idx = e->lease_idx;
+ e->lease_idx = UINT32_MAX;
+
+ for (i=0; i<d->num_share_modes; i++) {
+ if (d->share_modes[i].stale) {
+ continue;
+ }
+ if (e == &d->share_modes[i]) {
+ /* Not ourselves. */
+ continue;
+ }
+ if (d->share_modes[i].lease_idx == lease_idx) {
+ break;
+ }
+ }
+ if (i < d->num_share_modes) {
+ /*
+ * Found another one
+ */
+ return;
+ }
+
+ memcpy(&client_guid,
+ &d->leases[lease_idx].client_guid,
+ sizeof(client_guid));
+ lease_key = d->leases[lease_idx].lease_key;
+
+ d->num_leases -= 1;
+ d->leases[lease_idx] = d->leases[d->num_leases];
+
+ /*
+ * We changed the lease array. Fix all references to it.
+ */
+ for (i=0; i<d->num_share_modes; i++) {
+ if (d->share_modes[i].lease_idx == d->num_leases) {
+ d->share_modes[i].lease_idx = lease_idx;
+ d->share_modes[i].lease = &d->leases[lease_idx];
+ }
+ }
+
+ {
+ NTSTATUS status;
+
+ status = leases_db_del(&client_guid,
+ &lease_key,
+ &e->id);
+
+ DEBUG(10, ("%s: leases_db_del returned %s\n", __func__,
+ nt_errstr(status)));
+ }
+}
+
+/*
* In case d->share_modes[i] conflicts with something or otherwise is
* being used, we need to make sure the corresponding process still
* exists.
@@ -674,6 +755,8 @@ bool share_mode_stale_pid(struct share_mode_data *d, uint32_t idx)
}
}
+ remove_share_mode_lease(d, e);
+
d->modified = true;
return true;
}
@@ -782,6 +865,7 @@ bool del_share_mode(struct share_mode_lock *lck, files_struct *fsp)
if (e == NULL) {
return False;
}
+ remove_share_mode_lease(lck->data, e);
*e = lck->data->share_modes[lck->data->num_share_modes-1];
lck->data->num_share_modes -= 1;
lck->data->modified = True;
@@ -829,6 +913,7 @@ bool mark_share_mode_disconnected(struct share_mode_lock *lck,
bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
{
+ struct share_mode_data *d = lck->data;
struct share_mode_entry *e;
e = find_share_mode_entry(lck, fsp);
@@ -836,9 +921,9 @@ bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
return False;
}
- e->op_type = NO_OPLOCK;
- lck->data->modified = True;
- return True;
+ remove_share_mode_lease(d, e);
+ d->modified = True;
+ return true;
}
/*******************************************************************