[PATCH] Enhance time sampling of async IO VFS functions

Jeremy Allison jra at samba.org
Tue Mar 1 00:52:29 UTC 2016


On Mon, Feb 29, 2016 at 05:26:34PM +0100, Ralph Boehme wrote:
> On Sun, Feb 28, 2016 at 10:45:47AM -0800, Jeremy Allison wrote:
> > On Sun, Feb 28, 2016 at 05:45:24PM +0100, Volker Lendecke wrote:
> > > On Sun, Feb 28, 2016 at 08:39:19AM -0800, Jeremy Allison wrote:
> > > > > Is it theoretically possible to implement this feature without modifying
> > > > > tevent, just within asys.c? Apologies for not coming up with a polished
> > > > > proposal mself, but I would like to avoid bloat in such a central
> > > > > structure if possible.
> > > > 
> > > > Sure, if we change the param blocks to the smbd VFS aio
> > > > calls then we can do it only inside smbd.
> > > > 
> > > > I think the question Ralph had is more about if you
> > > > think this is worthwhile to add as a feature to tevent ?
> > > > 
> > > > Or did you just answer that question ? :-) :-).
> > > 
> > > Right now we have one case where someone really needs this feature. We
> > > have many cases that don't. So if there's an elegant way to do this
> > > without adding 8 bytes to struct tevent_req I'd prefer that.
> > 
> > I think that answers the question.
> > 
> > Ralph, I'm sorry - but can you re-do this by creating
> > a 'struct aiocb {... stuff...}' struct for the VFS
> > calls, so we don't have to keep adding extra params
> > if we need something new ?
> 
> attached. Please review & push if ok. I know this is cumbersome to
> review, so a big thanks in advance! :)
> 
> Hopefully I got the error return wrapping right in all places...

Looks really nice ! Thanks. I'm going to run a local make test
and if all goes well will push tomorrow.

> -- 
> SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
> phone: +49-551-370000-0, fax: +49-551-370000-9
> AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
> http://www.sernet.de,mailto:kontakt@sernet.de

> From 96abc158dc881f2d859279d619c0162ae2a7bf8e Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Fri, 26 Feb 2016 10:54:01 +0100
> Subject: [PATCH 1/8] s3/vfs: wrap async io function args inside struct
>  vfs_aio_state
> 
> Subsequent commits that are going to track aio request duration in the
> aio backends will use this.
> 
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
>  examples/VFS/skel_opaque.c       | 15 ++++++++-----
>  examples/VFS/skel_transparent.c  | 33 +++++++++++++++-------------
>  source3/include/vfs.h            | 17 ++++++++++-----
>  source3/modules/vfs_aio_fork.c   | 39 +++++++++++++++------------------
>  source3/modules/vfs_aio_linux.c  | 19 ++++++++--------
>  source3/modules/vfs_commit.c     | 11 +++++-----
>  source3/modules/vfs_default.c    | 18 ++++++++-------
>  source3/modules/vfs_full_audit.c | 33 +++++++++++++++-------------
>  source3/modules/vfs_glusterfs.c  | 23 +++++++++-----------
>  source3/modules/vfs_gpfs.c       | 22 ++++++++++---------
>  source3/modules/vfs_time_audit.c | 33 +++++++++++++++-------------
>  source3/modules/vfs_tsmsm.c      | 22 ++++++++++---------
>  source3/smbd/aio.c               | 33 ++++++++++++++--------------
>  source3/smbd/smb2_flush.c        |  7 +++---
>  source3/smbd/vfs.c               | 47 ++++++++++++++++++++--------------------
>  15 files changed, 195 insertions(+), 177 deletions(-)
> 
> diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c
> index 8961627..a92be13 100644
> --- a/examples/VFS/skel_opaque.c
> +++ b/examples/VFS/skel_opaque.c
> @@ -241,9 +241,10 @@ static struct tevent_req *skel_pread_send(struct vfs_handle_struct *handle,
>  	return NULL;
>  }
>  
> -static ssize_t skel_pread_recv(struct tevent_req *req, int *err)
> +static ssize_t skel_pread_recv(struct tevent_req *req,
> +			       struct vfs_aio_state *vfs_aio_state)
>  {
> -	*err = ENOSYS;
> +	vfs_aio_state->error = ENOSYS;
>  	return -1;
>  }
>  
> @@ -271,9 +272,10 @@ static struct tevent_req *skel_pwrite_send(struct vfs_handle_struct *handle,
>  	return NULL;
>  }
>  
> -static ssize_t skel_pwrite_recv(struct tevent_req *req, int *err)
> +static ssize_t skel_pwrite_recv(struct tevent_req *req,
> +				struct vfs_aio_state *vfs_aio_state)
>  {
> -	*err = ENOSYS;
> +	vfs_aio_state->error = ENOSYS;
>  	return -1;
>  }
>  
> @@ -321,9 +323,10 @@ static struct tevent_req *skel_fsync_send(struct vfs_handle_struct *handle,
>  	return NULL;
>  }
>  
> -static int skel_fsync_recv(struct tevent_req *req, int *err)
> +static int skel_fsync_recv(struct tevent_req *req,
> +			   struct vfs_aio_state *vfs_aio_state)
>  {
> -	*err = ENOSYS;
> +	vfs_aio_state->error = ENOSYS;
>  	return -1;
>  }
>  
> diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c
> index ac82432..3febf97 100644
> --- a/examples/VFS/skel_transparent.c
> +++ b/examples/VFS/skel_transparent.c
> @@ -241,7 +241,7 @@ static ssize_t skel_pread(vfs_handle_struct *handle, files_struct *fsp,
>  
>  struct skel_pread_state {
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void skel_pread_done(struct tevent_req *subreq);
> @@ -275,20 +275,21 @@ static void skel_pread_done(struct tevent_req *subreq)
>  	struct skel_pread_state *state =
>  	    tevent_req_data(req, struct skel_pread_state);
>  
> -	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t skel_pread_recv(struct tevent_req *req, int *err)
> +static ssize_t skel_pread_recv(struct tevent_req *req,
> +			       struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct skel_pread_state *state =
>  	    tevent_req_data(req, struct skel_pread_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> @@ -306,7 +307,7 @@ static ssize_t skel_pwrite(vfs_handle_struct *handle, files_struct *fsp,
>  
>  struct skel_pwrite_state {
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void skel_pwrite_done(struct tevent_req *subreq);
> @@ -341,20 +342,21 @@ static void skel_pwrite_done(struct tevent_req *subreq)
>  	struct skel_pwrite_state *state =
>  	    tevent_req_data(req, struct skel_pwrite_state);
>  
> -	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t skel_pwrite_recv(struct tevent_req *req, int *err)
> +static ssize_t skel_pwrite_recv(struct tevent_req *req,
> +				struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct skel_pwrite_state *state =
>  	    tevent_req_data(req, struct skel_pwrite_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> @@ -391,7 +393,7 @@ static int skel_fsync(vfs_handle_struct *handle, files_struct *fsp)
>  
>  struct skel_fsync_state {
>  	int ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void skel_fsync_done(struct tevent_req *subreq);
> @@ -423,20 +425,21 @@ static void skel_fsync_done(struct tevent_req *subreq)
>  	struct skel_fsync_state *state =
>  	    tevent_req_data(req, struct skel_fsync_state);
>  
> -	state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static int skel_fsync_recv(struct tevent_req *req, int *err)
> +static int skel_fsync_recv(struct tevent_req *req,
> +			   struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct skel_fsync_state *state =
>  	    tevent_req_data(req, struct skel_fsync_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> diff --git a/source3/include/vfs.h b/source3/include/vfs.h
> index b291206..ab67aab 100644
> --- a/source3/include/vfs.h
> +++ b/source3/include/vfs.h
> @@ -177,6 +177,7 @@
>  		const struct smb_filename * */
>  /* Version 35 - Change rmdir from const char *, to
>  		const struct smb_filename * */
> +/* Version 35 - Wrap aio async funtions args in a struct vfs_aio_state */
>  
>  #define SMB_VFS_INTERFACE_VERSION 35
>  
> @@ -518,6 +519,10 @@ enum vfs_fallocate_flags {
>  	VFS_FALLOCATE_FL_PUNCH_HOLE		= 0x0002,
>  };
>  
> +struct vfs_aio_state {
> +	int error;
> +};
> +
>  /*
>      Available VFS operations. These values must be in sync with vfs_ops struct
>      (struct vfs_fn_pointers and struct vfs_handle_pointers inside of struct vfs_ops).
> @@ -599,7 +604,7 @@ struct vfs_fn_pointers {
>  					    struct files_struct *fsp,
>  					    void *data,
>  					    size_t n, off_t offset);
> -	ssize_t (*pread_recv_fn)(struct tevent_req *req, int *err);
> +	ssize_t (*pread_recv_fn)(struct tevent_req *req, struct vfs_aio_state *state);
>  	ssize_t (*write_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, const void *data, size_t n);
>  	ssize_t (*pwrite_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, const void *data, size_t n, off_t offset);
>  	struct tevent_req *(*pwrite_send_fn)(struct vfs_handle_struct *handle,
> @@ -608,7 +613,7 @@ struct vfs_fn_pointers {
>  					     struct files_struct *fsp,
>  					     const void *data,
>  					     size_t n, off_t offset);
> -	ssize_t (*pwrite_recv_fn)(struct tevent_req *req, int *err);
> +	ssize_t (*pwrite_recv_fn)(struct tevent_req *req, struct vfs_aio_state *state);
>  	off_t (*lseek_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, off_t offset, int whence);
>  	ssize_t (*sendfile_fn)(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *header, off_t offset, size_t count);
>  	ssize_t (*recvfile_fn)(struct vfs_handle_struct *handle, int fromfd, files_struct *tofsp, off_t offset, size_t count);
> @@ -620,7 +625,7 @@ struct vfs_fn_pointers {
>  					    TALLOC_CTX *mem_ctx,
>  					    struct tevent_context *ev,
>  					    struct files_struct *fsp);
> -	int (*fsync_recv_fn)(struct tevent_req *req, int *err);
> +	int (*fsync_recv_fn)(struct tevent_req *req, struct vfs_aio_state *state);
>  	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);
> @@ -1022,7 +1027,7 @@ struct tevent_req *smb_vfs_call_pread_send(struct vfs_handle_struct *handle,
>  					   struct files_struct *fsp,
>  					   void *data,
>  					   size_t n, off_t offset);
> -ssize_t SMB_VFS_PREAD_RECV(struct tevent_req *req, int *perrno);
> +ssize_t SMB_VFS_PREAD_RECV(struct tevent_req *req, struct vfs_aio_state *state);
>  
>  ssize_t smb_vfs_call_write(struct vfs_handle_struct *handle,
>  			   struct files_struct *fsp, const void *data,
> @@ -1036,7 +1041,7 @@ struct tevent_req *smb_vfs_call_pwrite_send(struct vfs_handle_struct *handle,
>  					    struct files_struct *fsp,
>  					    const void *data,
>  					    size_t n, off_t offset);
> -ssize_t SMB_VFS_PWRITE_RECV(struct tevent_req *req, int *perrno);
> +ssize_t SMB_VFS_PWRITE_RECV(struct tevent_req *req, struct vfs_aio_state *state);
>  
>  off_t smb_vfs_call_lseek(struct vfs_handle_struct *handle,
>  			     struct files_struct *fsp, off_t offset,
> @@ -1057,7 +1062,7 @@ 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_FSYNC_RECV(struct tevent_req *req, struct vfs_aio_state *state);
>  
>  int smb_vfs_call_stat(struct vfs_handle_struct *handle,
>  		      struct smb_filename *smb_fname);
> diff --git a/source3/modules/vfs_aio_fork.c b/source3/modules/vfs_aio_fork.c
> index 472ef0c..4322381 100644
> --- a/source3/modules/vfs_aio_fork.c
> +++ b/source3/modules/vfs_aio_fork.c
> @@ -534,7 +534,7 @@ static int get_idle_child(struct vfs_handle_struct *handle,
>  struct aio_fork_pread_state {
>  	struct aio_child *child;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void aio_fork_pread_done(struct tevent_req *subreq);
> @@ -632,28 +632,27 @@ static void aio_fork_pread_done(struct tevent_req *subreq)
>  
>  	retbuf = (struct rw_ret *)buf;
>  	state->ret = retbuf->size;
> -	state->err = retbuf->ret_errno;
> +	state->vfs_aio_state.error = retbuf->ret_errno;
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t aio_fork_pread_recv(struct tevent_req *req, int *err)
> +static ssize_t aio_fork_pread_recv(struct tevent_req *req,
> +				   struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct aio_fork_pread_state *state = tevent_req_data(
>  		req, struct aio_fork_pread_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	if (state->ret == -1) {
> -		*err = state->err;
> -	}
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
>  struct aio_fork_pwrite_state {
>  	struct aio_child *child;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void aio_fork_pwrite_done(struct tevent_req *subreq);
> @@ -748,28 +747,27 @@ static void aio_fork_pwrite_done(struct tevent_req *subreq)
>  
>  	retbuf = (struct rw_ret *)buf;
>  	state->ret = retbuf->size;
> -	state->err = retbuf->ret_errno;
> +	state->vfs_aio_state.error = retbuf->ret_errno;
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t aio_fork_pwrite_recv(struct tevent_req *req, int *err)
> +static ssize_t aio_fork_pwrite_recv(struct tevent_req *req,
> +				    struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct aio_fork_pwrite_state *state = tevent_req_data(
>  		req, struct aio_fork_pwrite_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	if (state->ret == -1) {
> -		*err = state->err;
> -	}
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
>  struct aio_fork_fsync_state {
>  	struct aio_child *child;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void aio_fork_fsync_done(struct tevent_req *subreq);
> @@ -856,21 +854,20 @@ static void aio_fork_fsync_done(struct tevent_req *subreq)
>  
>  	retbuf = (struct rw_ret *)buf;
>  	state->ret = retbuf->size;
> -	state->err = retbuf->ret_errno;
> +	state->vfs_aio_state.error = retbuf->ret_errno;
>  	tevent_req_done(req);
>  }
>  
> -static int aio_fork_fsync_recv(struct tevent_req *req, int *err)
> +static int aio_fork_fsync_recv(struct tevent_req *req,
> +			       struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct aio_fork_fsync_state *state = tevent_req_data(
>  		req, struct aio_fork_fsync_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	if (state->ret == -1) {
> -		*err = state->err;
> -	}
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> diff --git a/source3/modules/vfs_aio_linux.c b/source3/modules/vfs_aio_linux.c
> index 4f6230a..b1d33b5 100644
> --- a/source3/modules/vfs_aio_linux.c
> +++ b/source3/modules/vfs_aio_linux.c
> @@ -139,7 +139,7 @@ static bool init_aio_linux(struct vfs_handle_struct *handle)
>  struct aio_linux_state {
>  	struct iocb event_iocb;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static struct tevent_req *aio_linux_pread_send(
> @@ -289,36 +289,35 @@ static void aio_linux_done(struct tevent_context *event_ctx,
>  
>  		if (finished.res < 0) {
>  			state->ret = -1;
> -			state->err = -finished.res;
> +			state->vfs_aio_state.error = -finished.res;
>  		} else {
>  			state->ret = finished.res;
> -			state->err = 0;
>  		}
>  		tevent_req_done(req);
>  		num_events -= 1;
>  	}
>  }
>  
> -static ssize_t aio_linux_recv(struct tevent_req *req, int *err)
> +static ssize_t aio_linux_recv(struct tevent_req *req,
> +			      struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct aio_linux_state *state = tevent_req_data(
>  		req, struct aio_linux_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	if (state->ret == -1) {
> -		*err = state->err;
> -	}
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> -static int aio_linux_int_recv(struct tevent_req *req, int *err)
> +static int aio_linux_int_recv(struct tevent_req *req,
> +			      struct vfs_aio_state *vfs_aio_state)
>  {
>  	/*
>  	 * Use implicit conversion ssize_t->int
>  	 */
> -	return aio_linux_recv(req, err);
> +	return aio_linux_recv(req, vfs_aio_state);
>  }
>  
>  static struct vfs_fn_pointers vfs_aio_linux_fns = {
> diff --git a/source3/modules/vfs_commit.c b/source3/modules/vfs_commit.c
> index f1e2743..b870eb2 100644
> --- a/source3/modules/vfs_commit.c
> +++ b/source3/modules/vfs_commit.c
> @@ -289,7 +289,7 @@ struct commit_pwrite_state {
>  	struct vfs_handle_struct *handle;
>  	struct files_struct *fsp;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void commit_pwrite_written(struct tevent_req *subreq);
> @@ -328,7 +328,7 @@ static void commit_pwrite_written(struct tevent_req *subreq)
>  		req, struct commit_pwrite_state);
>  	int commit_ret;
>  
> -	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  
>  	if (state->ret <= 0) {
> @@ -350,15 +350,16 @@ static void commit_pwrite_written(struct tevent_req *subreq)
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t commit_pwrite_recv(struct tevent_req *req, int *err)
> +static ssize_t commit_pwrite_recv(struct tevent_req *req,
> +				  struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct commit_pwrite_state *state =
>  		tevent_req_data(req, struct commit_pwrite_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
> index b13b517..0fa7a00 100644
> --- a/source3/modules/vfs_default.c
> +++ b/source3/modules/vfs_default.c
> @@ -742,7 +742,7 @@ struct vfswrap_asys_state {
>  	struct asys_context *asys_ctx;
>  	struct tevent_req *req;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  	SMBPROFILE_BASIC_ASYNC_STATE(profile_basic);
>  	SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
>  };
> @@ -889,33 +889,35 @@ static void vfswrap_asys_finished(struct tevent_context *ev,
>  		SMBPROFILE_BASIC_ASYNC_END(state->profile_basic);
>  		SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
>  		state->ret = result->ret;
> -		state->err = result->err;
> +		state->vfs_aio_state.error = result->err;
>  		tevent_req_defer_callback(req, ev);
>  		tevent_req_done(req);
>  	}
>  }
>  
> -static ssize_t vfswrap_asys_ssize_t_recv(struct tevent_req *req, int *err)
> +static ssize_t vfswrap_asys_ssize_t_recv(struct tevent_req *req,
> +					 struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct vfswrap_asys_state *state = tevent_req_data(
>  		req, struct vfswrap_asys_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> -static int vfswrap_asys_int_recv(struct tevent_req *req, int *err)
> +static int vfswrap_asys_int_recv(struct tevent_req *req,
> +				 struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct vfswrap_asys_state *state = tevent_req_data(
>  		req, struct vfswrap_asys_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c
> index 3dd2005..e4f541b 100644
> --- a/source3/modules/vfs_full_audit.c
> +++ b/source3/modules/vfs_full_audit.c
> @@ -1020,7 +1020,7 @@ struct smb_full_audit_pread_state {
>  	vfs_handle_struct *handle;
>  	files_struct *fsp;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void smb_full_audit_pread_done(struct tevent_req *subreq);
> @@ -1063,17 +1063,18 @@ static void smb_full_audit_pread_done(struct tevent_req *subreq)
>  	struct smb_full_audit_pread_state *state = tevent_req_data(
>  		req, struct smb_full_audit_pread_state);
>  
> -	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t smb_full_audit_pread_recv(struct tevent_req *req, int *err)
> +static ssize_t smb_full_audit_pread_recv(struct tevent_req *req,
> +					 struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct smb_full_audit_pread_state *state = tevent_req_data(
>  		req, struct smb_full_audit_pread_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		do_log(SMB_VFS_OP_PREAD_RECV, false, state->handle, "%s",
>  		       fsp_str_do_log(state->fsp));
>  		return -1;
> @@ -1082,7 +1083,7 @@ static ssize_t smb_full_audit_pread_recv(struct tevent_req *req, int *err)
>  	do_log(SMB_VFS_OP_PREAD_RECV, (state->ret >= 0), state->handle, "%s",
>  	       fsp_str_do_log(state->fsp));
>  
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> @@ -1117,7 +1118,7 @@ struct smb_full_audit_pwrite_state {
>  	vfs_handle_struct *handle;
>  	files_struct *fsp;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void smb_full_audit_pwrite_done(struct tevent_req *subreq);
> @@ -1161,17 +1162,18 @@ static void smb_full_audit_pwrite_done(struct tevent_req *subreq)
>  	struct smb_full_audit_pwrite_state *state = tevent_req_data(
>  		req, struct smb_full_audit_pwrite_state);
>  
> -	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t smb_full_audit_pwrite_recv(struct tevent_req *req, int *err)
> +static ssize_t smb_full_audit_pwrite_recv(struct tevent_req *req,
> +					  struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct smb_full_audit_pwrite_state *state = tevent_req_data(
>  		req, struct smb_full_audit_pwrite_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		do_log(SMB_VFS_OP_PWRITE_RECV, false, state->handle, "%s",
>  		       fsp_str_do_log(state->fsp));
>  		return -1;
> @@ -1180,7 +1182,7 @@ static ssize_t smb_full_audit_pwrite_recv(struct tevent_req *req, int *err)
>  	do_log(SMB_VFS_OP_PWRITE_RECV, (state->ret >= 0), state->handle, "%s",
>  	       fsp_str_do_log(state->fsp));
>  
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> @@ -1258,7 +1260,7 @@ struct smb_full_audit_fsync_state {
>  	vfs_handle_struct *handle;
>  	files_struct *fsp;
>  	int ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void smb_full_audit_fsync_done(struct tevent_req *subreq);
> @@ -1299,17 +1301,18 @@ static void smb_full_audit_fsync_done(struct tevent_req *subreq)
>  	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);
> +	state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static int smb_full_audit_fsync_recv(struct tevent_req *req, int *err)
> +static int smb_full_audit_fsync_recv(struct tevent_req *req,
> +				     struct vfs_aio_state *vfs_aio_state)
>  {
>  	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)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		do_log(SMB_VFS_OP_FSYNC_RECV, false, state->handle, "%s",
>  		       fsp_str_do_log(state->fsp));
>  		return -1;
> @@ -1318,7 +1321,7 @@ static int smb_full_audit_fsync_recv(struct tevent_req *req, int *err)
>  	do_log(SMB_VFS_OP_FSYNC_RECV, (state->ret >= 0), state->handle, "%s",
>  	       fsp_str_do_log(state->fsp));
>  
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
> index 8e5316d..556c137 100644
> --- a/source3/modules/vfs_glusterfs.c
> +++ b/source3/modules/vfs_glusterfs.c
> @@ -498,9 +498,9 @@ struct glusterfs_aio_wrapper {
>  
>  struct glusterfs_aio_state {
>  	ssize_t ret;
> -	int err;
>  	struct tevent_req *req;
>  	bool cancelled;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static int aio_wrapper_destructor(struct glusterfs_aio_wrapper *wrap)
> @@ -524,10 +524,9 @@ static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data)
>  
>  	if (ret < 0) {
>  		state->ret = -1;
> -		state->err = errno;
> +		state->vfs_aio_state.error = errno;
>  	} else {
>  		state->ret = ret;
> -		state->err = 0;
>  	}
>  
>  	/*
> @@ -648,7 +647,7 @@ static struct glusterfs_aio_state *aio_state_create(TALLOC_CTX *mem_ctx)
>  		return NULL;
>  	}
>  
> -	state = talloc(NULL, struct glusterfs_aio_state);
> +	state = talloc_zero(NULL, struct glusterfs_aio_state);
>  
>  	if (state == NULL) {
>  		TALLOC_FREE(req);
> @@ -657,8 +656,6 @@ static struct glusterfs_aio_state *aio_state_create(TALLOC_CTX *mem_ctx)
>  
>  	talloc_set_destructor(wrapper, aio_wrapper_destructor);
>  	state->cancelled = false;
> -	state->ret = 0;
> -	state->err = 0;
>  	state->req = req;
>  
>  	wrapper->state = state;
> @@ -736,7 +733,8 @@ static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
>  	return req;
>  }
>  
> -static ssize_t vfs_gluster_recv(struct tevent_req *req, int *err)
> +static ssize_t vfs_gluster_recv(struct tevent_req *req,
> +				struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct glusterfs_aio_state *state = NULL;
>  	struct glusterfs_aio_wrapper *wrapper = NULL;
> @@ -754,13 +752,11 @@ static ssize_t vfs_gluster_recv(struct tevent_req *req, int *err)
>  		return -1;
>  	}
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	if (state->ret == -1) {
> -		*err = state->err;
> -	}
>  
> +	*vfs_aio_state = state->vfs_aio_state;
>  	ret = state->ret;
>  
>  	/* Clean up the state, it is in a NULL context. */
> @@ -850,12 +846,13 @@ static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
>  	return req;
>  }
>  
> -static int vfs_gluster_fsync_recv(struct tevent_req *req, int *err)
> +static int vfs_gluster_fsync_recv(struct tevent_req *req,
> +				  struct vfs_aio_state *vfs_aio_state)
>  {
>  	/*
>  	 * Use implicit conversion ssize_t->int
>  	 */
> -	return vfs_gluster_recv(req, err);
> +	return vfs_gluster_recv(req, vfs_aio_state);
>  }
>  
>  static int vfs_gluster_stat(struct vfs_handle_struct *handle,
> diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c
> index 33a30d0..1616b4e 100644
> --- a/source3/modules/vfs_gpfs.c
> +++ b/source3/modules/vfs_gpfs.c
> @@ -2317,8 +2317,8 @@ static ssize_t vfs_gpfs_pread(vfs_handle_struct *handle, files_struct *fsp,
>  struct vfs_gpfs_pread_state {
>  	struct files_struct *fsp;
>  	ssize_t ret;
> -	int err;
>  	bool was_offline;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void vfs_gpfs_pread_done(struct tevent_req *subreq);
> @@ -2355,21 +2355,22 @@ static void vfs_gpfs_pread_done(struct tevent_req *subreq)
>  	struct vfs_gpfs_pread_state *state = tevent_req_data(
>  		req, struct vfs_gpfs_pread_state);
>  
> -	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t vfs_gpfs_pread_recv(struct tevent_req *req, int *err)
> +static ssize_t vfs_gpfs_pread_recv(struct tevent_req *req,
> +				   struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct vfs_gpfs_pread_state *state = tevent_req_data(
>  		req, struct vfs_gpfs_pread_state);
>  	struct files_struct *fsp = state->fsp;
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  
>  	if ((state->ret != -1) && state->was_offline) {
>  		DEBUG(10, ("sending notify\n"));
> @@ -2403,8 +2404,8 @@ static ssize_t vfs_gpfs_pwrite(vfs_handle_struct *handle, files_struct *fsp,
>  struct vfs_gpfs_pwrite_state {
>  	struct files_struct *fsp;
>  	ssize_t ret;
> -	int err;
>  	bool was_offline;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void vfs_gpfs_pwrite_done(struct tevent_req *subreq);
> @@ -2442,21 +2443,22 @@ static void vfs_gpfs_pwrite_done(struct tevent_req *subreq)
>  	struct vfs_gpfs_pwrite_state *state = tevent_req_data(
>  		req, struct vfs_gpfs_pwrite_state);
>  
> -	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req, int *err)
> +static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req,
> +				    struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct vfs_gpfs_pwrite_state *state = tevent_req_data(
>  		req, struct vfs_gpfs_pwrite_state);
>  	struct files_struct *fsp = state->fsp;
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  
>  	if ((state->ret != -1) && state->was_offline) {
>  		DEBUG(10, ("sending notify\n"));
> diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c
> index 11866fa..08acc4c 100644
> --- a/source3/modules/vfs_time_audit.c
> +++ b/source3/modules/vfs_time_audit.c
> @@ -678,7 +678,7 @@ struct smb_time_audit_pread_state {
>  	struct files_struct *fsp;
>  	struct timespec ts1;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void smb_time_audit_pread_done(struct tevent_req *subreq);
> @@ -715,12 +715,13 @@ static void smb_time_audit_pread_done(struct tevent_req *subreq)
>  	struct smb_time_audit_pread_state *state = tevent_req_data(
>  		req, struct smb_time_audit_pread_state);
>  
> -	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t smb_time_audit_pread_recv(struct tevent_req *req, int *err)
> +static ssize_t smb_time_audit_pread_recv(struct tevent_req *req,
> +					 struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct smb_time_audit_pread_state *state = tevent_req_data(
>  		req, struct smb_time_audit_pread_state);
> @@ -734,10 +735,10 @@ static ssize_t smb_time_audit_pread_recv(struct tevent_req *req, int *err)
>  		smb_time_audit_log_fsp("pread", timediff, state->fsp);
>  	}
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> @@ -786,7 +787,7 @@ struct smb_time_audit_pwrite_state {
>  	struct files_struct *fsp;
>  	struct timespec ts1;
>  	ssize_t ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void smb_time_audit_pwrite_done(struct tevent_req *subreq);
> @@ -823,12 +824,13 @@ static void smb_time_audit_pwrite_done(struct tevent_req *subreq)
>  	struct smb_time_audit_pwrite_state *state = tevent_req_data(
>  		req, struct smb_time_audit_pwrite_state);
>  
> -	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t smb_time_audit_pwrite_recv(struct tevent_req *req, int *err)
> +static ssize_t smb_time_audit_pwrite_recv(struct tevent_req *req,
> +					  struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct smb_time_audit_pwrite_state *state = tevent_req_data(
>  		req, struct smb_time_audit_pwrite_state);
> @@ -842,10 +844,10 @@ static ssize_t smb_time_audit_pwrite_recv(struct tevent_req *req, int *err)
>  		smb_time_audit_log_fsp("pwrite", timediff, state->fsp);
>  	}
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> @@ -953,7 +955,7 @@ struct smb_time_audit_fsync_state {
>  	struct files_struct *fsp;
>  	struct timespec ts1;
>  	int ret;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void smb_time_audit_fsync_done(struct tevent_req *subreq);
> @@ -988,12 +990,13 @@ static void smb_time_audit_fsync_done(struct tevent_req *subreq)
>  	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);
> +	state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static int smb_time_audit_fsync_recv(struct tevent_req *req, int *err)
> +static int smb_time_audit_fsync_recv(struct tevent_req *req,
> +				     struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct smb_time_audit_fsync_state *state = tevent_req_data(
>  		req, struct smb_time_audit_fsync_state);
> @@ -1007,10 +1010,10 @@ static int smb_time_audit_fsync_recv(struct tevent_req *req, int *err)
>  		smb_time_audit_log_fsp("fsync", timediff, state->fsp);
>  	}
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> diff --git a/source3/modules/vfs_tsmsm.c b/source3/modules/vfs_tsmsm.c
> index e4bc7eb..91daa6f 100644
> --- a/source3/modules/vfs_tsmsm.c
> +++ b/source3/modules/vfs_tsmsm.c
> @@ -289,8 +289,8 @@ static bool tsmsm_aio_force(struct vfs_handle_struct *handle, struct files_struc
>  struct tsmsm_pread_state {
>  	struct files_struct *fsp;
>  	ssize_t ret;
> -	int err;
>  	bool was_offline;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void tsmsm_pread_done(struct tevent_req *subreq);
> @@ -326,17 +326,18 @@ static void tsmsm_pread_done(struct tevent_req *subreq)
>  	struct tsmsm_pread_state *state = tevent_req_data(
>  		req, struct tsmsm_pread_state);
>  
> -	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t tsmsm_pread_recv(struct tevent_req *req, int *err)
> +static ssize_t tsmsm_pread_recv(struct tevent_req *req,
> +				struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct tsmsm_pread_state *state = tevent_req_data(
>  		req, struct tsmsm_pread_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
>  	if (state->ret >= 0 && state->was_offline) {
> @@ -345,15 +346,15 @@ static ssize_t tsmsm_pread_recv(struct tevent_req *req, int *err)
>  			     FILE_NOTIFY_CHANGE_ATTRIBUTES,
>  			     fsp->fsp_name->base_name);
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
>  struct tsmsm_pwrite_state {
>  	struct files_struct *fsp;
>  	ssize_t ret;
> -	int err;
>  	bool was_offline;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void tsmsm_pwrite_done(struct tevent_req *subreq);
> @@ -390,17 +391,18 @@ static void tsmsm_pwrite_done(struct tevent_req *subreq)
>  	struct tsmsm_pwrite_state *state = tevent_req_data(
>  		req, struct tsmsm_pwrite_state);
>  
> -	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->err);
> +	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	tevent_req_done(req);
>  }
>  
> -static ssize_t tsmsm_pwrite_recv(struct tevent_req *req, int *err)
> +static ssize_t tsmsm_pwrite_recv(struct tevent_req *req,
> +				 struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct tsmsm_pwrite_state *state = tevent_req_data(
>  		req, struct tsmsm_pwrite_state);
>  
> -	if (tevent_req_is_unix_error(req, err)) {
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
>  	if (state->ret >= 0 && state->was_offline) {
> @@ -409,7 +411,7 @@ static ssize_t tsmsm_pwrite_recv(struct tevent_req *req, int *err)
>  			     FILE_NOTIFY_CHANGE_ATTRIBUTES,
>  			     fsp->fsp_name->base_name);
>  	}
> -	*err = state->err;
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->ret;
>  }
>  
> diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
> index 32a1ce0..2958ac3 100644
> --- a/source3/smbd/aio.c
> +++ b/source3/smbd/aio.c
> @@ -274,13 +274,13 @@ static void aio_pread_smb1_done(struct tevent_req *req)
>  	char *outbuf = (char *)aio_ex->outbuf.data;
>  	char *data = smb_buf(outbuf) + 1 /* padding byte */;
>  	ssize_t nread;
> -	int err;
> +	struct vfs_aio_state vfs_aio_state;
>  
> -	nread = SMB_VFS_PREAD_RECV(req, &err);
> +	nread = SMB_VFS_PREAD_RECV(req, &vfs_aio_state);
>  	TALLOC_FREE(req);
>  
>  	DEBUG(10, ("pread_recv returned %d, err = %s\n", (int)nread,
> -		   (nread == -1) ? strerror(err) : "no error"));
> +		   (nread == -1) ? strerror(vfs_aio_state.error) : "no error"));
>  
>  	if (fsp == NULL) {
>  		DEBUG( 3, ("aio_pread_smb1_done: file closed whilst "
> @@ -296,9 +296,9 @@ static void aio_pread_smb1_done(struct tevent_req *req)
>  	if (nread < 0) {
>  		DEBUG( 3, ("handle_aio_read_complete: file %s nread == %d. "
>  			   "Error = %s\n", fsp_str_dbg(fsp), (int)nread,
> -			   strerror(err)));
> +			   strerror(vfs_aio_state.error)));
>  
> -		ERROR_NT(map_nt_error_from_unix(err));
> +		ERROR_NT(map_nt_error_from_unix(vfs_aio_state.error));
>  		outsize = srv_set_message(outbuf,0,0,true);
>  	} else {
>  		outsize = srv_set_message(outbuf, 12,
> @@ -377,13 +377,13 @@ static void pwrite_fsync_write_done(struct tevent_req *subreq)
>  	struct pwrite_fsync_state *state = tevent_req_data(
>  		req, struct pwrite_fsync_state);
>  	connection_struct *conn = state->fsp->conn;
> -	int err;
>  	bool do_sync;
> +	struct vfs_aio_state vfs_aio_state;
>  
> -	state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &err);
> +	state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	if (state->nwritten == -1) {
> -		tevent_req_error(req, err);
> +		tevent_req_error(req, vfs_aio_state.error);
>  		return;
>  	}
>  
> @@ -405,12 +405,13 @@ static void pwrite_fsync_sync_done(struct tevent_req *subreq)
>  {
>  	struct tevent_req *req = tevent_req_callback_data(
>  		subreq, struct tevent_req);
> -	int ret, err;
> +	int ret;
> +	struct vfs_aio_state vfs_aio_state;
>  
> -	ret = SMB_VFS_FSYNC_RECV(subreq, &err);
> +	ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	if (ret == -1) {
> -		tevent_req_error(req, err);
> +		tevent_req_error(req, vfs_aio_state.error);
>  		return;
>  	}
>  	tevent_req_done(req);
> @@ -775,13 +776,13 @@ static void aio_pread_smb2_done(struct tevent_req *req)
>  	files_struct *fsp = aio_ex->fsp;
>  	NTSTATUS status;
>  	ssize_t nread;
> -	int err = 0;
> +	struct vfs_aio_state vfs_aio_state = { 0 };
>  
> -	nread = SMB_VFS_PREAD_RECV(req, &err);
> +	nread = SMB_VFS_PREAD_RECV(req, &vfs_aio_state);
>  	TALLOC_FREE(req);
>  
>  	DEBUG(10, ("pread_recv returned %d, err = %s\n", (int)nread,
> -		   (nread == -1) ? strerror(err) : "no error"));
> +		   (nread == -1) ? strerror(vfs_aio_state.error) : "no error"));
>  
>  	if (fsp == NULL) {
>  		DEBUG(3, ("%s: request cancelled (mid[%ju])\n",
> @@ -797,7 +798,7 @@ static void aio_pread_smb2_done(struct tevent_req *req)
>  	/* Common error or success code processing for async or sync
>  	   read returns. */
>  
> -	status = smb2_read_complete(subreq, nread, err);
> +	status = smb2_read_complete(subreq, nread, vfs_aio_state.error);
>  
>  	if (nread > 0) {
>  		fsp->fh->pos = aio_ex->offset + nread;
> @@ -810,7 +811,7 @@ static void aio_pread_smb2_done(struct tevent_req *req)
>  		   fsp_str_dbg(aio_ex->fsp),
>  		   (double)aio_ex->offset,
>  		   (unsigned int)nread,
> -		   err, nt_errstr(status)));
> +		   vfs_aio_state.error, nt_errstr(status)));
>  
>  	if (!NT_STATUS_IS_OK(status)) {
>  		tevent_req_nterror(subreq, status);
> diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c
> index 00b0535..d077c62 100644
> --- a/source3/smbd/smb2_flush.c
> +++ b/source3/smbd/smb2_flush.c
> @@ -190,14 +190,15 @@ static void smbd_smb2_flush_done(struct tevent_req *subreq)
>  {
>  	struct tevent_req *req = tevent_req_callback_data(
>  		subreq, struct tevent_req);
> -	int ret, err;
> +	int ret;
> +	struct vfs_aio_state vfs_aio_state;
>  
>  	decrement_outstanding_aio_calls();
>  
> -	ret = SMB_VFS_FSYNC_RECV(subreq, &err);
> +	ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	if (ret == -1) {
> -		tevent_req_error(req, err);
> +		tevent_req_error(req, vfs_aio_state.error);
>  		return;
>  	}
>  	tevent_req_done(req);
> diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
> index dfc22be..5a385ea 100644
> --- a/source3/smbd/vfs.c
> +++ b/source3/smbd/vfs.c
> @@ -1586,8 +1586,9 @@ ssize_t smb_vfs_call_pread(struct vfs_handle_struct *handle,
>  }
>  
>  struct smb_vfs_call_pread_state {
> -	ssize_t (*recv_fn)(struct tevent_req *req, int *err);
> +	ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
>  	ssize_t retval;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void smb_vfs_call_pread_done(struct tevent_req *subreq);
> @@ -1625,27 +1626,26 @@ static void smb_vfs_call_pread_done(struct tevent_req *subreq)
>  		subreq, struct tevent_req);
>  	struct smb_vfs_call_pread_state *state = tevent_req_data(
>  		req, struct smb_vfs_call_pread_state);
> -	int err;
>  
> -	state->retval = state->recv_fn(subreq, &err);
> +	state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	if (state->retval == -1) {
> -		tevent_req_error(req, err);
> +		tevent_req_error(req, state->vfs_aio_state.error);
>  		return;
>  	}
>  	tevent_req_done(req);
>  }
>  
> -ssize_t SMB_VFS_PREAD_RECV(struct tevent_req *req, int *perrno)
> +ssize_t SMB_VFS_PREAD_RECV(struct tevent_req *req,
> +			   struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct smb_vfs_call_pread_state *state = tevent_req_data(
>  		req, struct smb_vfs_call_pread_state);
> -	int err;
>  
> -	if (tevent_req_is_unix_error(req, &err)) {
> -		*perrno = err;
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->retval;
>  }
>  
> @@ -1666,8 +1666,9 @@ ssize_t smb_vfs_call_pwrite(struct vfs_handle_struct *handle,
>  }
>  
>  struct smb_vfs_call_pwrite_state {
> -	ssize_t (*recv_fn)(struct tevent_req *req, int *err);
> +	ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
>  	ssize_t retval;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void smb_vfs_call_pwrite_done(struct tevent_req *subreq);
> @@ -1705,27 +1706,26 @@ static void smb_vfs_call_pwrite_done(struct tevent_req *subreq)
>  		subreq, struct tevent_req);
>  	struct smb_vfs_call_pwrite_state *state = tevent_req_data(
>  		req, struct smb_vfs_call_pwrite_state);
> -	int err;
>  
> -	state->retval = state->recv_fn(subreq, &err);
> +	state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	if (state->retval == -1) {
> -		tevent_req_error(req, err);
> +		tevent_req_error(req, state->vfs_aio_state.error);
>  		return;
>  	}
>  	tevent_req_done(req);
>  }
>  
> -ssize_t SMB_VFS_PWRITE_RECV(struct tevent_req *req, int *perrno)
> +ssize_t SMB_VFS_PWRITE_RECV(struct tevent_req *req,
> +			    struct vfs_aio_state *vfs_aio_state)
>  {
>  	struct smb_vfs_call_pwrite_state *state = tevent_req_data(
>  		req, struct smb_vfs_call_pwrite_state);
> -	int err;
>  
> -	if (tevent_req_is_unix_error(req, &err)) {
> -		*perrno = err;
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->retval;
>  }
>  
> @@ -1770,8 +1770,9 @@ int smb_vfs_call_fsync(struct vfs_handle_struct *handle,
>  }
>  
>  struct smb_vfs_call_fsync_state {
> -	int (*recv_fn)(struct tevent_req *req, int *err);
> +	int (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
>  	int retval;
> +	struct vfs_aio_state vfs_aio_state;
>  };
>  
>  static void smb_vfs_call_fsync_done(struct tevent_req *subreq);
> @@ -1806,27 +1807,25 @@ static void smb_vfs_call_fsync_done(struct tevent_req *subreq)
>  		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);
> +	state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
>  	TALLOC_FREE(subreq);
>  	if (state->retval == -1) {
> -		tevent_req_error(req, err);
> +		tevent_req_error(req, state->vfs_aio_state.error);
>  		return;
>  	}
>  	tevent_req_done(req);
>  }
>  
> -int SMB_VFS_FSYNC_RECV(struct tevent_req *req, int *perrno)
> +int SMB_VFS_FSYNC_RECV(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state)
>  {
>  	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;
> +	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
>  		return -1;
>  	}
> +	*vfs_aio_state = state->vfs_aio_state;
>  	return state->retval;
>  }
>  
> -- 
> 2.5.0
> 
> 
> From 4c8fbbd892d56ecad253505f3a437d74428d0271 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Mon, 29 Feb 2016 12:17:18 +0100
> Subject: [PATCH 2/8] s3/vfs: add duration to vfs_aio_state
> 
> This will be used in the aio backends to pass the competion time of the
> async request in the backend.
> 
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/include/vfs.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/source3/include/vfs.h b/source3/include/vfs.h
> index ab67aab..e3b0f29 100644
> --- a/source3/include/vfs.h
> +++ b/source3/include/vfs.h
> @@ -521,6 +521,7 @@ enum vfs_fallocate_flags {
>  
>  struct vfs_aio_state {
>  	int error;
> +	uint64_t duration;
>  };
>  
>  /*
> -- 
> 2.5.0
> 
> 
> From dcde9ab2ae9d08e61217b3cea0f6af4d18589091 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Thu, 25 Feb 2016 08:06:00 +0100
> Subject: [PATCH 3/8] s3:lib/asys: measure async request syscall duration
> 
> This uses time functions from lib/util/ which requires pulling in
> samba-util. This sucks, but there's just no way of rewrapping a minimal
> time utility library without modifying the public samba-util.
> 
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/lib/asys/asys.c        | 13 +++++++++++++
>  source3/lib/asys/asys.h        |  1 +
>  source3/lib/asys/wscript_build |  2 +-
>  3 files changed, 15 insertions(+), 1 deletion(-)
> 
> diff --git a/source3/lib/asys/asys.c b/source3/lib/asys/asys.c
> index 906d8cf..068b460 100644
> --- a/source3/lib/asys/asys.c
> +++ b/source3/lib/asys/asys.c
> @@ -20,6 +20,7 @@
>  #include <stdlib.h>
>  #include <errno.h>
>  #include "../pthreadpool/pthreadpool.h"
> +#include "lib/util/time.h"
>  
>  struct asys_pwrite_args {
>  	int fildes;
> @@ -52,6 +53,8 @@ struct asys_job {
>  	int err;
>  	char busy;
>  	char canceled;
> +	struct timespec start_time;
> +	struct timespec end_time;
>  };
>  
>  struct asys_context {
> @@ -189,7 +192,10 @@ static void asys_pwrite_do(void *private_data)
>  	struct asys_job *job = (struct asys_job *)private_data;
>  	struct asys_pwrite_args *args = &job->args.pwrite_args;
>  
> +	clock_gettime_mono(&job->start_time);
>  	job->ret = pwrite(args->fildes, args->buf, args->nbyte, args->offset);
> +	clock_gettime_mono(&job->end_time);
> +
>  	if (job->ret == -1) {
>  		job->err = errno;
>  	}
> @@ -231,7 +237,10 @@ static void asys_pread_do(void *private_data)
>  	struct asys_job *job = (struct asys_job *)private_data;
>  	struct asys_pread_args *args = &job->args.pread_args;
>  
> +	clock_gettime_mono(&job->start_time);
>  	job->ret = pread(args->fildes, args->buf, args->nbyte, args->offset);
> +	clock_gettime_mono(&job->end_time);
> +
>  	if (job->ret == -1) {
>  		job->err = errno;
>  	}
> @@ -269,7 +278,10 @@ static void asys_fsync_do(void *private_data)
>  	struct asys_job *job = (struct asys_job *)private_data;
>  	struct asys_fsync_args *args = &job->args.fsync_args;
>  
> +	clock_gettime_mono(&job->start_time);
>  	job->ret = fsync(args->fildes);
> +	clock_gettime_mono(&job->end_time);
> +
>  	if (job->ret == -1) {
>  		job->err = errno;
>  	}
> @@ -320,6 +332,7 @@ int asys_results(struct asys_context *ctx, struct asys_result *results,
>  			result->err = job->err;
>  		}
>  		result->private_data = job->private_data;
> +		result->duration = nsec_time_diff(&job->end_time, &job->start_time);
>  
>  		job->busy = 0;
>  	}
> diff --git a/source3/lib/asys/asys.h b/source3/lib/asys/asys.h
> index 7c3dfdf..f576bd3 100644
> --- a/source3/lib/asys/asys.h
> +++ b/source3/lib/asys/asys.h
> @@ -108,6 +108,7 @@ struct asys_result {
>  	ssize_t ret;
>  	int err;
>  	void *private_data;
> +	uint64_t duration;	/* nanoseconds */
>  };
>  
>  /**
> diff --git a/source3/lib/asys/wscript_build b/source3/lib/asys/wscript_build
> index 15de977..520994f 100644
> --- a/source3/lib/asys/wscript_build
> +++ b/source3/lib/asys/wscript_build
> @@ -2,7 +2,7 @@
>  
>  bld.SAMBA3_SUBSYSTEM('LIBASYS',
>  		     source='asys.c',
> -		     deps='PTHREADPOOL')
> +		     deps='PTHREADPOOL samba-util')
>  
>  bld.SAMBA3_BINARY('asystest',
>  		  source='tests.c',
> -- 
> 2.5.0
> 
> 
> From 860e184682a3464816867d429dd939366216df45 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Fri, 26 Feb 2016 12:29:02 +0100
> Subject: [PATCH 4/8] vfs/default: store async VFS op duration we got from
>  libasys
> 
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/modules/vfs_default.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
> index 0fa7a00..cc905fa 100644
> --- a/source3/modules/vfs_default.c
> +++ b/source3/modules/vfs_default.c
> @@ -890,6 +890,7 @@ static void vfswrap_asys_finished(struct tevent_context *ev,
>  		SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
>  		state->ret = result->ret;
>  		state->vfs_aio_state.error = result->err;
> +		state->vfs_aio_state.duration = result->duration;
>  		tevent_req_defer_callback(req, ev);
>  		tevent_req_done(req);
>  	}
> -- 
> 2.5.0
> 
> 
> From b8bedaba18da2836bd3197a6240f8fcee12f354c Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Fri, 26 Feb 2016 09:59:23 +0100
> Subject: [PATCH 5/8] vfs/aio_fork: measure async request syscall duration
> 
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/modules/vfs_aio_fork.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/source3/modules/vfs_aio_fork.c b/source3/modules/vfs_aio_fork.c
> index 4322381..a722102 100644
> --- a/source3/modules/vfs_aio_fork.c
> +++ b/source3/modules/vfs_aio_fork.c
> @@ -128,6 +128,7 @@ struct rw_cmd {
>  struct rw_ret {
>  	ssize_t size;
>  	int ret_errno;
> +	uint64_t duration;
>  };
>  
>  struct aio_child_list;
> @@ -310,6 +311,7 @@ static void aio_child_loop(int sockfd, struct mmap_area *map)
>  		ssize_t ret;
>  		struct rw_cmd cmd_struct;
>  		struct rw_ret ret_struct;
> +		struct timespec start, end;
>  
>  		ret = read_fd(sockfd, &cmd_struct, sizeof(cmd_struct), &fd);
>  		if (ret != sizeof(cmd_struct)) {
> @@ -341,6 +343,8 @@ static void aio_child_loop(int sockfd, struct mmap_area *map)
>  
>  		ZERO_STRUCT(ret_struct);
>  
> +		clock_gettime_mono(&start);
> +
>  		switch (cmd_struct.cmd) {
>  		case READ_CMD:
>  			ret_struct.size = sys_pread(
> @@ -366,6 +370,8 @@ static void aio_child_loop(int sockfd, struct mmap_area *map)
>  			errno = EINVAL;
>  		}
>  
> +		clock_gettime_mono(&end);
> +		ret_struct.duration = nsec_time_diff(&end, &start);
>  		DEBUG(10, ("aio_child_loop: syscall returned %d\n",
>  			   (int)ret_struct.size));
>  
> @@ -633,6 +639,7 @@ static void aio_fork_pread_done(struct tevent_req *subreq)
>  	retbuf = (struct rw_ret *)buf;
>  	state->ret = retbuf->size;
>  	state->vfs_aio_state.error = retbuf->ret_errno;
> +	state->vfs_aio_state.duration = retbuf->duration;
>  	tevent_req_done(req);
>  }
>  
> @@ -748,6 +755,7 @@ static void aio_fork_pwrite_done(struct tevent_req *subreq)
>  	retbuf = (struct rw_ret *)buf;
>  	state->ret = retbuf->size;
>  	state->vfs_aio_state.error = retbuf->ret_errno;
> +	state->vfs_aio_state.duration = retbuf->duration;
>  	tevent_req_done(req);
>  }
>  
> @@ -855,6 +863,7 @@ static void aio_fork_fsync_done(struct tevent_req *subreq)
>  	retbuf = (struct rw_ret *)buf;
>  	state->ret = retbuf->size;
>  	state->vfs_aio_state.error = retbuf->ret_errno;
> +	state->vfs_aio_state.duration = retbuf->duration;
>  	tevent_req_done(req);
>  }
>  
> -- 
> 2.5.0
> 
> 
> From 75727f6a2fab23c9e4da5a6337843273d8e46763 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Fri, 26 Feb 2016 10:52:39 +0100
> Subject: [PATCH 6/8] vfs/aio_linux: measure libaio aio function call duration
> 
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/modules/vfs_aio_linux.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/source3/modules/vfs_aio_linux.c b/source3/modules/vfs_aio_linux.c
> index b1d33b5..caa3149 100644
> --- a/source3/modules/vfs_aio_linux.c
> +++ b/source3/modules/vfs_aio_linux.c
> @@ -140,6 +140,7 @@ struct aio_linux_state {
>  	struct iocb event_iocb;
>  	ssize_t ret;
>  	struct vfs_aio_state vfs_aio_state;
> +	struct timespec start;
>  };
>  
>  static struct tevent_req *aio_linux_pread_send(
> @@ -167,6 +168,7 @@ static struct tevent_req *aio_linux_pread_send(
>  
>  	piocb = &state->event_iocb;
>  
> +	clock_gettime_mono(&state->start);
>  	ret = io_submit(io_ctx, 1, &piocb);
>  	if (ret < 0) {
>  		tevent_req_error(req, -ret);
> @@ -203,6 +205,7 @@ static struct tevent_req *aio_linux_pwrite_send(
>  
>  	piocb = &state->event_iocb;
>  
> +	clock_gettime_mono(&state->start);
>  	ret = io_submit(io_ctx, 1, &piocb);
>  	if (ret < 0) {
>  		tevent_req_error(req, -ret);
> @@ -237,6 +240,7 @@ static struct tevent_req *aio_linux_fsync_send(
>  
>  	piocb = &state->event_iocb;
>  
> +	clock_gettime_mono(&state->start);
>  	ret = io_submit(io_ctx, 1, &piocb);
>  	if (ret < 0) {
>  		tevent_req_error(req, -ret);
> @@ -252,10 +256,13 @@ static void aio_linux_done(struct tevent_context *event_ctx,
>  			   uint16_t flags, void *private_data)
>  {
>  	uint64_t num_events = 0;
> +	struct timespec end;
>  
>  	DEBUG(10, ("aio_linux_done called with flags=%d\n",
>  		   (int)flags));
>  
> +	clock_gettime_mono(&end);
> +
>  	/* Read the number of events available. */
>  	if (sys_read(event_fd, &num_events, sizeof(num_events)) !=
>  			sizeof(num_events)) {
> @@ -293,6 +300,7 @@ static void aio_linux_done(struct tevent_context *event_ctx,
>  		} else {
>  			state->ret = finished.res;
>  		}
> +		state->vfs_aio_state.duration = nsec_time_diff(&end, &state->start);
>  		tevent_req_done(req);
>  		num_events -= 1;
>  	}
> -- 
> 2.5.0
> 
> 
> From 0f7219dc8a8e7fe967f7d1a73c72a9753db31ca0 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Fri, 26 Feb 2016 11:14:36 +0100
> Subject: [PATCH 7/8] vfs/glusterfs: measure libglusterfs aio function call
>  duration
> 
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/modules/vfs_glusterfs.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
> index 556c137..4977504 100644
> --- a/source3/modules/vfs_glusterfs.c
> +++ b/source3/modules/vfs_glusterfs.c
> @@ -501,6 +501,7 @@ struct glusterfs_aio_state {
>  	struct tevent_req *req;
>  	bool cancelled;
>  	struct vfs_aio_state vfs_aio_state;
> +	struct timespec start;
>  };
>  
>  static int aio_wrapper_destructor(struct glusterfs_aio_wrapper *wrap)
> @@ -519,15 +520,19 @@ static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data)
>  {
>  	struct glusterfs_aio_state *state = NULL;
>  	int sts = 0;
> +	struct timespec end;
>  
>  	state = (struct glusterfs_aio_state *)data;
>  
> +	clock_gettime_mono(&end);
> +
>  	if (ret < 0) {
>  		state->ret = -1;
>  		state->vfs_aio_state.error = errno;
>  	} else {
>  		state->ret = ret;
>  	}
> +	state->vfs_aio_state.duration = nsec_time_diff(&end, &state->start);
>  
>  	/*
>  	 * Write the state pointer to glusterfs_aio_state to the
> @@ -687,6 +692,7 @@ static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
>  		return tevent_req_post(req, ev);
>  	}
>  
> +	clock_gettime_mono(&state->start);
>  	ret = glfs_pread_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
>  				fsp), data, n, offset, 0, aio_glusterfs_done,
>  				state);
> @@ -722,6 +728,7 @@ static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
>  		return tevent_req_post(req, ev);
>  	}
>  
> +	clock_gettime_mono(&state->start);
>  	ret = glfs_pwrite_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
>  				fsp), data, n, offset, 0, aio_glusterfs_done,
>  				state);
> @@ -837,6 +844,8 @@ static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
>  		tevent_req_error(req, EIO);
>  		return tevent_req_post(req, ev);
>  	}
> +
> +	clock_gettime_mono(&state->start);
>  	ret = glfs_fsync_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
>  				fsp), aio_glusterfs_done, req);
>  	if (ret < 0) {
> -- 
> 2.5.0
> 
> 
> From eb201e9ec82e541d2a4435af5480c84d473dad33 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Fri, 26 Feb 2016 12:54:23 +0100
> Subject: [PATCH 8/8] vfs/time_audit: use duration we get from the async
>  backend
> 
> Finally! The previous commits changed the VFS and the async backend to
> pass the duration of an aync operation up the stack.
> 
> We now can use this value instead of doing our own sampling which avoids
> the following problem:
> 
> 1. SMB2 read request received, added to the async queue
> 
> 2. SMB2 create_file request comes in, is processed and blocks for N
>    seconds in open()
> 
> 3. async read completes in the dispatcher thread, completion callback
>    will be called when we enter the main tevent loop
> 
> 4. open() completes after N seconds
> 
> 5. main tevent event loop is entered, async results are processed
> 
> 6. async read result is processed, time sampling will include the N
>    seconds blocked in open()
> 
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/modules/vfs_time_audit.c | 24 ++++++------------------
>  1 file changed, 6 insertions(+), 18 deletions(-)
> 
> diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c
> index 08acc4c..915f58e 100644
> --- a/source3/modules/vfs_time_audit.c
> +++ b/source3/modules/vfs_time_audit.c
> @@ -676,7 +676,6 @@ static ssize_t smb_time_audit_pread(vfs_handle_struct *handle,
>  
>  struct smb_time_audit_pread_state {
>  	struct files_struct *fsp;
> -	struct timespec ts1;
>  	ssize_t ret;
>  	struct vfs_aio_state vfs_aio_state;
>  };
> @@ -696,7 +695,6 @@ static struct tevent_req *smb_time_audit_pread_send(
>  	if (req == NULL) {
>  		return NULL;
>  	}
> -	clock_gettime_mono(&state->ts1);
>  	state->fsp = fsp;
>  
>  	subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
> @@ -725,14 +723,12 @@ static ssize_t smb_time_audit_pread_recv(struct tevent_req *req,
>  {
>  	struct smb_time_audit_pread_state *state = tevent_req_data(
>  		req, struct smb_time_audit_pread_state);
> -	struct timespec ts2;
>  	double timediff;
>  
> -	clock_gettime_mono(&ts2);
> -	timediff = nsec_time_diff(&ts2,&state->ts1)*1.0e-9;
> +	timediff = state->vfs_aio_state.duration * 1.0e-9;
>  
>  	if (timediff > audit_timeout) {
> -		smb_time_audit_log_fsp("pread", timediff, state->fsp);
> +		smb_time_audit_log_fsp("async pread", timediff, state->fsp);
>  	}
>  
>  	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
> @@ -785,7 +781,6 @@ static ssize_t smb_time_audit_pwrite(vfs_handle_struct *handle,
>  
>  struct smb_time_audit_pwrite_state {
>  	struct files_struct *fsp;
> -	struct timespec ts1;
>  	ssize_t ret;
>  	struct vfs_aio_state vfs_aio_state;
>  };
> @@ -805,7 +800,6 @@ static struct tevent_req *smb_time_audit_pwrite_send(
>  	if (req == NULL) {
>  		return NULL;
>  	}
> -	clock_gettime_mono(&state->ts1);
>  	state->fsp = fsp;
>  
>  	subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
> @@ -834,14 +828,12 @@ static ssize_t smb_time_audit_pwrite_recv(struct tevent_req *req,
>  {
>  	struct smb_time_audit_pwrite_state *state = tevent_req_data(
>  		req, struct smb_time_audit_pwrite_state);
> -	struct timespec ts2;
>  	double timediff;
>  
> -	clock_gettime_mono(&ts2);
> -	timediff = nsec_time_diff(&ts2,&state->ts1)*1.0e-9;
> +	timediff = state->vfs_aio_state.duration * 1.0e-9;
>  
>  	if (timediff > audit_timeout) {
> -		smb_time_audit_log_fsp("pwrite", timediff, state->fsp);
> +		smb_time_audit_log_fsp("async pwrite", timediff, state->fsp);
>  	}
>  
>  	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
> @@ -953,7 +945,6 @@ static int smb_time_audit_fsync(vfs_handle_struct *handle, files_struct *fsp)
>  
>  struct smb_time_audit_fsync_state {
>  	struct files_struct *fsp;
> -	struct timespec ts1;
>  	int ret;
>  	struct vfs_aio_state vfs_aio_state;
>  };
> @@ -972,7 +963,6 @@ static struct tevent_req *smb_time_audit_fsync_send(
>  	if (req == NULL) {
>  		return NULL;
>  	}
> -	clock_gettime_mono(&state->ts1);
>  	state->fsp = fsp;
>  
>  	subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
> @@ -1000,14 +990,12 @@ static int smb_time_audit_fsync_recv(struct tevent_req *req,
>  {
>  	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;
> +	timediff = state->vfs_aio_state.duration * 1.0e-9;
>  
>  	if (timediff > audit_timeout) {
> -		smb_time_audit_log_fsp("fsync", timediff, state->fsp);
> +		smb_time_audit_log_fsp("async fsync", timediff, state->fsp);
>  	}
>  
>  	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
> -- 
> 2.5.0
> 




More information about the samba-technical mailing list