s3-vfs: async fsync
authorVolker Lendecke <vl@samba.org>
Fri, 13 Jul 2012 08:22:25 +0000 (10:22 +0200)
committerJeremy Allison <jra@samba.org>
Wed, 18 Jul 2012 22:48:04 +0000 (15:48 -0700)
Signed-off-by: Jeremy Allison <jra@samba.org>
examples/VFS/skel_opaque.c
examples/VFS/skel_transparent.c
source3/include/vfs.h
source3/include/vfs_macros.h
source3/modules/vfs_default.c
source3/modules/vfs_full_audit.c
source3/modules/vfs_time_audit.c
source3/smbd/vfs.c

index 56fae8435b2423aecc47d70e4a955fbf6e26df80..03a5157e8ab1ae611a9c76f33bfc40858e64a191 100644 (file)
@@ -263,6 +263,20 @@ static int skel_fsync(vfs_handle_struct *handle, files_struct *fsp)
        return -1;
 }
 
+static struct tevent_req *skel_fsync_send(struct vfs_handle_struct *handle,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct files_struct *fsp)
+{
+       return NULL;
+}
+
+static int skel_fsync_recv(struct tevent_req *req, int *err)
+{
+       *err = ENOSYS;
+       return -1;
+}
+
 static int skel_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
 {
        errno = ENOSYS;
@@ -805,6 +819,8 @@ struct vfs_fn_pointers skel_opaque_fns = {
        .recvfile_fn = skel_recvfile,
        .rename_fn = skel_rename,
        .fsync_fn = skel_fsync,
+       .fsync_send_fn = skel_fsync_send,
+       .fsync_recv_fn = skel_fsync_recv,
        .stat_fn = skel_stat,
        .fstat_fn = skel_fstat,
        .lstat_fn = skel_lstat,
index 86a26090e39e9e0ff8fed9960111f4655100ba40..6981b5da050ed0322f318c02b4d69ef631d3808b 100644 (file)
@@ -338,6 +338,57 @@ static int skel_fsync(vfs_handle_struct *handle, files_struct *fsp)
        return SMB_VFS_NEXT_FSYNC(handle, fsp);
 }
 
+struct skel_fsync_state {
+       int ret;
+       int err;
+};
+
+static void skel_fsync_done(struct tevent_req *subreq);
+
+static struct tevent_req *skel_fsync_send(struct vfs_handle_struct *handle,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct files_struct *fsp)
+{
+       struct tevent_req *req, *subreq;
+       struct skel_fsync_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct skel_fsync_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, skel_fsync_done, req);
+       return req;
+}
+
+static void skel_fsync_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct skel_fsync_state *state = tevent_req_data(
+               req, struct skel_fsync_state);
+
+       state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->err);
+       TALLOC_FREE(subreq);
+       tevent_req_done(req);
+}
+
+static int skel_fsync_recv(struct tevent_req *req, int *err)
+{
+       struct skel_fsync_state *state = tevent_req_data(
+               req, struct skel_fsync_state);
+
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
+       }
+       *err = state->err;
+       return state->ret;
+}
+
 static int skel_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
 {
        return SMB_VFS_NEXT_STAT(handle, smb_fname);
@@ -849,6 +900,8 @@ struct vfs_fn_pointers skel_transparent_fns = {
        .recvfile_fn = skel_recvfile,
        .rename_fn = skel_rename,
        .fsync_fn = skel_fsync,
+       .fsync_send_fn = skel_fsync_send,
+       .fsync_recv_fn = skel_fsync_recv,
        .stat_fn = skel_stat,
        .fstat_fn = skel_fstat,
        .lstat_fn = skel_lstat,
index 479376db37348e27b623f2b27c127e90579b6a2c..c4ef5a304630d54674cc68de0e91a3f983687250 100644 (file)
@@ -540,6 +540,11 @@ struct vfs_fn_pointers {
                         const struct smb_filename *smb_fname_src,
                         const struct smb_filename *smb_fname_dst);
        int (*fsync_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp);
+       struct tevent_req *(*fsync_send_fn)(struct vfs_handle_struct *handle,
+                                           TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           struct files_struct *fsp);
+       int (*fsync_recv_fn)(struct tevent_req *req, int *err);
        int (*stat_fn)(struct vfs_handle_struct *handle, struct smb_filename *smb_fname);
        int (*fstat_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_STAT *sbuf);
        int (*lstat_fn)(struct vfs_handle_struct *handle, struct smb_filename *smb_filename);
@@ -923,6 +928,13 @@ int smb_vfs_call_rename(struct vfs_handle_struct *handle,
                        const struct smb_filename *smb_fname_dst);
 int smb_vfs_call_fsync(struct vfs_handle_struct *handle,
                       struct files_struct *fsp);
+
+struct tevent_req *smb_vfs_call_fsync_send(struct vfs_handle_struct *handle,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct files_struct *fsp);
+int SMB_VFS_FSYNC_RECV(struct tevent_req *req, int *perrno);
+
 int smb_vfs_call_stat(struct vfs_handle_struct *handle,
                      struct smb_filename *smb_fname);
 int smb_vfs_call_fstat(struct vfs_handle_struct *handle,
index b88d11222787eea2e8c65c9e59231780dd758b50..515f68f16e236516612f9ee22256a77f0ae1e9c4 100644 (file)
 #define SMB_VFS_NEXT_FSYNC(handle, fsp) \
        smb_vfs_call_fsync((handle)->next, (fsp))
 
+#define SMB_VFS_FSYNC_SEND(mem_ctx, ev, fsp) \
+       smb_vfs_call_fsync_send((fsp)->conn->vfs_handles, (mem_ctx), (ev), \
+                               (fsp))
+#define SMB_VFS_NEXT_FSYNC_SEND(mem_ctx, ev, handle, fsp)              \
+       smb_vfs_call_fsync_send((handle)->next, (mem_ctx), (ev), (fsp))
+
 #define SMB_VFS_STAT(conn, smb_fname) \
        smb_vfs_call_stat((conn)->vfs_handles, (smb_fname))
 #define SMB_VFS_NEXT_STAT(handle, smb_fname) \
index c79eed0b9708d167c40e3516c87b65f259df5208..002a5501fde027cad9860884a352b9491930635a 100644 (file)
@@ -737,6 +737,36 @@ static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
        return req;
 }
 
+static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
+                                            TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct files_struct *fsp)
+{
+       struct tevent_req *req;
+       struct vfswrap_asys_state *state;
+       int ret;
+
+       req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       if (!vfswrap_init_asys_ctx(handle->conn->sconn->conn)) {
+               tevent_req_oom(req);
+               return tevent_req_post(req, ev);
+       }
+       state->asys_ctx = handle->conn->sconn->conn->asys_ctx;
+       state->req = req;
+
+       ret = asys_fsync(state->asys_ctx, fsp->fh->fd, req);
+       if (ret != 0) {
+               tevent_req_error(req, ret);
+               return tevent_req_post(req, ev);
+       }
+       talloc_set_destructor(state, vfswrap_asys_state_destructor);
+
+       return req;
+}
+
 static void vfswrap_asys_finished(struct tevent_context *ev,
                                        struct tevent_fd *fde,
                                        uint16_t flags, void *p)
@@ -785,6 +815,18 @@ static ssize_t vfswrap_asys_ssize_t_recv(struct tevent_req *req, int *err)
        return state->ret;
 }
 
+static int vfswrap_asys_int_recv(struct tevent_req *req, int *err)
+{
+       struct vfswrap_asys_state *state = tevent_req_data(
+               req, struct vfswrap_asys_state);
+
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
+       }
+       *err = state->err;
+       return state->ret;
+}
+
 static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
 {
        off_t result = 0;
@@ -2314,6 +2356,8 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .recvfile_fn = vfswrap_recvfile,
        .rename_fn = vfswrap_rename,
        .fsync_fn = vfswrap_fsync,
+       .fsync_send_fn = vfswrap_fsync_send,
+       .fsync_recv_fn = vfswrap_asys_int_recv,
        .stat_fn = vfswrap_stat,
        .fstat_fn = vfswrap_fstat,
        .lstat_fn = vfswrap_lstat,
index 74cc663be83cd667743d97682b2975a2a6ee9853..1e5679dd6b29c82d6271c9f7da6e2974405f52f6 100644 (file)
@@ -123,6 +123,8 @@ typedef enum _vfs_op_type {
        SMB_VFS_OP_RECVFILE,
        SMB_VFS_OP_RENAME,
        SMB_VFS_OP_FSYNC,
+       SMB_VFS_OP_FSYNC_SEND,
+       SMB_VFS_OP_FSYNC_RECV,
        SMB_VFS_OP_STAT,
        SMB_VFS_OP_FSTAT,
        SMB_VFS_OP_LSTAT,
@@ -254,6 +256,8 @@ static struct {
        { SMB_VFS_OP_RECVFILE,  "recvfile" },
        { SMB_VFS_OP_RENAME,    "rename" },
        { SMB_VFS_OP_FSYNC,     "fsync" },
+       { SMB_VFS_OP_FSYNC_SEND,        "fsync_send" },
+       { SMB_VFS_OP_FSYNC_RECV,        "fsync_recv" },
        { SMB_VFS_OP_STAT,      "stat" },
        { SMB_VFS_OP_FSTAT,     "fstat" },
        { SMB_VFS_OP_LSTAT,     "lstat" },
@@ -1195,6 +1199,74 @@ static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp)
        return result;    
 }
 
+struct smb_full_audit_fsync_state {
+       vfs_handle_struct *handle;
+       files_struct *fsp;
+       int ret;
+       int err;
+};
+
+static void smb_full_audit_fsync_done(struct tevent_req *subreq);
+
+static struct tevent_req *smb_full_audit_fsync_send(
+       struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev, struct files_struct *fsp)
+{
+       struct tevent_req *req, *subreq;
+       struct smb_full_audit_fsync_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct smb_full_audit_fsync_state);
+       if (req == NULL) {
+               do_log(SMB_VFS_OP_FSYNC_SEND, false, handle, "%s",
+                      fsp_str_do_log(fsp));
+               return NULL;
+       }
+       state->handle = handle;
+       state->fsp = fsp;
+
+       subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
+       if (tevent_req_nomem(subreq, req)) {
+               do_log(SMB_VFS_OP_FSYNC_SEND, false, handle, "%s",
+                      fsp_str_do_log(fsp));
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smb_full_audit_fsync_done, req);
+
+       do_log(SMB_VFS_OP_FSYNC_SEND, true, handle, "%s", fsp_str_do_log(fsp));
+       return req;
+}
+
+static void smb_full_audit_fsync_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct smb_full_audit_fsync_state *state = tevent_req_data(
+               req, struct smb_full_audit_fsync_state);
+
+       state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->err);
+       TALLOC_FREE(subreq);
+       tevent_req_done(req);
+}
+
+static int smb_full_audit_fsync_recv(struct tevent_req *req, int *err)
+{
+       struct smb_full_audit_fsync_state *state = tevent_req_data(
+               req, struct smb_full_audit_fsync_state);
+
+       if (tevent_req_is_unix_error(req, err)) {
+               do_log(SMB_VFS_OP_FSYNC_RECV, false, state->handle, "%s",
+                      fsp_str_do_log(state->fsp));
+               return -1;
+       }
+
+       do_log(SMB_VFS_OP_FSYNC_RECV, (state->ret >= 0), state->handle, "%s",
+              fsp_str_do_log(state->fsp));
+
+       *err = state->err;
+       return state->ret;
+}
+
 static int smb_full_audit_stat(vfs_handle_struct *handle,
                               struct smb_filename *smb_fname)
 {
@@ -2271,6 +2343,8 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
        .recvfile_fn = smb_full_audit_recvfile,
        .rename_fn = smb_full_audit_rename,
        .fsync_fn = smb_full_audit_fsync,
+       .fsync_send_fn = smb_full_audit_fsync_send,
+       .fsync_recv_fn = smb_full_audit_fsync_recv,
        .stat_fn = smb_full_audit_stat,
        .fstat_fn = smb_full_audit_fstat,
        .lstat_fn = smb_full_audit_lstat,
index 16eb624ebb7a5c9362094a33e01d800794508cb1..ff9cf051203cb38b77a15c51ef6a1caf373a4e3b 100644 (file)
@@ -791,6 +791,69 @@ static int smb_time_audit_fsync(vfs_handle_struct *handle, files_struct *fsp)
        return result;
 }
 
+struct smb_time_audit_fsync_state {
+       struct timespec ts1;
+       int ret;
+       int err;
+};
+
+static void smb_time_audit_fsync_done(struct tevent_req *subreq);
+
+static struct tevent_req *smb_time_audit_fsync_send(
+       struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev, struct files_struct *fsp)
+{
+       struct tevent_req *req, *subreq;
+       struct smb_time_audit_fsync_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct smb_time_audit_fsync_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       clock_gettime_mono(&state->ts1);
+
+       subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smb_time_audit_fsync_done, req);
+       return req;
+}
+
+static void smb_time_audit_fsync_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct smb_time_audit_fsync_state *state = tevent_req_data(
+               req, struct smb_time_audit_fsync_state);
+
+       state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->err);
+       TALLOC_FREE(subreq);
+       tevent_req_done(req);
+}
+
+static int smb_time_audit_fsync_recv(struct tevent_req *req, int *err)
+{
+       struct smb_time_audit_fsync_state *state = tevent_req_data(
+               req, struct smb_time_audit_fsync_state);
+       struct timespec ts2;
+       double timediff;
+
+       clock_gettime_mono(&ts2);
+       timediff = nsec_time_diff(&ts2,&state->ts1)*1.0e-9;
+
+       if (timediff > audit_timeout) {
+               smb_time_audit_log("fsync", timediff);
+       }
+
+       if (tevent_req_is_unix_error(req, err)) {
+               return -1;
+       }
+       *err = state->err;
+       return state->ret;
+}
+
 static int smb_time_audit_stat(vfs_handle_struct *handle,
                               struct smb_filename *fname)
 {
@@ -2283,6 +2346,8 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
        .recvfile_fn = smb_time_audit_recvfile,
        .rename_fn = smb_time_audit_rename,
        .fsync_fn = smb_time_audit_fsync,
+       .fsync_send_fn = smb_time_audit_fsync_send,
+       .fsync_recv_fn = smb_time_audit_fsync_recv,
        .stat_fn = smb_time_audit_stat,
        .fstat_fn = smb_time_audit_fstat,
        .lstat_fn = smb_time_audit_lstat,
index 48d74cd17a6bb26a92d6794ccb2543af9ee9f97f..349f0a0b2f93bc5e49540113bfbf35c98af901d6 100644 (file)
@@ -1725,6 +1725,68 @@ int smb_vfs_call_fsync(struct vfs_handle_struct *handle,
        return handle->fns->fsync_fn(handle, fsp);
 }
 
+struct smb_vfs_call_fsync_state {
+       int (*recv_fn)(struct tevent_req *req, int *err);
+       int retval;
+};
+
+static void smb_vfs_call_fsync_done(struct tevent_req *subreq);
+
+struct tevent_req *smb_vfs_call_fsync_send(struct vfs_handle_struct *handle,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct files_struct *fsp)
+{
+       struct tevent_req *req, *subreq;
+       struct smb_vfs_call_fsync_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct smb_vfs_call_fsync_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       VFS_FIND(fsync_send);
+       state->recv_fn = handle->fns->fsync_recv_fn;
+
+       subreq = handle->fns->fsync_send_fn(handle, state, ev, fsp);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smb_vfs_call_fsync_done, req);
+       return req;
+}
+
+static void smb_vfs_call_fsync_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct smb_vfs_call_fsync_state *state = tevent_req_data(
+               req, struct smb_vfs_call_fsync_state);
+       int err;
+
+       state->retval = state->recv_fn(subreq, &err);
+       TALLOC_FREE(subreq);
+       if (state->retval == -1) {
+               tevent_req_error(req, err);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+int SMB_VFS_FSYNC_RECV(struct tevent_req *req, int *perrno)
+{
+       struct smb_vfs_call_fsync_state *state = tevent_req_data(
+               req, struct smb_vfs_call_fsync_state);
+       int err;
+
+       if (tevent_req_is_unix_error(req, &err)) {
+               *perrno = err;
+               return -1;
+       }
+       return state->retval;
+}
+
+
 int smb_vfs_call_stat(struct vfs_handle_struct *handle,
                      struct smb_filename *smb_fname)
 {