diff options
author | Jeremy Allison <jra@samba.org> | 2020-03-12 09:28:21 -0700 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2020-04-07 08:12:34 +0000 |
commit | 97e136880efb0d5e4d579300f137599287e9792b (patch) | |
tree | 5e7e7ebc37532871406394ed9f022a8d95ae12d0 | |
parent | 044cf379e541b574a2782945a607578e9687c279 (diff) | |
download | samba-97e136880efb0d5e4d579300f137599287e9792b.tar.gz |
s3: smbd: Add async internals of conn_force_tdis().
Commented out so it can be seen complete as
a diff. The next commit will replace the old
synchronous conn_force_tdis() code with the
new async code.
Uses a wait_queue to cause the force close
requests to stay pending until all outstanding
aio is finished on all file handles opened
on the connection.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14301
Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
(cherry picked from commit 4f9e0459cd06f0332083a4a465f49b5f258838fa)
-rw-r--r-- | source3/smbd/conn_idle.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/source3/smbd/conn_idle.c b/source3/smbd/conn_idle.c index 698dc6e3a32..b54cdf82274 100644 --- a/source3/smbd/conn_idle.c +++ b/source3/smbd/conn_idle.c @@ -23,6 +23,7 @@ #include "smbd/smbd.h" #include "smbd/globals.h" #include "rpc_server/rpc_pipes.h" +#include "lib/util/tevent_ntstatus.h" /**************************************************************************** Update last used timestamps. @@ -139,3 +140,150 @@ void conn_force_tdis( change_to_root_user(); reload_services(sconn, conn_snum_used, true); } + +#if 0 +struct conn_force_tdis_state { + struct tevent_queue *wait_queue; +}; + +static void conn_force_tdis_wait_done(struct tevent_req *subreq); + +static struct tevent_req *conn_force_tdis_send(connection_struct *conn) +{ + struct tevent_req *req; + struct conn_force_tdis_state *state; + struct tevent_req *subreq; + files_struct *fsp; + + /* Create this off the NULL context. We must clean up on return. */ + req = tevent_req_create(NULL, &state, + struct conn_force_tdis_state); + if (req == NULL) { + return NULL; + } + state->wait_queue = tevent_queue_create(state, + "conn_force_tdis_wait_queue"); + if (tevent_req_nomem(state->wait_queue, req)) { + TALLOC_FREE(req); + return NULL; + } + + /* + * Make sure that no new request will be able to use this tcon. + * This ensures that once all outstanding fsp->aio_requests + * on this tcon are done, we are safe to close it. + */ + conn->tcon->status = NT_STATUS_NETWORK_NAME_DELETED; + + for (fsp = conn->sconn->files; fsp; fsp = fsp->next) { + if (fsp->conn != conn) { + continue; + } + /* + * Flag the file as close in progress. + * This will prevent any more IO being + * done on it. Not strictly needed, but + * doesn't hurt to flag it as closing. + */ + fsp->closing = true; + + if (fsp->num_aio_requests > 0) { + /* + * Now wait until all aio requests on this fsp are + * finished. + * + * We don't set a callback, as we just want to block the + * wait queue and the talloc_free() of fsp->aio_request + * will remove the item from the wait queue. + */ + subreq = tevent_queue_wait_send(fsp->aio_requests, + conn->sconn->ev_ctx, + state->wait_queue); + if (tevent_req_nomem(subreq, req)) { + TALLOC_FREE(req); + return NULL; + } + } + } + /* + * Now we add our own waiter to the end of the queue, + * this way we get notified when all pending requests are finished + * and reply to the outstanding SMB1 request. + */ + subreq = tevent_queue_wait_send(state, + conn->sconn->ev_ctx, + state->wait_queue); + if (tevent_req_nomem(subreq, req)) { + TALLOC_FREE(req); + return NULL; + } + + tevent_req_set_callback(subreq, conn_force_tdis_wait_done, req); + return req; +} + +static void conn_force_tdis_wait_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + + tevent_queue_wait_recv(subreq); + TALLOC_FREE(subreq); + tevent_req_done(req); +} + +static NTSTATUS conn_force_tdis_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +static void conn_force_tdis_done(struct tevent_req *req) +{ + connection_struct *conn = tevent_req_callback_data( + req, connection_struct); + NTSTATUS status; + uint64_t vuid = UID_FIELD_INVALID; + struct smbXsrv_tcon *tcon = conn->tcon; + struct smbd_server_connection *sconn = conn->sconn; + + status = conn_force_tdis_recv(req); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("conn_force_tdis_recv of share '%s' " + "(wire_id=0x%08x) failed: %s\n", + tcon->global->share_name, + tcon->global->tcon_wire_id, + nt_errstr(status)); + return; + } + + if (conn->sconn->using_smb2) { + vuid = conn->vuid; + } + + DBG_WARNING("Closing " + "share '%s' (wire_id=0x%08x)\n", + tcon->global->share_name, + tcon->global->tcon_wire_id); + + conn = NULL; + status = smbXsrv_tcon_disconnect(tcon, vuid); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("smbXsrv_tcon_disconnect() of share '%s' " + "(wire_id=0x%08x) failed: %s\n", + tcon->global->share_name, + tcon->global->tcon_wire_id, + nt_errstr(status)); + return; + } + + TALLOC_FREE(tcon); + + /* + * As we've been awoken, we may have changed + * uid in the meantime. Ensure we're still root. + */ + change_to_root_user(); + reload_services(sconn, conn_snum_used, true); +} +#endif |