ceph: handle racing calls to ceph_init_dentry
The ->lookup() and prepopulate_readdir() callers are working with unhashed dentries, so we don't have to worry. The export.c callers, though, need to initialize something they got back from d_obtain_alias() and are potentially racing with other callers. Make sure we don't return unless the dentry is properly initialized (by us or someone else). Reported-by: Al Viro <viro@ZenIV.linux.org.uk> Reviewed-by: Yehuda Sadeh <yehuda@hq.newdream.net> Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
parent
dfabbed6fd
commit
48d0cbd124
1 changed files with 12 additions and 9 deletions
|
@ -40,14 +40,6 @@ int ceph_init_dentry(struct dentry *dentry)
|
|||
if (dentry->d_fsdata)
|
||||
return 0;
|
||||
|
||||
if (dentry->d_parent == NULL || /* nfs fh_to_dentry */
|
||||
ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
|
||||
d_set_d_op(dentry, &ceph_dentry_ops);
|
||||
else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
|
||||
d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
|
||||
else
|
||||
d_set_d_op(dentry, &ceph_snap_dentry_ops);
|
||||
|
||||
di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO);
|
||||
if (!di)
|
||||
return -ENOMEM; /* oh well */
|
||||
|
@ -58,10 +50,21 @@ int ceph_init_dentry(struct dentry *dentry)
|
|||
kmem_cache_free(ceph_dentry_cachep, di);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (dentry->d_parent == NULL || /* nfs fh_to_dentry */
|
||||
ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
|
||||
d_set_d_op(dentry, &ceph_dentry_ops);
|
||||
else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
|
||||
d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
|
||||
else
|
||||
d_set_d_op(dentry, &ceph_snap_dentry_ops);
|
||||
|
||||
di->dentry = dentry;
|
||||
di->lease_session = NULL;
|
||||
dentry->d_fsdata = di;
|
||||
dentry->d_time = jiffies;
|
||||
/* avoid reordering d_fsdata setup so that the check above is safe */
|
||||
smp_mb();
|
||||
dentry->d_fsdata = di;
|
||||
ceph_dentry_lru_add(dentry);
|
||||
out_unlock:
|
||||
spin_unlock(&dentry->d_lock);
|
||||
|
|
Loading…
Reference in a new issue