summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2012-07-17 22:24:51 +0200
committerJeremy Allison <jra@samba.org>2012-07-18 15:57:53 -0700
commit3e9f58be7e56b7990417e3f97a2d215f3591289e (patch)
tree2bc154d5c7c2a2bbeb4ac6ab948c427dab340a60
parent3da86cc23f20e5b852d08aa05dacabb2d6e496e2 (diff)
downloadsamba-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.h9
-rw-r--r--source3/smbd/aio.c5
-rw-r--r--source3/smbd/reply.c82
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).
****************************************************************************/