Commit 9358c6d4 authored by Sage Weil's avatar Sage Weil
Browse files

ceph: fix dentry rehashing on virtual .snap dir



If a lookup fails on the magic .snap directory, we bind it to a magic
snap directory inode in ceph_lookup_finish().  That code assumes the dentry
is unhashed, but a recent server-side change started returning NULL leases
on lookup failure, causing the .snap dentry to be hashed and NULL by
ceph_fill_trace().

This causes dentry hash chain corruption, or a dies when d_rehash()
includes
	BUG_ON(!d_unhashed(entry));

So, avoid processing the NULL dentry lease if it the dentry matches the
snapdir name in ceph_fill_trace().  That allows the lookup completion to
properly bind it to the snapdir inode.  BUG there if dentry is hashed to
be sure.

Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 2eaa9cfd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -488,6 +488,7 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
		struct inode *inode = ceph_get_snapdir(parent);
		dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n",
		     dentry, dentry->d_name.len, dentry->d_name.name, inode);
		BUG_ON(!d_unhashed(dentry));
		d_add(dentry, inode);
		err = 0;
	}
+9 −1
Original line number Diff line number Diff line
@@ -886,6 +886,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
	struct inode *in = NULL;
	struct ceph_mds_reply_inode *ininfo;
	struct ceph_vino vino;
	struct ceph_client *client = ceph_sb_to_client(sb);
	int i = 0;
	int err = 0;

@@ -949,7 +950,14 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
			return err;
	}

	if (rinfo->head->is_dentry && !req->r_aborted) {
	/*
	 * ignore null lease/binding on snapdir ENOENT, or else we
	 * will have trouble splicing in the virtual snapdir later
	 */
	if (rinfo->head->is_dentry && !req->r_aborted &&
	    (rinfo->head->is_target || strncmp(req->r_dentry->d_name.name,
					       client->mount_args->snapdir_name,
					       req->r_dentry->d_name.len))) {
		/*
		 * lookup link rename   : null -> possibly existing inode
		 * mknod symlink mkdir  : null -> new inode