From c8b77deff6bb182ec1a9b1cb969d33ddf986ac7a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Jul 2024 17:08:07 +0200 Subject: [PATCH] xfs: switch imeta namespace operations to be relative to the parent Source kernel commit: 8bdc67b1d64b3afa84e271115957a213503b0d98 Switch the imeta lookup / create / link APIs to work on [parent inode, pathname component] pairs instead of the multi-level xfs_imeta_path structure. This simplifies the code a lot, and makes the dependencies on the parent directory (there is only one right one) more clear. Note that the metapath code looks a bit off with this now, we might want to try the same unlink/relink trick as we do for the leaf files there. Signed-off-by: Christoph Hellwig --- libxfs/xfs_imeta.c | 294 ++++++---------------------------- libxfs/xfs_imeta.h | 54 ++----- libxfs/xfs_rtgroup.c | 21 --- libxfs/xfs_rtgroup.h | 4 - libxfs/xfs_rtrefcount_btree.h | 7 +- libxfs/xfs_rtrmap_btree.h | 7 +- 6 files changed, 68 insertions(+), 319 deletions(-) diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c index ab34e234d..312a6771d 100644 --- a/libxfs/xfs_imeta.c +++ b/libxfs/xfs_imeta.c @@ -56,23 +56,14 @@ * or the MMAPLOCK since metadata inodes should never be exposed to user space. */ -/* Is this path ok? */ -static inline bool -xfs_imeta_path_check( - const struct xfs_imeta_path *path) -{ - return path->im_depth <= XFS_IMETA_MAX_DEPTH; -} - static inline void xfs_imeta_set_xname( struct xfs_name *xname, - const struct xfs_imeta_path *path, - unsigned int path_idx, + const char *path, unsigned char ftype) { - xname->name = (const unsigned char *)path->im_path[path_idx]; - xname->len = strlen(path->im_path[path_idx]); + xname->name = (const unsigned char *)path; + xname->len = strlen(path); xname->type = ftype; } @@ -151,115 +142,43 @@ xfs_imeta_lookup_component( } /* - * Traverse a metadata directory tree path, returning the inode corresponding - * to the parent of the last path component. If any of the path components do - * not exist, return -ENOENT. Caller must supply a transaction to avoid - * livelocks on btree cycles. - * - * @dp is returned without any locks held. + * Look up a metadata inode from the metadata directory. If the path + * component doesn't exist, return -ENOENT. */ int -xfs_imeta_iget_parent( +xfs_imeta_lookup( struct xfs_trans *tp, - const struct xfs_imeta_path *path, - struct xfs_inode **dpp) + struct xfs_inode *dp, + const char *path, + xfs_ino_t *inop) { struct xfs_name xname; - struct xfs_mount *mp = tp->t_mountp; - struct xfs_inode *dp = NULL; - xfs_ino_t ino; - unsigned int i; int error; - /* Caller wanted the root, we're done! */ - if (path->im_depth == 0) - goto out; - - /* No metadata directory means no parent. */ - if (mp->m_metadirip == NULL) - return -ENOENT; - - /* Grab a new reference to the metadir root dir. */ - error = xfs_imeta_iget(tp, mp->m_metadirip->i_ino, S_IFDIR, &dp); - if (error) - return error; - - for (i = 0; i < path->im_depth - 1; i++) { - struct xfs_inode *ip = NULL; + xfs_imeta_set_xname(&xname, path, XFS_DIR3_FT_UNKNOWN); - xfs_ilock(dp, XFS_ILOCK_EXCL); - - /* Look up the name in the current directory. */ - xfs_imeta_set_xname(&xname, path, i, XFS_DIR3_FT_DIR); - error = xfs_imeta_lookup_component(tp, dp, &xname, &ino); - if (error) - goto out_rele; - - /* - * Grab the child inode while we still have the parent - * directory locked. - */ - error = xfs_imeta_iget(tp, ino, S_IFDIR, &ip); - if (error) - goto out_rele; - - xfs_iunlock(dp, XFS_ILOCK_EXCL); - xfs_irele(dp); - dp = ip; - } - -out: - *dpp = dp; - return 0; - -out_rele: + xfs_ilock(dp, XFS_ILOCK_EXCL); + error = xfs_imeta_lookup_component(tp, dp, &xname, inop); xfs_iunlock(dp, XFS_ILOCK_EXCL); - xfs_irele(dp); + return error; } -/* - * Look up a metadata inode from the metadata directory. If the last path - * component doesn't exist, return NULLFSINO. If any other part of the path - * does not exist, return -ENOENT so we can distinguish the two. - */ int -xfs_imeta_lookup( - struct xfs_trans *tp, - const struct xfs_imeta_path *path, - xfs_ino_t *inop) +xfs_imeta_load( + struct xfs_trans *tp, + struct xfs_inode *dp, + const char *path, + umode_t mode, + struct xfs_inode **ipp) { - struct xfs_name xname; - struct xfs_inode *dp = NULL; - int error; - - ASSERT(xfs_imeta_path_check(path)); - - /* Metadata directory root cannot be used with this function. */ - if (path->im_depth == 0) { - ASSERT(0); - return -EFSCORRUPTED; - } + int error; + xfs_ino_t ino; - /* Find the parent of the last path component. */ - error = xfs_imeta_iget_parent(tp, path, &dp); + error = xfs_imeta_lookup(tp, dp, path, &ino); if (error) return error; - - xfs_ilock(dp, XFS_ILOCK_EXCL); - - /* Look up the name in the current directory. */ - xfs_imeta_set_xname(&xname, path, path->im_depth - 1, path->im_ftype); - error = xfs_imeta_lookup_component(tp, dp, &xname, inop); - if (error == -ENOENT) { - *inop = NULLFSINO; - error = 0; - } - - xfs_iunlock(dp, XFS_ILOCK_EXCL); - xfs_irele(dp); - - return error; + return xfs_imeta_iget(tp, ino, mode, ipp); } /* Set up an inode to be recognized as a metadata directory inode. */ @@ -299,40 +218,18 @@ xfs_imeta_clear_iflag( /* Initialize a metadata update structure. */ static inline int xfs_imeta_init_update( - struct xfs_mount *mp, - const struct xfs_imeta_path *path, + struct xfs_inode *dp, + const char *path, struct xfs_imeta_update *upd) { - struct xfs_trans *tp; - int error; - - ASSERT(xfs_has_metadir(mp)); + ASSERT(xfs_has_metadir(dp->i_mount)); memset(upd, 0, sizeof(struct xfs_imeta_update)); - upd->mp = mp; + upd->mp = dp->i_mount; + upd->dp = dp; upd->path = path; - /* - * Find the parent of the last path component. If the parent path does - * not exist, we consider this corruption because paths are supposed - * to exist. For example, if the path is /quota/user, we require that - * /quota already exists. - */ - error = xfs_trans_alloc_empty(mp, &tp); - if (error) - return error; - error = xfs_imeta_iget_parent(tp, upd->path, &upd->dp); - xfs_trans_cancel(tp); - if (error == -ENOENT) { - xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); - return -EFSCORRUPTED; - } - if (xfs_metadata_is_sick(error)) - xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); - if (error) - return error; - - return xfs_parent_start(mp, &upd->ppargs); + return xfs_parent_start(upd->mp, &upd->ppargs); } /* @@ -362,9 +259,6 @@ xfs_imeta_teardown( if (upd->dp_locked) xfs_iunlock(upd->dp, XFS_ILOCK_EXCL); upd->dp_locked = false; - - xfs_irele(upd->dp); - upd->dp = NULL; } } @@ -374,13 +268,14 @@ xfs_imeta_teardown( */ int xfs_imeta_start_create( - struct xfs_mount *mp, - const struct xfs_imeta_path *path, + struct xfs_inode *dp, + const char *path, struct xfs_imeta_update *upd) { + struct xfs_mount *mp = dp->i_mount; int error; - error = xfs_imeta_init_update(mp, path, upd); + error = xfs_imeta_init_update(dp, path, upd); if (error) return error; @@ -442,19 +337,10 @@ xfs_imeta_create( unsigned int resblks; int error; - ASSERT(xfs_imeta_path_check(upd->path)); xfs_assert_ilocked(upd->dp, XFS_ILOCK_EXCL); - /* Metadata directory root cannot be created with this function. */ - if (upd->path->im_depth == 0) { - ASSERT(0); - xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); - return -EFSCORRUPTED; - } - /* Check that the name does not already exist in the directory. */ - xfs_imeta_set_xname(&xname, upd->path, upd->path->im_depth - 1, - XFS_DIR3_FT_UNKNOWN); + xfs_imeta_set_xname(&xname, upd->path, XFS_DIR3_FT_UNKNOWN); error = xfs_imeta_lookup_component(upd->tp, upd->dp, &xname, &ino); switch (error) { case -ENOENT: @@ -513,21 +399,20 @@ xfs_imeta_create( */ int xfs_imeta_start_link( - struct xfs_mount *mp, - const struct xfs_imeta_path *path, + struct xfs_inode *dp, + const char *path, struct xfs_inode *ip, struct xfs_imeta_update *upd) { + struct xfs_mount *mp = dp->i_mount; unsigned int resblks; int nospace_error = 0; int error; - error = xfs_imeta_init_update(mp, path, upd); + error = xfs_imeta_init_update(dp, path, upd); if (error) return error; - ASSERT(upd->dp != NULL); - upd->ip = ip; resblks = xfs_link_space_res(mp, MAXNAMELEN); @@ -576,20 +461,11 @@ xfs_imeta_link( unsigned int resblks; int error; - ASSERT(xfs_imeta_path_check(upd->path)); - xfs_assert_ilocked(upd->dp, XFS_ILOCK_EXCL); xfs_assert_ilocked(upd->ip, XFS_ILOCK_EXCL); - /* Metadata directory root cannot be linked. */ - if (upd->path->im_depth == 0) { - ASSERT(0); - xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); - return -EFSCORRUPTED; - } - /* Look up the name in the current directory. */ - xfs_imeta_set_xname(&xname, upd->path, upd->path->im_depth - 1, + xfs_imeta_set_xname(&xname, upd->path, xfs_mode_to_ftype(VFS_I(upd->ip)->i_mode)); error = xfs_imeta_lookup_component(upd->tp, upd->dp, &xname, &ino); switch (error) { @@ -643,19 +519,20 @@ xfs_imeta_cancel( } /* Create a metadata for the last component of the path. */ -STATIC int +int xfs_imeta_mkdir( - struct xfs_mount *mp, - const struct xfs_imeta_path *path) + struct xfs_inode *dp, + const char *path, + struct xfs_inode **ipp) { struct xfs_imeta_update upd = { }; int error; - if (xfs_is_shutdown(mp)) + if (xfs_is_shutdown(dp->i_mount)) return -EIO; /* Allocate a transaction to create the last directory. */ - error = xfs_imeta_start_create(mp, path, &upd); + error = xfs_imeta_start_create(dp, path, &upd); if (error) return error; @@ -665,12 +542,12 @@ xfs_imeta_mkdir( goto out_cancel; error = xfs_imeta_commit(&upd); + if (error) + goto out_irele; - /* - * We don't pass the directory we just created to the caller, so finish - * setting up the inode, then release the dir and the dquots. - */ - goto out_irele; + xfs_finish_inode_setup(upd.ip); + *ipp = upd.ip; + return 0; out_cancel: xfs_imeta_cancel(&upd, error); @@ -683,77 +560,6 @@ out_irele: return error; } -/* - * Make sure that every metadata directory path component exists and is a - * directory. - */ -int -xfs_imeta_ensure_dirpath( - struct xfs_mount *mp, - const struct xfs_imeta_path *path) -{ - struct xfs_imeta_path temp_path = { - .im_path = path->im_path, - .im_ftype = XFS_DIR3_FT_DIR, - }; - int error = 0; - - if (!xfs_has_metadir(mp)) - return 0; - - for (temp_path.im_depth = 1; - temp_path.im_depth < path->im_depth; - temp_path.im_depth++) { - error = xfs_imeta_mkdir(mp, &temp_path); - if (error && error != -EEXIST) - return error; - } - - return 0; -} - -/* Create a path to a file within the metadata directory tree. */ -int -xfs_imeta_create_file_path( - struct xfs_mount *mp, - unsigned int nr_components, - struct xfs_imeta_path **pathp) -{ - struct xfs_imeta_path *p; - const char **components; - - p = kzalloc(sizeof(struct xfs_imeta_path), GFP_KERNEL); - if (!p) - return -ENOMEM; - - components = kvcalloc(nr_components, sizeof(char *), GFP_KERNEL); - if (!components) { - kfree(p); - return -ENOMEM; - } - - p->im_depth = nr_components; - p->im_path = components; - p->im_ftype = XFS_DIR3_FT_REG_FILE; - *pathp = p; - return 0; -} - -/* Free a metadata directory tree path. */ -void -xfs_imeta_free_path( - const struct xfs_imeta_path *path) -{ - unsigned int i; - - for (i = 0; i < path->im_depth; i++) { - if ((path->im_dynamicmask & (1ULL << i)) && path->im_path[i]) - kfree(path->im_path[i]); - } - kfree(path->im_path); - kfree(path); -} - /* * Is the amount of space that could be allocated towards a given metadata * file at or beneath a certain threshold? diff --git a/libxfs/xfs_imeta.h b/libxfs/xfs_imeta.h index 33d5b6c5e..1391b4ee1 100644 --- a/libxfs/xfs_imeta.h +++ b/libxfs/xfs_imeta.h @@ -6,31 +6,13 @@ #ifndef __XFS_IMETA_H__ #define __XFS_IMETA_H__ -/* How deep can we nest metadata dirs? */ -#define XFS_IMETA_MAX_DEPTH 64 - -/* Key for looking up metadata inodes. */ -struct xfs_imeta_path { - /* Array of string pointers. */ - const char **im_path; - - /* Set bits correspond to components of im_path needing to be freed */ - unsigned long long im_dynamicmask; - - /* Number of strings in path. 0 here means the metadir root. */ - uint8_t im_depth; - - /* Expected file type. */ - uint8_t im_ftype; -}; - /* Cleanup widget for metadata inode creation and deletion. */ struct xfs_imeta_update { struct xfs_mount *mp; struct xfs_trans *tp; /* Path to metadata file */ - const struct xfs_imeta_path *path; + const char *path; /* Parent pointer update context */ struct xfs_parent_args *ppargs; @@ -45,41 +27,25 @@ struct xfs_imeta_update { unsigned int ip_locked:1; }; -/* Grab the last path component, mostly for tracing. */ -static inline const char * -xfs_imeta_lastpath( - const struct xfs_imeta_update *upd) -{ - if (upd->path && upd->path->im_path && upd->path->im_depth > 0) - return upd->path->im_path[upd->path->im_depth - 1]; - return "?"; -} - -int xfs_imeta_lookup(struct xfs_trans *tp, const struct xfs_imeta_path *path, - xfs_ino_t *ino); -int xfs_imeta_iget_parent(struct xfs_trans *tp, - const struct xfs_imeta_path *path, struct xfs_inode **dpp); - -int xfs_imeta_create_file_path(struct xfs_mount *mp, - unsigned int nr_components, struct xfs_imeta_path **pathp); -void xfs_imeta_free_path(const struct xfs_imeta_path *path); +int xfs_imeta_lookup(struct xfs_trans *tp, struct xfs_inode *dp, + const char *path, xfs_ino_t *ino); +int xfs_imeta_load(struct xfs_trans *tp, struct xfs_inode *dp, + const char *path, umode_t mode, struct xfs_inode **ipp); void xfs_imeta_set_iflag(struct xfs_trans *tp, struct xfs_inode *ip); void xfs_imeta_clear_iflag(struct xfs_trans *tp, struct xfs_inode *ip); -int xfs_imeta_ensure_dirpath(struct xfs_mount *mp, - const struct xfs_imeta_path *path); - -int xfs_imeta_start_create(struct xfs_mount *mp, - const struct xfs_imeta_path *path, +int xfs_imeta_start_create(struct xfs_inode *dp, const char *path, struct xfs_imeta_update *upd); int xfs_imeta_create(struct xfs_imeta_update *upd, umode_t mode); -int xfs_imeta_start_link(struct xfs_mount *mp, - const struct xfs_imeta_path *path, +int xfs_imeta_start_link(struct xfs_inode *dp, const char *path, struct xfs_inode *ip, struct xfs_imeta_update *upd); int xfs_imeta_link(struct xfs_imeta_update *upd); +int xfs_imeta_mkdir(struct xfs_inode *dp, const char *path, + struct xfs_inode **ipp); + int xfs_imeta_commit(struct xfs_imeta_update *upd); void xfs_imeta_cancel(struct xfs_imeta_update *upd, int error); diff --git a/libxfs/xfs_rtgroup.c b/libxfs/xfs_rtgroup.c index 3d880d955..34bad5593 100644 --- a/libxfs/xfs_rtgroup.c +++ b/libxfs/xfs_rtgroup.c @@ -486,24 +486,3 @@ xfs_rtgroup_get_geometry( xfs_rtgroup_geom_health(rtg, rgeo); return 0; } - -/* Create the metadata directory path for an RT inode. */ -struct xfs_imeta_path * -xfs_rtinode_create_path( - struct xfs_mount *mp, - xfs_rgnumber_t rgno, - const char *name) -{ - struct xfs_imeta_path *path; - - if (xfs_imeta_create_file_path(mp, 2, &path) < 0) - return NULL; - path->im_dynamicmask = 0x2; - path->im_path[0] = "realtime"; - path->im_path[1] = kasprintf(GFP_KERNEL, "%u.%s", rgno, name); - if (!path->im_path[1]) { - xfs_imeta_free_path(path); - return NULL; - } - return path; -} diff --git a/libxfs/xfs_rtgroup.h b/libxfs/xfs_rtgroup.h index 7cae44585..9e04101ef 100644 --- a/libxfs/xfs_rtgroup.h +++ b/libxfs/xfs_rtgroup.h @@ -267,9 +267,6 @@ void xfs_rtgroup_unlock(struct xfs_rtgroup *rtg, unsigned int rtglock_flags); int xfs_rtgroup_get_geometry(struct xfs_rtgroup *rtg, struct xfs_rtgroup_geometry *rgeo); - -struct xfs_imeta_path *xfs_rtinode_create_path(struct xfs_mount *mp, - xfs_rgnumber_t rgno, const char *name); #else # define xfs_rtgroup_block_count(mp, rgno) (0) # define xfs_rtgroup_update_super(bp, sb_bp) ((void)0) @@ -277,7 +274,6 @@ struct xfs_imeta_path *xfs_rtinode_create_path(struct xfs_mount *mp, # define xfs_rtgroup_lock(tp, rtg, gf) ((void)0) # define xfs_rtgroup_unlock(rtg, gf) ((void)0) # define xfs_rtgroup_get_geometry(rtg, rgeo) (-EOPNOTSUPP) -# define xfs_rtinode_create_path(...) (NULL) #endif /* CONFIG_XFS_RT */ #endif /* __LIBXFS_RTGROUP_H */ diff --git a/libxfs/xfs_rtrefcount_btree.h b/libxfs/xfs_rtrefcount_btree.h index df72debf8..20a45f2c2 100644 --- a/libxfs/xfs_rtrefcount_btree.h +++ b/libxfs/xfs_rtrefcount_btree.h @@ -11,7 +11,6 @@ struct xfs_btree_cur; struct xfs_mount; struct xbtree_ifakeroot; struct xfs_rtgroup; -struct xfs_imeta_path; /* refcounts only exist on crc enabled filesystems */ #define XFS_RTREFCOUNT_BLOCK_LEN XFS_BTREE_LBLOCK_CRC_LEN @@ -70,8 +69,10 @@ unsigned int xfs_rtrefcountbt_maxlevels_ondisk(void); int __init xfs_rtrefcountbt_init_cur_cache(void); void xfs_rtrefcountbt_destroy_cur_cache(void); -#define xfs_rtrefcountbt_create_path(mp, rgno) \ - xfs_rtinode_create_path((mp), (rgno), "refcount") +static inline const char *xfs_rtrefcountbt_path(xfs_rgnumber_t rgno) +{ + return kasprintf(GFP_KERNEL, "%u.refcount", rgno); +} xfs_filblks_t xfs_rtrefcountbt_calc_reserves(struct xfs_mount *mp); unsigned long long xfs_rtrefcountbt_calc_size(struct xfs_mount *mp, diff --git a/libxfs/xfs_rtrmap_btree.h b/libxfs/xfs_rtrmap_btree.h index 94f35229b..3bbdd3e64 100644 --- a/libxfs/xfs_rtrmap_btree.h +++ b/libxfs/xfs_rtrmap_btree.h @@ -11,7 +11,6 @@ struct xfs_btree_cur; struct xfs_mount; struct xbtree_ifakeroot; struct xfs_rtgroup; -struct xfs_imeta_path; struct xfbtree; /* rmaps only exist on crc enabled filesystems */ @@ -83,8 +82,10 @@ unsigned int xfs_rtrmapbt_maxlevels_ondisk(void); int __init xfs_rtrmapbt_init_cur_cache(void); void xfs_rtrmapbt_destroy_cur_cache(void); -#define xfs_rtrmapbt_create_path(mp, rgno) \ - xfs_rtinode_create_path((mp), (rgno), "rmap") +static inline const char *xfs_rtrmapbt_path(xfs_rgnumber_t rgno) +{ + return kasprintf(GFP_KERNEL, "%u.rmap", rgno); +} xfs_filblks_t xfs_rtrmapbt_calc_reserves(struct xfs_mount *mp); -- 2.50.1