summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2013-08-30 12:49:43 +0000
committerKarolin Seeger <kseeger@samba.org>2013-09-26 09:45:02 +0200
commit3a5ae0c11c4234950e6080a3b71f3d66db06edac (patch)
tree6868c8ebb8f54744b8bcc867dbc88ccf54489b00
parent9cfc00190882aea1915a721af2abbd07784ce6a7 (diff)
downloadsamba-3a5ae0c11c4234950e6080a3b71f3d66db06edac.tar.gz
smbd: Fix flawed share_mode_stale_pid API
The comment for this routine said: > Modifies d->num_share_modes, watch out in routines iterating over > that array. Well, it turns out that *every* caller of this API got it wrong. So I think it's better to change the routine. This leaves the array untouched while iterating but filters out the deleted ones while saving them back to disk. Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Michael Adam <obnox@samba.org> (cherry picked from commit 7d91ffc6fdc3b371564e14f09822a96264ea372a)
-rw-r--r--source3/librpc/idl/open_files.idl6
-rw-r--r--source3/locking/locking.c35
-rw-r--r--source3/locking/share_mode_lock.c24
3 files changed, 56 insertions, 9 deletions
diff --git a/source3/librpc/idl/open_files.idl b/source3/librpc/idl/open_files.idl
index a2e386f68c4..686bc02548a 100644
--- a/source3/librpc/idl/open_files.idl
+++ b/source3/librpc/idl/open_files.idl
@@ -23,6 +23,12 @@ interface open_files
uint32 uid;
uint16 flags;
uint32 name_hash;
+
+ /*
+ * In-memory flag indicating a non-existing pid. We don't want
+ * to store this share_mode_entry on disk.
+ */
+ [skip] boolean8 stale;
} share_mode_entry;
typedef [public] struct {
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index 602c30dfa21..5090082ba8b 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -617,6 +617,10 @@ bool is_valid_share_mode_entry(const struct share_mode_entry *e)
{
int num_props = 0;
+ if (e->stale) {
+ return false;
+ }
+
num_props += ((e->op_type == NO_OPLOCK) ? 1 : 0);
num_props += (EXCLUSIVE_OPLOCK_TYPE(e->op_type) ? 1 : 0);
num_props += (LEVEL_II_OPLOCK_TYPE(e->op_type) ? 1 : 0);
@@ -630,9 +634,7 @@ bool is_valid_share_mode_entry(const struct share_mode_entry *e)
/*
* In case d->share_modes[i] conflicts with something or otherwise is
* being used, we need to make sure the corresponding process still
- * exists. This routine checks it and potentially removes the entry
- * from d->share_modes. Modifies d->num_share_modes, watch out in
- * routines iterating over that array.
+ * exists.
*/
bool share_mode_stale_pid(struct share_mode_data *d, unsigned idx)
{
@@ -653,17 +655,32 @@ bool share_mode_stale_pid(struct share_mode_data *d, unsigned idx)
DEBUG(10, ("PID %s (index %u out of %u) does not exist anymore\n",
procid_str_static(&e->pid), idx,
(unsigned)d->num_share_modes));
- *e = d->share_modes[d->num_share_modes-1];
- d->num_share_modes -= 1;
- if (d->num_share_modes == 0 &&
- d->num_delete_tokens) {
+ e->stale = true;
+
+ if (d->num_delete_tokens != 0) {
+ uint32_t i, num_stale;
+
/*
* We cannot have any delete tokens
* if there are no valid share modes.
*/
- TALLOC_FREE(d->delete_tokens);
- d->num_delete_tokens = 0;
+
+ num_stale = 0;
+
+ for (i=0; i<d->num_share_modes; i++) {
+ if (d->share_modes[i].stale) {
+ num_stale += 1;
+ }
+ }
+
+ if (num_stale == d->num_share_modes) {
+ /*
+ * No non-stale share mode found
+ */
+ TALLOC_FREE(d->delete_tokens);
+ d->num_delete_tokens = 0;
+ }
}
d->modified = true;
diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c
index 0693cf54085..342f9108d6a 100644
--- a/source3/locking/share_mode_lock.c
+++ b/source3/locking/share_mode_lock.c
@@ -121,6 +121,7 @@ static struct share_mode_data *parse_share_modes(TALLOC_CTX *mem_ctx,
{
struct share_mode_data *d;
enum ndr_err_code ndr_err;
+ uint32_t i;
DATA_BLOB blob;
d = talloc(mem_ctx, struct share_mode_data);
@@ -140,6 +141,14 @@ static struct share_mode_data *parse_share_modes(TALLOC_CTX *mem_ctx,
goto fail;
}
+ /*
+ * Initialize the values that are [skip] in the idl. The NDR code does
+ * not initialize them.
+ */
+
+ for (i=0; i<d->num_share_modes; i++) {
+ d->share_modes[i].stale = false;
+ }
d->modified = false;
d->fresh = false;
@@ -162,12 +171,27 @@ static TDB_DATA unparse_share_modes(struct share_mode_data *d)
{
DATA_BLOB blob;
enum ndr_err_code ndr_err;
+ uint32_t i;
if (DEBUGLEVEL >= 10) {
DEBUG(10, ("unparse_share_modes:\n"));
NDR_PRINT_DEBUG(share_mode_data, d);
}
+ i = 0;
+ while (i < d->num_share_modes) {
+ if (d->share_modes[i].stale) {
+ /*
+ * Remove the stale entries before storing
+ */
+ struct share_mode_entry *m = d->share_modes;
+ m[i] = m[d->num_share_modes-1];
+ d->num_share_modes -= 1;
+ } else {
+ i += 1;
+ }
+ }
+
if (d->num_share_modes == 0) {
DEBUG(10, ("No used share mode found\n"));
return make_tdb_data(NULL, 0);