]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: enable CoW for realtime data
authorDarrick J. Wong <djwong@kernel.org>
Thu, 15 Aug 2024 18:49:29 +0000 (11:49 -0700)
committerChristoph Hellwig <hch@lst.de>
Sun, 22 Sep 2024 08:48:26 +0000 (10:48 +0200)
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.

While we're at it, add a missing xfs_mod_delalloc call when we remove
delalloc block reservation from the inode.  This is largely irrelvant
since realtime files do not use delalloc, but we want to avoid leaving
logic bombs.

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

index 2d36d967380e7c5c8089f4d137eff67db861dc1d..fa1317cc396c96abf83090e50cfd80efba31ead8 100644 (file)
@@ -130,6 +130,7 @@ extern void xfs_qm_mount_quotas(struct xfs_mount *);
 extern void xfs_qm_unmount(struct xfs_mount *);
 extern void xfs_qm_unmount_quotas(struct xfs_mount *);
 bool xfs_inode_near_dquot_enforcement(struct xfs_inode *ip, xfs_dqtype_t type);
+int xfs_quota_reserve_blkres(struct xfs_inode *ip, int64_t blocks);
 
 # ifdef CONFIG_XFS_LIVE_HOOKS
 void xfs_trans_mod_ino_dquot(struct xfs_trans *tp, struct xfs_inode *ip,
@@ -209,6 +210,11 @@ xfs_trans_reserve_quota_icreate(struct xfs_trans *tp, struct xfs_dquot *udqp,
 #define xfs_qm_unmount_quotas(mp)
 #define xfs_inode_near_dquot_enforcement(ip, type)                     (false)
 
+static inline int xfs_quota_reserve_blkres(struct xfs_inode *ip, int64_t blocks)
+{
+       return 0;
+}
+
 # ifdef CONFIG_XFS_LIVE_HOOKS
 #  define xfs_dqtrx_hook_enable()              ((void)0)
 #  define xfs_dqtrx_hook_disable()             ((void)0)
@@ -216,12 +222,6 @@ xfs_trans_reserve_quota_icreate(struct xfs_trans *tp, struct xfs_dquot *udqp,
 
 #endif /* CONFIG_XFS_QUOTA */
 
-static inline int
-xfs_quota_reserve_blkres(struct xfs_inode *ip, int64_t blocks)
-{
-       return xfs_trans_reserve_quota_nblks(NULL, ip, blocks, 0, false);
-}
-
 static inline void
 xfs_quota_unreserve_blkres(struct xfs_inode *ip, uint64_t blocks)
 {
index 2d7ea5419dc51de30ac2fed6980282b93e6ee6eb..2c6bad527b9e749fc3bfcc532d95049fa0ec1764 100644 (file)
@@ -439,20 +439,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;
 
@@ -1212,7 +1218,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);
@@ -1243,8 +1249,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,
@@ -1324,8 +1337,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;
        }
index ca7df018290e0edff19be69bdd9257eef02d69da..481ba3dc9f190d4b584afd4f57785f9a47fcf4b0 100644 (file)
@@ -1031,3 +1031,14 @@ xfs_trans_free_dqinfo(
        kmem_cache_free(xfs_dqtrx_cache, tp->t_dqinfo);
        tp->t_dqinfo = NULL;
 }
+
+int
+xfs_quota_reserve_blkres(
+       struct xfs_inode        *ip,
+       int64_t                 blocks)
+{
+       if (XFS_IS_REALTIME_INODE(ip))
+               return xfs_trans_reserve_quota_nblks(NULL, ip, 0, blocks,
+                               false);
+       return xfs_trans_reserve_quota_nblks(NULL, ip, blocks, 0, false);
+}