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 | /* |
