From: Ralph Boehme Date: Sat, 1 Feb 2025 09:37:40 +0000 (+0100) Subject: s3/brlock: add share_mode_do_locked_brl() X-Git-Tag: samba-4.21.6~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0d06276060f7aebefdffb51342de57212e75e8b2;p=thirdparty%2Fsamba.git s3/brlock: add share_mode_do_locked_brl() BUG: https://bugzilla.samba.org/show_bug.cgi?id=15767 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Ralph Boehme Signed-off-by: Stefan Metzmacher (cherry picked from commit e17fb732c89f8b34de00904383044de3c4f85bd0) --- diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index 51d9dc2e599..fcbce52f9c1 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -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; +} diff --git a/source3/locking/proto.h b/source3/locking/proto.h index 3413596baed..c9d769ba53f 100644 --- a/source3/locking/proto.h +++ b/source3/locking/proto.h @@ -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);