Commit 3a0dfa6a authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason

Btrfs: unset DCACHE_DISCONNECTED when mounting default subvol

A user was running into errors from an NFS export of a subvolume that had a
default subvol set.  When we mount a default subvol we will use d_obtain_alias()
to find an existing dentry for the subvolume in the case that the root subvol
has already been mounted, or a dummy one is allocated in the case that the root
subvol has not already been mounted.  This allows us to connect the dentry later
on if we wander into the path.  However if we don't ever wander into the path we
will keep DCACHE_DISCONNECTED set for a long time, which angers NFS.  It doesn't
appear to cause any problems but it is annoying nonetheless, so simply unset
DCACHE_DISCONNECTED in the get_default_root case and switch btrfs_lookup() to
use d_materialise_unique() instead which will make everything play nicely
together and reconnect stuff if we wander into the defaul subvol path from a
different way.  With this patch I'm no longer getting the NFS errors when
exporting a volume that has been mounted with a default subvol set.  Thanks,

cc: bfields@fieldses.org
cc: ebiederm@xmission.com
Signed-off-by: default avatarJosef Bacik <jbacik@fb.com>
Acked-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent feb5f965
...@@ -5150,7 +5150,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -5150,7 +5150,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_CAST(inode); return ERR_CAST(inode);
} }
return d_splice_alias(inode, dentry); return d_materialise_unique(dentry, inode);
} }
unsigned char btrfs_filetype_table[] = { unsigned char btrfs_filetype_table[] = {
......
...@@ -855,6 +855,7 @@ static struct dentry *get_default_root(struct super_block *sb, ...@@ -855,6 +855,7 @@ static struct dentry *get_default_root(struct super_block *sb,
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_key location; struct btrfs_key location;
struct inode *inode; struct inode *inode;
struct dentry *dentry;
u64 dir_id; u64 dir_id;
int new = 0; int new = 0;
...@@ -925,7 +926,13 @@ static struct dentry *get_default_root(struct super_block *sb, ...@@ -925,7 +926,13 @@ static struct dentry *get_default_root(struct super_block *sb,
return dget(sb->s_root); return dget(sb->s_root);
} }
return d_obtain_alias(inode); dentry = d_obtain_alias(inode);
if (!IS_ERR(dentry)) {
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~DCACHE_DISCONNECTED;
spin_unlock(&dentry->d_lock);
}
return dentry;
} }
static int btrfs_fill_super(struct super_block *sb, static int btrfs_fill_super(struct super_block *sb,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment