]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: allow internal RT devices for zoned mode
authorChristoph Hellwig <hch@lst.de>
Sun, 17 Nov 2024 07:53:10 +0000 (08:53 +0100)
committerChristoph Hellwig <hch@lst.de>
Mon, 3 Mar 2025 15:16:45 +0000 (08:16 -0700)
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.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
fs/xfs/libxfs/xfs_group.h
fs/xfs/libxfs/xfs_rtgroup.h
fs/xfs/libxfs/xfs_sb.c
fs/xfs/xfs_file.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_super.c

index 242b05627c7a6ea862c8dc0b30fc4a93281d0682..a70096113384e019ae0b095d2458d3aba379c496 100644 (file)
@@ -107,9 +107,11 @@ xfs_gbno_to_daddr(
        xfs_agblock_t           gbno)
 {
        struct xfs_mount        *mp = xg->xg_mount;
-       uint32_t                blocks = mp->m_groups[xg->xg_type].blocks;
+       struct xfs_groups       *g = &mp->m_groups[xg->xg_type];
+       xfs_fsblock_t           fsbno;
 
-       return XFS_FSB_TO_BB(mp, (xfs_fsblock_t)xg->xg_gno * blocks + gbno);
+       fsbno = (xfs_fsblock_t)xg->xg_gno * g->blocks + gbno;
+       return XFS_FSB_TO_BB(mp, g->start_fsb + fsbno);
 }
 
 static inline uint32_t
index 9c7e03f913cb5322fb16ec3fa3d699e1a111c83e..e35d1d7983275ca8e8a6e2e65fb4d738b0b87459 100644 (file)
@@ -230,7 +230,8 @@ xfs_rtb_to_daddr(
        xfs_rgnumber_t          rgno = xfs_rtb_to_rgno(mp, rtbno);
        uint64_t                start_bno = (xfs_rtblock_t)rgno * g->blocks;
 
-       return XFS_FSB_TO_BB(mp, start_bno + (rtbno & g->blkmask));
+       return XFS_FSB_TO_BB(mp,
+               g->start_fsb + start_bno + (rtbno & g->blkmask));
 }
 
 static inline xfs_rtblock_t
@@ -238,10 +239,11 @@ xfs_daddr_to_rtb(
        struct xfs_mount        *mp,
        xfs_daddr_t             daddr)
 {
-       xfs_rfsblock_t          bno = XFS_BB_TO_FSBT(mp, daddr);
+       struct xfs_groups       *g = &mp->m_groups[XG_TYPE_RTG];
+       xfs_rfsblock_t          bno;
 
+       bno = XFS_BB_TO_FSBT(mp, daddr) - g->start_fsb;
        if (xfs_has_rtgroups(mp)) {
-               struct xfs_groups *g = &mp->m_groups[XG_TYPE_RTG];
                xfs_rgnumber_t  rgno;
                uint32_t        rgbno;
 
index b13d88a10ace135e6610f0bae0286f8fd01c2006..52a04aae44e87cec3bd4b85c5868c89dbaa0cf49 100644 (file)
@@ -1204,6 +1204,7 @@ 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);
+               rgs->start_fsb = mp->m_sb.sb_rtstart;
        } else {
                rgs->blocks = 0;
                rgs->blklog = 0;
index d66eea31b60ab88c4726d8277525d007abf8ba24..f597f94e2c80589ba544a60573fe09c3376a1951 100644 (file)
@@ -150,7 +150,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 b2c7337910116d2b26c0176e21e603d9f6343413..ee2cefbd5df8ac9d9a4d9a548a0fd8fe205a3180 100644 (file)
@@ -308,6 +308,10 @@ xfs_growfs_data(
        if (!mutex_trylock(&mp->m_growlock))
                return -EWOULDBLOCK;
 
+       /* we can't grow the data section when an internal RT section exists */
+       if (in->newblocks != mp->m_sb.sb_dblocks && mp->m_sb.sb_rtstart)
+               return -EINVAL;
+
        /* update imaxpct separately to the physical grow of the filesystem */
        if (in->imaxpct != mp->m_sb.sb_imax_pct) {
                error = xfs_growfs_imaxpct(mp, in->imaxpct);
index 790847d565e0d2fdad88b5e71b088770f3c0d275..f08bba9ddb2ba0d85a7b7d68fbd9223bc01d46e6 100644 (file)
@@ -103,6 +103,13 @@ struct xfs_groups {
         * rtgroup, so this mask must be 64-bit.
         */
        uint64_t                blkmask;
+
+       /*
+        * Start of the first group in the device.  This is used to support a
+        * RT device following the data device on the same block device for
+        * SMR hard drives.
+        */
+       xfs_fsblock_t           start_fsb;
 };
 
 struct xfs_freecounter {
index afe8664804a92f341f7315da2d79777ab6056f33..741ccdde2dbe6d7fb557fade72d98e7655b13956 100644 (file)
@@ -1266,7 +1266,8 @@ xfs_rt_check_size(
                return -EFBIG;
        }
 
-       error = xfs_buf_read_uncached(mp->m_rtdev_targp, daddr,
+       error = xfs_buf_read_uncached(mp->m_rtdev_targp,
+                       XFS_FSB_TO_BB(mp, mp->m_sb.sb_rtstart) + daddr,
                        XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
        if (error)
                xfs_warn(mp, "cannot read last RT device sector (%lld)",
index 817aae726ec1b65bcb984013149b9521dd5ef85c..86d61f3d83cd48267e00e006c6af334dc960f724 100644 (file)
@@ -533,7 +533,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)
@@ -757,7 +765,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);