From: "J. Bruce Fields" <bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
To: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: Christoph Hellwig <hch-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>,
Al Viro <viro-3bDd1+5oDREiFSDQTTA3OLVCufUGDwFn@public.gmane.org>,
linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
"J. Bruce Fields"
<bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Subject: [PATCH 5/5] exportfs: fix quadratic behavior in filehandle lookup
Date: Tue, 15 Oct 2013 16:39:33 -0400 [thread overview]
Message-ID: <1381869574-10662-6-git-send-email-bfields@redhat.com> (raw)
In-Reply-To: <1381869574-10662-1-git-send-email-bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
From: "J. Bruce Fields" <bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
We shouldn't really have to re-lookup the parents on each pass through.
This should make behavior linear instead of quadratic as a function of
directory depth.
Signed-off-by: J. Bruce Fields <bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/exportfs/expfs.c | 105 +++++++++++++++++++--------------------------------
1 file changed, 39 insertions(+), 66 deletions(-)
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index afa7c9c..08544ae 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -69,11 +69,7 @@ find_acceptable_alias(struct dentry *result,
return NULL;
}
-/*
- * Find root of a disconnected subtree and return a reference to it.
- */
-static struct dentry *
-find_disconnected_root(struct dentry *dentry)
+static bool dentry_connected(struct dentry *dentry)
{
dget(dentry);
while (!IS_ROOT(dentry)) {
@@ -81,13 +77,14 @@ find_disconnected_root(struct dentry *dentry)
if (!(parent->d_flags & DCACHE_DISCONNECTED)) {
dput(parent);
- break;
+ dput(dentry);
+ return true;
}
dput(dentry);
dentry = parent;
}
- return dentry;
+ return false;
}
static void clear_disconnected(struct dentry *dentry)
@@ -109,11 +106,13 @@ static void clear_disconnected(struct dentry *dentry)
/*
* Return the parent directory on success.
*
- * Return NULL to keep trying.
+ * If it races with a rename or unlink, assume the other operation
+ * connected it, but return NULL to indicate the caller should check
+ * this just to make sure the filesystem isn't nuts.
*
* Otherwise return an error.
*/
-static int reconnect_one(struct vfsmount *mnt, struct dentry *dentry, char *nbuf, int *noprogress)
+static struct dentry *reconnect_one(struct vfsmount *mnt, struct dentry *dentry, char *nbuf)
{
struct dentry *parent;
struct dentry *tmp;
@@ -137,20 +136,17 @@ static int reconnect_one(struct vfsmount *mnt, struct dentry *dentry, char *nbuf
err = PTR_ERR(parent);
dprintk("%s: get_parent of %ld failed, err %d\n",
__func__, dentry->d_inode->i_ino, err);
- return err;
+ return parent;
}
dprintk("%s: find name of %lu in %lu\n", __func__,
dentry->d_inode->i_ino, parent->d_inode->i_ino);
err = exportfs_get_name(mnt, parent, nbuf, dentry);
if (err) {
- dput(parent);
if (err == -ENOENT)
- /* some race between get_parent and
- * get_name? just try again
- */
- return 0;
- return err;
+ return NULL;
+ dput(parent);
+ return ERR_PTR(err);
}
dprintk("%s: found name: %s\n", __func__, nbuf);
mutex_lock(&parent->d_inode->i_mutex);
@@ -160,26 +156,13 @@ static int reconnect_one(struct vfsmount *mnt, struct dentry *dentry, char *nbuf
err = PTR_ERR(tmp);
dprintk("%s: lookup failed: %d\n",
__func__, err);
- dput(parent);
- return err;
+ return NULL;
}
- /* we didn't really want tmp, we really wanted
- * a side-effect of the lookup.
- * hopefully, tmp == dentry, though it isn't really
- * a problem if it isn't
- */
- if (tmp == dentry)
- *noprogress = 0;
- else
- printk("%s: tmp != dentry\n", __func__);
+ /* Note tmp != dentry is possible at this point, but that's OK */
dput(tmp);
- dput(parent);
- if (IS_ROOT(dentry)) {
- /* something went wrong, we have to give up */
- dput(dentry);
- return -ESTALE;
- }
- return 0;
+ if (IS_ROOT(dentry))
+ return ERR_PTR(-ESTALE);
+ return parent;
}
/*
@@ -190,51 +173,41 @@ static int reconnect_one(struct vfsmount *mnt, struct dentry *dentry, char *nbuf
static int
reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
{
- int noprogress = 0;
- int err = -ESTALE;
+ struct dentry *dentry, *parent;
- /*
- * It is possible that a confused file system might not let us complete
- * the path to the root. For example, if get_parent returns a directory
- * in which we cannot find a name for the child. While this implies a
- * very sick filesystem we don't want it to cause knfsd to spin. Hence
- * the noprogress counter. If we go through the loop 10 times (2 is
- * probably enough) without getting anywhere, we just give up
- */
- while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) {
- struct dentry *dentry = find_disconnected_root(target_dir);
+ dentry = dget(target_dir);
- if (!IS_ROOT(dentry)) {
- /* must have found a connected parent - great */
- clear_disconnected(target_dir);
- noprogress = 0;
- dput(dentry);
- continue;
- }
+ while (dentry->d_flags & DCACHE_DISCONNECTED) {
if (dentry == mnt->mnt_sb->s_root) {
- printk(KERN_ERR "export: Eeek filesystem root is not connected, impossible\n");
- clear_disconnected(target_dir);
- noprogress = 0;
+ WARN_ON_ONCE(1);
+ break;
+ }
+ if (!IS_ROOT(dentry)) {
+ parent = dget_parent(dentry);
dput(dentry);
+ dentry = parent;
continue;
}
/*
* We have hit the top of a disconnected path, try to
* find parent and connect.
*/
- err = reconnect_one(mnt, dentry, nbuf, &noprogress);
- if (err)
- return err;
+ parent = reconnect_one(mnt, dentry, nbuf);
dput(dentry);
+ if (!parent)
+ break;
+ if (IS_ERR(parent))
+ return PTR_ERR(parent);
+ dentry = parent;
}
-
- if (target_dir->d_flags & DCACHE_DISCONNECTED) {
- /* something went wrong - oh-well */
- if (!err)
- err = -ESTALE;
- return err;
+ /*
+ * Should be unnecessary, but let's be careful:
+ */
+ if (!dentry_connected(target_dir)) {
+ WARN_ON_ONCE(1);
+ return -ESTALE;
}
-
+ clear_disconnected(target_dir);
return 0;
}
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2013-10-15 20:39 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-10-15 20:39 simplify reconnecting dentries looked up by filehandle J. Bruce Fields
2013-10-15 20:39 ` [PATCH 1/5] exportfs: clear DISCONNECTED on all parents sooner J. Bruce Fields
[not found] ` <1381869574-10662-2-git-send-email-bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-10-16 7:13 ` Christoph Hellwig
[not found] ` <20131016071343.GB27799-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
2013-10-16 13:56 ` J. Bruce Fields
2013-10-15 20:39 ` [PATCH 2/5] exportfs: move most of reconnect_path to helper function J. Bruce Fields
[not found] ` <1381869574-10662-3-git-send-email-bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-10-16 7:16 ` Christoph Hellwig
[not found] ` <1381869574-10662-1-git-send-email-bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-10-15 20:39 ` [PATCH 3/5] exportfs: make variable names more helpful J. Bruce Fields
[not found] ` <1381869574-10662-4-git-send-email-bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-10-16 7:18 ` Christoph Hellwig
2013-10-15 20:39 ` J. Bruce Fields [this message]
[not found] ` <1381869574-10662-6-git-send-email-bfields-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-10-16 8:04 ` [PATCH 5/5] exportfs: fix quadratic behavior in filehandle lookup Christoph Hellwig
2013-10-16 18:29 ` J. Bruce Fields
2013-10-16 19:22 ` J. Bruce Fields
2013-10-16 22:00 ` J. Bruce Fields
2013-10-16 18:24 ` simplify reconnecting dentries looked up by filehandle Christoph Hellwig
2013-10-15 20:39 ` [PATCH 4/5] exportfs: slight reorganization of reconnect loop J. Bruce Fields
2013-10-16 7:19 ` Christoph Hellwig
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=1381869574-10662-6-git-send-email-bfields@redhat.com \
--to=bfields-h+wxahxf7alqt0dzr+alfa@public.gmane.org \
--cc=hch-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org \
--cc=linux-fsdevel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=viro-3bDd1+5oDREiFSDQTTA3OLVCufUGDwFn@public.gmane.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).