From: Volker Lendecke Date: Thu, 27 Jun 2019 15:23:07 +0000 (+0200) Subject: smbd: Add share_mode_do_locked() X-Git-Tag: samba-4.11.0rc1~104 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=44a77e6a5f9cb8c051648eb8f6759aadf3596544;p=thirdparty%2Fsamba.git smbd: Add share_mode_do_locked() This is made for efficient locking of share mode records in locking.tdb. Right now we already need that when accessing leases.tdb, and soon it will be required for brlock.tdb as well. It does not give direct access to the parsed share mode entry, but the record is available for dbwrap_watched_wakeup() within downgrade_lease(). It can be freely nested with get_share_mode_lock calls, the record will be shared and proper nesting should be checked. Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- diff --git a/source3/locking/proto.h b/source3/locking/proto.h index 15826a9d4af..604d66ebd3a 100644 --- a/source3/locking/proto.h +++ b/source3/locking/proto.h @@ -125,6 +125,15 @@ struct share_mode_lock *get_share_mode_lock( const char *servicepath, const struct smb_filename *smb_fname, const struct timespec *old_write_time); + +struct db_record; +NTSTATUS share_mode_do_locked( + struct file_id id, + void (*fn)(struct db_record *rec, + bool *modified_dependent, + void *private_data), + void *private_data); + struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, struct file_id id); struct tevent_req *fetch_share_mode_send(TALLOC_CTX *mem_ctx, diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c index f80b9845d16..456dea92229 100644 --- a/source3/locking/share_mode_lock.c +++ b/source3/locking/share_mode_lock.c @@ -533,8 +533,29 @@ struct share_mode_lock *get_share_mode_lock( goto fail; } } else { - /* This panic will go away in the next commit */ - smb_panic("static_share_mode_record != NULL\n"); + TDB_DATA static_key; + int cmp; + + static_key = dbwrap_record_get_key(static_share_mode_record); + + cmp = tdb_data_cmp(static_key, key); + if (cmp != 0) { + DBG_WARNING("Can not lock two share modes " + "simultaneously\n"); + return NULL; + } + + status = get_static_share_mode_data( + static_share_mode_record, + id, + servicepath, + smb_fname, + old_write_time); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("get_static_share_mode_data failed: %s\n", + nt_errstr(status)); + goto fail; + } } done: @@ -600,6 +621,90 @@ static int share_mode_lock_destructor(struct share_mode_lock *lck) return 0; } +struct share_mode_do_locked_state { + void (*fn)(struct db_record *rec, + bool *modified_dependent, + void *private_data); + void *private_data; +}; + +static void share_mode_do_locked_fn(struct db_record *rec, + void *private_data) +{ + struct share_mode_do_locked_state *state = private_data; + bool modified_dependent = false; + bool reset_static_share_mode_record = false; + + if (static_share_mode_record == NULL) { + static_share_mode_record = rec; + static_share_mode_record_talloced = false; + reset_static_share_mode_record = true; + } else { + SMB_ASSERT(static_share_mode_record == rec); + } + + state->fn(rec, &modified_dependent, state->private_data); + + if (modified_dependent) { + dbwrap_watched_wakeup(rec); + } + + if (reset_static_share_mode_record) { + static_share_mode_record = NULL; + } +} + +NTSTATUS share_mode_do_locked( + struct file_id id, + void (*fn)(struct db_record *rec, + bool *modified_dependent, + void *private_data), + void *private_data) +{ + TDB_DATA key = locking_key(&id); + size_t refcount = static_share_mode_data_refcount; + + if (static_share_mode_record != NULL) { + bool modified_dependent = false; + TDB_DATA static_key; + int cmp; + + static_key = dbwrap_record_get_key(static_share_mode_record); + + cmp = tdb_data_cmp(static_key, key); + if (cmp != 0) { + DBG_WARNING("Can not lock two share modes " + "simultaneously\n"); + return NT_STATUS_INVALID_LOCK_SEQUENCE; + } + + fn(static_share_mode_record, + &modified_dependent, + private_data); + + if (modified_dependent) { + dbwrap_watched_wakeup(static_share_mode_record); + } + } else { + struct share_mode_do_locked_state state = { + .fn = fn, .private_data = private_data, + }; + NTSTATUS status; + + status = dbwrap_do_locked( + lock_db, key, share_mode_do_locked_fn, &state); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("dbwrap_do_locked failed: %s\n", + nt_errstr(status)); + return status; + } + } + + SMB_ASSERT(refcount == static_share_mode_data_refcount); + + return NT_STATUS_OK; +} + struct fetch_share_mode_unlocked_state { TALLOC_CTX *mem_ctx; struct share_mode_lock *lck;