* [PATCH] cifs: clean up page array when uncached write send fails
@ 2014-02-06 19:42 Jeff Layton
[not found] ` <1391715764-21225-1-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 5+ messages in thread
From: Jeff Layton @ 2014-02-06 19:42 UTC (permalink / raw)
To: smfrench-Re5JQEeQqe8AvxtiuMwx3w; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
In the event that a send fails in an uncached write, or we end up
needing to reissue it (-EAGAIN case), we'll kfree the wdata but
the pages currently leak.
Fix this by adding a new kref release routine for uncached writedata
that releases the pages, and have the uncached codepaths use that.
Signed-off-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/cifs/file.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 853d6d1..d76c935 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2331,9 +2331,20 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
}
static void
-cifs_uncached_writev_complete(struct work_struct *work)
+cifs_uncached_writedata_release(struct kref *refcount)
{
int i;
+ struct cifs_writedata *wdata = container_of(refcount,
+ struct cifs_writedata, refcount);
+
+ for (i = 0; i < wdata->nr_pages; i++)
+ put_page(wdata->pages[i]);
+ cifs_writedata_release(refcount);
+}
+
+static void
+cifs_uncached_writev_complete(struct work_struct *work)
+{
struct cifs_writedata *wdata = container_of(work,
struct cifs_writedata, work);
struct inode *inode = wdata->cfile->dentry->d_inode;
@@ -2347,12 +2358,7 @@ cifs_uncached_writev_complete(struct work_struct *work)
complete(&wdata->done);
- if (wdata->result != -EAGAIN) {
- for (i = 0; i < wdata->nr_pages; i++)
- put_page(wdata->pages[i]);
- }
-
- kref_put(&wdata->refcount, cifs_writedata_release);
+ kref_put(&wdata->refcount, cifs_uncached_writedata_release);
}
/* attempt to send write to server, retry on any -EAGAIN errors */
@@ -2454,7 +2460,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
rc = cifs_uncached_retry_writev(wdata);
if (rc) {
- kref_put(&wdata->refcount, cifs_writedata_release);
+ kref_put(&wdata->refcount, cifs_uncached_writedata_release);
break;
}
@@ -2496,7 +2502,7 @@ restart_loop:
}
}
list_del_init(&wdata->list);
- kref_put(&wdata->refcount, cifs_writedata_release);
+ kref_put(&wdata->refcount, cifs_uncached_writedata_release);
}
if (total_written > 0)
--
1.8.5.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] cifs: clean up page array when uncached write send fails
[not found] ` <1391715764-21225-1-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2014-02-07 13:15 ` Jeff Layton
2014-02-07 16:02 ` [PATCH v2] " Jeff Layton
1 sibling, 0 replies; 5+ messages in thread
From: Jeff Layton @ 2014-02-07 13:15 UTC (permalink / raw)
To: smfrench-Re5JQEeQqe8AvxtiuMwx3w; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Thu, 6 Feb 2014 14:42:44 -0500
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> In the event that a send fails in an uncached write, or we end up
> needing to reissue it (-EAGAIN case), we'll kfree the wdata but
> the pages currently leak.
>
> Fix this by adding a new kref release routine for uncached writedata
> that releases the pages, and have the uncached codepaths use that.
>
> Signed-off-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> ---
> fs/cifs/file.c | 24 +++++++++++++++---------
> 1 file changed, 15 insertions(+), 9 deletions(-)
>
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index 853d6d1..d76c935 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -2331,9 +2331,20 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
> }
>
> static void
> -cifs_uncached_writev_complete(struct work_struct *work)
> +cifs_uncached_writedata_release(struct kref *refcount)
> {
> int i;
> + struct cifs_writedata *wdata = container_of(refcount,
> + struct cifs_writedata, refcount);
> +
> + for (i = 0; i < wdata->nr_pages; i++)
> + put_page(wdata->pages[i]);
> + cifs_writedata_release(refcount);
> +}
> +
> +static void
> +cifs_uncached_writev_complete(struct work_struct *work)
> +{
> struct cifs_writedata *wdata = container_of(work,
> struct cifs_writedata, work);
> struct inode *inode = wdata->cfile->dentry->d_inode;
> @@ -2347,12 +2358,7 @@ cifs_uncached_writev_complete(struct work_struct *work)
>
> complete(&wdata->done);
>
> - if (wdata->result != -EAGAIN) {
> - for (i = 0; i < wdata->nr_pages; i++)
> - put_page(wdata->pages[i]);
> - }
> -
> - kref_put(&wdata->refcount, cifs_writedata_release);
> + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
> }
>
> /* attempt to send write to server, retry on any -EAGAIN errors */
> @@ -2454,7 +2460,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
> wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
> rc = cifs_uncached_retry_writev(wdata);
> if (rc) {
> - kref_put(&wdata->refcount, cifs_writedata_release);
> + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
> break;
> }
>
> @@ -2496,7 +2502,7 @@ restart_loop:
> }
> }
> list_del_init(&wdata->list);
> - kref_put(&wdata->refcount, cifs_writedata_release);
> + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
> }
>
> if (total_written > 0)
Hi Stevem
I just realized this patch isn't quite right. We have to propagate
the kref release function to the ->async_writev code. Please hold off
on merging this yet until I can do a v2.
Thanks,
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2] cifs: clean up page array when uncached write send fails
[not found] ` <1391715764-21225-1-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2014-02-07 13:15 ` Jeff Layton
@ 2014-02-07 16:02 ` Jeff Layton
[not found] ` <1391788961-26028-1-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
1 sibling, 1 reply; 5+ messages in thread
From: Jeff Layton @ 2014-02-07 16:02 UTC (permalink / raw)
To: smfrench-Re5JQEeQqe8AvxtiuMwx3w; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
In the event that a send fails in an uncached write, or we end up
needing to reissue it (-EAGAIN case), we'll kfree the wdata but
the pages currently leak.
Fix this by adding a new kref release routine for uncached writedata
that releases the pages, and have the uncached codepaths use that.
Signed-off-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/cifs/cifsglob.h | 2 +-
fs/cifs/cifsproto.h | 2 +-
fs/cifs/cifssmb.c | 6 +++---
fs/cifs/file.c | 28 +++++++++++++++++-----------
fs/cifs/smb2pdu.c | 4 ++--
fs/cifs/smb2proto.h | 2 +-
6 files changed, 25 insertions(+), 19 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a245d1809ed8..57d07e704d97 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -323,7 +323,7 @@ struct smb_version_operations {
/* async read from the server */
int (*async_readv)(struct cifs_readdata *);
/* async write to the server */
- int (*async_writev)(struct cifs_writedata *);
+ int (*async_writev)(struct cifs_writedata *, void (*release)(struct kref *));
/* sync read from the server */
int (*sync_read)(const unsigned int, struct cifsFileInfo *,
struct cifs_io_parms *, unsigned int *, char **,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 79e6e9a93a8c..a4f90c0d9950 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -488,7 +488,7 @@ void cifs_readdata_release(struct kref *refcount);
int cifs_async_readv(struct cifs_readdata *rdata);
int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
-int cifs_async_writev(struct cifs_writedata *wdata);
+int cifs_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref));
void cifs_writev_complete(struct work_struct *work);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
work_func_t complete);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 4d881c35eeca..0726ab413b8c 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1910,7 +1910,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
do {
server = tlink_tcon(wdata->cfile->tlink)->ses->server;
- rc = server->ops->async_writev(wdata);
+ rc = server->ops->async_writev(wdata, cifs_writedata_release);
} while (rc == -EAGAIN);
for (i = 0; i < wdata->nr_pages; i++) {
@@ -2031,7 +2031,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
/* cifs_async_writev - send an async write, and set up mid to handle result */
int
-cifs_async_writev(struct cifs_writedata *wdata)
+cifs_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref))
{
int rc = -EACCES;
WRITE_REQ *smb = NULL;
@@ -2105,7 +2105,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
if (rc == 0)
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
else
- kref_put(&wdata->refcount, cifs_writedata_release);
+ kref_put(&wdata->refcount, release);
async_writev_out:
cifs_small_buf_release(smb);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 853d6d1cc822..03d1f454c713 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2043,7 +2043,7 @@ retry:
}
wdata->pid = wdata->cfile->pid;
server = tlink_tcon(wdata->cfile->tlink)->ses->server;
- rc = server->ops->async_writev(wdata);
+ rc = server->ops->async_writev(wdata, cifs_writedata_release);
} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
for (i = 0; i < nr_pages; ++i)
@@ -2331,9 +2331,20 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
}
static void
-cifs_uncached_writev_complete(struct work_struct *work)
+cifs_uncached_writedata_release(struct kref *refcount)
{
int i;
+ struct cifs_writedata *wdata = container_of(refcount,
+ struct cifs_writedata, refcount);
+
+ for (i = 0; i < wdata->nr_pages; i++)
+ put_page(wdata->pages[i]);
+ cifs_writedata_release(refcount);
+}
+
+static void
+cifs_uncached_writev_complete(struct work_struct *work)
+{
struct cifs_writedata *wdata = container_of(work,
struct cifs_writedata, work);
struct inode *inode = wdata->cfile->dentry->d_inode;
@@ -2347,12 +2358,7 @@ cifs_uncached_writev_complete(struct work_struct *work)
complete(&wdata->done);
- if (wdata->result != -EAGAIN) {
- for (i = 0; i < wdata->nr_pages; i++)
- put_page(wdata->pages[i]);
- }
-
- kref_put(&wdata->refcount, cifs_writedata_release);
+ kref_put(&wdata->refcount, cifs_uncached_writedata_release);
}
/* attempt to send write to server, retry on any -EAGAIN errors */
@@ -2370,7 +2376,7 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
if (rc != 0)
continue;
}
- rc = server->ops->async_writev(wdata);
+ rc = server->ops->async_writev(wdata, cifs_uncached_writedata_release);
} while (rc == -EAGAIN);
return rc;
@@ -2454,7 +2460,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
rc = cifs_uncached_retry_writev(wdata);
if (rc) {
- kref_put(&wdata->refcount, cifs_writedata_release);
+ kref_put(&wdata->refcount, cifs_uncached_writedata_release);
break;
}
@@ -2496,7 +2502,7 @@ restart_loop:
}
}
list_del_init(&wdata->list);
- kref_put(&wdata->refcount, cifs_writedata_release);
+ kref_put(&wdata->refcount, cifs_uncached_writedata_release);
}
if (total_written > 0)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 2013234b73ad..8c04bdeda136 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1890,7 +1890,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
/* smb2_async_writev - send an async write, and set up mid to handle result */
int
-smb2_async_writev(struct cifs_writedata *wdata)
+smb2_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref))
{
int rc = -EACCES;
struct smb2_write_req *req = NULL;
@@ -1938,7 +1938,7 @@ smb2_async_writev(struct cifs_writedata *wdata)
smb2_writev_callback, wdata, 0);
if (rc) {
- kref_put(&wdata->refcount, cifs_writedata_release);
+ kref_put(&wdata->refcount, release);
cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 93adc64666f3..1833724542cd 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -123,7 +123,7 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
extern int smb2_async_readv(struct cifs_readdata *rdata);
extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, char **buf, int *buf_type);
-extern int smb2_async_writev(struct cifs_writedata *wdata);
+extern int smb2_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref));
extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, struct kvec *iov, int n_vec);
extern int SMB2_echo(struct TCP_Server_Info *server);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2] cifs: clean up page array when uncached write send fails
[not found] ` <1391788961-26028-1-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2014-02-07 16:26 ` Pavel Shilovsky
[not found] ` <CAKywueTk-9GSrRpu_YHRccuQ7bzep-8=PzQEX1p1waDu00UVAA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 5+ messages in thread
From: Pavel Shilovsky @ 2014-02-07 16:26 UTC (permalink / raw)
To: Jeff Layton; +Cc: Steve French, linux-cifs
2014-02-07 20:02 GMT+04:00 Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>:
> In the event that a send fails in an uncached write, or we end up
> needing to reissue it (-EAGAIN case), we'll kfree the wdata but
> the pages currently leak.
>
> Fix this by adding a new kref release routine for uncached writedata
> that releases the pages, and have the uncached codepaths use that.
>
> Signed-off-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> ---
> fs/cifs/cifsglob.h | 2 +-
> fs/cifs/cifsproto.h | 2 +-
> fs/cifs/cifssmb.c | 6 +++---
> fs/cifs/file.c | 28 +++++++++++++++++-----------
> fs/cifs/smb2pdu.c | 4 ++--
> fs/cifs/smb2proto.h | 2 +-
> 6 files changed, 25 insertions(+), 19 deletions(-)
>
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index a245d1809ed8..57d07e704d97 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -323,7 +323,7 @@ struct smb_version_operations {
> /* async read from the server */
> int (*async_readv)(struct cifs_readdata *);
> /* async write to the server */
> - int (*async_writev)(struct cifs_writedata *);
> + int (*async_writev)(struct cifs_writedata *, void (*release)(struct kref *));
> /* sync read from the server */
> int (*sync_read)(const unsigned int, struct cifsFileInfo *,
> struct cifs_io_parms *, unsigned int *, char **,
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 79e6e9a93a8c..a4f90c0d9950 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -488,7 +488,7 @@ void cifs_readdata_release(struct kref *refcount);
> int cifs_async_readv(struct cifs_readdata *rdata);
> int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
>
> -int cifs_async_writev(struct cifs_writedata *wdata);
> +int cifs_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref));
> void cifs_writev_complete(struct work_struct *work);
> struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
> work_func_t complete);
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 4d881c35eeca..0726ab413b8c 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -1910,7 +1910,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
>
> do {
> server = tlink_tcon(wdata->cfile->tlink)->ses->server;
> - rc = server->ops->async_writev(wdata);
> + rc = server->ops->async_writev(wdata, cifs_writedata_release);
> } while (rc == -EAGAIN);
>
> for (i = 0; i < wdata->nr_pages; i++) {
> @@ -2031,7 +2031,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
>
> /* cifs_async_writev - send an async write, and set up mid to handle result */
> int
> -cifs_async_writev(struct cifs_writedata *wdata)
> +cifs_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref))
> {
> int rc = -EACCES;
> WRITE_REQ *smb = NULL;
> @@ -2105,7 +2105,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
> if (rc == 0)
> cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
> else
> - kref_put(&wdata->refcount, cifs_writedata_release);
> + kref_put(&wdata->refcount, release);
>
> async_writev_out:
> cifs_small_buf_release(smb);
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index 853d6d1cc822..03d1f454c713 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -2043,7 +2043,7 @@ retry:
> }
> wdata->pid = wdata->cfile->pid;
> server = tlink_tcon(wdata->cfile->tlink)->ses->server;
> - rc = server->ops->async_writev(wdata);
> + rc = server->ops->async_writev(wdata, cifs_writedata_release);
> } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
>
> for (i = 0; i < nr_pages; ++i)
> @@ -2331,9 +2331,20 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
> }
>
> static void
> -cifs_uncached_writev_complete(struct work_struct *work)
> +cifs_uncached_writedata_release(struct kref *refcount)
> {
> int i;
> + struct cifs_writedata *wdata = container_of(refcount,
> + struct cifs_writedata, refcount);
> +
> + for (i = 0; i < wdata->nr_pages; i++)
> + put_page(wdata->pages[i]);
> + cifs_writedata_release(refcount);
> +}
> +
> +static void
> +cifs_uncached_writev_complete(struct work_struct *work)
> +{
> struct cifs_writedata *wdata = container_of(work,
> struct cifs_writedata, work);
> struct inode *inode = wdata->cfile->dentry->d_inode;
> @@ -2347,12 +2358,7 @@ cifs_uncached_writev_complete(struct work_struct *work)
>
> complete(&wdata->done);
>
> - if (wdata->result != -EAGAIN) {
> - for (i = 0; i < wdata->nr_pages; i++)
> - put_page(wdata->pages[i]);
> - }
> -
> - kref_put(&wdata->refcount, cifs_writedata_release);
> + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
> }
>
> /* attempt to send write to server, retry on any -EAGAIN errors */
> @@ -2370,7 +2376,7 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
> if (rc != 0)
> continue;
> }
> - rc = server->ops->async_writev(wdata);
> + rc = server->ops->async_writev(wdata, cifs_uncached_writedata_release);
> } while (rc == -EAGAIN);
>
> return rc;
> @@ -2454,7 +2460,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
> wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
> rc = cifs_uncached_retry_writev(wdata);
> if (rc) {
> - kref_put(&wdata->refcount, cifs_writedata_release);
> + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
> break;
> }
>
> @@ -2496,7 +2502,7 @@ restart_loop:
> }
> }
> list_del_init(&wdata->list);
> - kref_put(&wdata->refcount, cifs_writedata_release);
> + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
> }
>
> if (total_written > 0)
> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
> index 2013234b73ad..8c04bdeda136 100644
> --- a/fs/cifs/smb2pdu.c
> +++ b/fs/cifs/smb2pdu.c
> @@ -1890,7 +1890,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
>
> /* smb2_async_writev - send an async write, and set up mid to handle result */
> int
> -smb2_async_writev(struct cifs_writedata *wdata)
> +smb2_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref))
> {
> int rc = -EACCES;
> struct smb2_write_req *req = NULL;
> @@ -1938,7 +1938,7 @@ smb2_async_writev(struct cifs_writedata *wdata)
> smb2_writev_callback, wdata, 0);
>
> if (rc) {
> - kref_put(&wdata->refcount, cifs_writedata_release);
> + kref_put(&wdata->refcount, release);
> cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
> }
>
> diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
> index 93adc64666f3..1833724542cd 100644
> --- a/fs/cifs/smb2proto.h
> +++ b/fs/cifs/smb2proto.h
> @@ -123,7 +123,7 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
> extern int smb2_async_readv(struct cifs_readdata *rdata);
> extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
> unsigned int *nbytes, char **buf, int *buf_type);
> -extern int smb2_async_writev(struct cifs_writedata *wdata);
> +extern int smb2_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref));
> extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
> unsigned int *nbytes, struct kvec *iov, int n_vec);
> extern int SMB2_echo(struct TCP_Server_Info *server);
> --
> 1.8.5.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Reviewed-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] cifs: clean up page array when uncached write send fails
[not found] ` <CAKywueTk-9GSrRpu_YHRccuQ7bzep-8=PzQEX1p1waDu00UVAA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2014-02-08 2:51 ` Steve French
0 siblings, 0 replies; 5+ messages in thread
From: Steve French @ 2014-02-08 2:51 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: Jeff Layton, linux-cifs
merged into cifs-2.6.git for-next after minor formatting changes (80
column checkpatch warnings)
On Fri, Feb 7, 2014 at 10:26 AM, Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> 2014-02-07 20:02 GMT+04:00 Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>:
>> In the event that a send fails in an uncached write, or we end up
>> needing to reissue it (-EAGAIN case), we'll kfree the wdata but
>> the pages currently leak.
>>
>> Fix this by adding a new kref release routine for uncached writedata
>> that releases the pages, and have the uncached codepaths use that.
>>
>> Signed-off-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> ---
>> fs/cifs/cifsglob.h | 2 +-
>> fs/cifs/cifsproto.h | 2 +-
>> fs/cifs/cifssmb.c | 6 +++---
>> fs/cifs/file.c | 28 +++++++++++++++++-----------
>> fs/cifs/smb2pdu.c | 4 ++--
>> fs/cifs/smb2proto.h | 2 +-
>> 6 files changed, 25 insertions(+), 19 deletions(-)
>>
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index a245d1809ed8..57d07e704d97 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -323,7 +323,7 @@ struct smb_version_operations {
>> /* async read from the server */
>> int (*async_readv)(struct cifs_readdata *);
>> /* async write to the server */
>> - int (*async_writev)(struct cifs_writedata *);
>> + int (*async_writev)(struct cifs_writedata *, void (*release)(struct kref *));
>> /* sync read from the server */
>> int (*sync_read)(const unsigned int, struct cifsFileInfo *,
>> struct cifs_io_parms *, unsigned int *, char **,
>> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
>> index 79e6e9a93a8c..a4f90c0d9950 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -488,7 +488,7 @@ void cifs_readdata_release(struct kref *refcount);
>> int cifs_async_readv(struct cifs_readdata *rdata);
>> int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
>>
>> -int cifs_async_writev(struct cifs_writedata *wdata);
>> +int cifs_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref));
>> void cifs_writev_complete(struct work_struct *work);
>> struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
>> work_func_t complete);
>> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
>> index 4d881c35eeca..0726ab413b8c 100644
>> --- a/fs/cifs/cifssmb.c
>> +++ b/fs/cifs/cifssmb.c
>> @@ -1910,7 +1910,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
>>
>> do {
>> server = tlink_tcon(wdata->cfile->tlink)->ses->server;
>> - rc = server->ops->async_writev(wdata);
>> + rc = server->ops->async_writev(wdata, cifs_writedata_release);
>> } while (rc == -EAGAIN);
>>
>> for (i = 0; i < wdata->nr_pages; i++) {
>> @@ -2031,7 +2031,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
>>
>> /* cifs_async_writev - send an async write, and set up mid to handle result */
>> int
>> -cifs_async_writev(struct cifs_writedata *wdata)
>> +cifs_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref))
>> {
>> int rc = -EACCES;
>> WRITE_REQ *smb = NULL;
>> @@ -2105,7 +2105,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
>> if (rc == 0)
>> cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
>> else
>> - kref_put(&wdata->refcount, cifs_writedata_release);
>> + kref_put(&wdata->refcount, release);
>>
>> async_writev_out:
>> cifs_small_buf_release(smb);
>> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
>> index 853d6d1cc822..03d1f454c713 100644
>> --- a/fs/cifs/file.c
>> +++ b/fs/cifs/file.c
>> @@ -2043,7 +2043,7 @@ retry:
>> }
>> wdata->pid = wdata->cfile->pid;
>> server = tlink_tcon(wdata->cfile->tlink)->ses->server;
>> - rc = server->ops->async_writev(wdata);
>> + rc = server->ops->async_writev(wdata, cifs_writedata_release);
>> } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
>>
>> for (i = 0; i < nr_pages; ++i)
>> @@ -2331,9 +2331,20 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
>> }
>>
>> static void
>> -cifs_uncached_writev_complete(struct work_struct *work)
>> +cifs_uncached_writedata_release(struct kref *refcount)
>> {
>> int i;
>> + struct cifs_writedata *wdata = container_of(refcount,
>> + struct cifs_writedata, refcount);
>> +
>> + for (i = 0; i < wdata->nr_pages; i++)
>> + put_page(wdata->pages[i]);
>> + cifs_writedata_release(refcount);
>> +}
>> +
>> +static void
>> +cifs_uncached_writev_complete(struct work_struct *work)
>> +{
>> struct cifs_writedata *wdata = container_of(work,
>> struct cifs_writedata, work);
>> struct inode *inode = wdata->cfile->dentry->d_inode;
>> @@ -2347,12 +2358,7 @@ cifs_uncached_writev_complete(struct work_struct *work)
>>
>> complete(&wdata->done);
>>
>> - if (wdata->result != -EAGAIN) {
>> - for (i = 0; i < wdata->nr_pages; i++)
>> - put_page(wdata->pages[i]);
>> - }
>> -
>> - kref_put(&wdata->refcount, cifs_writedata_release);
>> + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
>> }
>>
>> /* attempt to send write to server, retry on any -EAGAIN errors */
>> @@ -2370,7 +2376,7 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
>> if (rc != 0)
>> continue;
>> }
>> - rc = server->ops->async_writev(wdata);
>> + rc = server->ops->async_writev(wdata, cifs_uncached_writedata_release);
>> } while (rc == -EAGAIN);
>>
>> return rc;
>> @@ -2454,7 +2460,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
>> wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
>> rc = cifs_uncached_retry_writev(wdata);
>> if (rc) {
>> - kref_put(&wdata->refcount, cifs_writedata_release);
>> + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
>> break;
>> }
>>
>> @@ -2496,7 +2502,7 @@ restart_loop:
>> }
>> }
>> list_del_init(&wdata->list);
>> - kref_put(&wdata->refcount, cifs_writedata_release);
>> + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
>> }
>>
>> if (total_written > 0)
>> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
>> index 2013234b73ad..8c04bdeda136 100644
>> --- a/fs/cifs/smb2pdu.c
>> +++ b/fs/cifs/smb2pdu.c
>> @@ -1890,7 +1890,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
>>
>> /* smb2_async_writev - send an async write, and set up mid to handle result */
>> int
>> -smb2_async_writev(struct cifs_writedata *wdata)
>> +smb2_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref))
>> {
>> int rc = -EACCES;
>> struct smb2_write_req *req = NULL;
>> @@ -1938,7 +1938,7 @@ smb2_async_writev(struct cifs_writedata *wdata)
>> smb2_writev_callback, wdata, 0);
>>
>> if (rc) {
>> - kref_put(&wdata->refcount, cifs_writedata_release);
>> + kref_put(&wdata->refcount, release);
>> cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
>> }
>>
>> diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
>> index 93adc64666f3..1833724542cd 100644
>> --- a/fs/cifs/smb2proto.h
>> +++ b/fs/cifs/smb2proto.h
>> @@ -123,7 +123,7 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
>> extern int smb2_async_readv(struct cifs_readdata *rdata);
>> extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
>> unsigned int *nbytes, char **buf, int *buf_type);
>> -extern int smb2_async_writev(struct cifs_writedata *wdata);
>> +extern int smb2_async_writev(struct cifs_writedata *wdata, void (*release)(struct kref *kref));
>> extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
>> unsigned int *nbytes, struct kvec *iov, int n_vec);
>> extern int SMB2_echo(struct TCP_Server_Info *server);
>> --
>> 1.8.5.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> Reviewed-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>
> --
> Best regards,
> Pavel Shilovsky.
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2014-02-08 2:51 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-06 19:42 [PATCH] cifs: clean up page array when uncached write send fails Jeff Layton
[not found] ` <1391715764-21225-1-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2014-02-07 13:15 ` Jeff Layton
2014-02-07 16:02 ` [PATCH v2] " Jeff Layton
[not found] ` <1391788961-26028-1-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2014-02-07 16:26 ` Pavel Shilovsky
[not found] ` <CAKywueTk-9GSrRpu_YHRccuQ7bzep-8=PzQEX1p1waDu00UVAA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-02-08 2:51 ` Steve French
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.