]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3/brlock: add share_mode_do_locked_brl()
authorRalph Boehme <slow@samba.org>
Sat, 1 Feb 2025 09:37:40 +0000 (10:37 +0100)
committerJule Anger <janger@samba.org>
Thu, 17 Apr 2025 11:31:14 +0000 (11:31 +0000)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15767

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Ralph Boehme <slow@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
(cherry picked from commit e17fb732c89f8b34de00904383044de3c4f85bd0)

source3/locking/brlock.c
source3/locking/proto.h

index 51d9dc2e599aab93e53c4fbf47dc5281e62419c6..fcbce52f9c1b96ffac2ea5c8bdc70dc28f0860e7 100644 (file)
@@ -34,6 +34,7 @@
 #include "serverid.h"
 #include "messages.h"
 #include "util_tdb.h"
+#include "source3/locking/share_mode_lock.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_LOCKING
@@ -1927,3 +1928,105 @@ done:
        talloc_free(frame);
        return ret;
 }
+
+struct share_mode_do_locked_brl_state {
+       share_mode_do_locked_brl_fn_t cb;
+       void *cb_data;
+       struct files_struct *fsp;
+       NTSTATUS status;
+};
+
+static void share_mode_do_locked_brl_fn(struct share_mode_lock *lck,
+                                       void *private_data)
+{
+       struct share_mode_do_locked_brl_state *state = private_data;
+       struct byte_range_lock *br_lck = NULL;
+       TDB_DATA key = make_tdb_data((uint8_t *)&state->fsp->file_id,
+                                    sizeof(state->fsp->file_id));
+
+       if (lp_locking(state->fsp->conn->params) &&
+           state->fsp->fsp_flags.can_lock)
+       {
+               br_lck = brl_get_locks_readonly_parse(talloc_tos(),
+                                                     state->fsp);
+               if (br_lck == NULL) {
+                       state->status = NT_STATUS_NO_MEMORY;
+                       return;
+               }
+       }
+
+       state->cb(lck, br_lck, state->cb_data);
+
+       if (br_lck == NULL || !br_lck->modified) {
+               TALLOC_FREE(br_lck);
+               return;
+       }
+
+       br_lck->record = dbwrap_fetch_locked(brlock_db, br_lck, key);
+       if (br_lck->record == NULL) {
+               DBG_ERR("Could not lock byte range lock entry for '%s'\n",
+                       fsp_str_dbg(state->fsp));
+               TALLOC_FREE(br_lck);
+               state->status = NT_STATUS_INTERNAL_DB_ERROR;
+               return;
+       }
+
+       byte_range_lock_flush(br_lck);
+       share_mode_wakeup_waiters(br_lck->fsp->file_id);
+       TALLOC_FREE(br_lck);
+}
+
+/*
+ * Run cb with a glock'ed locking.tdb record, providing both a share_mode_lock
+ * and a br_lck object. An initial read-only, but upgradable, br_lck object is
+ * fetched from brlock.tdb while holding the glock on the locking.tdb record.
+ *
+ * This function only ever hold one low-level TDB chainlock at a time on either
+ * locking.tdb or brlock.tdb, so it can't run afoul any lock order violations.
+ *
+ * Note that br_lck argument in the callback might be NULL in case lp_locking()
+ * is disabled, the fsp doesn't allow locking or is a directory, so either
+ * the caller or the callback have to check for this.
+ */
+NTSTATUS share_mode_do_locked_brl(files_struct *fsp,
+                                 share_mode_do_locked_brl_fn_t cb,
+                                 void *cb_data)
+{
+       static bool recursion_guard;
+       TALLOC_CTX *frame = NULL;
+       struct share_mode_do_locked_brl_state state = {
+               .fsp = fsp,
+               .cb = cb,
+               .cb_data = cb_data,
+       };
+       NTSTATUS status;
+
+       SMB_ASSERT(!recursion_guard);
+
+       /* silently return ok on print files as we don't do locking there */
+       if (fsp->print_file) {
+               return NT_STATUS_OK;
+       }
+
+       frame = talloc_stackframe();
+
+       recursion_guard = true;
+       status = share_mode_do_locked_vfs_allowed(
+                                       fsp->file_id,
+                                       share_mode_do_locked_brl_fn,
+                                       &state);
+       recursion_guard = false;
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("share_mode_do_locked_vfs_allowed() failed for %s - %s\n",
+                       fsp_str_dbg(fsp), nt_errstr(status));
+               TALLOC_FREE(frame);
+               return status;
+       }
+       if (!NT_STATUS_IS_OK(state.status)) {
+               TALLOC_FREE(frame);
+               return state.status;
+       }
+
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+}
index 89a9f01bb571354157953edaba174ae1459850bc..0b22093b918aa8761750c35dca82aa2e6570d487 100644 (file)
@@ -87,6 +87,14 @@ struct byte_range_lock *brl_get_locks_for_locking(TALLOC_CTX *mem_ctx,
                                                  files_struct *fsp,
                                                  TALLOC_CTX *req_mem_ctx,
                                                  const struct GUID *req_guid);
+struct share_mode_lock;
+typedef void (*share_mode_do_locked_brl_fn_t)(
+       struct share_mode_lock *lck,
+       struct byte_range_lock *br_lck, /* br_lck can be NULL */
+       void *private_data);
+NTSTATUS share_mode_do_locked_brl(files_struct *fsp,
+                share_mode_do_locked_brl_fn_t fn,
+                void *private_data);
 struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
                                        files_struct *fsp);
 struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp);