ceph: protect d_parent access in ceph_d_revalidate
Protect d_parent with d_lock. Carry a reference. Simplify the flow so that there is a single exit point and cleanup. Reviewed-by: Yehuda Sadeh <yehuda@hq.newdream.net> Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
@@ -1024,36 +1024,38 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
|
|||||||
*/
|
*/
|
||||||
static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
|
static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
|
int valid = 0;
|
||||||
struct inode *dir;
|
struct inode *dir;
|
||||||
|
|
||||||
if (nd && nd->flags & LOOKUP_RCU)
|
if (nd && nd->flags & LOOKUP_RCU)
|
||||||
return -ECHILD;
|
return -ECHILD;
|
||||||
|
|
||||||
dir = dentry->d_parent->d_inode;
|
|
||||||
|
|
||||||
dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
|
dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
|
||||||
dentry->d_name.len, dentry->d_name.name, dentry->d_inode,
|
dentry->d_name.len, dentry->d_name.name, dentry->d_inode,
|
||||||
ceph_dentry(dentry)->offset);
|
ceph_dentry(dentry)->offset);
|
||||||
|
|
||||||
|
dir = ceph_get_dentry_parent_inode(dentry);
|
||||||
|
|
||||||
/* 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 '%.*s' inode %p is SNAPPED\n", dentry,
|
dout("d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry,
|
||||||
dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
|
dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
|
||||||
goto out_touch;
|
valid = 1;
|
||||||
|
} else if (dentry->d_inode &&
|
||||||
|
ceph_snap(dentry->d_inode) == CEPH_SNAPDIR) {
|
||||||
|
valid = 1;
|
||||||
|
} else if (dentry_lease_is_valid(dentry) ||
|
||||||
|
dir_lease_is_valid(dir, dentry)) {
|
||||||
|
valid = 1;
|
||||||
}
|
}
|
||||||
if (dentry->d_inode && ceph_snap(dentry->d_inode) == CEPH_SNAPDIR)
|
|
||||||
goto out_touch;
|
|
||||||
|
|
||||||
if (dentry_lease_is_valid(dentry) ||
|
dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid");
|
||||||
dir_lease_is_valid(dir, dentry))
|
if (valid)
|
||||||
goto out_touch;
|
ceph_dentry_lru_touch(dentry);
|
||||||
|
else
|
||||||
dout("d_revalidate %p invalid\n", dentry);
|
d_drop(dentry);
|
||||||
d_drop(dentry);
|
iput(dir);
|
||||||
return 0;
|
return valid;
|
||||||
out_touch:
|
|
||||||
ceph_dentry_lru_touch(dentry);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user