aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2011-07-26 14:30:15 -0400
committerSage Weil <sage@newdream.net>2011-07-26 14:30:15 -0400
commit48d0cbd1242aac969560ef8b90f26ee3b09a6a5c (patch)
tree228a26f8ee7d555d67c6a00e5346f3b558a2e48c
parentdfabbed6fdd509dc2beb89c954bc36014a1bc7cb (diff)
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>
-rw-r--r--fs/ceph/dir.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index f39a409db0ea..883c9546111d 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -40,14 +40,6 @@ int ceph_init_dentry(struct dentry *dentry)
40 if (dentry->d_fsdata) 40 if (dentry->d_fsdata)
41 return 0; 41 return 0;
42 42
43 if (dentry->d_parent == NULL || /* nfs fh_to_dentry */
44 ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
45 d_set_d_op(dentry, &ceph_dentry_ops);
46 else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
47 d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
48 else
49 d_set_d_op(dentry, &ceph_snap_dentry_ops);
50
51 di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO); 43 di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO);
52 if (!di) 44 if (!di)
53 return -ENOMEM; /* oh well */ 45 return -ENOMEM; /* oh well */
@@ -58,10 +50,21 @@ int ceph_init_dentry(struct dentry *dentry)
58 kmem_cache_free(ceph_dentry_cachep, di); 50 kmem_cache_free(ceph_dentry_cachep, di);
59 goto out_unlock; 51 goto out_unlock;
60 } 52 }
53
54 if (dentry->d_parent == NULL || /* nfs fh_to_dentry */
55 ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
56 d_set_d_op(dentry, &ceph_dentry_ops);
57 else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
58 d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
59 else
60 d_set_d_op(dentry, &ceph_snap_dentry_ops);
61
61 di->dentry = dentry; 62 di->dentry = dentry;
62 di->lease_session = NULL; 63 di->lease_session = NULL;
63 dentry->d_fsdata = di;
64 dentry->d_time = jiffies; 64 dentry->d_time = jiffies;
65 /* avoid reordering d_fsdata setup so that the check above is safe */
66 smp_mb();
67 dentry->d_fsdata = di;
65 ceph_dentry_lru_add(dentry); 68 ceph_dentry_lru_add(dentry);
66out_unlock: 69out_unlock:
67 spin_unlock(&dentry->d_lock); 70 spin_unlock(&dentry->d_lock);