]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: switch imeta namespace operations to be relative to the parent
authorChristoph Hellwig <hch@lst.de>
Wed, 10 Jul 2024 15:08:07 +0000 (17:08 +0200)
committerChristoph Hellwig <hch@lst.de>
Wed, 10 Jul 2024 15:08:07 +0000 (17:08 +0200)
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 <hch@lst.de>
libxfs/xfs_imeta.c
libxfs/xfs_imeta.h
libxfs/xfs_rtgroup.c
libxfs/xfs_rtgroup.h
libxfs/xfs_rtrefcount_btree.h
libxfs/xfs_rtrmap_btree.h

index ab34e234db108a58f1bb89df7c3c2b094d23c014..312a6771d90eea6d5de762281f5373cddc580c8a 100644 (file)
  * 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?
index 33d5b6c5e6c6944c288158f693be94fd713f7af6..1391b4ee1693879ad27f2c6db22f708d857a19ff 100644 (file)
@@ -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);
 
index 3d880d9555510abcb2b6002e50d2eb639d397652..34bad559342be4d1aedd7868802283f3a4ce8145 100644 (file)
@@ -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;
-}
index 7cae4458589b4609d579047df2d4fbcd5c02043e..9e04101ef690def5281b43affd25600a34c14837 100644 (file)
@@ -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 */
index df72debf8874fde1b00d1566df085862f2f64629..20a45f2c2976b895d298185b8a59fc1121120810 100644 (file)
@@ -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,
index 94f35229b18dfbf4243de86cf8c17a992514a7cd..3bbdd3e646dc2bc4048dd4791392e98cc2c358f1 100644 (file)
@@ -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);