From: Benny Halevy <bhalevy@panasas.com>
To: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: linux-nfs@vger.kernel.org
Subject: Re: [PATCH] nfs: handle nfs_{read,write,commit}_rpcsetup errors
Date: Tue, 15 Apr 2008 10:09:50 +0300 [thread overview]
Message-ID: <480454BE.30500@panasas.com> (raw)
In-Reply-To: <1208195681.11223.18.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>
On Apr. 14, 2008, 20:54 +0300, Trond Myklebust <Trond.Myklebust@netapp.com> wrote:
> On Mon, 2008-04-14 at 20:31 +0300, Benny Halevy wrote:
>> Currently, nfs_{read,write,commit}_rpcsetup return no errors.
>> All three call rpc_run_task that can fail when out of memory.
>> Ignoring these failures leads to hangs.
>
> How?
I've seen this with instrumentation I've put in the rpc_run_task path.
However, I reexamined the call sites and I agree that since we pass
both task_setup_data.task and task_setup_data.rpc_message.rpc_cred
rpc_run_task will never fail in the current implementation.
How about adding the following BUG()s instead?
Benny
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 5a70be5..9db9db1 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -206,6 +206,8 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
task = rpc_run_task(&task_setup_data);
if (!IS_ERR(task))
rpc_put_task(task);
+ else
+ BUG();
}
static void
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index bed6341..06e6363 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -849,6 +849,8 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
task = rpc_run_task(&task_setup_data);
if (!IS_ERR(task))
rpc_put_task(task);
+ else
+ BUG();
}
/*
@@ -1216,6 +1218,8 @@ static void nfs_commit_rpcsetup(struct list_head *head,
task = rpc_run_task(&task_setup_data);
if (!IS_ERR(task))
rpc_put_task(task);
+ else
+ BUG();
}
/*
>
>> Signed-off-by: Benny Halevy <bhalevy@panasas.com>
>> ---
>> fs/nfs/read.c | 35 +++++++++++++++++++++--------
>> fs/nfs/write.c | 66 ++++++++++++++++++++++++++++++++++++-------------------
>> 2 files changed, 68 insertions(+), 33 deletions(-)
>>
>> diff --git a/fs/nfs/read.c b/fs/nfs/read.c
>> index 5a70be5..85df148 100644
>> --- a/fs/nfs/read.c
>> +++ b/fs/nfs/read.c
>> @@ -156,7 +156,7 @@ static void nfs_readpage_release(struct nfs_page *req)
>> /*
>> * Set up the NFS read request struct
>> */
>> -static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
>> +static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
>> const struct rpc_call_ops *call_ops,
>> unsigned int count, unsigned int offset)
>> {
>> @@ -204,8 +204,10 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
>> (unsigned long long)data->args.offset);
>>
>> task = rpc_run_task(&task_setup_data);
>> - if (!IS_ERR(task))
>> - rpc_put_task(task);
>> + if (unlikely(IS_ERR(task)))
>> + return PTR_ERR(task);
>> + rpc_put_task(task);
>> + return 0;
>> }
>>
>> static void
>> @@ -242,6 +244,7 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne
>> size_t rsize = NFS_SERVER(inode)->rsize, nbytes;
>> unsigned int offset;
>> int requests = 0;
>> + int ret = -ENOMEM;
>> LIST_HEAD(list);
>>
>> nfs_list_remove_request(req);
>> @@ -271,8 +274,12 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne
>>
>> if (nbytes < rsize)
>> rsize = nbytes;
>> - nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
>> - rsize, offset);
>> + ret = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
>> + rsize, offset);
>> + if (unlikely(ret)) {
>> + list_add(&data->pages, &list);
>
> NACK. This is a use-after-free case.
>
> The call to rpc_run_task() is _guaranteed_ to always call
> nfs_readpage_release(). You therefore no longer hold the page lock, nor
> can you rely on 'data' still being around.
>
> The same applies to all the other "fixes".
Agreed. I missed that.
Benny
>
> Trond
>
prev parent reply other threads:[~2008-04-15 7:10 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-04-14 17:31 [PATCH] nfs: handle nfs_{read,write,commit}_rpcsetup errors Benny Halevy
2008-04-14 17:54 ` Trond Myklebust
[not found] ` <1208195681.11223.18.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>
2008-04-15 7:09 ` Benny Halevy [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=480454BE.30500@panasas.com \
--to=bhalevy@panasas.com \
--cc=Trond.Myklebust@netapp.com \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.