]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: support an internal zoned rtdev
authorChristoph Hellwig <hch@lst.de>
Tue, 5 Nov 2024 08:29:14 +0000 (09:29 +0100)
committerChristoph Hellwig <hch@lst.de>
Tue, 5 Nov 2024 08:29:55 +0000 (09:29 +0100)
Allow creating an RT subvolume on the same device as the main data
device.  This is mostly used for SMR HDDs where the conventional zones
are used for the data device and the sequential write required zones
for the zoned RT section.  One day we should also support the log
on sequential write required zones, but that is not supported here.

Signed-off-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_format.h
fs/xfs/libxfs/xfs_group.h
fs/xfs/libxfs/xfs_ondisk.h
fs/xfs/libxfs/xfs_rtgroup.h
fs/xfs/libxfs/xfs_sb.c
fs/xfs/xfs_file.c
fs/xfs/xfs_fsmap.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_super.c
fs/xfs/xfs_zone_gc.c

index 72a3b8c3d408c1b4eb74bd30863593069e553367..84c62db0331ce94602eb7fdf07d07f943a710979 100644 (file)
@@ -178,9 +178,9 @@ typedef struct xfs_sb {
 
        xfs_rgnumber_t  sb_rgcount;     /* number of realtime groups */
        xfs_rtxlen_t    sb_rgextents;   /* size of a realtime group in rtx */
-
        uint8_t         sb_rgblklog;    /* rt group number shift */
        uint8_t         sb_pad[7];      /* zeroes */
+       xfs_fsblock_t   sb_rtstart;     /* start of internal RT section in BB */
 
        /* must be padded to 64 bit alignment */
 } xfs_sb_t;
@@ -270,9 +270,9 @@ struct xfs_dsb {
        __be64          sb_metadirino;  /* metadata directory tree root */
        __be32          sb_rgcount;     /* # of realtime groups */
        __be32          sb_rgextents;   /* size of rtgroup in rtx */
-
        __u8            sb_rgblklog;    /* rt group number shift */
        __u8            sb_pad[7];      /* zeroes */
+       __be64          sb_rtstart;     /* start of internal RT section in BB */
 
        /*
         * The size of this structure must be padded to 64 bit alignment.
index 3c85bdec3904b8b9ba8c9b62840678304a00e546..1f124b0f434b41f5b680728534c5e560338b9d6f 100644 (file)
@@ -108,10 +108,14 @@ xfs_gbno_to_daddr(
 {
        struct xfs_mount        *mp = xg->xg_mount;
        struct xfs_groups       *g = &mp->m_groups[xg->xg_type];
+       uint64_t                fsb;
 
        if (g->has_daddr_gaps)
-               return XFS_FSB_TO_BB(mp, xfs_gbno_to_fsb(xg, gbno));
-       return XFS_FSB_TO_BB(mp, (xfs_fsblock_t)xg->xg_gno * g->blocks + gbno);
+               fsb = xfs_gbno_to_fsb(xg, gbno);
+       else
+               fsb = (xfs_fsblock_t)xg->xg_gno * g->blocks + gbno;
+
+       return XFS_FSB_TO_BB(mp, fsb) + g->start_daddr;
 }
 
 static inline uint32_t
index a85ecddaa48eed37ecbe796fb055ff7c6f5332f8..018f30f203b4f372bdee3a18f4fa3a10eefd5fbc 100644 (file)
@@ -233,8 +233,8 @@ xfs_check_ondisk_structs(void)
                        16299260424LL);
 
        /* superblock field checks we got from xfs/122 */
-       XFS_CHECK_STRUCT_SIZE(struct xfs_dsb,           288);
-       XFS_CHECK_STRUCT_SIZE(struct xfs_sb,            288);
+       XFS_CHECK_STRUCT_SIZE(struct xfs_dsb,           296);
+       XFS_CHECK_STRUCT_SIZE(struct xfs_sb,            296);
        XFS_CHECK_SB_OFFSET(sb_magicnum,                0);
        XFS_CHECK_SB_OFFSET(sb_blocksize,               4);
        XFS_CHECK_SB_OFFSET(sb_dblocks,                 8);
@@ -295,6 +295,7 @@ xfs_check_ondisk_structs(void)
        XFS_CHECK_SB_OFFSET(sb_rgextents,               276);
        XFS_CHECK_SB_OFFSET(sb_rgblklog,                280);
        XFS_CHECK_SB_OFFSET(sb_pad,                     281);
+       XFS_CHECK_SB_OFFSET(sb_rtstart,                 288);
 }
 
 #endif /* __XFS_ONDISK_H */
index fb329350f4d3b8fa6a89ad75f8ca8750d8d7de1a..89bfcefb484bfa9e94dddf2b259ef73d729f2ec7 100644 (file)
@@ -223,7 +223,7 @@ xfs_rtb_to_daddr(
                rtbno = (xfs_rtblock_t)rgno * g->blocks + (rtbno & g->blkmask);
        }
 
-       return XFS_FSB_TO_BB(mp, rtbno);
+       return XFS_FSB_TO_BB(mp, rtbno) + mp->m_sb.sb_rtstart;
 }
 
 static inline xfs_rtblock_t
@@ -232,8 +232,9 @@ xfs_daddr_to_rtb(
        xfs_daddr_t             daddr)
 {
        struct xfs_groups       *g = &mp->m_groups[XG_TYPE_RTG];
-       xfs_rfsblock_t          bno = XFS_BB_TO_FSBT(mp, daddr);
+       xfs_rfsblock_t          bno;
 
+       bno = XFS_BB_TO_FSBT(mp, daddr - mp->m_sb.sb_rtstart);
        if (xfs_has_rtgroups(mp) && !g->has_daddr_gaps) {
                xfs_rgnumber_t  rgno;
                uint32_t        rgbno;
index ccd742274d0fdbd1973fd152d92e0568ee6cc22c..b478691326437e3b06f0588db76185285d32293d 100644 (file)
@@ -833,6 +833,11 @@ __xfs_sb_from_disk(
                to->sb_rgcount = 1;
                to->sb_rgextents = 0;
        }
+
+       if (to->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_ZONED)
+               to->sb_rtstart = be64_to_cpu(from->sb_rtstart);
+       else
+               to->sb_rtstart = 0;
 }
 
 void
@@ -999,6 +1004,9 @@ xfs_sb_to_disk(
                to->sb_rbmino = cpu_to_be64(0);
                to->sb_rsumino = cpu_to_be64(0);
        }
+
+       if (from->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_ZONED)
+               to->sb_rtstart = cpu_to_be64(from->sb_rtstart);
 }
 
 /*
@@ -1144,6 +1152,9 @@ xfs_sb_mount_rextsize(
                rgs->blocks = sbp->sb_rgextents * sbp->sb_rextsize;
                rgs->blklog = mp->m_sb.sb_rgblklog;
                rgs->blkmask = xfs_mask32lo(mp->m_sb.sb_rgblklog);
+               if (xfs_sb_has_incompat_feature(sbp,
+                               XFS_SB_FEAT_INCOMPAT_ZONED))
+                       rgs->start_daddr = mp->m_sb.sb_rtstart;
                if (xfs_sb_has_incompat_feature(sbp,
                                XFS_SB_FEAT_INCOMPAT_ZONE_GAPS))
                        rgs->has_daddr_gaps = true;
index 6cccb7c9560b7a66573226fa608be13ae11da4cf..e50529d65f2e1ed6aded1e3ddb7960ee49a2acc7 100644 (file)
@@ -153,7 +153,7 @@ xfs_file_fsync(
         * ensure newly written file data make it to disk before logging the new
         * inode size in case of an extending write.
         */
-       if (XFS_IS_REALTIME_INODE(ip))
+       if (XFS_IS_REALTIME_INODE(ip) && mp->m_rtdev_targp != mp->m_ddev_targp)
                error = blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev);
        else if (mp->m_logdev_targp != mp->m_ddev_targp)
                error = blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
index f6d20da34aba1d6bc97b87bfda059bcd2bb17c0a..c53f13987fa65df1a13b2d4c2e810906ddfc165b 100644 (file)
@@ -1140,7 +1140,12 @@ xfs_getfsmap(
                handlers[1].fn = xfs_getfsmap_logdev;
        }
 #ifdef CONFIG_XFS_RT
-       if (mp->m_rtdev_targp) {
+       /*
+        * I have no idea how to make the fsmap interface fit two totally
+        * different space pools on the same device.  But maybe there is a
+        * way?  Darrick, come help me! :)
+        */
+       if (mp->m_rtdev_targp && mp->m_rtdev_targp != mp->m_ddev_targp) {
                handlers[2].nr_sectors = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
                handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
                if (use_rmap)
index a66f5a4687fd4817fed41d830b6f44e76d471a04..4565f4c9ea1f8eb4c2c2c85c7b8cbec8bf20102a 100644 (file)
@@ -112,6 +112,8 @@ struct xfs_groups {
         * maps 1:1 to the device address space.
         */
        bool                    has_daddr_gaps;
+
+       xfs_daddr_t             start_daddr;
 };
 
 enum {
index cafd757e2b42bc74af633f15ccc0bc367452326a..ab05988d809e2a22e13593cdc5ede42348674388 100644 (file)
@@ -1343,7 +1343,7 @@ xfs_rt_check_size(
        struct xfs_buf          *bp;
        int                     error;
 
-       if (XFS_BB_TO_FSB(mp, daddr) != last_block) {
+       if (xfs_daddr_to_rtb(mp, daddr) != last_block) {
                xfs_warn(mp, "RT device size overflow: %llu != %llu",
                        xfs_daddr_to_rtb(mp, daddr), last_block);
                return -EFBIG;
index 31db792a0585d138b14703ac2e23b453cea1a605..9c59514990267934d006a0a1ae13024d0582fc3c 100644 (file)
@@ -544,7 +544,15 @@ xfs_setup_devices(
                if (error)
                        return error;
        }
-       if (mp->m_rtdev_targp) {
+
+       if (mp->m_sb.sb_rtstart) {
+               if (mp->m_rtdev_targp) {
+                       xfs_warn(mp,
+               "can't use internal and external rtdev at the same time");
+                       return -EINVAL;
+               }
+               mp->m_rtdev_targp = mp->m_ddev_targp;
+       } else if (mp->m_rtname) {
                error = xfs_setsize_buftarg(mp->m_rtdev_targp,
                                            mp->m_sb.sb_sectsize);
                if (error)
@@ -768,7 +776,7 @@ xfs_mount_free(
 {
        if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
                xfs_free_buftarg(mp->m_logdev_targp);
-       if (mp->m_rtdev_targp)
+       if (mp->m_rtdev_targp && mp->m_rtdev_targp != mp->m_ddev_targp)
                xfs_free_buftarg(mp->m_rtdev_targp);
        if (mp->m_ddev_targp)
                xfs_free_buftarg(mp->m_ddev_targp);
index f2cf0c9f48a1811229c7e333fdd28c300b214f6a..3eddc792eb1f033f55f20c2f0c1cf5f91c6a87e9 100644 (file)
@@ -1344,8 +1344,8 @@ xfs_mount_zones(
 "zoned device support requires CONFIG_BLK_DEV_ZONED");
                        return -EINVAL;
                }
-               error = blkdev_report_zones(bt->bt_bdev, 0, mp->m_sb.sb_rgcount,
-                                           xfs_get_zone_info_cb, mp);
+               error = blkdev_report_zones(bt->bt_bdev, mp->m_sb.sb_rtstart,
+                               mp->m_sb.sb_rgcount, xfs_get_zone_info_cb, mp);
                if (error < 0)
                        return error;
        }