RE: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-29 Thread Tom Talpey
> -Original Message-
> From: linux-cifs-ow...@vger.kernel.org  On
> Behalf Of Long Li
> Sent: Thursday, November 29, 2018 4:30 PM
> To: Pavel Shilovsky 
> Cc: Steve French ; linux-cifs ;
> samba-technical ; Kernel Mailing List
> 
> Subject: RE: [Patch v4 2/3] CIFS: Add support for direct I/O write
> 
> > Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> >
> > ср, 28 нояб. 2018 г. в 18:20, Long Li :
> > >
> > > > Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> > > >
> > > > ср, 31 окт. 2018 г. в 15:26, Long Li :
> > > > >
> > > > > From: Long Li 
> > > > >
> > > > > With direct I/O write, user supplied buffers are pinned to the
> > > > > memory and data are transferred directly from user buffers to the
> > transport layer.
> > > > >
> > > > > Change in v3: add support for kernel AIO
> > > > >
> > > > > Change in v4:
> > > > > Refactor common write code to __cifs_writev for direct and non-direct
> > I/O.
> > > > > Retry on direct I/O failure.
> > > > >
> > > > > Signed-off-by: Long Li 
> > > > > ---
> > > > >  fs/cifs/cifsfs.h |   1 +
> > > > >  fs/cifs/file.c   | 194
> > +++
> > > > 
> > > > >  2 files changed, 154 insertions(+), 41 deletions(-)
> > > > >
> > > > > diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index
> > > > > 7fba9aa..e9c5103 100644
> > > > > --- a/fs/cifs/cifsfs.h
> > > > > +++ b/fs/cifs/cifsfs.h
> > > > > @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb
> > > > > *iocb, struct iov_iter *to);  extern ssize_t
> > > > > cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to);
> > > > > extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct
> > > > > iov_iter *to);  extern ssize_t cifs_user_writev(struct kiocb
> > > > > *iocb, struct iov_iter *from);
> > > > > +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct
> > > > > +iov_iter *from);
> > > > >  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct
> > > > > iov_iter *from);  extern int cifs_lock(struct file *, int, struct
> > > > > file_lock *); extern int cifs_fsync(struct file *, loff_t, loff_t,
> > > > > int); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index
> > > > > daab878..1a41c04 100644
> > > > > --- a/fs/cifs/file.c
> > > > > +++ b/fs/cifs/file.c
> > > > > @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata
> > > > > *wdata, struct iov_iter *from,  }
> > > > >
> > > > >  static int
> > > > > +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head
> > > > > +*wdata_list, struct cifs_aio_ctx *ctx) {
> > > > > +   int wait_retry = 0;
> > > > > +   unsigned int wsize, credits;
> > > > > +   int rc;
> > > > > +   struct TCP_Server_Info *server =
> > > > > +tlink_tcon(wdata->cfile->tlink)->ses->server;
> > > > > +
> > > > > +   /*
> > > > > +* Try to resend this wdata, waiting for credits up to 3 
> > > > > seconds.
> > > > > +* Note: we are attempting to resend the whole wdata not
> > > > > + in
> > > > segments
> > > > > +*/
> > > > > +   do {
> > > > > +   rc = server->ops->wait_mtu_credits(server,
> > > > > + wdata->bytes, , );
> > > > > +
> > > > > +   if (rc)
> > > > > +   break;
> > > > > +
> > > > > +   if (wsize < wdata->bytes) {
> > > > > +   add_credits_and_wake_if(server, credits, 0);
> > > > > +   msleep(1000);
> > > > > +   wait_retry++;
> > > > > +   }
> > > > > +   } while (wsize < wdata->bytes && wait_retry < 3);
> > > > > +
> > > > > +   if (wsize < wdata->bytes) {
> > > > > +   rc = -EBUSY;
> > > > > +  

RE: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-29 Thread Tom Talpey
> -Original Message-
> From: linux-cifs-ow...@vger.kernel.org  On
> Behalf Of Long Li
> Sent: Thursday, November 29, 2018 4:30 PM
> To: Pavel Shilovsky 
> Cc: Steve French ; linux-cifs ;
> samba-technical ; Kernel Mailing List
> 
> Subject: RE: [Patch v4 2/3] CIFS: Add support for direct I/O write
> 
> > Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> >
> > ср, 28 нояб. 2018 г. в 18:20, Long Li :
> > >
> > > > Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> > > >
> > > > ср, 31 окт. 2018 г. в 15:26, Long Li :
> > > > >
> > > > > From: Long Li 
> > > > >
> > > > > With direct I/O write, user supplied buffers are pinned to the
> > > > > memory and data are transferred directly from user buffers to the
> > transport layer.
> > > > >
> > > > > Change in v3: add support for kernel AIO
> > > > >
> > > > > Change in v4:
> > > > > Refactor common write code to __cifs_writev for direct and non-direct
> > I/O.
> > > > > Retry on direct I/O failure.
> > > > >
> > > > > Signed-off-by: Long Li 
> > > > > ---
> > > > >  fs/cifs/cifsfs.h |   1 +
> > > > >  fs/cifs/file.c   | 194
> > +++
> > > > 
> > > > >  2 files changed, 154 insertions(+), 41 deletions(-)
> > > > >
> > > > > diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index
> > > > > 7fba9aa..e9c5103 100644
> > > > > --- a/fs/cifs/cifsfs.h
> > > > > +++ b/fs/cifs/cifsfs.h
> > > > > @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb
> > > > > *iocb, struct iov_iter *to);  extern ssize_t
> > > > > cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to);
> > > > > extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct
> > > > > iov_iter *to);  extern ssize_t cifs_user_writev(struct kiocb
> > > > > *iocb, struct iov_iter *from);
> > > > > +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct
> > > > > +iov_iter *from);
> > > > >  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct
> > > > > iov_iter *from);  extern int cifs_lock(struct file *, int, struct
> > > > > file_lock *); extern int cifs_fsync(struct file *, loff_t, loff_t,
> > > > > int); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index
> > > > > daab878..1a41c04 100644
> > > > > --- a/fs/cifs/file.c
> > > > > +++ b/fs/cifs/file.c
> > > > > @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata
> > > > > *wdata, struct iov_iter *from,  }
> > > > >
> > > > >  static int
> > > > > +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head
> > > > > +*wdata_list, struct cifs_aio_ctx *ctx) {
> > > > > +   int wait_retry = 0;
> > > > > +   unsigned int wsize, credits;
> > > > > +   int rc;
> > > > > +   struct TCP_Server_Info *server =
> > > > > +tlink_tcon(wdata->cfile->tlink)->ses->server;
> > > > > +
> > > > > +   /*
> > > > > +* Try to resend this wdata, waiting for credits up to 3 
> > > > > seconds.
> > > > > +* Note: we are attempting to resend the whole wdata not
> > > > > + in
> > > > segments
> > > > > +*/
> > > > > +   do {
> > > > > +   rc = server->ops->wait_mtu_credits(server,
> > > > > + wdata->bytes, , );
> > > > > +
> > > > > +   if (rc)
> > > > > +   break;
> > > > > +
> > > > > +   if (wsize < wdata->bytes) {
> > > > > +   add_credits_and_wake_if(server, credits, 0);
> > > > > +   msleep(1000);
> > > > > +   wait_retry++;
> > > > > +   }
> > > > > +   } while (wsize < wdata->bytes && wait_retry < 3);
> > > > > +
> > > > > +   if (wsize < wdata->bytes) {
> > > > > +   rc = -EBUSY;
> > > > > +  

RE: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-29 Thread Long Li
> Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> 
> ср, 28 нояб. 2018 г. в 18:20, Long Li :
> >
> > > Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> > >
> > > ср, 31 окт. 2018 г. в 15:26, Long Li :
> > > >
> > > > From: Long Li 
> > > >
> > > > With direct I/O write, user supplied buffers are pinned to the
> > > > memory and data are transferred directly from user buffers to the
> transport layer.
> > > >
> > > > Change in v3: add support for kernel AIO
> > > >
> > > > Change in v4:
> > > > Refactor common write code to __cifs_writev for direct and non-direct
> I/O.
> > > > Retry on direct I/O failure.
> > > >
> > > > Signed-off-by: Long Li 
> > > > ---
> > > >  fs/cifs/cifsfs.h |   1 +
> > > >  fs/cifs/file.c   | 194
> +++
> > > 
> > > >  2 files changed, 154 insertions(+), 41 deletions(-)
> > > >
> > > > diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index
> > > > 7fba9aa..e9c5103 100644
> > > > --- a/fs/cifs/cifsfs.h
> > > > +++ b/fs/cifs/cifsfs.h
> > > > @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb
> > > > *iocb, struct iov_iter *to);  extern ssize_t
> > > > cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to);
> > > > extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct
> > > > iov_iter *to);  extern ssize_t cifs_user_writev(struct kiocb
> > > > *iocb, struct iov_iter *from);
> > > > +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct
> > > > +iov_iter *from);
> > > >  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct
> > > > iov_iter *from);  extern int cifs_lock(struct file *, int, struct
> > > > file_lock *); extern int cifs_fsync(struct file *, loff_t, loff_t,
> > > > int); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index
> > > > daab878..1a41c04 100644
> > > > --- a/fs/cifs/file.c
> > > > +++ b/fs/cifs/file.c
> > > > @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata
> > > > *wdata, struct iov_iter *from,  }
> > > >
> > > >  static int
> > > > +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head
> > > > +*wdata_list, struct cifs_aio_ctx *ctx) {
> > > > +   int wait_retry = 0;
> > > > +   unsigned int wsize, credits;
> > > > +   int rc;
> > > > +   struct TCP_Server_Info *server =
> > > > +tlink_tcon(wdata->cfile->tlink)->ses->server;
> > > > +
> > > > +   /*
> > > > +* Try to resend this wdata, waiting for credits up to 3 
> > > > seconds.
> > > > +* Note: we are attempting to resend the whole wdata not
> > > > + in
> > > segments
> > > > +*/
> > > > +   do {
> > > > +   rc = server->ops->wait_mtu_credits(server,
> > > > + wdata->bytes, , );
> > > > +
> > > > +   if (rc)
> > > > +   break;
> > > > +
> > > > +   if (wsize < wdata->bytes) {
> > > > +   add_credits_and_wake_if(server, credits, 0);
> > > > +   msleep(1000);
> > > > +   wait_retry++;
> > > > +   }
> > > > +   } while (wsize < wdata->bytes && wait_retry < 3);
> > > > +
> > > > +   if (wsize < wdata->bytes) {
> > > > +   rc = -EBUSY;
> > > > +   goto out;
> > > > +   }
> > > > +
> > > > +   rc = -EAGAIN;
> > > > +   while (rc == -EAGAIN)
> > > > +   if (!wdata->cfile->invalidHandle ||
> > > > +   !(rc = cifs_reopen_file(wdata->cfile, false)))
> > > > +   rc = server->ops->async_writev(wdata,
> > > > +
> > > > + cifs_uncached_writedata_release);
> > > > +
> > > > +   if (!rc) {
> > > > +   list_add_tail(>list, wdata_list);
> > > > +   return 0;
> > > > +   }
> > > > +
> > > > +   add_cr

RE: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-29 Thread Long Li
> Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> 
> ср, 28 нояб. 2018 г. в 18:20, Long Li :
> >
> > > Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> > >
> > > ср, 31 окт. 2018 г. в 15:26, Long Li :
> > > >
> > > > From: Long Li 
> > > >
> > > > With direct I/O write, user supplied buffers are pinned to the
> > > > memory and data are transferred directly from user buffers to the
> transport layer.
> > > >
> > > > Change in v3: add support for kernel AIO
> > > >
> > > > Change in v4:
> > > > Refactor common write code to __cifs_writev for direct and non-direct
> I/O.
> > > > Retry on direct I/O failure.
> > > >
> > > > Signed-off-by: Long Li 
> > > > ---
> > > >  fs/cifs/cifsfs.h |   1 +
> > > >  fs/cifs/file.c   | 194
> +++
> > > 
> > > >  2 files changed, 154 insertions(+), 41 deletions(-)
> > > >
> > > > diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index
> > > > 7fba9aa..e9c5103 100644
> > > > --- a/fs/cifs/cifsfs.h
> > > > +++ b/fs/cifs/cifsfs.h
> > > > @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb
> > > > *iocb, struct iov_iter *to);  extern ssize_t
> > > > cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to);
> > > > extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct
> > > > iov_iter *to);  extern ssize_t cifs_user_writev(struct kiocb
> > > > *iocb, struct iov_iter *from);
> > > > +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct
> > > > +iov_iter *from);
> > > >  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct
> > > > iov_iter *from);  extern int cifs_lock(struct file *, int, struct
> > > > file_lock *); extern int cifs_fsync(struct file *, loff_t, loff_t,
> > > > int); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index
> > > > daab878..1a41c04 100644
> > > > --- a/fs/cifs/file.c
> > > > +++ b/fs/cifs/file.c
> > > > @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata
> > > > *wdata, struct iov_iter *from,  }
> > > >
> > > >  static int
> > > > +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head
> > > > +*wdata_list, struct cifs_aio_ctx *ctx) {
> > > > +   int wait_retry = 0;
> > > > +   unsigned int wsize, credits;
> > > > +   int rc;
> > > > +   struct TCP_Server_Info *server =
> > > > +tlink_tcon(wdata->cfile->tlink)->ses->server;
> > > > +
> > > > +   /*
> > > > +* Try to resend this wdata, waiting for credits up to 3 
> > > > seconds.
> > > > +* Note: we are attempting to resend the whole wdata not
> > > > + in
> > > segments
> > > > +*/
> > > > +   do {
> > > > +   rc = server->ops->wait_mtu_credits(server,
> > > > + wdata->bytes, , );
> > > > +
> > > > +   if (rc)
> > > > +   break;
> > > > +
> > > > +   if (wsize < wdata->bytes) {
> > > > +   add_credits_and_wake_if(server, credits, 0);
> > > > +   msleep(1000);
> > > > +   wait_retry++;
> > > > +   }
> > > > +   } while (wsize < wdata->bytes && wait_retry < 3);
> > > > +
> > > > +   if (wsize < wdata->bytes) {
> > > > +   rc = -EBUSY;
> > > > +   goto out;
> > > > +   }
> > > > +
> > > > +   rc = -EAGAIN;
> > > > +   while (rc == -EAGAIN)
> > > > +   if (!wdata->cfile->invalidHandle ||
> > > > +   !(rc = cifs_reopen_file(wdata->cfile, false)))
> > > > +   rc = server->ops->async_writev(wdata,
> > > > +
> > > > + cifs_uncached_writedata_release);
> > > > +
> > > > +   if (!rc) {
> > > > +   list_add_tail(>list, wdata_list);
> > > > +   return 0;
> > > > +   }
> > > > +
> > > > +   add_cr

Re: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-29 Thread Pavel Shilovsky
ср, 28 нояб. 2018 г. в 18:20, Long Li :
>
> > Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> >
> > ср, 31 окт. 2018 г. в 15:26, Long Li :
> > >
> > > From: Long Li 
> > >
> > > With direct I/O write, user supplied buffers are pinned to the memory
> > > and data are transferred directly from user buffers to the transport 
> > > layer.
> > >
> > > Change in v3: add support for kernel AIO
> > >
> > > Change in v4:
> > > Refactor common write code to __cifs_writev for direct and non-direct I/O.
> > > Retry on direct I/O failure.
> > >
> > > Signed-off-by: Long Li 
> > > ---
> > >  fs/cifs/cifsfs.h |   1 +
> > >  fs/cifs/file.c   | 194 +++
> > 
> > >  2 files changed, 154 insertions(+), 41 deletions(-)
> > >
> > > diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index
> > > 7fba9aa..e9c5103 100644
> > > --- a/fs/cifs/cifsfs.h
> > > +++ b/fs/cifs/cifsfs.h
> > > @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb *iocb,
> > > struct iov_iter *to);  extern ssize_t cifs_direct_readv(struct kiocb
> > > *iocb, struct iov_iter *to);  extern ssize_t cifs_strict_readv(struct
> > > kiocb *iocb, struct iov_iter *to);  extern ssize_t
> > > cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
> > > +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter
> > > +*from);
> > >  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter
> > > *from);  extern int cifs_lock(struct file *, int, struct file_lock *);
> > > extern int cifs_fsync(struct file *, loff_t, loff_t, int); diff --git
> > > a/fs/cifs/file.c b/fs/cifs/file.c index daab878..1a41c04 100644
> > > --- a/fs/cifs/file.c
> > > +++ b/fs/cifs/file.c
> > > @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata
> > > *wdata, struct iov_iter *from,  }
> > >
> > >  static int
> > > +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head
> > > +*wdata_list, struct cifs_aio_ctx *ctx) {
> > > +   int wait_retry = 0;
> > > +   unsigned int wsize, credits;
> > > +   int rc;
> > > +   struct TCP_Server_Info *server =
> > > +tlink_tcon(wdata->cfile->tlink)->ses->server;
> > > +
> > > +   /*
> > > +* Try to resend this wdata, waiting for credits up to 3 seconds.
> > > +* Note: we are attempting to resend the whole wdata not in
> > segments
> > > +*/
> > > +   do {
> > > +   rc = server->ops->wait_mtu_credits(server,
> > > + wdata->bytes, , );
> > > +
> > > +   if (rc)
> > > +   break;
> > > +
> > > +   if (wsize < wdata->bytes) {
> > > +   add_credits_and_wake_if(server, credits, 0);
> > > +   msleep(1000);
> > > +   wait_retry++;
> > > +   }
> > > +   } while (wsize < wdata->bytes && wait_retry < 3);
> > > +
> > > +   if (wsize < wdata->bytes) {
> > > +   rc = -EBUSY;
> > > +   goto out;
> > > +   }
> > > +
> > > +   rc = -EAGAIN;
> > > +   while (rc == -EAGAIN)
> > > +   if (!wdata->cfile->invalidHandle ||
> > > +   !(rc = cifs_reopen_file(wdata->cfile, false)))
> > > +   rc = server->ops->async_writev(wdata,
> > > +
> > > + cifs_uncached_writedata_release);
> > > +
> > > +   if (!rc) {
> > > +   list_add_tail(>list, wdata_list);
> > > +   return 0;
> > > +   }
> > > +
> > > +   add_credits_and_wake_if(server, wdata->credits, 0);
> > > +out:
> > > +   kref_put(>refcount, cifs_uncached_writedata_release);
> > > +
> > > +   return rc;
> > > +}
> > > +
> > > +static int
> > >  cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
> > >  struct cifsFileInfo *open_file,
> > >  struct cifs_sb_info *cifs_sb, struct list_head
> > > *wdata_list, @@ -2537,6 +2586,8 @@ cifs_write_from_iter(loff_t offset,
> > size_t len, struct 

Re: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-29 Thread Pavel Shilovsky
ср, 28 нояб. 2018 г. в 18:20, Long Li :
>
> > Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> >
> > ср, 31 окт. 2018 г. в 15:26, Long Li :
> > >
> > > From: Long Li 
> > >
> > > With direct I/O write, user supplied buffers are pinned to the memory
> > > and data are transferred directly from user buffers to the transport 
> > > layer.
> > >
> > > Change in v3: add support for kernel AIO
> > >
> > > Change in v4:
> > > Refactor common write code to __cifs_writev for direct and non-direct I/O.
> > > Retry on direct I/O failure.
> > >
> > > Signed-off-by: Long Li 
> > > ---
> > >  fs/cifs/cifsfs.h |   1 +
> > >  fs/cifs/file.c   | 194 +++
> > 
> > >  2 files changed, 154 insertions(+), 41 deletions(-)
> > >
> > > diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index
> > > 7fba9aa..e9c5103 100644
> > > --- a/fs/cifs/cifsfs.h
> > > +++ b/fs/cifs/cifsfs.h
> > > @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb *iocb,
> > > struct iov_iter *to);  extern ssize_t cifs_direct_readv(struct kiocb
> > > *iocb, struct iov_iter *to);  extern ssize_t cifs_strict_readv(struct
> > > kiocb *iocb, struct iov_iter *to);  extern ssize_t
> > > cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
> > > +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter
> > > +*from);
> > >  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter
> > > *from);  extern int cifs_lock(struct file *, int, struct file_lock *);
> > > extern int cifs_fsync(struct file *, loff_t, loff_t, int); diff --git
> > > a/fs/cifs/file.c b/fs/cifs/file.c index daab878..1a41c04 100644
> > > --- a/fs/cifs/file.c
> > > +++ b/fs/cifs/file.c
> > > @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata
> > > *wdata, struct iov_iter *from,  }
> > >
> > >  static int
> > > +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head
> > > +*wdata_list, struct cifs_aio_ctx *ctx) {
> > > +   int wait_retry = 0;
> > > +   unsigned int wsize, credits;
> > > +   int rc;
> > > +   struct TCP_Server_Info *server =
> > > +tlink_tcon(wdata->cfile->tlink)->ses->server;
> > > +
> > > +   /*
> > > +* Try to resend this wdata, waiting for credits up to 3 seconds.
> > > +* Note: we are attempting to resend the whole wdata not in
> > segments
> > > +*/
> > > +   do {
> > > +   rc = server->ops->wait_mtu_credits(server,
> > > + wdata->bytes, , );
> > > +
> > > +   if (rc)
> > > +   break;
> > > +
> > > +   if (wsize < wdata->bytes) {
> > > +   add_credits_and_wake_if(server, credits, 0);
> > > +   msleep(1000);
> > > +   wait_retry++;
> > > +   }
> > > +   } while (wsize < wdata->bytes && wait_retry < 3);
> > > +
> > > +   if (wsize < wdata->bytes) {
> > > +   rc = -EBUSY;
> > > +   goto out;
> > > +   }
> > > +
> > > +   rc = -EAGAIN;
> > > +   while (rc == -EAGAIN)
> > > +   if (!wdata->cfile->invalidHandle ||
> > > +   !(rc = cifs_reopen_file(wdata->cfile, false)))
> > > +   rc = server->ops->async_writev(wdata,
> > > +
> > > + cifs_uncached_writedata_release);
> > > +
> > > +   if (!rc) {
> > > +   list_add_tail(>list, wdata_list);
> > > +   return 0;
> > > +   }
> > > +
> > > +   add_credits_and_wake_if(server, wdata->credits, 0);
> > > +out:
> > > +   kref_put(>refcount, cifs_uncached_writedata_release);
> > > +
> > > +   return rc;
> > > +}
> > > +
> > > +static int
> > >  cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
> > >  struct cifsFileInfo *open_file,
> > >  struct cifs_sb_info *cifs_sb, struct list_head
> > > *wdata_list, @@ -2537,6 +2586,8 @@ cifs_write_from_iter(loff_t offset,
> > size_t len, struct 

RE: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-28 Thread Long Li
> Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> 
> ср, 31 окт. 2018 г. в 15:26, Long Li :
> >
> > From: Long Li 
> >
> > With direct I/O write, user supplied buffers are pinned to the memory
> > and data are transferred directly from user buffers to the transport layer.
> >
> > Change in v3: add support for kernel AIO
> >
> > Change in v4:
> > Refactor common write code to __cifs_writev for direct and non-direct I/O.
> > Retry on direct I/O failure.
> >
> > Signed-off-by: Long Li 
> > ---
> >  fs/cifs/cifsfs.h |   1 +
> >  fs/cifs/file.c   | 194 +++
> 
> >  2 files changed, 154 insertions(+), 41 deletions(-)
> >
> > diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index
> > 7fba9aa..e9c5103 100644
> > --- a/fs/cifs/cifsfs.h
> > +++ b/fs/cifs/cifsfs.h
> > @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb *iocb,
> > struct iov_iter *to);  extern ssize_t cifs_direct_readv(struct kiocb
> > *iocb, struct iov_iter *to);  extern ssize_t cifs_strict_readv(struct
> > kiocb *iocb, struct iov_iter *to);  extern ssize_t
> > cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
> > +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter
> > +*from);
> >  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter
> > *from);  extern int cifs_lock(struct file *, int, struct file_lock *);
> > extern int cifs_fsync(struct file *, loff_t, loff_t, int); diff --git
> > a/fs/cifs/file.c b/fs/cifs/file.c index daab878..1a41c04 100644
> > --- a/fs/cifs/file.c
> > +++ b/fs/cifs/file.c
> > @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata
> > *wdata, struct iov_iter *from,  }
> >
> >  static int
> > +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head
> > +*wdata_list, struct cifs_aio_ctx *ctx) {
> > +   int wait_retry = 0;
> > +   unsigned int wsize, credits;
> > +   int rc;
> > +   struct TCP_Server_Info *server =
> > +tlink_tcon(wdata->cfile->tlink)->ses->server;
> > +
> > +   /*
> > +* Try to resend this wdata, waiting for credits up to 3 seconds.
> > +* Note: we are attempting to resend the whole wdata not in
> segments
> > +*/
> > +   do {
> > +   rc = server->ops->wait_mtu_credits(server,
> > + wdata->bytes, , );
> > +
> > +   if (rc)
> > +   break;
> > +
> > +   if (wsize < wdata->bytes) {
> > +   add_credits_and_wake_if(server, credits, 0);
> > +   msleep(1000);
> > +   wait_retry++;
> > +   }
> > +   } while (wsize < wdata->bytes && wait_retry < 3);
> > +
> > +   if (wsize < wdata->bytes) {
> > +   rc = -EBUSY;
> > +   goto out;
> > +   }
> > +
> > +   rc = -EAGAIN;
> > +   while (rc == -EAGAIN)
> > +   if (!wdata->cfile->invalidHandle ||
> > +   !(rc = cifs_reopen_file(wdata->cfile, false)))
> > +   rc = server->ops->async_writev(wdata,
> > +
> > + cifs_uncached_writedata_release);
> > +
> > +   if (!rc) {
> > +   list_add_tail(>list, wdata_list);
> > +   return 0;
> > +   }
> > +
> > +   add_credits_and_wake_if(server, wdata->credits, 0);
> > +out:
> > +   kref_put(>refcount, cifs_uncached_writedata_release);
> > +
> > +   return rc;
> > +}
> > +
> > +static int
> >  cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
> >  struct cifsFileInfo *open_file,
> >  struct cifs_sb_info *cifs_sb, struct list_head
> > *wdata_list, @@ -2537,6 +2586,8 @@ cifs_write_from_iter(loff_t offset,
> size_t len, struct iov_iter *from,
> > loff_t saved_offset = offset;
> > pid_t pid;
> > struct TCP_Server_Info *server;
> > +   struct page **pagevec;
> > +   size_t start;
> >
> > if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
> > pid = open_file->pid;
> > @@ -2553,38 +2604,74 @@ cifs_write_from_iter(loff_t offset, size_t len,
> struct iov_iter *from,
> > if (rc)
> > break;
> >
> >

RE: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-28 Thread Long Li
> Subject: Re: [Patch v4 2/3] CIFS: Add support for direct I/O write
> 
> ср, 31 окт. 2018 г. в 15:26, Long Li :
> >
> > From: Long Li 
> >
> > With direct I/O write, user supplied buffers are pinned to the memory
> > and data are transferred directly from user buffers to the transport layer.
> >
> > Change in v3: add support for kernel AIO
> >
> > Change in v4:
> > Refactor common write code to __cifs_writev for direct and non-direct I/O.
> > Retry on direct I/O failure.
> >
> > Signed-off-by: Long Li 
> > ---
> >  fs/cifs/cifsfs.h |   1 +
> >  fs/cifs/file.c   | 194 +++
> 
> >  2 files changed, 154 insertions(+), 41 deletions(-)
> >
> > diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index
> > 7fba9aa..e9c5103 100644
> > --- a/fs/cifs/cifsfs.h
> > +++ b/fs/cifs/cifsfs.h
> > @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb *iocb,
> > struct iov_iter *to);  extern ssize_t cifs_direct_readv(struct kiocb
> > *iocb, struct iov_iter *to);  extern ssize_t cifs_strict_readv(struct
> > kiocb *iocb, struct iov_iter *to);  extern ssize_t
> > cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
> > +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter
> > +*from);
> >  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter
> > *from);  extern int cifs_lock(struct file *, int, struct file_lock *);
> > extern int cifs_fsync(struct file *, loff_t, loff_t, int); diff --git
> > a/fs/cifs/file.c b/fs/cifs/file.c index daab878..1a41c04 100644
> > --- a/fs/cifs/file.c
> > +++ b/fs/cifs/file.c
> > @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata
> > *wdata, struct iov_iter *from,  }
> >
> >  static int
> > +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head
> > +*wdata_list, struct cifs_aio_ctx *ctx) {
> > +   int wait_retry = 0;
> > +   unsigned int wsize, credits;
> > +   int rc;
> > +   struct TCP_Server_Info *server =
> > +tlink_tcon(wdata->cfile->tlink)->ses->server;
> > +
> > +   /*
> > +* Try to resend this wdata, waiting for credits up to 3 seconds.
> > +* Note: we are attempting to resend the whole wdata not in
> segments
> > +*/
> > +   do {
> > +   rc = server->ops->wait_mtu_credits(server,
> > + wdata->bytes, , );
> > +
> > +   if (rc)
> > +   break;
> > +
> > +   if (wsize < wdata->bytes) {
> > +   add_credits_and_wake_if(server, credits, 0);
> > +   msleep(1000);
> > +   wait_retry++;
> > +   }
> > +   } while (wsize < wdata->bytes && wait_retry < 3);
> > +
> > +   if (wsize < wdata->bytes) {
> > +   rc = -EBUSY;
> > +   goto out;
> > +   }
> > +
> > +   rc = -EAGAIN;
> > +   while (rc == -EAGAIN)
> > +   if (!wdata->cfile->invalidHandle ||
> > +   !(rc = cifs_reopen_file(wdata->cfile, false)))
> > +   rc = server->ops->async_writev(wdata,
> > +
> > + cifs_uncached_writedata_release);
> > +
> > +   if (!rc) {
> > +   list_add_tail(>list, wdata_list);
> > +   return 0;
> > +   }
> > +
> > +   add_credits_and_wake_if(server, wdata->credits, 0);
> > +out:
> > +   kref_put(>refcount, cifs_uncached_writedata_release);
> > +
> > +   return rc;
> > +}
> > +
> > +static int
> >  cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
> >  struct cifsFileInfo *open_file,
> >  struct cifs_sb_info *cifs_sb, struct list_head
> > *wdata_list, @@ -2537,6 +2586,8 @@ cifs_write_from_iter(loff_t offset,
> size_t len, struct iov_iter *from,
> > loff_t saved_offset = offset;
> > pid_t pid;
> > struct TCP_Server_Info *server;
> > +   struct page **pagevec;
> > +   size_t start;
> >
> > if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
> > pid = open_file->pid;
> > @@ -2553,38 +2604,74 @@ cifs_write_from_iter(loff_t offset, size_t len,
> struct iov_iter *from,
> > if (rc)
> > break;
> >
> >

Re: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-16 Thread Pavel Shilovsky
ср, 31 окт. 2018 г. в 15:26, Long Li :
>
> From: Long Li 
>
> With direct I/O write, user supplied buffers are pinned to the memory and data
> are transferred directly from user buffers to the transport layer.
>
> Change in v3: add support for kernel AIO
>
> Change in v4:
> Refactor common write code to __cifs_writev for direct and non-direct I/O.
> Retry on direct I/O failure.
>
> Signed-off-by: Long Li 
> ---
>  fs/cifs/cifsfs.h |   1 +
>  fs/cifs/file.c   | 194 
> +++
>  2 files changed, 154 insertions(+), 41 deletions(-)
>
> diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
> index 7fba9aa..e9c5103 100644
> --- a/fs/cifs/cifsfs.h
> +++ b/fs/cifs/cifsfs.h
> @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb *iocb, struct 
> iov_iter *to);
>  extern ssize_t cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to);
>  extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to);
>  extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
> +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from);
>  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from);
>  extern int cifs_lock(struct file *, int, struct file_lock *);
>  extern int cifs_fsync(struct file *, loff_t, loff_t, int);
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index daab878..1a41c04 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata *wdata, 
> struct iov_iter *from,
>  }
>
>  static int
> +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head 
> *wdata_list, struct cifs_aio_ctx *ctx)
> +{
> +   int wait_retry = 0;
> +   unsigned int wsize, credits;
> +   int rc;
> +   struct TCP_Server_Info *server = 
> tlink_tcon(wdata->cfile->tlink)->ses->server;
> +
> +   /*
> +* Try to resend this wdata, waiting for credits up to 3 seconds.
> +* Note: we are attempting to resend the whole wdata not in segments
> +*/
> +   do {
> +   rc = server->ops->wait_mtu_credits(server, wdata->bytes, 
> , );
> +
> +   if (rc)
> +   break;
> +
> +   if (wsize < wdata->bytes) {
> +   add_credits_and_wake_if(server, credits, 0);
> +   msleep(1000);
> +   wait_retry++;
> +   }
> +   } while (wsize < wdata->bytes && wait_retry < 3);
> +
> +   if (wsize < wdata->bytes) {
> +   rc = -EBUSY;
> +   goto out;
> +   }
> +
> +   rc = -EAGAIN;
> +   while (rc == -EAGAIN)
> +   if (!wdata->cfile->invalidHandle ||
> +   !(rc = cifs_reopen_file(wdata->cfile, false)))
> +   rc = server->ops->async_writev(wdata,
> +   cifs_uncached_writedata_release);
> +
> +   if (!rc) {
> +   list_add_tail(>list, wdata_list);
> +   return 0;
> +   }
> +
> +   add_credits_and_wake_if(server, wdata->credits, 0);
> +out:
> +   kref_put(>refcount, cifs_uncached_writedata_release);
> +
> +   return rc;
> +}
> +
> +static int
>  cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
>  struct cifsFileInfo *open_file,
>  struct cifs_sb_info *cifs_sb, struct list_head 
> *wdata_list,
> @@ -2537,6 +2586,8 @@ cifs_write_from_iter(loff_t offset, size_t len, struct 
> iov_iter *from,
> loff_t saved_offset = offset;
> pid_t pid;
> struct TCP_Server_Info *server;
> +   struct page **pagevec;
> +   size_t start;
>
> if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
> pid = open_file->pid;
> @@ -2553,38 +2604,74 @@ cifs_write_from_iter(loff_t offset, size_t len, 
> struct iov_iter *from,
> if (rc)
> break;
>
> -   nr_pages = get_numpages(wsize, len, _len);
> -   wdata = cifs_writedata_alloc(nr_pages,
> +   if (ctx->direct_io) {
> +   cur_len = iov_iter_get_pages_alloc(
> +   from, , wsize, );
> +   if (cur_len < 0) {
> +   cifs_dbg(VFS,
> +   "direct_writev couldn't get user 
> pages "
> +   "(rc=%zd) iter type %d iov_offset %zd 
> count"
> +   " %zd\n",
> +   cur_len, from->type,
> +   from->iov_offset, from->count);
> +   dump_stack();
> +   break;
> +   }
> +   iov_iter_advance(from, cur_len);
> +
> +   nr_pages = (cur_len + start + PAGE_SIZE - 1) / 
> PAGE_SIZE;
> +
> +

Re: [Patch v4 2/3] CIFS: Add support for direct I/O write

2018-11-16 Thread Pavel Shilovsky
ср, 31 окт. 2018 г. в 15:26, Long Li :
>
> From: Long Li 
>
> With direct I/O write, user supplied buffers are pinned to the memory and data
> are transferred directly from user buffers to the transport layer.
>
> Change in v3: add support for kernel AIO
>
> Change in v4:
> Refactor common write code to __cifs_writev for direct and non-direct I/O.
> Retry on direct I/O failure.
>
> Signed-off-by: Long Li 
> ---
>  fs/cifs/cifsfs.h |   1 +
>  fs/cifs/file.c   | 194 
> +++
>  2 files changed, 154 insertions(+), 41 deletions(-)
>
> diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
> index 7fba9aa..e9c5103 100644
> --- a/fs/cifs/cifsfs.h
> +++ b/fs/cifs/cifsfs.h
> @@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb *iocb, struct 
> iov_iter *to);
>  extern ssize_t cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to);
>  extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to);
>  extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
> +extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from);
>  extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from);
>  extern int cifs_lock(struct file *, int, struct file_lock *);
>  extern int cifs_fsync(struct file *, loff_t, loff_t, int);
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index daab878..1a41c04 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata *wdata, 
> struct iov_iter *from,
>  }
>
>  static int
> +cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head 
> *wdata_list, struct cifs_aio_ctx *ctx)
> +{
> +   int wait_retry = 0;
> +   unsigned int wsize, credits;
> +   int rc;
> +   struct TCP_Server_Info *server = 
> tlink_tcon(wdata->cfile->tlink)->ses->server;
> +
> +   /*
> +* Try to resend this wdata, waiting for credits up to 3 seconds.
> +* Note: we are attempting to resend the whole wdata not in segments
> +*/
> +   do {
> +   rc = server->ops->wait_mtu_credits(server, wdata->bytes, 
> , );
> +
> +   if (rc)
> +   break;
> +
> +   if (wsize < wdata->bytes) {
> +   add_credits_and_wake_if(server, credits, 0);
> +   msleep(1000);
> +   wait_retry++;
> +   }
> +   } while (wsize < wdata->bytes && wait_retry < 3);
> +
> +   if (wsize < wdata->bytes) {
> +   rc = -EBUSY;
> +   goto out;
> +   }
> +
> +   rc = -EAGAIN;
> +   while (rc == -EAGAIN)
> +   if (!wdata->cfile->invalidHandle ||
> +   !(rc = cifs_reopen_file(wdata->cfile, false)))
> +   rc = server->ops->async_writev(wdata,
> +   cifs_uncached_writedata_release);
> +
> +   if (!rc) {
> +   list_add_tail(>list, wdata_list);
> +   return 0;
> +   }
> +
> +   add_credits_and_wake_if(server, wdata->credits, 0);
> +out:
> +   kref_put(>refcount, cifs_uncached_writedata_release);
> +
> +   return rc;
> +}
> +
> +static int
>  cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
>  struct cifsFileInfo *open_file,
>  struct cifs_sb_info *cifs_sb, struct list_head 
> *wdata_list,
> @@ -2537,6 +2586,8 @@ cifs_write_from_iter(loff_t offset, size_t len, struct 
> iov_iter *from,
> loff_t saved_offset = offset;
> pid_t pid;
> struct TCP_Server_Info *server;
> +   struct page **pagevec;
> +   size_t start;
>
> if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
> pid = open_file->pid;
> @@ -2553,38 +2604,74 @@ cifs_write_from_iter(loff_t offset, size_t len, 
> struct iov_iter *from,
> if (rc)
> break;
>
> -   nr_pages = get_numpages(wsize, len, _len);
> -   wdata = cifs_writedata_alloc(nr_pages,
> +   if (ctx->direct_io) {
> +   cur_len = iov_iter_get_pages_alloc(
> +   from, , wsize, );
> +   if (cur_len < 0) {
> +   cifs_dbg(VFS,
> +   "direct_writev couldn't get user 
> pages "
> +   "(rc=%zd) iter type %d iov_offset %zd 
> count"
> +   " %zd\n",
> +   cur_len, from->type,
> +   from->iov_offset, from->count);
> +   dump_stack();
> +   break;
> +   }
> +   iov_iter_advance(from, cur_len);
> +
> +   nr_pages = (cur_len + start + PAGE_SIZE - 1) / 
> PAGE_SIZE;
> +
> +

[Patch v4 2/3] CIFS: Add support for direct I/O write

2018-10-31 Thread Long Li
From: Long Li 

With direct I/O write, user supplied buffers are pinned to the memory and data
are transferred directly from user buffers to the transport layer.

Change in v3: add support for kernel AIO

Change in v4:
Refactor common write code to __cifs_writev for direct and non-direct I/O.
Retry on direct I/O failure.

Signed-off-by: Long Li 
---
 fs/cifs/cifsfs.h |   1 +
 fs/cifs/file.c   | 194 +++
 2 files changed, 154 insertions(+), 41 deletions(-)

diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 7fba9aa..e9c5103 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb *iocb, struct 
iov_iter *to);
 extern ssize_t cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to);
 extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to);
 extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
+extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from);
 extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from);
 extern int cifs_lock(struct file *, int, struct file_lock *);
 extern int cifs_fsync(struct file *, loff_t, loff_t, int);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index daab878..1a41c04 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata *wdata, 
struct iov_iter *from,
 }
 
 static int
+cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, 
struct cifs_aio_ctx *ctx)
+{
+   int wait_retry = 0;
+   unsigned int wsize, credits;
+   int rc;
+   struct TCP_Server_Info *server = 
tlink_tcon(wdata->cfile->tlink)->ses->server;
+
+   /*
+* Try to resend this wdata, waiting for credits up to 3 seconds.
+* Note: we are attempting to resend the whole wdata not in segments
+*/
+   do {
+   rc = server->ops->wait_mtu_credits(server, wdata->bytes, 
, );
+
+   if (rc)
+   break;
+
+   if (wsize < wdata->bytes) {
+   add_credits_and_wake_if(server, credits, 0);
+   msleep(1000);
+   wait_retry++;
+   }
+   } while (wsize < wdata->bytes && wait_retry < 3);
+
+   if (wsize < wdata->bytes) {
+   rc = -EBUSY;
+   goto out;
+   }
+
+   rc = -EAGAIN;
+   while (rc == -EAGAIN)
+   if (!wdata->cfile->invalidHandle ||
+   !(rc = cifs_reopen_file(wdata->cfile, false)))
+   rc = server->ops->async_writev(wdata,
+   cifs_uncached_writedata_release);
+
+   if (!rc) {
+   list_add_tail(>list, wdata_list);
+   return 0;
+   }
+
+   add_credits_and_wake_if(server, wdata->credits, 0);
+out:
+   kref_put(>refcount, cifs_uncached_writedata_release);
+
+   return rc;
+}
+
+static int
 cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
 struct cifsFileInfo *open_file,
 struct cifs_sb_info *cifs_sb, struct list_head *wdata_list,
@@ -2537,6 +2586,8 @@ cifs_write_from_iter(loff_t offset, size_t len, struct 
iov_iter *from,
loff_t saved_offset = offset;
pid_t pid;
struct TCP_Server_Info *server;
+   struct page **pagevec;
+   size_t start;
 
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
pid = open_file->pid;
@@ -2553,38 +2604,74 @@ cifs_write_from_iter(loff_t offset, size_t len, struct 
iov_iter *from,
if (rc)
break;
 
-   nr_pages = get_numpages(wsize, len, _len);
-   wdata = cifs_writedata_alloc(nr_pages,
+   if (ctx->direct_io) {
+   cur_len = iov_iter_get_pages_alloc(
+   from, , wsize, );
+   if (cur_len < 0) {
+   cifs_dbg(VFS,
+   "direct_writev couldn't get user pages "
+   "(rc=%zd) iter type %d iov_offset %zd 
count"
+   " %zd\n",
+   cur_len, from->type,
+   from->iov_offset, from->count);
+   dump_stack();
+   break;
+   }
+   iov_iter_advance(from, cur_len);
+
+   nr_pages = (cur_len + start + PAGE_SIZE - 1) / 
PAGE_SIZE;
+
+   wdata = cifs_writedata_direct_alloc(pagevec,
 cifs_uncached_writev_complete);
-   if (!wdata) {
-   rc = -ENOMEM;
-   add_credits_and_wake_if(server, credits, 0);
-  

[Patch v4 2/3] CIFS: Add support for direct I/O write

2018-10-31 Thread Long Li
From: Long Li 

With direct I/O write, user supplied buffers are pinned to the memory and data
are transferred directly from user buffers to the transport layer.

Change in v3: add support for kernel AIO

Change in v4:
Refactor common write code to __cifs_writev for direct and non-direct I/O.
Retry on direct I/O failure.

Signed-off-by: Long Li 
---
 fs/cifs/cifsfs.h |   1 +
 fs/cifs/file.c   | 194 +++
 2 files changed, 154 insertions(+), 41 deletions(-)

diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 7fba9aa..e9c5103 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -105,6 +105,7 @@ extern ssize_t cifs_user_readv(struct kiocb *iocb, struct 
iov_iter *to);
 extern ssize_t cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to);
 extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to);
 extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
+extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from);
 extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from);
 extern int cifs_lock(struct file *, int, struct file_lock *);
 extern int cifs_fsync(struct file *, loff_t, loff_t, int);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index daab878..1a41c04 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2524,6 +2524,55 @@ wdata_fill_from_iovec(struct cifs_writedata *wdata, 
struct iov_iter *from,
 }
 
 static int
+cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, 
struct cifs_aio_ctx *ctx)
+{
+   int wait_retry = 0;
+   unsigned int wsize, credits;
+   int rc;
+   struct TCP_Server_Info *server = 
tlink_tcon(wdata->cfile->tlink)->ses->server;
+
+   /*
+* Try to resend this wdata, waiting for credits up to 3 seconds.
+* Note: we are attempting to resend the whole wdata not in segments
+*/
+   do {
+   rc = server->ops->wait_mtu_credits(server, wdata->bytes, 
, );
+
+   if (rc)
+   break;
+
+   if (wsize < wdata->bytes) {
+   add_credits_and_wake_if(server, credits, 0);
+   msleep(1000);
+   wait_retry++;
+   }
+   } while (wsize < wdata->bytes && wait_retry < 3);
+
+   if (wsize < wdata->bytes) {
+   rc = -EBUSY;
+   goto out;
+   }
+
+   rc = -EAGAIN;
+   while (rc == -EAGAIN)
+   if (!wdata->cfile->invalidHandle ||
+   !(rc = cifs_reopen_file(wdata->cfile, false)))
+   rc = server->ops->async_writev(wdata,
+   cifs_uncached_writedata_release);
+
+   if (!rc) {
+   list_add_tail(>list, wdata_list);
+   return 0;
+   }
+
+   add_credits_and_wake_if(server, wdata->credits, 0);
+out:
+   kref_put(>refcount, cifs_uncached_writedata_release);
+
+   return rc;
+}
+
+static int
 cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
 struct cifsFileInfo *open_file,
 struct cifs_sb_info *cifs_sb, struct list_head *wdata_list,
@@ -2537,6 +2586,8 @@ cifs_write_from_iter(loff_t offset, size_t len, struct 
iov_iter *from,
loff_t saved_offset = offset;
pid_t pid;
struct TCP_Server_Info *server;
+   struct page **pagevec;
+   size_t start;
 
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
pid = open_file->pid;
@@ -2553,38 +2604,74 @@ cifs_write_from_iter(loff_t offset, size_t len, struct 
iov_iter *from,
if (rc)
break;
 
-   nr_pages = get_numpages(wsize, len, _len);
-   wdata = cifs_writedata_alloc(nr_pages,
+   if (ctx->direct_io) {
+   cur_len = iov_iter_get_pages_alloc(
+   from, , wsize, );
+   if (cur_len < 0) {
+   cifs_dbg(VFS,
+   "direct_writev couldn't get user pages "
+   "(rc=%zd) iter type %d iov_offset %zd 
count"
+   " %zd\n",
+   cur_len, from->type,
+   from->iov_offset, from->count);
+   dump_stack();
+   break;
+   }
+   iov_iter_advance(from, cur_len);
+
+   nr_pages = (cur_len + start + PAGE_SIZE - 1) / 
PAGE_SIZE;
+
+   wdata = cifs_writedata_direct_alloc(pagevec,
 cifs_uncached_writev_complete);
-   if (!wdata) {
-   rc = -ENOMEM;
-   add_credits_and_wake_if(server, credits, 0);
-