s3-smb1: Postpone close_file until all aio is handled
authorVolker Lendecke <vl@samba.org>
Tue, 17 Jul 2012 20:24:51 +0000 (22:24 +0200)
committerJeremy Allison <jra@samba.org>
Wed, 18 Jul 2012 22:57:53 +0000 (15:57 -0700)
Thanks to Jeremy for this simple idea

Signed-off-by: Jeremy Allison <jra@samba.org>
source3/include/vfs.h
source3/smbd/aio.c
source3/smbd/reply.c

index c4ef5a304630d54674cc68de0e91a3f983687250..c5b896db0f2464abc751c7b3e6a2c5eef0aab83b 100644 (file)
@@ -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 {
index 1923ef889fce56552ea8cfdcf32cdd5b5b292f4b..9f7390bba37d6b6bd9addb690a3ccc39f9f0613e 100644 (file)
@@ -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;
 }
 
index 954938cbe30a96e16d6fd35c83fdbb7c8270dffc..2022af72b07f1b426e0d6ca9c78c2b5d149e08a3 100644 (file)
@@ -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).
 ****************************************************************************/