]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
smbd: add handle lease breaking when deleting files at session shutdown time
authorRalph Boehme <slow@samba.org>
Tue, 17 Sep 2024 05:16:51 +0000 (07:16 +0200)
committerRalph Boehme <slow@samba.org>
Tue, 5 Nov 2024 14:39:30 +0000 (14:39 +0000)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15608

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
selftest/knownfail.d/samba3.smb2.lease
source3/smbd/smbXsrv_session.c
source3/smbd/smbXsrv_session.h

index ab810f6a64c543bead99f87c06e4e7d4d623b3b3..f3b57214ad663e4827c040985b40356956a10935 100644 (file)
@@ -1,3 +1,2 @@
 ^samba3.smb2.lease.initial_delete_disconnect\(fileserver\)
-^samba3.smb2.lease.initial_delete_logoff\(fileserver\)
 ^samba3.smb2.lease.initial_delete_tdis\(fileserver\)
index 36f39c68a14fa7b7d109e1defd4fa7867765ac0c..72ce1a0d4cb4b24b34f01a6e6063badd209447ee 100644 (file)
@@ -1739,6 +1739,19 @@ struct smb2srv_session_shutdown_state {
 
 static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq);
 
+struct check_for_lease_break_fsp_cmp_state {
+       struct smbXsrv_session *session;
+};
+
+static bool check_for_lease_break_fsp_cmp_fn(struct files_struct *fsp,
+                                            void *private_data)
+{
+       struct check_for_lease_break_fsp_cmp_state *state =
+               (struct check_for_lease_break_fsp_cmp_state *)private_data;
+
+       return (fsp->vuid == state->session->global->session_wire_id);
+}
+
 struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct smbXsrv_session *session,
@@ -1748,6 +1761,7 @@ struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
        struct smb2srv_session_shutdown_state *state = NULL;
        struct tevent_req *subreq = NULL;
        struct smbXsrv_connection *xconn = NULL;
+       struct check_for_lease_break_fsp_cmp_state fsp_cmp_state;
        size_t len = 0;
 
        /*
@@ -1797,6 +1811,21 @@ struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
                }
        }
 
+       fsp_cmp_state = (struct check_for_lease_break_fsp_cmp_state) {
+               .session = session,
+       };
+
+       smbXsrv_wait_for_handle_lease_break(
+               req,
+               ev,
+               session->client,
+               state->wait_queue,
+               check_for_lease_break_fsp_cmp_fn,
+               &fsp_cmp_state);
+       if (!tevent_req_is_in_progress(req)) {
+               return tevent_req_post(req, ev);
+       }
+
        len = tevent_queue_length(state->wait_queue);
        if (len == 0) {
                tevent_req_done(req);
@@ -2517,3 +2546,132 @@ NTSTATUS smbXsrv_session_global_traverse(
 
        return status;
 }
+
+static struct files_struct *smbXsrv_wait_for_handle_lease_break_fn(
+                                               struct files_struct *fsp,
+                                               void *private_data);
+static void smbXsrv_wait_for_handle_lease_break_done(
+                                               struct tevent_req *subreq);
+
+struct delay_for_handle_lease_break_state {
+       struct tevent_req *req;
+       struct tevent_context *ev;
+       struct smbXsrv_client *client;
+       struct tevent_queue *wait_queue;
+       bool (*fsp_cmp_fn)(struct files_struct *fsp,
+                          void *private_data);
+       void *fsp_cmp_private_data;
+};
+
+void smbXsrv_wait_for_handle_lease_break(
+                               struct tevent_req *req,
+                               struct tevent_context *ev,
+                               struct smbXsrv_client *client,
+                               struct tevent_queue *wait_queue,
+                               bool (*fsp_cmp_fn)(struct files_struct *fsp,
+                                                  void *private_data),
+                               void *fsp_cmp_private_data)
+{
+       struct delay_for_handle_lease_break_state state;
+
+       state = (struct delay_for_handle_lease_break_state) {
+               .req = req,
+               .ev = ev,
+               .client = client,
+               .wait_queue = wait_queue,
+               .fsp_cmp_fn = fsp_cmp_fn,
+               .fsp_cmp_private_data = fsp_cmp_private_data,
+       };
+
+       files_forall(client->sconn,
+                    smbXsrv_wait_for_handle_lease_break_fn,
+                    &state);
+}
+
+static struct files_struct *smbXsrv_wait_for_handle_lease_break_fn(
+                                               struct files_struct *fsp,
+                                               void *private_data)
+{
+       struct delay_for_handle_lease_break_state *state = private_data;
+       struct tevent_req *subreq = NULL;
+       struct share_mode_lock *lck = NULL;
+       struct timeval timeout = timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0);
+       bool match;
+       NTSTATUS status;
+
+       match = state->fsp_cmp_fn(fsp, state->fsp_cmp_private_data);
+       if (!match) {
+               return NULL;
+       }
+
+       if (!fsp->fsp_flags.initial_delete_on_close) {
+               return NULL;
+       }
+
+       lck = get_existing_share_mode_lock(fsp, fsp->file_id);
+       if (lck == NULL) {
+               /* No opens on this file */
+               return NULL;
+       }
+
+       subreq = delay_for_handle_lease_break_send(fsp,
+                                                  state->ev,
+                                                  timeout,
+                                                  fsp,
+                                                  &lck);
+       if (tevent_req_nomem(subreq, state->req)) {
+               TALLOC_FREE(lck);
+               /* Reminder: returning != NULL means STOP traverse */
+               return fsp;
+       }
+       if (tevent_req_is_in_progress(subreq)) {
+               struct tevent_req *wait_subreq = NULL;
+
+               tevent_req_set_callback(
+                       subreq,
+                       smbXsrv_wait_for_handle_lease_break_done,
+                       state->req);
+
+               /*
+                * This just adds a blocker that unblocks when subreq is
+                * completed and goes away.
+                */
+               wait_subreq = tevent_queue_wait_send(subreq,
+                                                    state->ev,
+                                                    state->wait_queue);
+               if (wait_subreq == NULL) {
+                       exit_server("tevent_queue_wait_send failed");
+               }
+               return NULL;
+       }
+
+       status = delay_for_handle_lease_break_recv(subreq, state->req, &lck);
+       TALLOC_FREE(subreq);
+       TALLOC_FREE(lck);
+       if (tevent_req_nterror(state->req, status)) {
+               DBG_ERR("delay_for_handle_lease_break_recv failed %s\n",
+                       nt_errstr(status));
+               return fsp;
+       }
+       return NULL;
+}
+
+static void smbXsrv_wait_for_handle_lease_break_done(
+                                               struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct share_mode_lock *lck = NULL;
+       NTSTATUS status;
+
+       status = delay_for_handle_lease_break_recv(subreq,
+                                                  req,
+                                                  &lck);
+       TALLOC_FREE(subreq);
+       TALLOC_FREE(lck);
+       if (tevent_req_nterror(req, status)) {
+               DBG_ERR("delay_for_handle_lease_break_recv failed %s\n",
+                       nt_errstr(status));
+               return;
+       }
+}
index e2a28e0d13685a20159085015735a72712bcc9ec..4c1262c700bb1f05a33b08f0e4fa129cf702aa33 100644 (file)
@@ -107,4 +107,13 @@ struct tevent_req *smb2srv_session_close_previous_send(
        uint64_t current_session_id);
 NTSTATUS smb2srv_session_close_previous_recv(struct tevent_req *req);
 
+void smbXsrv_wait_for_handle_lease_break(
+                               struct tevent_req *req,
+                               struct tevent_context *ev,
+                               struct smbXsrv_client *client,
+                               struct tevent_queue *wait_queue,
+                               bool (*fsp_cmp_fn)(struct files_struct *fsp,
+                                                  void *private_data),
+                               void *fsp_cmp_private_data);
+
 #endif