diff mbox

[1/3] NFS: Don't invalidate a submounted dentry in nfs_prime_dcache()

Message ID 1424736897-95767-1-git-send-email-trond.myklebust@primarydata.com (mailing list archive)
State New, archived
Headers show

Commit Message

Trond Myklebust Feb. 24, 2015, 12:14 a.m. UTC
If we're traversing a directory which contains a submounted filesystem,
or one that has a referral, the NFS server that is processing the READDIR
request will often return information for the underlying (mounted-on)
directory. It may, or may not, also return filehandle information.

If this happens, and the lookup in nfs_prime_dcache() returns the
dentry for the submounted directory, the filehandle comparison will
fail, and we call d_invalidate(). Post-commit 8ed936b5671bf
("vfs: Lazily remove mounts on unlinked files and directories."), this
means the entire subtree is unmounted.

The following minimal patch addresses this problem by punting on
the invalidation if there is a submount.

Kudos to Neil Brown <neilb@suse.de> for having tracked down this
issue (see link).

Reported-by: Nix <nix@esperi.org.uk>
Link: http://lkml.kernel.org/r/87iofju9ht.fsf@spindle.srvr.nix
Cc: stable@vger.kernel.org # 3.18+
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfs/dir.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Trond Myklebust Feb. 24, 2015, 3:09 a.m. UTC | #1
On Mon, Feb 23, 2015 at 7:14 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> If we're traversing a directory which contains a submounted filesystem,
> or one that has a referral, the NFS server that is processing the READDIR
> request will often return information for the underlying (mounted-on)
> directory. It may, or may not, also return filehandle information.
>
> If this happens, and the lookup in nfs_prime_dcache() returns the
> dentry for the submounted directory, the filehandle comparison will
> fail, and we call d_invalidate(). Post-commit 8ed936b5671bf
> ("vfs: Lazily remove mounts on unlinked files and directories."), this
> means the entire subtree is unmounted.
>
> The following minimal patch addresses this problem by punting on
> the invalidation if there is a submount.
>
> Kudos to Neil Brown <neilb@suse.de> for having tracked down this
> issue (see link).
>
> Reported-by: Nix <nix@esperi.org.uk>
> Link: http://lkml.kernel.org/r/87iofju9ht.fsf@spindle.srvr.nix
> Cc: stable@vger.kernel.org # 3.18+
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfs/dir.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> index 9b0c55cb2a2e..0da617a61c0b 100644
> --- a/fs/nfs/dir.c
> +++ b/fs/nfs/dir.c
> @@ -479,6 +479,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
>
>         dentry = d_lookup(parent, &filename);
>         if (dentry != NULL) {
> +               /* Is there a mountpoint here? If so, just exit */
> +               if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid,
> +                                       &entry->fattr->fsid))
> +                       goto out;
>                 if (nfs_same_file(dentry, entry)) {
>                         nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
>                         status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
> --

...and this of course needs the test for NFS_ATTR_FATTR_FSID from
3/3.... I've updated.
NeilBrown Feb. 24, 2015, 9:44 p.m. UTC | #2
On Mon, 23 Feb 2015 19:14:55 -0500 Trond Myklebust
<trond.myklebust@primarydata.com> wrote:

> If we're traversing a directory which contains a submounted filesystem,
> or one that has a referral, the NFS server that is processing the READDIR
> request will often return information for the underlying (mounted-on)
> directory. It may, or may not, also return filehandle information.
> 
> If this happens, and the lookup in nfs_prime_dcache() returns the
> dentry for the submounted directory, the filehandle comparison will
> fail, and we call d_invalidate(). Post-commit 8ed936b5671bf
> ("vfs: Lazily remove mounts on unlinked files and directories."), this
> means the entire subtree is unmounted.
> 
> The following minimal patch addresses this problem by punting on
> the invalidation if there is a submount.
> 
> Kudos to Neil Brown <neilb@suse.de> for having tracked down this
> issue (see link).
> 
> Reported-by: Nix <nix@esperi.org.uk>
> Link: http://lkml.kernel.org/r/87iofju9ht.fsf@spindle.srvr.nix
> Cc: stable@vger.kernel.org # 3.18+
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfs/dir.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> index 9b0c55cb2a2e..0da617a61c0b 100644
> --- a/fs/nfs/dir.c
> +++ b/fs/nfs/dir.c
> @@ -479,6 +479,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
>  
>  	dentry = d_lookup(parent, &filename);
>  	if (dentry != NULL) {
> +		/* Is there a mountpoint here? If so, just exit */
> +		if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid,
> +					&entry->fattr->fsid))
> +			goto out;

Surely we should  only consider fattr->fsid if NFS_ATTR_FATTR_FSID is set.
In the case of the Linux NFSv3 server, if this were a mountpoint on the
server, then NFS_ATTR_FATTR_FSID will not be set (as the server returns
neither postop attrs nor filehandle).

I realise that this issue is addressed in the subsequent patch (3/3), but
that isn't tagged for -stable, and this is.

NeilBrown



>  		if (nfs_same_file(dentry, entry)) {
>  			nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
>  			status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
NeilBrown Feb. 24, 2015, 9:49 p.m. UTC | #3
On Mon, 23 Feb 2015 22:09:09 -0500 Trond Myklebust
<trond.myklebust@primarydata.com> wrote:

> On Mon, Feb 23, 2015 at 7:14 PM, Trond Myklebust
> <trond.myklebust@primarydata.com> wrote:
> > If we're traversing a directory which contains a submounted filesystem,
> > or one that has a referral, the NFS server that is processing the READDIR
> > request will often return information for the underlying (mounted-on)
> > directory. It may, or may not, also return filehandle information.
> >
> > If this happens, and the lookup in nfs_prime_dcache() returns the
> > dentry for the submounted directory, the filehandle comparison will
> > fail, and we call d_invalidate(). Post-commit 8ed936b5671bf
> > ("vfs: Lazily remove mounts on unlinked files and directories."), this
> > means the entire subtree is unmounted.
> >
> > The following minimal patch addresses this problem by punting on
> > the invalidation if there is a submount.
> >
> > Kudos to Neil Brown <neilb@suse.de> for having tracked down this
> > issue (see link).
> >
> > Reported-by: Nix <nix@esperi.org.uk>
> > Link: http://lkml.kernel.org/r/87iofju9ht.fsf@spindle.srvr.nix
> > Cc: stable@vger.kernel.org # 3.18+
> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> > ---
> >  fs/nfs/dir.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> >
> > diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> > index 9b0c55cb2a2e..0da617a61c0b 100644
> > --- a/fs/nfs/dir.c
> > +++ b/fs/nfs/dir.c
> > @@ -479,6 +479,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
> >
> >         dentry = d_lookup(parent, &filename);
> >         if (dentry != NULL) {
> > +               /* Is there a mountpoint here? If so, just exit */
> > +               if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid,
> > +                                       &entry->fattr->fsid))
> > +                       goto out;
> >                 if (nfs_same_file(dentry, entry)) {
> >                         nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
> >                         status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
> > --
> 
> ...and this of course needs the test for NFS_ATTR_FATTR_FSID from
> 3/3.... I've updated.
> 
> 
> 

Sorry ... I didn't see this before my earlier reply...

What exactly do you do if NFS_ATTR_FATTR_FSID isn't set?
Hopefully you "goto out".

Thanks,
NeilBrown
Trond Myklebust Feb. 25, 2015, 12:17 a.m. UTC | #4
On Tue, Feb 24, 2015 at 4:49 PM, NeilBrown <neilb@suse.de> wrote:
> On Mon, 23 Feb 2015 22:09:09 -0500 Trond Myklebust
> <trond.myklebust@primarydata.com> wrote:
>
>> On Mon, Feb 23, 2015 at 7:14 PM, Trond Myklebust
>> <trond.myklebust@primarydata.com> wrote:
>> > If we're traversing a directory which contains a submounted filesystem,
>> > or one that has a referral, the NFS server that is processing the READDIR
>> > request will often return information for the underlying (mounted-on)
>> > directory. It may, or may not, also return filehandle information.
>> >
>> > If this happens, and the lookup in nfs_prime_dcache() returns the
>> > dentry for the submounted directory, the filehandle comparison will
>> > fail, and we call d_invalidate(). Post-commit 8ed936b5671bf
>> > ("vfs: Lazily remove mounts on unlinked files and directories."), this
>> > means the entire subtree is unmounted.
>> >
>> > The following minimal patch addresses this problem by punting on
>> > the invalidation if there is a submount.
>> >
>> > Kudos to Neil Brown <neilb@suse.de> for having tracked down this
>> > issue (see link).
>> >
>> > Reported-by: Nix <nix@esperi.org.uk>
>> > Link: http://lkml.kernel.org/r/87iofju9ht.fsf@spindle.srvr.nix
>> > Cc: stable@vger.kernel.org # 3.18+
>> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
>> > ---
>> >  fs/nfs/dir.c | 4 ++++
>> >  1 file changed, 4 insertions(+)
>> >
>> > diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
>> > index 9b0c55cb2a2e..0da617a61c0b 100644
>> > --- a/fs/nfs/dir.c
>> > +++ b/fs/nfs/dir.c
>> > @@ -479,6 +479,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
>> >
>> >         dentry = d_lookup(parent, &filename);
>> >         if (dentry != NULL) {
>> > +               /* Is there a mountpoint here? If so, just exit */
>> > +               if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid,
>> > +                                       &entry->fattr->fsid))
>> > +                       goto out;
>> >                 if (nfs_same_file(dentry, entry)) {
>> >                         nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
>> >                         status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
>> > --
>>
>> ...and this of course needs the test for NFS_ATTR_FATTR_FSID from
>> 3/3.... I've updated.
>>
>>
>>
>
> Sorry ... I didn't see this before my earlier reply...
>
> What exactly do you do if NFS_ATTR_FATTR_FSID isn't set?
> Hopefully you "goto out".
>

Yes. The test is made immediately upon entering the function, and so a
simple 'return' is sufficient.
Nix March 12, 2015, 11:15 p.m. UTC | #5
On 24 Feb 2015, Trond Myklebust stated:

> If we're traversing a directory which contains a submounted filesystem,
> or one that has a referral, the NFS server that is processing the READDIR
> request will often return information for the underlying (mounted-on)
> directory. It may, or may not, also return filehandle information.

FWIW, this never seems to have made it into 3.19.x, nor is it in the
stable queue. Was this intentional?

> Cc: stable@vger.kernel.org # 3.18+

(... hm, I guess so...)
diff mbox

Patch

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 9b0c55cb2a2e..0da617a61c0b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -479,6 +479,10 @@  void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
 
 	dentry = d_lookup(parent, &filename);
 	if (dentry != NULL) {
+		/* Is there a mountpoint here? If so, just exit */
+		if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid,
+					&entry->fattr->fsid))
+			goto out;
 		if (nfs_same_file(dentry, entry)) {
 			nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 			status = nfs_refresh_inode(dentry->d_inode, entry->fattr);