]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: enable CoW for realtime data
authorDarrick J. Wong <djwong@kernel.org>
Tue, 15 Oct 2024 19:40:25 +0000 (12:40 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Fri, 1 Nov 2024 20:47:10 +0000 (13:47 -0700)
Update our write paths to support copy on write on the rt volume.  This
works in more or less the same way as it does on the data device, with
the major exception that we never do delalloc on the rt volume.

Because we consider unwritten CoW fork staging extents to be incore
quota reservation, we update xfs_quota_reserve_blkres to support this
case.  Though xfs doesn't allow rt and quota together, the change is
trivial and we shouldn't leave a logic bomb here.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/xfs_reflink.c

index a349313a890a8b0faf9f2076bbd7e7476f83f6e7..0b3a78877ad9a6d74970ecf25acdbd114d585c05 100644 (file)
@@ -438,20 +438,26 @@ xfs_reflink_fill_cow_hole(
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        xfs_filblks_t           resaligned;
-       xfs_extlen_t            resblks;
+       unsigned int            dblocks = 0, rblocks = 0;
        int                     nimaps;
        int                     error;
        bool                    found;
 
        resaligned = xfs_aligned_fsb_count(imap->br_startoff,
                imap->br_blockcount, xfs_get_cowextsz_hint(ip));
-       resblks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
+       if (XFS_IS_REALTIME_INODE(ip)) {
+               dblocks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
+               rblocks = resaligned;
+       } else {
+               dblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
+               rblocks = 0;
+       }
 
        xfs_iunlock(ip, *lockmode);
        *lockmode = 0;
 
-       error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write, resblks, 0,
-                       false, &tp);
+       error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write, dblocks,
+                       rblocks, false, &tp);
        if (error)
                return error;
 
@@ -1211,7 +1217,7 @@ xfs_reflink_remap_extent(
        struct xfs_trans        *tp;
        xfs_off_t               newlen;
        int64_t                 qdelta = 0;
-       unsigned int            resblks;
+       unsigned int            dblocks, rblocks, resblks;
        bool                    quota_reserved = true;
        bool                    smap_real;
        bool                    dmap_written = xfs_bmap_is_written_extent(dmap);
@@ -1242,8 +1248,15 @@ xfs_reflink_remap_extent(
         * we're remapping.
         */
        resblks = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
+       if (XFS_IS_REALTIME_INODE(ip)) {
+               dblocks = resblks;
+               rblocks = dmap->br_blockcount;
+       } else {
+               dblocks = resblks + dmap->br_blockcount;
+               rblocks = 0;
+       }
        error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write,
-                       resblks + dmap->br_blockcount, 0, false, &tp);
+                       dblocks, rblocks, false, &tp);
        if (error == -EDQUOT || error == -ENOSPC) {
                quota_reserved = false;
                error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write,
@@ -1323,8 +1336,15 @@ xfs_reflink_remap_extent(
         * done.
         */
        if (!quota_reserved && !smap_real && dmap_written) {
-               error = xfs_trans_reserve_quota_nblks(tp, ip,
-                               dmap->br_blockcount, 0, false);
+               if (XFS_IS_REALTIME_INODE(ip)) {
+                       dblocks = 0;
+                       rblocks = dmap->br_blockcount;
+               } else {
+                       dblocks = dmap->br_blockcount;
+                       rblocks = 0;
+               }
+               error = xfs_trans_reserve_quota_nblks(tp, ip, dblocks, rblocks,
+                               false);
                if (error)
                        goto out_cancel;
        }