dcache: d_obtain_alias callers don't all want DISCONNECTED
There are a few d_obtain_alias callers that are using it to get the
root of a filesystem which may already have an alias somewhere else.
This is not the same as the filehandle-lookup case, and none of them
actually need DCACHE_DISCONNECTED set.
It isn't really a serious problem, but it would really be clearer if we
reserved DCACHE_DISCONNECTED for those cases where it's actually needed.
In the btrfs case this was causing a spurious printk from
nfsd/nfsfh.c:fh_verify when it found an unexpected DCACHE_DISCONNECTED
dentry. Josef worked around this by unsetting DCACHE_DISCONNECTED
manually in 3a0dfa6a12 "Btrfs: unset DCACHE_DISCONNECTED when mounting
default subvol", and this replaces that workaround.
Cc: Josef Bacik <jbacik@fb.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
@@ -851,7 +851,6 @@ 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;
|
||||||
|
|
||||||
@@ -922,13 +921,7 @@ setup_root:
|
|||||||
return dget(sb->s_root);
|
return dget(sb->s_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
dentry = d_obtain_alias(inode);
|
return d_obtain_root(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,
|
||||||
|
|||||||
@@ -755,7 +755,7 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
root = d_obtain_alias(inode);
|
root = d_obtain_root(inode);
|
||||||
}
|
}
|
||||||
ceph_init_dentry(root);
|
ceph_init_dentry(root);
|
||||||
dout("open_root_inode success, root dentry is %p\n", root);
|
dout("open_root_inode success, root dentry is %p\n", root);
|
||||||
|
|||||||
69
fs/dcache.c
69
fs/dcache.c
@@ -1781,25 +1781,7 @@ struct dentry *d_find_any_alias(struct inode *inode)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(d_find_any_alias);
|
EXPORT_SYMBOL(d_find_any_alias);
|
||||||
|
|
||||||
/**
|
struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
|
||||||
* d_obtain_alias - find or allocate a dentry for a given inode
|
|
||||||
* @inode: inode to allocate the dentry for
|
|
||||||
*
|
|
||||||
* Obtain a dentry for an inode resulting from NFS filehandle conversion or
|
|
||||||
* similar open by handle operations. The returned dentry may be anonymous,
|
|
||||||
* or may have a full name (if the inode was already in the cache).
|
|
||||||
*
|
|
||||||
* When called on a directory inode, we must ensure that the inode only ever
|
|
||||||
* has one dentry. If a dentry is found, that is returned instead of
|
|
||||||
* allocating a new one.
|
|
||||||
*
|
|
||||||
* On successful return, the reference to the inode has been transferred
|
|
||||||
* to the dentry. In case of an error the reference on the inode is released.
|
|
||||||
* To make it easier to use in export operations a %NULL or IS_ERR inode may
|
|
||||||
* be passed in and will be the error will be propagate to the return value,
|
|
||||||
* with a %NULL @inode replaced by ERR_PTR(-ESTALE).
|
|
||||||
*/
|
|
||||||
struct dentry *d_obtain_alias(struct inode *inode)
|
|
||||||
{
|
{
|
||||||
static const struct qstr anonstring = QSTR_INIT("/", 1);
|
static const struct qstr anonstring = QSTR_INIT("/", 1);
|
||||||
struct dentry *tmp;
|
struct dentry *tmp;
|
||||||
@@ -1830,7 +1812,10 @@ struct dentry *d_obtain_alias(struct inode *inode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* attach a disconnected dentry */
|
/* attach a disconnected dentry */
|
||||||
add_flags = d_flags_for_inode(inode) | DCACHE_DISCONNECTED;
|
add_flags = d_flags_for_inode(inode);
|
||||||
|
|
||||||
|
if (disconnected)
|
||||||
|
add_flags |= DCACHE_DISCONNECTED;
|
||||||
|
|
||||||
spin_lock(&tmp->d_lock);
|
spin_lock(&tmp->d_lock);
|
||||||
tmp->d_inode = inode;
|
tmp->d_inode = inode;
|
||||||
@@ -1851,8 +1836,52 @@ struct dentry *d_obtain_alias(struct inode *inode)
|
|||||||
iput(inode);
|
iput(inode);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* d_obtain_alias - find or allocate a DISCONNECTED dentry for a given inode
|
||||||
|
* @inode: inode to allocate the dentry for
|
||||||
|
*
|
||||||
|
* Obtain a dentry for an inode resulting from NFS filehandle conversion or
|
||||||
|
* similar open by handle operations. The returned dentry may be anonymous,
|
||||||
|
* or may have a full name (if the inode was already in the cache).
|
||||||
|
*
|
||||||
|
* When called on a directory inode, we must ensure that the inode only ever
|
||||||
|
* has one dentry. If a dentry is found, that is returned instead of
|
||||||
|
* allocating a new one.
|
||||||
|
*
|
||||||
|
* On successful return, the reference to the inode has been transferred
|
||||||
|
* to the dentry. In case of an error the reference on the inode is released.
|
||||||
|
* To make it easier to use in export operations a %NULL or IS_ERR inode may
|
||||||
|
* be passed in and the error will be propagated to the return value,
|
||||||
|
* with a %NULL @inode replaced by ERR_PTR(-ESTALE).
|
||||||
|
*/
|
||||||
|
struct dentry *d_obtain_alias(struct inode *inode)
|
||||||
|
{
|
||||||
|
return __d_obtain_alias(inode, 1);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(d_obtain_alias);
|
EXPORT_SYMBOL(d_obtain_alias);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* d_obtain_root - find or allocate a dentry for a given inode
|
||||||
|
* @inode: inode to allocate the dentry for
|
||||||
|
*
|
||||||
|
* Obtain an IS_ROOT dentry for the root of a filesystem.
|
||||||
|
*
|
||||||
|
* We must ensure that directory inodes only ever have one dentry. If a
|
||||||
|
* dentry is found, that is returned instead of allocating a new one.
|
||||||
|
*
|
||||||
|
* On successful return, the reference to the inode has been transferred
|
||||||
|
* to the dentry. In case of an error the reference on the inode is
|
||||||
|
* released. A %NULL or IS_ERR inode may be passed in and will be the
|
||||||
|
* error will be propagate to the return value, with a %NULL @inode
|
||||||
|
* replaced by ERR_PTR(-ESTALE).
|
||||||
|
*/
|
||||||
|
struct dentry *d_obtain_root(struct inode *inode)
|
||||||
|
{
|
||||||
|
return __d_obtain_alias(inode, 0);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(d_obtain_root);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* d_add_ci - lookup or allocate new dentry with case-exact name
|
* d_add_ci - lookup or allocate new dentry with case-exact name
|
||||||
* @inode: the inode case-insensitive lookup has found
|
* @inode: the inode case-insensitive lookup has found
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
|
|||||||
* if the dentry tree reaches them; however if the dentry already
|
* if the dentry tree reaches them; however if the dentry already
|
||||||
* exists, we'll pick it up at this point and use it as the root
|
* exists, we'll pick it up at this point and use it as the root
|
||||||
*/
|
*/
|
||||||
ret = d_obtain_alias(inode);
|
ret = d_obtain_root(inode);
|
||||||
if (IS_ERR(ret)) {
|
if (IS_ERR(ret)) {
|
||||||
dprintk("nfs_get_root: get root dentry failed\n");
|
dprintk("nfs_get_root: get root dentry failed\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
@@ -942,7 +942,7 @@ static int nilfs_get_root_dentry(struct super_block *sb,
|
|||||||
iput(inode);
|
iput(inode);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dentry = d_obtain_alias(inode);
|
dentry = d_obtain_root(inode);
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
ret = PTR_ERR(dentry);
|
ret = PTR_ERR(dentry);
|
||||||
goto failed_dentry;
|
goto failed_dentry;
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
|
|||||||
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
|
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
|
||||||
extern struct dentry *d_find_any_alias(struct inode *inode);
|
extern struct dentry *d_find_any_alias(struct inode *inode);
|
||||||
extern struct dentry * d_obtain_alias(struct inode *);
|
extern struct dentry * d_obtain_alias(struct inode *);
|
||||||
|
extern struct dentry * d_obtain_root(struct inode *);
|
||||||
extern void shrink_dcache_sb(struct super_block *);
|
extern void shrink_dcache_sb(struct super_block *);
|
||||||
extern void shrink_dcache_parent(struct dentry *);
|
extern void shrink_dcache_parent(struct dentry *);
|
||||||
extern void shrink_dcache_for_umount(struct super_block *);
|
extern void shrink_dcache_for_umount(struct super_block *);
|
||||||
|
|||||||
Reference in New Issue
Block a user