From: Ralph Boehme Date: Wed, 4 Sep 2024 15:58:45 +0000 (+0200) Subject: smbd: add contend_dirleases() X-Git-Tag: tdb-1.4.13~710 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1b53fd14995bc91b62a0bef64b50355247fdc21d;p=thirdparty%2Fsamba.git smbd: add contend_dirleases() Checks for Directory Lease breaks on the parent directory of smb_fname. Gets a sharemode lock on the locking.tdb record of the directory, hence it mustn't be called if the caller still has another sharmode lock. Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher --- diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index f70cc224e88..bf1cb07cede 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -736,6 +736,9 @@ void smbd_contend_level2_oplocks_begin(files_struct *fsp, enum level2_contention_type type); void smbd_contend_level2_oplocks_end(files_struct *fsp, enum level2_contention_type type); +void contend_dirleases(struct connection_struct *conn, + const struct smb_filename *smb_fname, + const struct smb2_lease *lease); bool init_oplocks(struct smbd_server_connection *sconn); void init_kernel_oplocks(struct smbd_server_connection *sconn); diff --git a/source3/smbd/smb2_oplock.c b/source3/smbd/smb2_oplock.c index aa1053d0064..c278db25239 100644 --- a/source3/smbd/smb2_oplock.c +++ b/source3/smbd/smb2_oplock.c @@ -1247,6 +1247,133 @@ static bool do_break_oplock_to_none(struct share_mode_entry *e, return false; } +struct dirlease_break_state { + struct smbd_server_connection *sconn; + struct file_id file_id; + struct smb2_lease_key parent_lease_key; + uint32_t total_lease_types; +}; + +static bool do_dirlease_break_to_none(struct share_mode_entry *e, + void *private_data) +{ + struct dirlease_break_state *state = private_data; + uint32_t current_state = 0; + NTSTATUS status; + + DBG_DEBUG("lease_key=%"PRIu64"/%"PRIu64"\n", + e->lease_key.data[0], + e->lease_key.data[1]); + + status = leases_db_get(&e->client_guid, + &e->lease_key, + &state->file_id, + ¤t_state, + NULL, /* breaking */ + NULL, /* breaking_to_requested */ + NULL, /* breaking_to_required */ + NULL, /* lease_version */ + NULL); /* epoch */ + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("leases_db_get failed: %s\n", + nt_errstr(status)); + return false; + } + + if (share_entry_stale_pid(e)) { + return false; + } + + state->total_lease_types |= current_state; + + if (smb2_lease_key_equal(&state->parent_lease_key, &e->lease_key)) { + return false; + } + + if ((current_state & (SMB2_LEASE_READ | SMB2_LEASE_HANDLE)) == 0) { + return false; + } + + DBG_DEBUG("Breaking %"PRIu64"/%"PRIu64" to none\n", + e->lease_key.data[0], + e->lease_key.data[1]); + + send_break_to_none(state->sconn->msg_ctx, &state->file_id, e); + return false; +} + +void contend_dirleases(struct connection_struct *conn, + const struct smb_filename *smb_fname, + const struct smb2_lease *lease) +{ + struct dirlease_break_state state = { + .sconn = conn->sconn, + }; + struct share_mode_lock *lck = NULL; + struct smb_filename *parent_fname = NULL; + uint32_t access_mask, share_mode; + NTSTATUS status; + int ret; + bool ok; + + if (lease != NULL) { + DBG_DEBUG("Parent leasekey %"PRIx64"/%"PRIx64"\n", + lease->parent_lease_key.data[0], + lease->parent_lease_key.data[1]); + state.parent_lease_key = lease->parent_lease_key; + } + + status = SMB_VFS_PARENT_PATHNAME(conn, + talloc_tos(), + smb_fname, + &parent_fname, + NULL); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("parent_smb_fname() for [%s] failed: %s\n", + smb_fname_str_dbg(smb_fname), strerror(errno)); + return; + } + + ret = SMB_VFS_STAT(conn, parent_fname); + if (ret != 0) { + DBG_ERR("Failed to stat [%s]: %s\n", + smb_fname_str_dbg(parent_fname), strerror(errno)); + TALLOC_FREE(parent_fname); + return; + } + + state.file_id = vfs_file_id_from_sbuf(conn, &parent_fname->st); + TALLOC_FREE(parent_fname); + + lck = get_existing_share_mode_lock(talloc_tos(), state.file_id); + if (lck == NULL) { + /* + * No sharemode db entry -> no leases. + */ + return; + } + + ok = share_mode_forall_leases(lck, do_dirlease_break_to_none, &state); + if (!ok) { + DBG_WARNING("share_mode_forall_leases failed\n"); + } + + /* + * While we're at it, update lease type. + */ + share_mode_flags_get(lck, + &access_mask, + &share_mode, + NULL); + share_mode_flags_set(lck, + access_mask, + share_mode, + state.total_lease_types, + NULL); + + TALLOC_FREE(lck); +} + /**************************************************************************** This function is called on any file modification or lock request. If a file is level 2 oplocked then it must tell all other level 2 holders to break to