Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5f86dc3 authored by Sage Weil's avatar Sage Weil
Browse files

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: default avatarYehuda Sadeh <yehuda@hq.newdream.net>
Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent bf1c6aca
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -1244,9 +1244,8 @@ void ceph_dentry_lru_del(struct dentry *dn)
 * Return name hash for a given dentry.  This is dependent on
 * the parent directory's hash function.
 */
unsigned ceph_dentry_hash(struct dentry *dn)
unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn)
{
	struct inode *dir = dn->d_parent->d_inode;
	struct ceph_inode_info *dci = ceph_inode(dir);

	switch (dci->i_dir_layout.dl_dir_hash) {
+15 −9
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
	int type;
	struct ceph_nfs_fh *fh = (void *)rawfh;
	struct ceph_nfs_confh *cfh = (void *)rawfh;
	struct dentry *parent = dentry->d_parent;
	struct dentry *parent;
	struct inode *inode = dentry->d_inode;
	int connected_handle_length = sizeof(*cfh)/4;
	int handle_length = sizeof(*fh)/4;
@@ -55,26 +55,33 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
	if (ceph_snap(inode) != CEPH_NOSNAP)
		return -EINVAL;

	spin_lock(&dentry->d_lock);
	parent = dget(dentry->d_parent);
	spin_unlock(&dentry->d_lock);

	if (*max_len >= connected_handle_length) {
		dout("encode_fh %p connectable\n", dentry);
		cfh->ino = ceph_ino(dentry->d_inode);
		cfh->parent_ino = ceph_ino(parent->d_inode);
		cfh->parent_name_hash = ceph_dentry_hash(parent);
		cfh->parent_name_hash = ceph_dentry_hash(parent->d_inode,
							 dentry);
		*max_len = connected_handle_length;
		type = 2;
	} else if (*max_len >= handle_length) {
		if (connectable) {
			*max_len = connected_handle_length;
			return 255;
		}
			type = 255;
		} else {
			dout("encode_fh %p\n", dentry);
			fh->ino = ceph_ino(dentry->d_inode);
			*max_len = handle_length;
			type = 1;
		}
	} else {
		*max_len = handle_length;
		return 255;
		type = 255;
	}
	dput(parent);
	return type;
}

@@ -123,7 +130,6 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,
		return dentry;
	}
	err = ceph_init_dentry(dentry);

	if (err < 0) {
		iput(inode);
		return ERR_PTR(err);
+1 −1
Original line number Diff line number Diff line
@@ -670,7 +670,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
		} else {
			/* dir + name */
			inode = dir;
			hash = ceph_dentry_hash(req->r_dentry);
			hash = ceph_dentry_hash(dir, req->r_dentry);
			is_hash = true;
		}
	}
+1 −1
Original line number Diff line number Diff line
@@ -800,7 +800,7 @@ extern void ceph_dentry_lru_add(struct dentry *dn);
extern void ceph_dentry_lru_touch(struct dentry *dn);
extern void ceph_dentry_lru_del(struct dentry *dn);
extern void ceph_invalidate_dentry_lease(struct dentry *dentry);
extern unsigned ceph_dentry_hash(struct dentry *dn);
extern unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn);
extern struct inode *ceph_get_dentry_parent_inode(struct dentry *dentry);

/*