ceph: fix RCU case handling in ceph_d_revalidate()
For RCU case ->d_revalidate() is called with rcu_read_lock() and without pinning the dentry passed to it. Which means that it can't rely upon ->d_inode remaining stable; that's the reason for d_inode_rcu(), actually. Make sure we don't reload ->d_inode there. Cc: stable@vger.kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
parent
ea60ed6fcf
commit
aa8dd81673
|
@ -1553,36 +1553,37 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||||
{
|
{
|
||||||
int valid = 0;
|
int valid = 0;
|
||||||
struct dentry *parent;
|
struct dentry *parent;
|
||||||
struct inode *dir;
|
struct inode *dir, *inode;
|
||||||
|
|
||||||
if (flags & LOOKUP_RCU) {
|
if (flags & LOOKUP_RCU) {
|
||||||
parent = READ_ONCE(dentry->d_parent);
|
parent = READ_ONCE(dentry->d_parent);
|
||||||
dir = d_inode_rcu(parent);
|
dir = d_inode_rcu(parent);
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return -ECHILD;
|
return -ECHILD;
|
||||||
|
inode = d_inode_rcu(dentry);
|
||||||
} else {
|
} else {
|
||||||
parent = dget_parent(dentry);
|
parent = dget_parent(dentry);
|
||||||
dir = d_inode(parent);
|
dir = d_inode(parent);
|
||||||
|
inode = d_inode(dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
dout("d_revalidate %p '%pd' inode %p offset %lld\n", dentry,
|
dout("d_revalidate %p '%pd' inode %p offset %lld\n", dentry,
|
||||||
dentry, d_inode(dentry), ceph_dentry(dentry)->offset);
|
dentry, inode, ceph_dentry(dentry)->offset);
|
||||||
|
|
||||||
/* always trust cached snapped dentries, snapdir dentry */
|
/* always trust cached snapped dentries, snapdir dentry */
|
||||||
if (ceph_snap(dir) != CEPH_NOSNAP) {
|
if (ceph_snap(dir) != CEPH_NOSNAP) {
|
||||||
dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
|
dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
|
||||||
dentry, d_inode(dentry));
|
dentry, inode);
|
||||||
valid = 1;
|
valid = 1;
|
||||||
} else if (d_really_is_positive(dentry) &&
|
} else if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
|
||||||
ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) {
|
|
||||||
valid = 1;
|
valid = 1;
|
||||||
} else {
|
} else {
|
||||||
valid = dentry_lease_is_valid(dentry, flags);
|
valid = dentry_lease_is_valid(dentry, flags);
|
||||||
if (valid == -ECHILD)
|
if (valid == -ECHILD)
|
||||||
return valid;
|
return valid;
|
||||||
if (valid || dir_lease_is_valid(dir, dentry)) {
|
if (valid || dir_lease_is_valid(dir, dentry)) {
|
||||||
if (d_really_is_positive(dentry))
|
if (inode)
|
||||||
valid = ceph_is_any_caps(d_inode(dentry));
|
valid = ceph_is_any_caps(inode);
|
||||||
else
|
else
|
||||||
valid = 1;
|
valid = 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue