From: Ric Wheeler <rwheeler@redhat.com>
To: Miklos Szeredi <miklos@szeredi.hu>,
Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: Anand Avati <avati@redhat.com>, Brian Foster <bfoster@redhat.com>,
Linux FS Devel <linux-fsdevel@vger.kernel.org>,
Alexander Viro <aviro@redhat.com>,
David Howells <dhowells@redhat.com>,
Eric Paris <eparis@redhat.com>,
Linux NFS list <linux-nfs@vger.kernel.org>
Subject: Re: [PATCH] [REPOST] fuse: drop dentry on failed revalidate
Date: Thu, 01 Aug 2013 14:45:45 -0400 [thread overview]
Message-ID: <51FAACD9.8020205@redhat.com> (raw)
In-Reply-To: <20130801163940.GA1356@tucsk.piliscsaba.szeredi.hu>
On 08/01/2013 12:39 PM, Miklos Szeredi wrote:
> On Tue, Jul 30, 2013 at 03:30:45PM -0400, Ric Wheeler wrote:
>> On 07/30/2013 12:16 PM, Miklos Szeredi wrote:
>>>>> fs/fuse/dir.c | 4 ++++
>>>>> 1 file changed, 4 insertions(+)
>>>>>
>>>>> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
>>>>> index a1d9047..83c217e 100644
>>>>> --- a/fs/fuse/dir.c
>>>>> +++ b/fs/fuse/dir.c
>>>>> @@ -226,6 +226,10 @@ static int fuse_dentry_revalidate(struct dentry
>>>>> *entry, unsigned int flags)
>>>>> if (!err) {
>>>>> struct fuse_inode *fi = get_fuse_inode(inode);
>>>>> if (outarg.nodeid != get_node_id(inode)) {
>>>>> + if (!have_submounts(entry)) {
>>>>> + shrink_dcache_parent(entry);
>>>>> + d_drop(entry);
>>>>> + }
>>> Doing d_drop() on a subtree really has problems. Take this example:
>>>
>>> cd /mnt/foo/bar
>>> mkdir my-mount-point
>>> [->d_revalidate() drops "/mnt/foo"]
>>> mount whatever on ./my-mount-point
>>> cd /
>>>
>>> At this point that mount is not accessible in any way. The only way
>>> to umount it is to lazy umount the parent mount. If the parent mount
>>> was root, then that's not a practical thing to do.
>>>
>>> AFAICS nothing prevents this from happening on NFS and root privs are
>>> not required (e.g. mounting a fuse fs on an NFS home dir).
>>>
> Here's a patch that tries to address the mount issue in NFS (and in FUSE in the
> future). I haven't yet tested it, just interested in whether the concept looks
> OK or not.
>
> Not sure if the ENOENT is the best error. Also I have a little fear that this
> will cause a regression in some weird setup. Possibly we should use a new
> dentry flag for unhashing the directory dentry specifically to invalidate it.
>
> Thanks,
> Miklos
Adding in the NFS list for broader review.
I thought that the issue was primarily in FUSE itself, not seen in practice in NFS?
Ric
>
>
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 87bdb53..5c51217 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -1103,6 +1103,34 @@ rename_retry:
> }
> EXPORT_SYMBOL(have_submounts);
>
> +static bool __has_unlinked_ancestor(struct dentry *dentry)
> +{
> + struct dentry *this;
> +
> + for (this = dentry; !IS_ROOT(this); this = this->d_parent) {
> + if (d_unhashed(this))
> + return true;
> + }
> + return false;
> +}
> +
> +/*
> + * Called by mount code to check if the mountpoint is reachable (e.g. NFS can
> + * unhash a directory dentry and then the complete subtree can become
> + * unreachable).
> + */
> +bool has_unlinked_ancestor(struct dentry *dentry)
> +{
> + bool found;
> +
> + /* Need exclusion wrt. have_submounts() */
> + write_seqlock(&rename_lock);
> + found = __has_unlinked_ancestor(dentry);
> + write_sequnlock(&rename_lock);
> +
> + return found;
> +}
> +
> /*
> * Search the dentry child list of the specified parent,
> * and move any unused dentries to the end of the unused
> diff --git a/fs/internal.h b/fs/internal.h
> index 7c5f01c..d232355 100644
> --- a/fs/internal.h
> +++ b/fs/internal.h
> @@ -126,6 +126,7 @@ extern int invalidate_inodes(struct super_block *, bool);
> * dcache.c
> */
> extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
> +extern bool has_unlinked_ancestor(struct dentry *dentry);
>
> /*
> * read_write.c
> diff --git a/fs/namespace.c b/fs/namespace.c
> index 7b1ca9b..bb92a9c 100644
> --- a/fs/namespace.c
> +++ b/fs/namespace.c
> @@ -634,6 +634,15 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
> }
> dentry->d_flags |= DCACHE_MOUNTED;
> spin_unlock(&dentry->d_lock);
> +
> + if (has_unlinked_ancestor(dentry)) {
> + spin_lock(&dentry->d_lock);
> + dentry->d_flags &= ~DCACHE_MOUNTED;
> + spin_unlock(&dentry->d_lock);
> + kfree(mp);
> + return ERR_PTR(-ENOENT);
> + }
> +
> mp->m_dentry = dentry;
> mp->m_count = 1;
> list_add(&mp->m_hash, chain);
WARNING: multiple messages have this Message-ID (diff)
From: Ric Wheeler <rwheeler-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
To: Miklos Szeredi <miklos-sUDqSbJrdHQHWmgEVkV9KA@public.gmane.org>,
Trond Myklebust
<Trond.Myklebust-HgOvQuBEEgTQT0dZR+AlfA@public.gmane.org>
Cc: Anand Avati <avati-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
Brian Foster <bfoster-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
Linux FS Devel
<linux-fsdevel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
Alexander Viro <aviro-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
Eric Paris <eparis-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
Linux NFS list
<linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [PATCH] [REPOST] fuse: drop dentry on failed revalidate
Date: Thu, 01 Aug 2013 14:45:45 -0400 [thread overview]
Message-ID: <51FAACD9.8020205@redhat.com> (raw)
In-Reply-To: <20130801163940.GA1356-nYI/l+Q8b4r16c5iV7KQqR1Qg9XOENNVk/YoNI2nt5o@public.gmane.org>
On 08/01/2013 12:39 PM, Miklos Szeredi wrote:
> On Tue, Jul 30, 2013 at 03:30:45PM -0400, Ric Wheeler wrote:
>> On 07/30/2013 12:16 PM, Miklos Szeredi wrote:
>>>>> fs/fuse/dir.c | 4 ++++
>>>>> 1 file changed, 4 insertions(+)
>>>>>
>>>>> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
>>>>> index a1d9047..83c217e 100644
>>>>> --- a/fs/fuse/dir.c
>>>>> +++ b/fs/fuse/dir.c
>>>>> @@ -226,6 +226,10 @@ static int fuse_dentry_revalidate(struct dentry
>>>>> *entry, unsigned int flags)
>>>>> if (!err) {
>>>>> struct fuse_inode *fi = get_fuse_inode(inode);
>>>>> if (outarg.nodeid != get_node_id(inode)) {
>>>>> + if (!have_submounts(entry)) {
>>>>> + shrink_dcache_parent(entry);
>>>>> + d_drop(entry);
>>>>> + }
>>> Doing d_drop() on a subtree really has problems. Take this example:
>>>
>>> cd /mnt/foo/bar
>>> mkdir my-mount-point
>>> [->d_revalidate() drops "/mnt/foo"]
>>> mount whatever on ./my-mount-point
>>> cd /
>>>
>>> At this point that mount is not accessible in any way. The only way
>>> to umount it is to lazy umount the parent mount. If the parent mount
>>> was root, then that's not a practical thing to do.
>>>
>>> AFAICS nothing prevents this from happening on NFS and root privs are
>>> not required (e.g. mounting a fuse fs on an NFS home dir).
>>>
> Here's a patch that tries to address the mount issue in NFS (and in FUSE in the
> future). I haven't yet tested it, just interested in whether the concept looks
> OK or not.
>
> Not sure if the ENOENT is the best error. Also I have a little fear that this
> will cause a regression in some weird setup. Possibly we should use a new
> dentry flag for unhashing the directory dentry specifically to invalidate it.
>
> Thanks,
> Miklos
Adding in the NFS list for broader review.
I thought that the issue was primarily in FUSE itself, not seen in practice in NFS?
Ric
>
>
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 87bdb53..5c51217 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -1103,6 +1103,34 @@ rename_retry:
> }
> EXPORT_SYMBOL(have_submounts);
>
> +static bool __has_unlinked_ancestor(struct dentry *dentry)
> +{
> + struct dentry *this;
> +
> + for (this = dentry; !IS_ROOT(this); this = this->d_parent) {
> + if (d_unhashed(this))
> + return true;
> + }
> + return false;
> +}
> +
> +/*
> + * Called by mount code to check if the mountpoint is reachable (e.g. NFS can
> + * unhash a directory dentry and then the complete subtree can become
> + * unreachable).
> + */
> +bool has_unlinked_ancestor(struct dentry *dentry)
> +{
> + bool found;
> +
> + /* Need exclusion wrt. have_submounts() */
> + write_seqlock(&rename_lock);
> + found = __has_unlinked_ancestor(dentry);
> + write_sequnlock(&rename_lock);
> +
> + return found;
> +}
> +
> /*
> * Search the dentry child list of the specified parent,
> * and move any unused dentries to the end of the unused
> diff --git a/fs/internal.h b/fs/internal.h
> index 7c5f01c..d232355 100644
> --- a/fs/internal.h
> +++ b/fs/internal.h
> @@ -126,6 +126,7 @@ extern int invalidate_inodes(struct super_block *, bool);
> * dcache.c
> */
> extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
> +extern bool has_unlinked_ancestor(struct dentry *dentry);
>
> /*
> * read_write.c
> diff --git a/fs/namespace.c b/fs/namespace.c
> index 7b1ca9b..bb92a9c 100644
> --- a/fs/namespace.c
> +++ b/fs/namespace.c
> @@ -634,6 +634,15 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
> }
> dentry->d_flags |= DCACHE_MOUNTED;
> spin_unlock(&dentry->d_lock);
> +
> + if (has_unlinked_ancestor(dentry)) {
> + spin_lock(&dentry->d_lock);
> + dentry->d_flags &= ~DCACHE_MOUNTED;
> + spin_unlock(&dentry->d_lock);
> + kfree(mp);
> + return ERR_PTR(-ENOENT);
> + }
> +
> mp->m_dentry = dentry;
> mp->m_count = 1;
> list_add(&mp->m_hash, chain);
--
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-08-01 18:45 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20130725055209.GA15621@sh-el5.eng.rdu2.redhat.com>
2013-07-25 14:42 ` [PATCH] [REPOST] fuse: drop dentry on failed revalidate Ric Wheeler
2013-07-30 16:16 ` Miklos Szeredi
2013-07-30 19:30 ` Ric Wheeler
2013-08-01 16:39 ` Miklos Szeredi
2013-08-01 18:45 ` Ric Wheeler [this message]
2013-08-01 18:45 ` Ric Wheeler
2013-08-02 9:02 ` Miklos Szeredi
2013-08-02 9:02 ` Miklos Szeredi
2013-08-02 11:43 ` Jeff Layton
2013-08-02 11:43 ` Jeff Layton
2013-08-02 14:30 ` Miklos Szeredi
2013-08-02 16:58 ` Jeff Layton
2013-08-02 16:58 ` Jeff Layton
2013-08-02 12:17 ` Jeff Layton
2013-08-02 14:42 ` Miklos Szeredi
2013-08-02 17:32 ` Jeff Layton
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=51FAACD9.8020205@redhat.com \
--to=rwheeler@redhat.com \
--cc=Trond.Myklebust@netapp.com \
--cc=avati@redhat.com \
--cc=aviro@redhat.com \
--cc=bfoster@redhat.com \
--cc=dhowells@redhat.com \
--cc=eparis@redhat.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=miklos@szeredi.hu \
/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.