From: Jeff Layton <jlayton@xxxxxxxxxx> 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: Jeff Layton <jlayton@xxxxxxxxxx> Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> --- fs/ceph/dir.c | 2 ++ fs/ceph/export.c | 9 +++++---- fs/ceph/inode.c | 14 +++++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 83d9358854fb..f7a790ed62c4 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -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)); diff --git a/fs/ceph/export.c b/fs/ceph/export.c index e088843a7734..f22156ee7306 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -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); } diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 156f849f5385..5db7bf4c6a26 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -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; -- 2.11.0