RE: [Patch v4 2/3] CIFS: Add support for direct I/O write
> -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
> -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
> 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
> 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
ср, 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
ср, 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
> 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
> 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
ср, 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
ср, 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
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
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); -