]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_spaceman: wrap radix tree accesses in find_owner.c
authorDarrick J. Wong <djwong@kernel.org>
Wed, 7 Aug 2024 22:54:53 +0000 (15:54 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 14 Aug 2024 03:08:26 +0000 (20:08 -0700)
Wrap the raw radix tree accesses here so that we can provide an
alternate implementation on platforms where radix tree indices cannot
store a full 64-bit inode number.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
spaceman/Makefile
spaceman/find_owner.c
spaceman/relocation.c [new file with mode: 0644]
spaceman/relocation.h [new file with mode: 0644]

index b35ab1dbd2f44051f3b2e67991b779d7d94f9d73..8980208285f610bb64b694313db9f1b21dacf492 100644 (file)
@@ -17,6 +17,7 @@ CFILES = \
        init.c \
        move_inode.c \
        prealloc.c \
+       relocation.c \
        trim.c
 LSRCFILES = xfs_info.sh
 
index 7a656d80d21217a77c5ec6228f10ac987072af18..80b239f9ac5de87ef3abcaf694ff6874406ac6dc 100644 (file)
 #include <linux/fsmap.h>
 #include "space.h"
 #include "input.h"
+#include "relocation.h"
 
 static cmdinfo_t find_owner_cmd;
 static cmdinfo_t resolve_owner_cmd;
 
 #define NR_EXTENTS 128
 
-static RADIX_TREE(inode_tree, 0);
-#define MOVE_INODE     0
-#define MOVE_BLOCKS    1
-#define INODE_PATH     2
-int inode_count;
-int inode_paths;
-
 static void
 track_inode_chunks(
        struct xfs_fd   *xfd,
@@ -39,7 +33,7 @@ track_inode_chunks(
        uint64_t        first_ino = cvt_agino_to_ino(xfd, agno,
                                                cvt_agbno_to_agino(xfd, agbno));
        uint64_t        num_inodes = cvt_b_to_inode_count(xfd, length);
-       int             i;
+       uint64_t        i;
 
        printf(_("AG %d\tInode Range to move: 0x%llx - 0x%llx (length 0x%llx)\n"),
                        agno,
@@ -47,14 +41,8 @@ track_inode_chunks(
                        (unsigned long long)first_ino + num_inodes - 1,
                        (unsigned long long)length);
 
-       for (i = 0; i < num_inodes; i++) {
-               if (!radix_tree_lookup(&inode_tree, first_ino + i)) {
-                       radix_tree_insert(&inode_tree, first_ino + i,
-                                       (void *)first_ino + i);
-                       inode_count++;
-               }
-               radix_tree_tag_set(&inode_tree, first_ino + i, MOVE_INODE);
-       }
+       for (i = 0; i < num_inodes; i++)
+               set_reloc_iflag(first_ino + i, MOVE_INODE);
 }
 
 static void
@@ -65,7 +53,7 @@ track_inode(
        uint64_t        physaddr,
        uint64_t        length)
 {
-       if (radix_tree_tag_get(&inode_tree, owner, MOVE_BLOCKS))
+       if (test_reloc_iflag(owner, MOVE_BLOCKS))
                return;
 
        printf(_("AG %d\tInode 0x%llx: blocks to move to move: 0x%llx - 0x%llx\n"),
@@ -73,11 +61,8 @@ track_inode(
                        (unsigned long long)owner,
                        (unsigned long long)physaddr,
                        (unsigned long long)physaddr + length - 1);
-       if (!radix_tree_lookup(&inode_tree, owner)) {
-               radix_tree_insert(&inode_tree, owner, (void *)owner);
-               inode_count++;
-       }
-       radix_tree_tag_set(&inode_tree, owner, MOVE_BLOCKS);
+
+       set_reloc_iflag(owner, MOVE_BLOCKS);
 }
 
 static void
@@ -111,7 +96,7 @@ scan_ag(
        h->fmr_offset = ULLONG_MAX;
 
        while (true) {
-               printf("Inode count %d\n", inode_count);
+               printf("Inode count %llu\n", get_reloc_count());
                ret = ioctl(xfd->fd, FS_IOC_GETFSMAP, fsmap);
                if (ret < 0) {
                        fprintf(stderr, _("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
@@ -245,18 +230,6 @@ find_owner_init(void)
        add_command(&find_owner_cmd);
 }
 
-/*
- * for each dirent we get returned, look up the inode tree to see if it is an
- * inode we need to process. If it is, then replace the entry in the tree with
- * a structure containing the current path and mark the entry as resolved.
- */
-struct inode_path {
-       uint64_t                ino;
-       struct list_head        path_list;
-       uint32_t                link_count;
-       char                    path[1];
-};
-
 static int
 resolve_owner_cb(
        const char              *path,
@@ -266,14 +239,14 @@ resolve_owner_cb(
 {
        struct inode_path       *ipath, *slot_ipath;
        int                     pathlen;
-       void                    **slot;
+       struct inode_path       **slot;
 
        /*
         * Lookup the slot rather than the entry so we can replace the contents
         * without another lookup later on.
         */
-       slot = radix_tree_lookup_slot(&inode_tree, stat->st_ino);
-       if (!slot || *slot == NULL)
+       slot = get_reloc_ipath_slot(stat->st_ino);
+       if (!slot)
                return 0;
 
        /* Could not get stat data? Fail! */
@@ -303,11 +276,10 @@ _("Aborting: Storing path %s for inode 0x%lx failed: %s\n"),
         * set the link count of the path to 1 and replace the slot contents
         * with our new_ipath.
         */
-       if (stat->st_ino == (uint64_t)*slot) {
+       if (*slot == UNLINKED_IPATH) {
                ipath->link_count = 1;
                *slot = ipath;
-               radix_tree_tag_set(&inode_tree, stat->st_ino, INODE_PATH);
-               inode_paths++;
+               set_reloc_iflag(stat->st_ino, INODE_PATH);
                return 0;
        }
 
@@ -351,18 +323,15 @@ list_inode_paths(void)
                bool            move_blocks;
                bool            move_inode;
 
-               ret = radix_tree_gang_lookup_tag(&inode_tree, (void **)&ipath,
-                                               idx, 1, INODE_PATH);
-               if (!ret)
+               ipath = get_next_reloc_ipath(idx);
+               if (!ipath)
                        break;
                idx = ipath->ino + 1;
 
                /* Grab status tags and remove from tree. */
-               move_blocks = radix_tree_tag_get(&inode_tree, ipath->ino,
-                                               MOVE_BLOCKS);
-               move_inode = radix_tree_tag_get(&inode_tree, ipath->ino,
-                                               MOVE_INODE);
-               radix_tree_delete(&inode_tree, ipath->ino);
+               move_blocks = test_reloc_iflag(ipath->ino, MOVE_BLOCKS);
+               move_inode = test_reloc_iflag(ipath->ino, MOVE_INODE);
+               forget_reloc_ino(ipath->ino);
 
                /* Print the initial path with inode number and state. */
                printf("0x%.16llx\t%s\t%s\t%8d\t%s\n",
@@ -400,9 +369,8 @@ list_inode_paths(void)
        do {
                uint64_t        ino;
 
-
-               ret = radix_tree_gang_lookup(&inode_tree, (void **)&ino, idx, 1);
-               if (!ret) {
+               ino = get_next_reloc_unlinked(idx);
+               if (!ino) {
                        if (idx != 0)
                                ret = -EBUSY;
                        break;
@@ -410,7 +378,7 @@ list_inode_paths(void)
                idx = ino + 1;
                printf(_("No path found for inode 0x%llx!\n"),
                                (unsigned long long)ino);
-               radix_tree_delete(&inode_tree, ino);
+               forget_reloc_ino(ino);
        } while (true);
 
        return ret;
@@ -426,7 +394,7 @@ resolve_owner_f(
 {
        int     ret;
 
-       if (!inode_tree.rnode) {
+       if (!is_reloc_populated()) {
                fprintf(stderr,
 _("Inode list has not been populated. No inodes to resolve.\n"));
                return 0;
diff --git a/spaceman/relocation.c b/spaceman/relocation.c
new file mode 100644 (file)
index 0000000..7c7d9a2
--- /dev/null
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 Red Hat, Inc.
+ * All Rights Reserved.
+ */
+
+#include "libxfs.h"
+#include "libfrog/fsgeom.h"
+#include "libfrog/radix-tree.h"
+#include "libfrog/paths.h"
+#include "command.h"
+#include "init.h"
+#include "space.h"
+#include "input.h"
+#include "relocation.h"
+#include "handle.h"
+
+static unsigned long long inode_count;
+static unsigned long long inode_paths;
+
+unsigned long long
+get_reloc_count(void)
+{
+       return inode_count;
+}
+
+static RADIX_TREE(relocation_data, 0);
+
+bool
+is_reloc_populated(void)
+{
+       return relocation_data.rnode != NULL;
+}
+
+bool
+test_reloc_iflag(
+       uint64_t        ino,
+       unsigned int    flag)
+{
+       return radix_tree_tag_get(&relocation_data, ino, flag);
+}
+
+void
+set_reloc_iflag(
+       uint64_t        ino,
+       unsigned int    flag)
+{
+       if (!radix_tree_lookup(&relocation_data, ino)) {
+               radix_tree_insert(&relocation_data, ino, UNLINKED_IPATH);
+               if (flag != INODE_PATH)
+                       inode_count++;
+       }
+       if (flag == INODE_PATH)
+               inode_paths++;
+
+       radix_tree_tag_set(&relocation_data, ino, flag);
+}
+
+struct inode_path *
+get_next_reloc_ipath(
+       uint64_t        ino)
+{
+       struct inode_path       *ipath;
+       int                     ret;
+
+       ret = radix_tree_gang_lookup_tag(&relocation_data, (void **)&ipath,
+                       ino, 1, INODE_PATH);
+       if (!ret)
+               return NULL;
+       return ipath;
+}
+
+uint64_t
+get_next_reloc_unlinked(
+       uint64_t        ino)
+{
+       uint64_t        next_ino;
+       int             ret;
+
+       ret = radix_tree_gang_lookup(&relocation_data, (void **)&next_ino, ino,
+                       1);
+       if (!ret)
+               return 0;
+       return next_ino;
+}
+
+/*
+ * Return a pointer to a pointer where the caller can read or write a pointer
+ * to an inode path structure.
+ *
+ * The pointed-to pointer will be set to UNLINKED_IPATH if there is no ipath
+ * associated with this inode but the inode has been flagged for relocation.
+ *
+ * Returns NULL if the inode is not flagged for relocation.
+ */
+struct inode_path **
+get_reloc_ipath_slot(
+       uint64_t                ino)
+{
+       struct inode_path       **slot;
+
+       slot = (struct inode_path **)radix_tree_lookup_slot(&relocation_data,
+                       ino);
+       if (!slot || *slot == NULL)
+               return NULL;
+       return slot;
+}
+
+void
+forget_reloc_ino(
+       uint64_t                ino)
+{
+       radix_tree_delete(&relocation_data, ino);
+}
diff --git a/spaceman/relocation.h b/spaceman/relocation.h
new file mode 100644 (file)
index 0000000..f05a871
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 Red Hat, Inc.
+ * All Rights Reserved.
+ */
+#ifndef XFS_SPACEMAN_RELOCATION_H_
+#define XFS_SPACEMAN_RELOCATION_H_
+
+bool is_reloc_populated(void);
+unsigned long long get_reloc_count(void);
+
+/*
+ * Tags for the relocation_data tree that indicate what it contains and the
+ * discovery information that needed to be stored.
+ */
+#define MOVE_INODE     0
+#define MOVE_BLOCKS    1
+#define INODE_PATH     2
+
+bool test_reloc_iflag(uint64_t ino, unsigned int flag);
+void set_reloc_iflag(uint64_t ino, unsigned int flag);
+struct inode_path *get_next_reloc_ipath(uint64_t ino);
+uint64_t get_next_reloc_unlinked(uint64_t ino);
+struct inode_path **get_reloc_ipath_slot(uint64_t ino);
+void forget_reloc_ino(uint64_t ino);
+
+/*
+ * When the entry in the relocation_data tree is tagged with INODE_PATH, the
+ * entry contains a structure that tracks the discovered paths to the inode. If
+ * the inode has multiple hard links, then we chain each individual path found
+ * via the path_list and record the number of paths in the link_count entry.
+ */
+struct inode_path {
+       uint64_t                ino;
+       struct list_head        path_list;
+       uint32_t                link_count;
+       char                    path[1];
+};
+
+/*
+ * Sentinel value for inodes that we have to move but haven't yet found a path
+ * to.
+ */
+#define UNLINKED_IPATH         ((struct inode_path *)1)
+
+#endif /* XFS_SPACEMAN_RELOCATION_H_ */