diff options
author | Volker Lendecke <vl@samba.org> | 2012-07-17 22:24:51 +0200 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2012-07-18 15:57:53 -0700 |
commit | 3e9f58be7e56b7990417e3f97a2d215f3591289e (patch) | |
tree | 2bc154d5c7c2a2bbeb4ac6ab948c427dab340a60 | |
parent | 3da86cc23f20e5b852d08aa05dacabb2d6e496e2 (diff) | |
download | samba-3e9f58be7e56b7990417e3f97a2d215f3591289e.tar.gz samba-3e9f58be7e56b7990417e3f97a2d215f3591289e.tar.bz2 samba-3e9f58be7e56b7990417e3f97a2d215f3591289e.zip |
s3-smb1: Postpone close_file until all aio is handled
Thanks to Jeremy for this simple idea
Signed-off-by: Jeremy Allison <jra@samba.org>
-rw-r--r-- | source3/include/vfs.h | 9 | ||||
-rw-r--r-- | source3/smbd/aio.c | 5 | ||||
-rw-r--r-- | source3/smbd/reply.c | 82 |
3 files changed, 95 insertions, 1 deletions
diff --git a/source3/include/vfs.h b/source3/include/vfs.h index c4ef5a3046..c5b896db0f 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -251,6 +251,15 @@ typedef struct files_struct { unsigned num_aio_requests; struct tevent_req **aio_requests; + + /* + * If a close request comes in while we still have aio_requests + * around, we need to hold back the close. When all aio_requests are + * done, the aio completion routines need tevent_wait_done() on + * this. A bit ugly, but before we have close_file() fully async + * possibly the simplest approach. Thanks, Jeremy for the idea. + */ + struct tevent_req *deferred_close; } files_struct; struct vuid_cache_entry { diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c index 1923ef889f..9f7390bba3 100644 --- a/source3/smbd/aio.c +++ b/source3/smbd/aio.c @@ -23,6 +23,7 @@ #include "smbd/globals.h" #include "../lib/util/tevent_ntstatus.h" #include "../lib/util/tevent_unix.h" +#include "lib/tevent_wait.h" /**************************************************************************** The buffer we keep around whilst an aio request is in process. @@ -107,6 +108,10 @@ static int aio_del_req_from_fsp(struct aio_req_fsp_link *lnk) } fsp->num_aio_requests -= 1; fsp->aio_requests[i] = fsp->aio_requests[fsp->num_aio_requests]; + + if (fsp->num_aio_requests == 0) { + tevent_wait_done(fsp->deferred_close); + } return 0; } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 954938cbe3..2022af72b0 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -41,6 +41,7 @@ #include "auth.h" #include "smbprofile.h" #include "../lib/tsocket/tsocket.h" +#include "lib/tevent_wait.h" /**************************************************************************** Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext @@ -4812,6 +4813,13 @@ void reply_exit(struct smb_request *req) return; } +struct reply_close_state { + files_struct *fsp; + struct smb_request *smbreq; +}; + +static void do_smb1_close(struct tevent_req *req); + void reply_close(struct smb_request *req) { connection_struct *conn = req->conn; @@ -4853,6 +4861,39 @@ void reply_close(struct smb_request *req) set_close_write_time(fsp, convert_time_t_to_timespec(t)); } + if (fsp->num_aio_requests != 0) { + + struct reply_close_state *state; + + DEBUG(10, ("closing with aio %u requests pending\n", + fsp->num_aio_requests)); + + /* + * We depend on the aio_extra destructor to take care of this + * close request once fsp->num_aio_request drops to 0. + */ + + fsp->deferred_close = tevent_wait_send( + fsp, fsp->conn->sconn->ev_ctx); + if (fsp->deferred_close == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + state = talloc(fsp, struct reply_close_state); + if (state == NULL) { + TALLOC_FREE(fsp->deferred_close); + status = NT_STATUS_NO_MEMORY; + goto done; + } + state->fsp = fsp; + state->smbreq = talloc_move(fsp, &req); + tevent_req_set_callback(fsp->deferred_close, do_smb1_close, + state); + END_PROFILE(SMBclose); + return; + } + /* * close_file() returns the unix errno if an error was detected on * close - normally this is due to a disk full error. If not then it @@ -4860,7 +4901,7 @@ void reply_close(struct smb_request *req) */ status = close_file(req, fsp, NORMAL_CLOSE); - +done: if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBclose); @@ -4872,6 +4913,45 @@ void reply_close(struct smb_request *req) return; } +static void do_smb1_close(struct tevent_req *req) +{ + struct reply_close_state *state = tevent_req_callback_data( + req, struct reply_close_state); + struct smb_request *smbreq; + NTSTATUS status; + int ret; + + ret = tevent_wait_recv(req); + TALLOC_FREE(req); + if (ret != 0) { + DEBUG(10, ("tevent_wait_recv returned %s\n", + strerror(ret))); + /* + * Continue anyway, this should never happen + */ + } + + /* + * fsp->smb2_close_request right now is a talloc grandchild of + * fsp. When we close_file(fsp), it would go with it. No chance to + * reply... + */ + smbreq = talloc_move(talloc_tos(), &state->smbreq); + + status = close_file(smbreq, state->fsp, NORMAL_CLOSE); + if (NT_STATUS_IS_OK(status)) { + reply_outbuf(smbreq, 0, 0); + } else { + reply_nterror(smbreq, status); + } + if (!srv_send_smb(smbreq->sconn, smbreq->outbuf, true, + smbreq->seqnum+1, encrypt, NULL)) { + exit_server_cleanly("handle_aio_read_complete: srv_send_smb " + "failed."); + } + TALLOC_FREE(smbreq); +} + /**************************************************************************** Reply to a writeclose (Core+ protocol). ****************************************************************************/ |