Commit 3e10a15f authored by Jeff Layton's avatar Jeff Layton Committed by Al Viro
Browse files

ceph: fix up error handling with snapdirs



There are several warts in the snapdir error handling. The -EOPNOTSUPP
return in __snapfh_to_dentry is currently lost, and the call to
ceph_handle_snapdir is not currently checked at all.

Fix all of this up and eliminate a BUG_ON in ceph_get_snapdir. We can
handle that case with a warning and return an error.

Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 6e3e2c43
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -677,6 +677,8 @@ int ceph_handle_snapdir(struct ceph_mds_request *req,
	    strcmp(dentry->d_name.name,
		   fsc->mount_options->snapdir_name) == 0) {
		struct inode *inode = ceph_get_snapdir(parent);
		if (IS_ERR(inode))
			return PTR_ERR(inode);
		dout("ENOENT on snapdir %p '%pd', linking to snapdir %p\n",
		     dentry, dentry, inode);
		BUG_ON(!d_unhashed(dentry));
+5 −4
Original line number Diff line number Diff line
@@ -248,9 +248,10 @@ static struct dentry *__snapfh_to_dentry(struct super_block *sb,
			ihold(inode);
		} else {
			/* mds does not support lookup snapped inode */
			err = -EOPNOTSUPP;
			inode = NULL;
			inode = ERR_PTR(-EOPNOTSUPP);
		}
	} else {
		inode = ERR_PTR(-ESTALE);
	}
	ceph_mdsc_put_request(req);

@@ -261,8 +262,8 @@ static struct dentry *__snapfh_to_dentry(struct super_block *sb,
		dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d",
		      vino.ino, vino.snap, sfh->parent_ino, sfh->hash, err);
	}
	if (!inode)
		return ERR_PTR(-ESTALE);
	if (IS_ERR(inode))
		return ERR_CAST(inode);
	/* see comments in ceph_get_parent() */
	return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode);
}
+13 −1
Original line number Diff line number Diff line
@@ -78,9 +78,21 @@ struct inode *ceph_get_snapdir(struct inode *parent)
	struct inode *inode = ceph_get_inode(parent->i_sb, vino);
	struct ceph_inode_info *ci = ceph_inode(inode);

	BUG_ON(!S_ISDIR(parent->i_mode));
	if (IS_ERR(inode))
		return inode;

	if (!S_ISDIR(parent->i_mode)) {
		pr_warn_once("bad snapdir parent type (mode=0%o)\n",
			     parent->i_mode);
		return ERR_PTR(-ENOTDIR);
	}

	if (!(inode->i_state & I_NEW) && !S_ISDIR(inode->i_mode)) {
		pr_warn_once("bad snapdir inode type (mode=0%o)\n",
			     inode->i_mode);
		return ERR_PTR(-ENOTDIR);
	}

	inode->i_mode = parent->i_mode;
	inode->i_uid = parent->i_uid;
	inode->i_gid = parent->i_gid;