Whamcloud - gitweb
LU-137 osd-ldiskfs: pass through resize ioctl 61/20161/16
authorAndreas Dilger <adilger@whamcloud.com>
Wed, 23 Nov 2022 23:13:12 +0000 (16:13 -0700)
committerOleg Drokin <green@whamcloud.com>
Fri, 19 May 2023 07:00:58 +0000 (07:00 +0000)
Pass through the EXT4_IOC_RESIZE_FS ioctl to the underlying ldiskfs
code so that it is possible to online resize MDT and OST filesystems.

When running resize2fs against a filesystem, it compares st_rdev of
the block device against st_dev of the mounted filesystem, so the
mounted Lustre stub filesystem needs to return proper stat information
from the ldiskfs root directory.  Add in a server_getattr() method
to the server inode_operations.  Using generic_fillattr() is enough,
we don't need the added complexity of calling ext4_getattr() (which
does not exist on directories for all kernel versions).

Change the OSD API from returning the superblock with dt_mnt_sb_get()
to returning the vfsmount with dt_mnt_get(), since it also contains
the superblock, but is more useful for calling some inode methods.

Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Change-Id: I934ae1f495bd15c6435be81b51ed04f0986c0322
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/20161
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Alex Deiter <alex.deiter@gmail.com>
Reviewed-by: Li Dongyang <dongyangli@ddn.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/include/dt_object.h
lustre/include/lvfs.h
lustre/include/obd_support.h
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/llite/llite_lib.c
lustre/osd-ldiskfs/osd_handler.c
lustre/osd-ldiskfs/osd_internal.h
lustre/target/tgt_mount.c

index 3009070..c4e2d62 100644 (file)
@@ -117,8 +117,8 @@ struct dt_txn_commit_cb {
  * Operations on dt device.
  */
 struct dt_device_operations {
-        /**
-         * Return device-wide statistics.
+       /**
+        * Return device-wide statistics.
         *
         * Return device-wide stats including block size, total and
         * free blocks, total and free objects, etc. See struct obd_statfs
@@ -130,13 +130,13 @@ struct dt_device_operations {
         *
         * \retval 0            on success
         * \retval negative     negated errno on error
-         */
-        int   (*dt_statfs)(const struct lu_env *env,
+        */
+       int   (*dt_statfs)(const struct lu_env *env,
                           struct dt_device *dev,
                           struct obd_statfs *osfs,
                           struct obd_statfs_info *info);
 
-        /**
+       /**
         * Create transaction.
         *
         * Create in-memory structure representing the transaction for the
@@ -151,11 +151,11 @@ struct dt_device_operations {
         *
         * \retval pointer to handle    if creation succeeds
         * \retval ERR_PTR(errno)       if creation fails
-         */
-        struct thandle *(*dt_trans_create)(const struct lu_env *env,
-                                           struct dt_device *dev);
+        */
+       struct thandle *(*dt_trans_create)(const struct lu_env *env,
+                                          struct dt_device *dev);
 
-        /**
+       /**
         * Start transaction.
         *
         * Start the transaction. The transaction described by \a th can be
@@ -172,8 +172,8 @@ struct dt_device_operations {
         *
         * \retval 0            on success
         * \retval negative     negated errno on error
-         */
-        int   (*dt_trans_start)(const struct lu_env *env,
+        */
+       int   (*dt_trans_start)(const struct lu_env *env,
                                struct dt_device *dev,
                                struct thandle *th);
 
@@ -197,8 +197,8 @@ struct dt_device_operations {
                               struct dt_device *dev,
                               struct thandle *th);
 
-        /**
-         * Add commit callback to the transaction.
+       /**
+        * Add commit callback to the transaction.
         *
         * Add a commit callback to the given transaction handle. The callback
         * will be called when the associated transaction is stored. I.e. the
@@ -216,11 +216,11 @@ struct dt_device_operations {
         *
         * \retval 0            on success
         * \retval negative     negated errno on error
-         */
-        int   (*dt_trans_cb_add)(struct thandle *th,
-                                 struct dt_txn_commit_cb *dcb);
+        */
+       int   (*dt_trans_cb_add)(struct thandle *th,
+                                struct dt_txn_commit_cb *dcb);
 
-        /**
+       /**
         * Return FID of root index object.
         *
         * Return the FID of the root object in the filesystem. This object
@@ -234,13 +234,13 @@ struct dt_device_operations {
         *
         * \retval 0            on success
         * \retval negative     negated errno on error
-         */
-        int   (*dt_root_get)(const struct lu_env *env,
+        */
+       int   (*dt_root_get)(const struct lu_env *env,
                             struct dt_device *dev,
                             struct lu_fid *f);
 
-        /**
-         * Return device configuration data.
+       /**
+        * Return device configuration data.
         *
         * Return device (disk fs, actually) specific configuration.
         * The configuration isn't subject to change at runtime.
@@ -249,17 +249,17 @@ struct dt_device_operations {
         * \param[in] env       execution environment for this thread
         * \param[in] dev       dt device
         * \param[out] param    configuration parameters
-         */
-        void  (*dt_conf_get)(const struct lu_env *env,
-                             const struct dt_device *dev,
-                             struct dt_device_param *param);
+        */
+       void  (*dt_conf_get)(const struct lu_env *env,
+                            const struct dt_device *dev,
+                            struct dt_device_param *param);
 
        /**
-        * Return device's super block.
+        * Return device's vfsmount.
         *
         * \param[in] dev       dt device
         */
-       struct super_block *(*dt_mnt_sb_get)(const struct dt_device *dev);
+       struct vfsmount *(*dt_mnt_get)(const struct dt_device *dev);
 
        /**
         * Sync the device.
@@ -2706,21 +2706,21 @@ static inline int dt_root_get(const struct lu_env *env, struct dt_device *dev,
 }
 
 static inline void dt_conf_get(const struct lu_env *env,
-                               const struct dt_device *dev,
-                               struct dt_device_param *param)
+                              const struct dt_device *dev,
+                              struct dt_device_param *param)
 {
-        LASSERT(dev);
-        LASSERT(dev->dd_ops);
-        LASSERT(dev->dd_ops->dt_conf_get);
-        return dev->dd_ops->dt_conf_get(env, dev, param);
+       LASSERT(dev);
+       LASSERT(dev->dd_ops);
+       LASSERT(dev->dd_ops->dt_conf_get);
+       return dev->dd_ops->dt_conf_get(env, dev, param);
 }
 
-static inline struct super_block *dt_mnt_sb_get(const struct dt_device *dev)
+static inline struct vfsmount *dt_mnt_get(const struct dt_device *dev)
 {
        LASSERT(dev);
        LASSERT(dev->dd_ops);
-       if (dev->dd_ops->dt_mnt_sb_get)
-               return dev->dd_ops->dt_mnt_sb_get(dev);
+       if (dev->dd_ops->dt_mnt_get)
+               return dev->dd_ops->dt_mnt_get(dev);
 
        return ERR_PTR(-EOPNOTSUPP);
 }
index 2ca2f19..9154e98 100644 (file)
@@ -69,4 +69,32 @@ static inline void OBD_SET_CTXT_MAGIC(struct lvfs_run_ctxt *ctxt)
 void push_ctxt(struct lvfs_run_ctxt *save, struct lvfs_run_ctxt *new_ctx);
 void pop_ctxt(struct lvfs_run_ctxt *saved, struct lvfs_run_ctxt *new_ctx);
 
+#if !defined(HAVE_ALLOC_FILE_PSEUDO) && defined(HAVE_SERVER_SUPPORT)
+#define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
+                                           (flag & __FMODE_NONOTIFY)))
+static inline
+struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt,
+                              const char *name, int flags,
+                              const struct file_operations *fops)
+{
+       struct qstr this = QSTR_INIT(name, strlen(name));
+       struct path path;
+       struct file *file;
+
+       path.dentry = d_alloc_pseudo(mnt->mnt_sb, &this);
+       if (!path.dentry)
+               return ERR_PTR(-ENOMEM);
+       path.mnt = mntget(mnt);
+       d_instantiate(path.dentry, inode);
+       file = alloc_file(&path, OPEN_FMODE(flags), fops);
+       if (IS_ERR(file)) {
+               ihold(inode);
+               path_put(&path);
+       } else {
+               file->f_flags = flags;
+       }
+       return file;
+}
+#endif /* !HAVE_ALLOC_FILE_PSEUDO */
+
 #endif
index 8b8c4f9..1619780 100644 (file)
@@ -1029,7 +1029,7 @@ static inline int lustre_to_lma_flags(__u32 la_flags)
  * for the client inode i_flags.  The LUSTRE_*_FL are the Lustre wire
  * protocol equivalents of LDISKFS_*_FL values stored on disk, while
  * the S_* flags are kernel-internal values that change between kernel
- * versions. These flags are set/cleared via FSFILT_IOC_{GET,SET}_FLAGS.
+ * versions. These are set/cleared via FS_IOC_GETFLAGS/FS_IOC_SETFLAGS.
  * See b=16526 for a full history.
  */
 static inline int ll_ext_to_inode_flags(int ext_flags)
index 69d4ac9..6df699c 100644 (file)
@@ -253,7 +253,9 @@ typedef struct statx lstatx_t;
 /* for statfs() */
 #define LL_SUPER_MAGIC 0x0BD00BD0
 
-#define FSFILT_IOC_GETVERSION          _IOR('f', 3, long)
+#define LL_IOC_GETVERSION              _IOR('f', 3, long)
+#define FSFILT_IOC_GETVERSION          LL_IOC_GETVERSION /* backward compat */
+#define LL_IOC_RESIZE_FS               _IOW('f', 16, __u64)
 
 /* FIEMAP flags supported by Lustre */
 #define LUSTRE_FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_DEVICE_ORDER)
index b3dd42e..9a6e896 100644 (file)
@@ -3002,7 +3002,7 @@ int ll_iocontrol(struct inode *inode, struct file *file,
        switch (cmd) {
        case BLKSSZGET:
                RETURN(put_user(PAGE_SIZE, (int __user *)uarg));
-       case FSFILT_IOC_GETVERSION:
+       case LL_IOC_GETVERSION:
        case FS_IOC_GETVERSION:
                RETURN(put_user(inode->i_generation, (int __user *)uarg));
        case FS_IOC_GETFLAGS: {
index 2e5be01..efb68c8 100644 (file)
@@ -2554,9 +2554,9 @@ out:
        param->ddp_has_lseek_data_hole = true;
 }
 
-static struct super_block *osd_mnt_sb_get(const struct dt_device *d)
+static struct vfsmount *osd_mnt_get(const struct dt_device *d)
 {
-       return osd_sb(osd_dt_dev(d));
+       return osd_dt_dev(d)->od_mnt;
 }
 
 /*
@@ -2709,7 +2709,7 @@ static const struct dt_device_operations osd_dt_ops = {
        .dt_trans_stop            = osd_trans_stop,
        .dt_trans_cb_add          = osd_trans_cb_add,
        .dt_conf_get              = osd_conf_get,
-       .dt_mnt_sb_get            = osd_mnt_sb_get,
+       .dt_mnt_get               = osd_mnt_get,
        .dt_sync                  = osd_sync,
        .dt_ro                    = osd_ro,
        .dt_commit_async          = osd_commit_async,
index e2f03ec..1cec2ee 100644 (file)
@@ -612,35 +612,6 @@ struct osd_iobuf {
 
 #define osd_dirty_inode(inode, flag)  (inode)->i_sb->s_op->dirty_inode((inode), flag)
 
-#ifndef HAVE_ALLOC_FILE_PSEUDO
-
-#define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
-                                           (flag & __FMODE_NONOTIFY)))
-static inline
-struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt,
-                              const char *name, int flags,
-                              const struct file_operations *fops)
-{
-       struct qstr this = QSTR_INIT(name, strlen(name));
-       struct path path;
-       struct file *file;
-
-       path.dentry = d_alloc_pseudo(mnt->mnt_sb, &this);
-       if (!path.dentry)
-               return ERR_PTR(-ENOMEM);
-       path.mnt = mntget(mnt);
-       d_instantiate(path.dentry, inode);
-       file = alloc_file(&path, OPEN_FMODE(flags), fops);
-       if (IS_ERR(file)) {
-               ihold(inode);
-               path_put(&path);
-       } else {
-               file->f_flags = flags;
-       }
-       return file;
-}
-#endif /* !HAVE_ALLOC_FILE_PSEUDO */
-
 #ifdef HAVE_INODE_TIMESPEC64
 # define osd_timespec                  timespec64
 #else
index ca48aa4..bf559e2 100644 (file)
@@ -1850,11 +1850,53 @@ static const struct super_operations server_ops = {
        .show_options   = server_show_options,
 };
 
+#if defined(HAVE_USER_NAMESPACE_ARG)
+# define USERNS_ARG mnt_userns,
+#else
+# define USERNS_ARG
+# ifdef HAVE_INODEOPS_ENHANCED_GETATTR
+#  define server_getattr(ns, path, st, rq, fl) server_getattr(path, st, rq, fl)
+# endif
+#endif
+
 /*
- * Xattr support for Lustre servers
+ * inode operations for Lustre server mountpoints
  */
+#if defined(HAVE_USER_NAMESPACE_ARG) || defined(HAVE_INODEOPS_ENHANCED_GETATTR)
+static int server_getattr(struct user_namespace *mnt_userns,
+                         const struct path *path, struct kstat *stat,
+                         u32 request_mask, unsigned int flags)
+{
+       struct inode *inode = d_inode(path->dentry);
+#else
+static int server_getattr(struct vfsmount *mnt, struct dentry *de,
+                         struct kstat *stat)
+{
+       struct inode *inode = de->d_inode;
+#endif
+       struct lustre_sb_info *lsi = s2lsi(inode->i_sb);
+       struct vfsmount *root_mnt;
+       struct inode *root_inode;
+
+       root_mnt = dt_mnt_get(lsi->lsi_dt_dev);
+       if (IS_ERR(root_mnt))
+               root_inode = igrab(inode);
+       else
+               root_inode = igrab(root_mnt->mnt_sb->s_root->d_inode);
+       if (!root_inode)
+               return -EACCES;
+
+       CDEBUG(D_SUPER, "%s: root_inode from %s ino=%lu, dev=%x\n",
+              lsi->lsi_svname, root_inode == inode ? "lsi" : "vfsmnt",
+              root_inode->i_ino, root_inode->i_rdev);
+       generic_fillattr(USERNS_ARG root_inode, stat);
+       iput(root_inode);
+
+       return 0;
+}
+
 #ifdef HAVE_IOP_XATTR
-static ssize_t lustre_getxattr(struct dentry *dentry, const char *name,
+static ssize_t server_getxattr(struct dentry *dentry, const char *name,
                                void *buffer, size_t size)
 {
        if (!selinux_is_enabled())
@@ -1862,24 +1904,28 @@ static ssize_t lustre_getxattr(struct dentry *dentry, const char *name,
        return -ENODATA;
 }
 
-static int lustre_setxattr(struct dentry *dentry, const char *name,
+static int server_setxattr(struct dentry *dentry, const char *name,
                            const void *value, size_t size, int flags)
 {
        return -EOPNOTSUPP;
 }
 #endif
 
-static ssize_t lustre_listxattr(struct dentry *d_entry, char *name,
+static ssize_t server_listxattr(struct dentry *d_entry, char *name,
                                size_t size)
 {
        return -EOPNOTSUPP;
 }
 
-static bool is_cmd_supported(unsigned int command)
+static bool is_cmd_supported(unsigned int cmd)
 {
-       switch (command) {
+       CDEBUG(D_SUPER, "ioctl cmd=%x\n", cmd);
+
+       switch (cmd) {
        case FITRIM:
                return true;
+       case LL_IOC_RESIZE_FS:
+               return true;
        default:
                return false;
        }
@@ -1887,37 +1933,41 @@ static bool is_cmd_supported(unsigned int command)
        return false;
 }
 
-static long server_ioctl(struct file *filp, unsigned int command,
-                        unsigned long arg)
+static long server_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-       struct file active_filp;
-       struct inode *inode = file_inode(filp);
-       struct lustre_sb_info *lsi = s2lsi(inode->i_sb);
-       struct super_block *dd_sb = dt_mnt_sb_get(lsi->lsi_dt_dev);
-       struct inode *active_inode;
+       struct lustre_sb_info *lsi = s2lsi(file_inode(filp)->i_sb);
+       struct vfsmount *root_mnt;
+       struct file *root_filp;
+       struct inode *root_inode;
        int err = -EOPNOTSUPP;
 
-       if (IS_ERR(dd_sb) || !is_cmd_supported(command))
+       if (!is_cmd_supported(cmd))
+               return err;
+
+       root_mnt = dt_mnt_get(lsi->lsi_dt_dev);
+       if (IS_ERR(root_mnt))
                return err;
 
-       active_inode = igrab(dd_sb->s_root->d_inode);
-       if (!active_inode)
+       root_inode = igrab(root_mnt->mnt_root->d_inode);
+       if (!root_inode)
                return -EACCES;
 
-       active_filp.f_inode = active_inode;
-       if (active_inode->i_fop && active_inode->i_fop->unlocked_ioctl)
-               err = active_inode->i_fop->unlocked_ioctl(&active_filp,
-                                                         command, arg);
-       iput(active_inode);
+       root_filp = alloc_file_pseudo(root_inode, root_mnt, "/",
+                                     O_RDWR | O_NOATIME, root_inode->i_fop);
+       if (root_inode->i_fop && root_inode->i_fop->unlocked_ioctl)
+               err = root_inode->i_fop->unlocked_ioctl(root_filp, cmd, arg);
+       fput(root_filp);
+
        return err;
 }
 
 static const struct inode_operations server_inode_operations = {
+       .getattr        = server_getattr,
 #ifdef HAVE_IOP_XATTR
-       .setxattr       = lustre_setxattr,
-       .getxattr       = lustre_getxattr,
+       .setxattr       = server_setxattr,
+       .getxattr       = server_getxattr,
 #endif
-       .listxattr      = lustre_listxattr,
+       .listxattr      = server_listxattr,
 };
 
 static const struct file_operations server_file_operations = {