diff --git a/selftest/knownfail.d/samba3.smb2.lease b/selftest/knownfail.d/samba3.smb2.lease index ab810f6a64c..f3b57214ad6 100644 --- a/selftest/knownfail.d/samba3.smb2.lease +++ b/selftest/knownfail.d/samba3.smb2.lease @@ -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\) diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c index 36f39c68a14..72ce1a0d4cb 100644 --- a/source3/smbd/smbXsrv_session.c +++ b/source3/smbd/smbXsrv_session.c @@ -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; + } +} diff --git a/source3/smbd/smbXsrv_session.h b/source3/smbd/smbXsrv_session.h index e2a28e0d136..4c1262c700b 100644 --- a/source3/smbd/smbXsrv_session.h +++ b/source3/smbd/smbXsrv_session.h @@ -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