From ac0380dc519aa15310670d164e98453861ef332a Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Wed, 23 Nov 2022 16:13:12 -0700 Subject: [PATCH] LU-137 osd-ldiskfs: pass through resize ioctl 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 Change-Id: I934ae1f495bd15c6435be81b51ed04f0986c0322 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/20161 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Alex Deiter Reviewed-by: Li Dongyang Reviewed-by: Oleg Drokin --- lustre/include/dt_object.h | 72 +++++++++---------- lustre/include/lvfs.h | 28 ++++++++ lustre/include/obd_support.h | 2 +- lustre/include/uapi/linux/lustre/lustre_user.h | 4 +- lustre/llite/llite_lib.c | 2 +- lustre/osd-ldiskfs/osd_handler.c | 6 +- lustre/osd-ldiskfs/osd_internal.h | 29 -------- lustre/target/tgt_mount.c | 98 +++++++++++++++++++------- 8 files changed, 146 insertions(+), 95 deletions(-) diff --git a/lustre/include/dt_object.h b/lustre/include/dt_object.h index 30090709..c4e2d62 100644 --- a/lustre/include/dt_object.h +++ b/lustre/include/dt_object.h @@ -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); } diff --git a/lustre/include/lvfs.h b/lustre/include/lvfs.h index 2ca2f19..9154e98 100644 --- a/lustre/include/lvfs.h +++ b/lustre/include/lvfs.h @@ -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 diff --git a/lustre/include/obd_support.h b/lustre/include/obd_support.h index 8b8c4f9..1619780 100644 --- a/lustre/include/obd_support.h +++ b/lustre/include/obd_support.h @@ -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) diff --git a/lustre/include/uapi/linux/lustre/lustre_user.h b/lustre/include/uapi/linux/lustre/lustre_user.h index 69d4ac9..6df699c 100644 --- a/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/lustre/include/uapi/linux/lustre/lustre_user.h @@ -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) diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index b3dd42e..9a6e896 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -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: { diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index 2e5be01..efb68c8 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -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, diff --git a/lustre/osd-ldiskfs/osd_internal.h b/lustre/osd-ldiskfs/osd_internal.h index e2f03ec..1cec2ee 100644 --- a/lustre/osd-ldiskfs/osd_internal.h +++ b/lustre/osd-ldiskfs/osd_internal.h @@ -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 diff --git a/lustre/target/tgt_mount.c b/lustre/target/tgt_mount.c index ca48aa4..bf559e2 100644 --- a/lustre/target/tgt_mount.c +++ b/lustre/target/tgt_mount.c @@ -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 = { -- 1.8.3.1