OSDN Git Service

ceph: fix up error handling with snapdirs
authorJeff Layton <jlayton@kernel.org>
Thu, 25 Feb 2021 20:04:15 +0000 (15:04 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 8 Mar 2021 15:19:36 +0000 (10:19 -0500)
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@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/inode.c

index 83d9358..f7a790e 100644 (file)
@@ -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));
index e088843..f22156e 100644 (file)
@@ -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);
 }
index 156f849..5db7bf4 100644 (file)
@@ -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;