From: NeilBrown <neilb@suse.de>
To: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Trond Myklebust <trond.myklebust@primarydata.com>,
linux-nfs@vger.kernel.org
Subject: Re: [PATCH 2/8] NFS: prepare for RCU-walk support but pushing tests later in code.
Date: Thu, 6 Mar 2014 16:47:11 +1100 [thread overview]
Message-ID: <20140306164711.5bda7693@notabene.brown> (raw)
In-Reply-To: <20140305064946.GY18016@ZenIV.linux.org.uk>
[-- Attachment #1: Type: text/plain, Size: 6243 bytes --]
On Wed, 5 Mar 2014 06:49:46 +0000 Al Viro <viro@ZenIV.linux.org.uk> wrote:
> On Wed, Mar 05, 2014 at 04:59:33PM +1100, NeilBrown wrote:
> > > b) having already become negative.
> >
> > I didn't think dentries ever became negative. When a file is deleted the old
> > positive dentry is unlinked and a new negative dentry is created in it's
> > place.
> > Or has that changed since last I looked?
>
> It has never been true. See what d_delete() is doing. If there was only
> one reference to dentry, it *does* become negative.
Seems I missed that - thanks.
>
> > If they can become negative, then I could
> > dir = ACCESS_ONCE(parent->d_inode);
> > if (!dir)
> > return -ECHILD;
> >
> > Do you think that would be safe?
>
> Depends on what you do with it afterwards...
It deferences i_sb, reads a couple of integer fields (never writes) and
rcu_dereference(NFS_I(inode)->delegation);
which will currently always be NULL on a directory and if we ever did have
directory delegation, should clearly be safe to reference under rcu.
Here is my current version of that patch.
Thanks again,
NeilBrown
From 8b85de80ccc7be4e9a31a547737e091fba2ae81f Mon Sep 17 00:00:00 2001
From: NeilBrown <neilb@suse.de>
Date: Tue, 4 Mar 2014 15:06:58 +1100
Subject: [PATCH] NFS: prepare for RCU-walk support but pushing tests later in
code.
nfs_lookup_revalidate, nfs4_lookup_revalidate, and nfs_permission
all need to understand and handle RCU-walk for NFS to gain the
benefits of RCU-walk for cached information.
Currently these functions all immediately return -ECHILD
if the relevant flag (LOOKUP_RCU or MAY_NOT_BLOCK) is set.
This patch pushes those tests later in the code so that we only abort
immediately before we enter rcu-unsafe code. As subsequent patches
make that rcu-unsafe code rcu-safe, several of these new tests will
disappear.
With this patch there are several paths through the code which will no
longer return -ECHILD during an RCU-walk. However these are mostly
error paths or other uninteresting cases.
A noteworthy change in nfs_lookup_revalidate is that we don't take
(or put) the reference to ->d_parent when LOOKUP_RCU is set.
Rather we rcu_dereference ->d_parent, and check that ->d_inode
is not NULL. We also check that ->d_parent hasn't changed after
all the tests.
In nfs4_lookup_revalidate we simple avoid testing LOOKUP_RCU on the
path that simply calls nfs_lookup_revalidate() as that function
already performs the required test.
Signed-off-by: NeilBrown <neilb@suse.de>
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f5509f95f261..7530acdc5c42 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1055,21 +1055,30 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
struct nfs4_label *label = NULL;
int error;
- if (flags & LOOKUP_RCU)
- return -ECHILD;
-
- parent = dget_parent(dentry);
- dir = parent->d_inode;
+ if (flags & LOOKUP_RCU) {
+ parent = rcu_dereference(dentry->d_parent);
+ dir = ACCESS_ONCE(parent->d_inode);
+ if (!dir)
+ return -ECHILD;
+ } else {
+ parent = dget_parent(dentry);
+ dir = parent->d_inode;
+ }
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
inode = dentry->d_inode;
if (!inode) {
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+
if (nfs_neg_need_reval(dir, dentry, flags))
goto out_bad;
goto out_valid_noent;
}
if (is_bad_inode(inode)) {
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n",
__func__, dentry);
goto out_bad;
@@ -1078,6 +1087,9 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
goto out_set_verifier;
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+
/* Force a full look up iff the parent directory has changed */
if (!nfs_is_exclusive_create(dir, flags) && nfs_check_verifier(dir, dentry)) {
if (nfs_lookup_verify_inode(inode, flags))
@@ -1120,13 +1132,18 @@ out_set_verifier:
/* Success: notify readdir to use READDIRPLUS */
nfs_advise_use_readdirplus(dir);
out_valid_noent:
- dput(parent);
+ if (flags & LOOKUP_RCU) {
+ if (parent != rcu_dereference(dentry->d_parent))
+ return -ECHILD;
+ } else
+ dput(parent);
dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
__func__, dentry);
return 1;
out_zap_parent:
nfs_zap_caches(dir);
out_bad:
+ BUG_ON(flags & LOOKUP_RCU);
nfs_free_fattr(fattr);
nfs_free_fhandle(fhandle);
nfs4_label_free(label);
@@ -1152,6 +1169,7 @@ out_zap_parent:
__func__, dentry);
return 0;
out_error:
+ BUG_ON(flags & LOOKUP_RCU);
nfs_free_fattr(fattr);
nfs_free_fhandle(fhandle);
nfs4_label_free(label);
@@ -1499,9 +1517,6 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
struct inode *inode;
int ret = 0;
- if (flags & LOOKUP_RCU)
- return -ECHILD;
-
if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY))
goto no_open;
if (d_mountpoint(dentry))
@@ -1518,6 +1533,9 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
struct dentry *parent;
struct inode *dir;
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+
parent = dget_parent(dentry);
dir = parent->d_inode;
if (!nfs_neg_need_reval(dir, dentry, flags))
@@ -2273,9 +2291,6 @@ int nfs_permission(struct inode *inode, int mask)
struct rpc_cred *cred;
int res = 0;
- if (mask & MAY_NOT_BLOCK)
- return -ECHILD;
-
nfs_inc_stats(inode, NFSIOS_VFSACCESS);
if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
@@ -2302,6 +2317,9 @@ force_lookup:
if (!NFS_PROTO(inode)->access)
goto out_notsup;
+ if (mask & MAY_NOT_BLOCK)
+ return -ECHILD;
+
cred = rpc_lookup_cred();
if (!IS_ERR(cred)) {
res = nfs_do_access(inode, cred, mask);
@@ -2316,6 +2334,9 @@ out:
inode->i_sb->s_id, inode->i_ino, mask, res);
return res;
out_notsup:
+ if (mask & MAY_NOT_BLOCK)
+ return -ECHILD;
+
res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (res == 0)
res = generic_permission(inode, mask);
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
next prev parent reply other threads:[~2014-03-06 5:47 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-05 3:00 [PATCH/RFC 0/8] Extend RCU-walk support to NFS NeilBrown
2014-03-05 3:00 ` [PATCH 7/8] NFS: teach nfs_lookup_verify_inode to handle LOOKUP_RCU NeilBrown
2014-03-05 3:00 ` [PATCH 1/8] NFS: nfs4_lookup_revalidate: only evaluate parent if it will be used NeilBrown
2014-03-05 3:00 ` [PATCH 5/8] NFS: teach nfs_do_access to understand MAY_NOT_BLOCK NeilBrown
2014-03-05 3:00 ` [PATCH 2/8] NFS: prepare for RCU-walk support but pushing tests later in code NeilBrown
2014-03-05 5:34 ` Al Viro
2014-03-05 5:59 ` NeilBrown
2014-03-05 6:49 ` Al Viro
2014-03-06 5:47 ` NeilBrown [this message]
2014-03-05 3:00 ` [PATCH 3/8] sunrpc/auth: allow lockless (rcu) lookup of credential cache NeilBrown
2014-03-05 3:00 ` [PATCH 4/8] sunrpc/auth: add 'rcu_walk' arg to rpc_lookup_cred NeilBrown
2014-03-05 14:43 ` Trond Myklebust
2014-03-06 5:50 ` NeilBrown
2014-03-05 3:00 ` [PATCH 8/8] NFS: allow lockless access to access_cache NeilBrown
2014-03-05 15:11 ` Trond Myklebust
2014-03-06 6:03 ` NeilBrown
2014-03-05 3:00 ` [PATCH 6/8] NFS: teach nfs_neg_need_reval to understand LOOKUP_RCU NeilBrown
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=20140306164711.5bda7693@notabene.brown \
--to=neilb@suse.de \
--cc=linux-nfs@vger.kernel.org \
--cc=trond.myklebust@primarydata.com \
--cc=viro@ZenIV.linux.org.uk \
/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.