diff options
author | Sage Weil <sage@newdream.net> | 2011-07-26 14:30:55 -0400 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2011-07-26 14:30:55 -0400 |
commit | e5f86dc377e7ff2b4195831153a85a3e76fefff2 (patch) | |
tree | f15c11fc2c9b08e64555bbb601e582dc8f7325bd | |
parent | bf1c6aca96c9d2f117dc7e590c2bc2304e7febe1 (diff) |
ceph: avoid d_parent in ceph_dentry_hash; fix ceph_encode_fh() hashing bug
Have caller pass in a safely-obtained reference to the parent directory
for calculating a dentry's hash valud.
While we're here, simpify the flow through ceph_encode_fh() so that there
is a single exit point and cleanup.
Also fix a bug with the dentry hash calculation: calculate the hash for the
dentry we were given, not its parent.
Reviewed-by: Yehuda Sadeh <yehuda@hq.newdream.net>
Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r-- | fs/ceph/dir.c | 3 | ||||
-rw-r--r-- | fs/ceph/export.c | 24 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 2 | ||||
-rw-r--r-- | fs/ceph/super.h | 2 |
4 files changed, 18 insertions, 13 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 31d27f8f8261..33a19df72288 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -1244,9 +1244,8 @@ void ceph_dentry_lru_del(struct dentry *dn) | |||
1244 | * Return name hash for a given dentry. This is dependent on | 1244 | * Return name hash for a given dentry. This is dependent on |
1245 | * the parent directory's hash function. | 1245 | * the parent directory's hash function. |
1246 | */ | 1246 | */ |
1247 | unsigned ceph_dentry_hash(struct dentry *dn) | 1247 | unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn) |
1248 | { | 1248 | { |
1249 | struct inode *dir = dn->d_parent->d_inode; | ||
1250 | struct ceph_inode_info *dci = ceph_inode(dir); | 1249 | struct ceph_inode_info *dci = ceph_inode(dir); |
1251 | 1250 | ||
1252 | switch (dci->i_dir_layout.dl_dir_hash) { | 1251 | switch (dci->i_dir_layout.dl_dir_hash) { |
diff --git a/fs/ceph/export.c b/fs/ceph/export.c index f67b687550de..9fbcdecaaccd 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c | |||
@@ -46,7 +46,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len, | |||
46 | int type; | 46 | int type; |
47 | struct ceph_nfs_fh *fh = (void *)rawfh; | 47 | struct ceph_nfs_fh *fh = (void *)rawfh; |
48 | struct ceph_nfs_confh *cfh = (void *)rawfh; | 48 | struct ceph_nfs_confh *cfh = (void *)rawfh; |
49 | struct dentry *parent = dentry->d_parent; | 49 | struct dentry *parent; |
50 | struct inode *inode = dentry->d_inode; | 50 | struct inode *inode = dentry->d_inode; |
51 | int connected_handle_length = sizeof(*cfh)/4; | 51 | int connected_handle_length = sizeof(*cfh)/4; |
52 | int handle_length = sizeof(*fh)/4; | 52 | int handle_length = sizeof(*fh)/4; |
@@ -55,26 +55,33 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len, | |||
55 | if (ceph_snap(inode) != CEPH_NOSNAP) | 55 | if (ceph_snap(inode) != CEPH_NOSNAP) |
56 | return -EINVAL; | 56 | return -EINVAL; |
57 | 57 | ||
58 | spin_lock(&dentry->d_lock); | ||
59 | parent = dget(dentry->d_parent); | ||
60 | spin_unlock(&dentry->d_lock); | ||
61 | |||
58 | if (*max_len >= connected_handle_length) { | 62 | if (*max_len >= connected_handle_length) { |
59 | dout("encode_fh %p connectable\n", dentry); | 63 | dout("encode_fh %p connectable\n", dentry); |
60 | cfh->ino = ceph_ino(dentry->d_inode); | 64 | cfh->ino = ceph_ino(dentry->d_inode); |
61 | cfh->parent_ino = ceph_ino(parent->d_inode); | 65 | cfh->parent_ino = ceph_ino(parent->d_inode); |
62 | cfh->parent_name_hash = ceph_dentry_hash(parent); | 66 | cfh->parent_name_hash = ceph_dentry_hash(parent->d_inode, |
67 | dentry); | ||
63 | *max_len = connected_handle_length; | 68 | *max_len = connected_handle_length; |
64 | type = 2; | 69 | type = 2; |
65 | } else if (*max_len >= handle_length) { | 70 | } else if (*max_len >= handle_length) { |
66 | if (connectable) { | 71 | if (connectable) { |
67 | *max_len = connected_handle_length; | 72 | *max_len = connected_handle_length; |
68 | return 255; | 73 | type = 255; |
74 | } else { | ||
75 | dout("encode_fh %p\n", dentry); | ||
76 | fh->ino = ceph_ino(dentry->d_inode); | ||
77 | *max_len = handle_length; | ||
78 | type = 1; | ||
69 | } | 79 | } |
70 | dout("encode_fh %p\n", dentry); | ||
71 | fh->ino = ceph_ino(dentry->d_inode); | ||
72 | *max_len = handle_length; | ||
73 | type = 1; | ||
74 | } else { | 80 | } else { |
75 | *max_len = handle_length; | 81 | *max_len = handle_length; |
76 | return 255; | 82 | type = 255; |
77 | } | 83 | } |
84 | dput(parent); | ||
78 | return type; | 85 | return type; |
79 | } | 86 | } |
80 | 87 | ||
@@ -123,7 +130,6 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, | |||
123 | return dentry; | 130 | return dentry; |
124 | } | 131 | } |
125 | err = ceph_init_dentry(dentry); | 132 | err = ceph_init_dentry(dentry); |
126 | |||
127 | if (err < 0) { | 133 | if (err < 0) { |
128 | iput(inode); | 134 | iput(inode); |
129 | return ERR_PTR(err); | 135 | return ERR_PTR(err); |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 3b1e743b8c8d..8a09cd5a659e 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -670,7 +670,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc, | |||
670 | } else { | 670 | } else { |
671 | /* dir + name */ | 671 | /* dir + name */ |
672 | inode = dir; | 672 | inode = dir; |
673 | hash = ceph_dentry_hash(req->r_dentry); | 673 | hash = ceph_dentry_hash(dir, req->r_dentry); |
674 | is_hash = true; | 674 | is_hash = true; |
675 | } | 675 | } |
676 | } | 676 | } |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index c1eb9a014b74..35dc9656e499 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -800,7 +800,7 @@ extern void ceph_dentry_lru_add(struct dentry *dn); | |||
800 | extern void ceph_dentry_lru_touch(struct dentry *dn); | 800 | extern void ceph_dentry_lru_touch(struct dentry *dn); |
801 | extern void ceph_dentry_lru_del(struct dentry *dn); | 801 | extern void ceph_dentry_lru_del(struct dentry *dn); |
802 | extern void ceph_invalidate_dentry_lease(struct dentry *dentry); | 802 | extern void ceph_invalidate_dentry_lease(struct dentry *dentry); |
803 | extern unsigned ceph_dentry_hash(struct dentry *dn); | 803 | extern unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn); |
804 | extern struct inode *ceph_get_dentry_parent_inode(struct dentry *dentry); | 804 | extern struct inode *ceph_get_dentry_parent_inode(struct dentry *dentry); |
805 | 805 | ||
806 | /* | 806 | /* |