]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
smbd: Add share_mode_do_locked()
authorVolker Lendecke <vl@samba.org>
Thu, 27 Jun 2019 15:23:07 +0000 (17:23 +0200)
committerRalph Boehme <slow@samba.org>
Thu, 4 Jul 2019 14:03:29 +0000 (14:03 +0000)
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 <vl@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/locking/proto.h
source3/locking/share_mode_lock.c

index 15826a9d4af11f7f1fd0931688907d08eab94955..604d66ebd3a9d390dd9df0ad9d0739e217132b97 100644 (file)
@@ -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,
index f80b9845d163274d6585352d1f5c9210f2d7adb8..456dea92229abac0b98397a82decfd370cea7b20 100644 (file)
@@ -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;