From: Ralph Boehme Date: Wed, 2 Apr 2025 12:52:03 +0000 (+0200) Subject: smbd: use share_mode_do_locked_brl() in vfs_default_durable_reconnect() X-Git-Tag: samba-4.21.6~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb5640df4757ee037170083e89280b1ecdce4c46;p=thirdparty%2Fsamba.git smbd: use share_mode_do_locked_brl() in vfs_default_durable_reconnect() BUG: https://bugzilla.samba.org/show_bug.cgi?id=15767 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (backported from commit dc03a06ffcc79d0818ae4a36fe3f2df705144138) [slow@samba.org: conflict due to removed delayed write time handling] [slow@samba.org: conflict due to filename_convert_dirfsp_rel()] --- diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index 4dcae87691b..edc5c34ebc3 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -1424,14 +1424,14 @@ bool brl_mark_disconnected(struct files_struct *fsp, return true; } -bool brl_reconnect_disconnected(struct files_struct *fsp) +bool brl_reconnect_disconnected(struct files_struct *fsp, + struct byte_range_lock *br_lck) { uint32_t tid = fsp->conn->cnum; uint64_t smblctx; uint64_t fnum = fsp->fnum; unsigned int i; struct server_id self = messaging_server_id(fsp->conn->sconn->msg_ctx); - struct byte_range_lock *br_lck = NULL; if (fsp->op == NULL) { return false; @@ -1449,13 +1449,7 @@ bool brl_reconnect_disconnected(struct files_struct *fsp) * them instead. */ - br_lck = brl_get_locks(talloc_tos(), fsp); - if (br_lck == NULL) { - return false; - } - if (br_lck->num_locks == 0) { - TALLOC_FREE(br_lck); return true; } @@ -1468,22 +1462,18 @@ bool brl_reconnect_disconnected(struct files_struct *fsp) */ if (lock->context.smblctx != smblctx) { - TALLOC_FREE(br_lck); return false; } if (lock->context.tid != TID_FIELD_INVALID) { - TALLOC_FREE(br_lck); return false; } if (!server_id_is_disconnected(&lock->context.pid)) { - TALLOC_FREE(br_lck); return false; } if (lock->fnum != FNUM_FIELD_INVALID) { - TALLOC_FREE(br_lck); return false; } @@ -1494,7 +1484,6 @@ bool brl_reconnect_disconnected(struct files_struct *fsp) fsp->current_lock_count = br_lck->num_locks; br_lck->modified = true; - TALLOC_FREE(br_lck); return true; } diff --git a/source3/locking/proto.h b/source3/locking/proto.h index d3b4e02bc26..37d382833fc 100644 --- a/source3/locking/proto.h +++ b/source3/locking/proto.h @@ -83,7 +83,8 @@ struct brl_connectstate { bool brl_mark_disconnected(struct files_struct *fsp, struct byte_range_lock *br_lck); -bool brl_reconnect_disconnected(struct files_struct *fsp); +bool brl_reconnect_disconnected(struct files_struct *fsp, + struct byte_range_lock *br_lck); void brl_close_fnum(struct byte_range_lock *br_lck); int brl_forall(void (*fn)(struct file_id id, struct server_id pid, enum brl_type lock_type, diff --git a/source3/smbd/durable.c b/source3/smbd/durable.c index d315cb21ccc..82777d3b81b 100644 --- a/source3/smbd/durable.c +++ b/source3/smbd/durable.c @@ -563,121 +563,42 @@ static bool durable_reconnect_fn( return false; /* Look at potential other entries */ } -NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn, - struct smb_request *smb1req, - struct smbXsrv_open *op, - const DATA_BLOB old_cookie, - TALLOC_CTX *mem_ctx, - files_struct **result, - DATA_BLOB *new_cookie) +struct vfs_default_durable_reconnect_state { + NTSTATUS status; + TALLOC_CTX *mem_ctx; + struct smb_request *smb1req; + struct smbXsrv_open *op; + struct vfs_default_durable_cookie cookie; + struct files_struct *fsp; + DATA_BLOB new_cookie_blob; +}; + +static void vfs_default_durable_reconnect_fn(struct share_mode_lock *lck, + struct byte_range_lock *br_lck, + void *private_data) { + struct vfs_default_durable_reconnect_state *state = private_data; const struct loadparm_substitution *lp_sub = loadparm_s3_global_substitution(); - struct share_mode_lock *lck; + struct files_struct *fsp = state->fsp; struct share_mode_entry e = { .pid = { .pid = 0, }}; - struct durable_reconnect_state rstate = { .op = op, .e = &e, }; - struct files_struct *fsp = NULL; - NTSTATUS status; - bool ok; - int ret; + struct durable_reconnect_state rstate = { .op = state->op, .e = &e, }; struct vfs_open_how how = { .flags = 0, }; struct file_id file_id; - struct smb_filename *smb_fname = NULL; - enum ndr_err_code ndr_err; - struct vfs_default_durable_cookie cookie; - DATA_BLOB new_cookie_blob = data_blob_null; bool have_share_mode_entry = false; - - *result = NULL; - *new_cookie = data_blob_null; - - if (!lp_durable_handles(SNUM(conn))) { - return NT_STATUS_NOT_SUPPORTED; - } - - /* - * the checks for kernel oplocks - * and similar things are done - * in the vfs_default_durable_cookie() - * call below. - */ - - ndr_err = ndr_pull_struct_blob_all( - &old_cookie, - talloc_tos(), - &cookie, - (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - status = ndr_map_error2ntstatus(ndr_err); - return status; - } - - if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (!cookie.allow_reconnect) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - - if (strcmp(cookie.servicepath, conn->connectpath) != 0) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - - /* Create an smb_filename with stream_name == NULL. */ - smb_fname = synthetic_smb_fname(talloc_tos(), - cookie.base_name, - NULL, - NULL, - 0, - 0); - if (smb_fname == NULL) { - return NT_STATUS_NO_MEMORY; - } - - ret = SMB_VFS_LSTAT(conn, smb_fname); - if (ret == -1) { - status = map_nt_error_from_unix_common(errno); - DEBUG(1, ("Unable to lstat stream: %s => %s\n", - smb_fname_str_dbg(smb_fname), - nt_errstr(status))); - return status; - } - - if (!S_ISREG(smb_fname->st.st_ex_mode)) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - - file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st); - if (!file_id_equal(&cookie.id, &file_id)) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - - /* - * 1. check entry in locking.tdb - */ - - lck = get_existing_share_mode_lock(mem_ctx, file_id); - if (lck == NULL) { - DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock " - "not obtained from db\n")); - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } + int ret; + bool ok; ok = share_mode_forall_entries(lck, durable_reconnect_fn, &rstate); if (!ok) { DBG_WARNING("share_mode_forall_entries failed\n"); - status = NT_STATUS_INTERNAL_DB_ERROR; + state->status = NT_STATUS_INTERNAL_DB_ERROR; goto fail; } if (e.pid.pid == 0) { DBG_WARNING("Did not find a unique valid share mode entry\n"); - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto fail; } @@ -685,69 +606,36 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn, DEBUG(5, ("vfs_default_durable_reconnect: denying durable " "reconnect for handle that was not marked " "disconnected (e.g. smbd or cluster node died)\n")); - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto fail; } - if (e.share_file_id != op->global->open_persistent_id) { + if (e.share_file_id != state->op->global->open_persistent_id) { DBG_INFO("denying durable " "share_file_id changed %"PRIu64" != %"PRIu64" " "(e.g. another client had opened the file)\n", e.share_file_id, - op->global->open_persistent_id); - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + state->op->global->open_persistent_id); + state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto fail; } if ((e.access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) && - !CAN_WRITE(conn)) + !CAN_WRITE(fsp->conn)) { DEBUG(5, ("vfs_default_durable_reconnect: denying durable " "share[%s] is not writeable anymore\n", - lp_servicename(talloc_tos(), lp_sub, SNUM(conn)))); - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - goto fail; - } - - /* - * 2. proceed with opening file - */ - - status = fsp_new(conn, conn, &fsp); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("vfs_default_durable_reconnect: failed to create " - "new fsp: %s\n", nt_errstr(status))); + lp_servicename(talloc_tos(), lp_sub, SNUM(fsp->conn)))); + state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto fail; } fh_set_private_options(fsp->fh, e.private_options); - fsp->file_id = file_id; - fsp->file_pid = smb1req->smbpid; - fsp->vuid = smb1req->vuid; fsp->open_time = e.time; fsp->access_mask = e.access_mask; fsp->fsp_flags.can_read = ((fsp->access_mask & FILE_READ_DATA) != 0); fsp->fsp_flags.can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0); - fsp->fnum = op->local_id; - fsp_set_gen_id(fsp); - /* - * TODO: - * Do we need to store the modified flag in the DB? - */ - fsp->fsp_flags.modified = false; - /* - * no durables for directories - */ - fsp->fsp_flags.is_directory = false; - /* - * For normal files, can_lock == !is_directory - */ - fsp->fsp_flags.can_lock = true; - /* - * We do not support aio write behind for smb2 - */ - fsp->fsp_flags.aio_write_behind = false; fsp->oplock_type = e.op_type; if (fsp->oplock_type == LEASE_OPLOCK) { @@ -760,21 +648,21 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn, */ if (!GUID_equal(fsp_client_guid(fsp), &e.client_guid)) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto fail; } - status = leases_db_get( + state->status = leases_db_get( &e.client_guid, &e.lease_key, - &file_id, + &fsp->file_id, ¤t_state, /* current_state */ NULL, /* breaking */ NULL, /* breaking_to_requested */ NULL, /* breaking_to_required */ &lease_version, /* lease_version */ &epoch); /* epoch */ - if (!NT_STATUS_IS_OK(status)) { + if (!NT_STATUS_IS_OK(state->status)) { goto fail; } @@ -785,53 +673,46 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn, lease_version, epoch); if (fsp->lease == NULL) { - status = NT_STATUS_NO_MEMORY; + state->status = NT_STATUS_NO_MEMORY; goto fail; } } - fsp->initial_allocation_size = cookie.initial_allocation_size; - fh_set_position_information(fsp->fh, cookie.position_information); + fsp->initial_allocation_size = state->cookie.initial_allocation_size; + fh_set_position_information(fsp->fh, state->cookie.position_information); fsp->fsp_flags.update_write_time_triggered = - cookie.update_write_time_triggered; + state->cookie.update_write_time_triggered; fsp->fsp_flags.update_write_time_on_close = - cookie.update_write_time_on_close; - fsp->fsp_flags.write_time_forced = cookie.write_time_forced; + state->cookie.update_write_time_on_close; + fsp->fsp_flags.write_time_forced = state->cookie.write_time_forced; fsp->close_write_time = nt_time_to_full_timespec( - cookie.close_write_time); + state->cookie.close_write_time); - status = fsp_set_smb_fname(fsp, smb_fname); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("vfs_default_durable_reconnect: " - "fsp_set_smb_fname failed: %s\n", - nt_errstr(status))); - goto fail; - } - - op->compat = fsp; - fsp->op = op; + state->op->compat = fsp; + fsp->op = state->op; ok = reset_share_mode_entry( lck, e.pid, e.share_file_id, - messaging_server_id(conn->sconn->msg_ctx), - smb1req->mid, + messaging_server_id(fsp->conn->sconn->msg_ctx), + state->smb1req->mid, fh_get_gen_id(fsp->fh)); if (!ok) { DBG_DEBUG("Could not set new share_mode_entry values\n"); - status = NT_STATUS_INTERNAL_ERROR; + state->status = NT_STATUS_INTERNAL_ERROR; goto fail; } have_share_mode_entry = true; - ok = brl_reconnect_disconnected(fsp); - if (!ok) { - status = NT_STATUS_INTERNAL_ERROR; - DEBUG(1, ("vfs_default_durable_reconnect: " - "failed to reopen brlocks: %s\n", - nt_errstr(status))); - goto fail; + if (br_lck != NULL) { + ok = brl_reconnect_disconnected(fsp, br_lck); + if (!ok) { + state->status = NT_STATUS_INTERNAL_ERROR; + DBG_ERR("failed to reopen brlocks: %s\n", + nt_errstr(state->status)); + goto fail; + } } /* @@ -845,10 +726,9 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn, how.flags = O_RDONLY; } - status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, &how); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("vfs_default_durable_reconnect: failed to open " - "file: %s\n", nt_errstr(status))); + state->status = fd_openat(fsp->conn->cwd_fsp, fsp->fsp_name, fsp, &how); + if (!NT_STATUS_IS_OK(state->status)) { + DBG_ERR("failed to open file: %s\n", nt_errstr(state->status)); goto fail; } @@ -863,70 +743,66 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn, ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st); if (ret == -1) { - status = map_nt_error_from_unix_common(errno); - DEBUG(1, ("Unable to fstat stream: %s => %s\n", - smb_fname_str_dbg(smb_fname), - nt_errstr(status))); + state->status = map_nt_error_from_unix_common(errno); + DBG_ERR("Unable to fstat stream: %s => %s\n", + fsp_str_dbg(fsp), + nt_errstr(state->status)); goto fail; } if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto fail; } - file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st); - if (!file_id_equal(&cookie.id, &file_id)) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + file_id = vfs_file_id_from_sbuf(fsp->conn, &fsp->fsp_name->st); + if (!file_id_equal(&state->cookie.id, &file_id)) { + state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto fail; } (void)fdos_mode(fsp); - ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info, + ok = vfs_default_durable_reconnect_check_stat(&state->cookie.stat_info, &fsp->fsp_name->st, fsp_str_dbg(fsp)); if (!ok) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto fail; } - status = set_file_oplock(fsp); - if (!NT_STATUS_IS_OK(status)) { + state->status = set_file_oplock(fsp); + if (!NT_STATUS_IS_OK(state->status)) { goto fail; } - status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("vfs_default_durable_reconnect: " - "vfs_default_durable_cookie - %s\n", - nt_errstr(status))); + state->status = vfs_default_durable_cookie(fsp, + state->mem_ctx, + &state->new_cookie_blob); + if (!NT_STATUS_IS_OK(state->status)) { + DBG_ERR("vfs_default_durable_cookie - %s\n", + nt_errstr(state->status)); goto fail; } - smb1req->chain_fsp = fsp; - smb1req->smb2req->compat_chain_fsp = fsp; - - DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n", - fsp_str_dbg(fsp))); + state->smb1req->chain_fsp = fsp; + state->smb1req->smb2req->compat_chain_fsp = fsp; - TALLOC_FREE(lck); + DBG_DEBUG("opened file '%s'\n", fsp_str_dbg(fsp)); fsp->fsp_flags.is_fsa = true; - *result = fsp; - *new_cookie = new_cookie_blob; - - return NT_STATUS_OK; + state->status = NT_STATUS_OK; + return; fail: - if (fsp != NULL && have_share_mode_entry) { + if (have_share_mode_entry) { /* * Something is screwed up, delete the sharemode entry. */ del_share_mode(lck, fsp); } - if (fsp != NULL && fsp_get_pathref_fd(fsp) != -1) { + if (fsp_get_pathref_fd(fsp) != -1) { NTSTATUS close_status; close_status = fd_close(fsp); if (!NT_STATUS_IS_OK(close_status)) { @@ -934,11 +810,156 @@ fail: nt_errstr(close_status)); } } - TALLOC_FREE(lck); - if (fsp != NULL) { - op->compat = NULL; - fsp->op = NULL; - file_free(smb1req, fsp); + state->op->compat = NULL; + fsp->op = NULL; +} + +NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn, + struct smb_request *smb1req, + struct smbXsrv_open *op, + const DATA_BLOB old_cookie, + TALLOC_CTX *mem_ctx, + files_struct **result, + DATA_BLOB *new_cookie) +{ + struct vfs_default_durable_reconnect_state state; + struct smb_filename *smb_fname = NULL; + struct file_id file_id; + NTSTATUS status; + enum ndr_err_code ndr_err; + int ret; + + *result = NULL; + *new_cookie = data_blob_null; + + if (!lp_durable_handles(SNUM(conn))) { + return NT_STATUS_NOT_SUPPORTED; + } + + state = (struct vfs_default_durable_reconnect_state) { + .mem_ctx = mem_ctx, + .smb1req = smb1req, + .op = op, + }; + + /* + * the checks for kernel oplocks + * and similar things are done + * in the vfs_default_durable_cookie() + * call below. + */ + + ndr_err = ndr_pull_struct_blob_all( + &old_cookie, + talloc_tos(), + &state.cookie, + (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = ndr_map_error2ntstatus(ndr_err); + return status; } - return status; + + if (strcmp(state.cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (state.cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!state.cookie.allow_reconnect) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (strcmp(state.cookie.servicepath, conn->connectpath) != 0) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* Create an smb_filename with stream_name == NULL. */ + smb_fname = synthetic_smb_fname(talloc_tos(), + state.cookie.base_name, + NULL, + NULL, + 0, + 0); + if (smb_fname == NULL) { + return NT_STATUS_NO_MEMORY; + } + + ret = SMB_VFS_LSTAT(conn, smb_fname); + if (ret == -1) { + status = map_nt_error_from_unix_common(errno); + DEBUG(1, ("Unable to lstat stream: %s => %s\n", + smb_fname_str_dbg(smb_fname), + nt_errstr(status))); + return status; + } + if (!S_ISREG(smb_fname->st.st_ex_mode)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st); + if (!file_id_equal(&state.cookie.id, &file_id)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + status = fsp_new(conn, conn, &state.fsp); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("failed to create new fsp: %s\n", + nt_errstr(status)); + return status; + } + state.fsp->file_id = file_id; + state.fsp->file_pid = smb1req->smbpid; + state.fsp->vuid = smb1req->vuid; + state.fsp->fnum = op->local_id; + fsp_set_gen_id(state.fsp); + + status = fsp_set_smb_fname(state.fsp, smb_fname); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("fsp_set_smb_fname failed: %s\n", + nt_errstr(status)); + file_free(smb1req, state.fsp); + return status; + } + + /* + * TODO: + * Do we need to store the modified flag in the DB? + */ + state.fsp->fsp_flags.modified = false; + /* + * no durables for directories + */ + state.fsp->fsp_flags.is_directory = false; + /* + * For normal files, can_lock == !is_directory + */ + state.fsp->fsp_flags.can_lock = true; + /* + * We do not support aio write behind for smb2 + */ + state.fsp->fsp_flags.aio_write_behind = false; + + status = share_mode_do_locked_brl(state.fsp, + vfs_default_durable_reconnect_fn, + &state); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("share_mode_do_locked_brl [%s] failed: %s\n", + smb_fname_str_dbg(smb_fname), nt_errstr(status)); + file_free(smb1req, state.fsp); + return status; + } + if (!NT_STATUS_IS_OK(state.status)) { + DBG_ERR("default_durable_reconnect_fn [%s] failed: %s\n", + smb_fname_str_dbg(smb_fname), + nt_errstr(state.status)); + file_free(smb1req, state.fsp); + return state.status; + } + + *result = state.fsp; + *new_cookie = state.new_cookie_blob; + + return NT_STATUS_OK; }