xfs: Check for extent overflow when trivally adding a new extent
authorChandan Babu R <chandanrlinux@gmail.com>
Sat, 23 Jan 2021 00:48:11 +0000 (16:48 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Sat, 23 Jan 2021 00:54:47 +0000 (16:54 -0800)
When adding a new data extent (without modifying an inode's existing
extents) the extent count increases only by 1. This commit checks for
extent count overflow in such cases.

Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_inode_fork.h
fs/xfs/xfs_bmap_item.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_rtalloc.c

index bc446418e2276fa0f840ca6d7189eb5090c73d29..32aeacf6f055abdffb5f747ebb91c8481a6d4c5f 100644 (file)
@@ -4527,6 +4527,12 @@ xfs_bmapi_convert_delalloc(
                return error;
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+       error = xfs_iext_count_may_overflow(ip, whichfork,
+                       XFS_IEXT_ADD_NOSPLIT_CNT);
+       if (error)
+               goto out_trans_cancel;
+
        xfs_trans_ijoin(tp, ip, 0);
 
        if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &bma.icur, &bma.got) ||
index 0beb8e2a00becf3abec2fecf898b2e5da1011693..7fc2b129a2e79ff998acc4c0ced441cf8d18e205 100644 (file)
@@ -34,6 +34,12 @@ struct xfs_ifork {
 #define        XFS_IFEXTENTS   0x02    /* All extent pointers are read in */
 #define        XFS_IFBROOT     0x04    /* i_broot points to the bmap b-tree root */
 
+/*
+ * Worst-case increase in the fork extent count when we're adding a single
+ * extent to a fork and there's no possibility of splitting an existing mapping.
+ */
+#define XFS_IEXT_ADD_NOSPLIT_CNT       (1)
+
 /*
  * Fork handling.
  */
index 93e4d8ae6e92b6d2b91ed7eb89717cda8dde487c..0534304ed0a7dc9c0ce66b6fbf04df46fa49f69e 100644 (file)
@@ -508,6 +508,13 @@ xfs_bui_item_recover(
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, 0);
 
+       if (bui_type == XFS_BMAP_MAP) {
+               error = xfs_iext_count_may_overflow(ip, whichfork,
+                               XFS_IEXT_ADD_NOSPLIT_CNT);
+               if (error)
+                       goto err_cancel;
+       }
+
        count = bmap->me_len;
        error = xfs_trans_log_finish_bmap_update(tp, budp, bui_type, ip,
                        whichfork, bmap->me_startoff, bmap->me_startblock,
index 7371a7f7c652943ea4b06baef0dea79de1ace5db..db44bfaabe8812d3c0a53526a13a533acf177809 100644 (file)
@@ -822,6 +822,11 @@ xfs_alloc_file_space(
                if (error)
                        goto error1;
 
+               error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
+                               XFS_IEXT_ADD_NOSPLIT_CNT);
+               if (error)
+                       goto error0;
+
                xfs_trans_ijoin(tp, ip, 0);
 
                error = xfs_bmapi_write(tp, ip, startoffset_fsb,
index 1d95ed387d66d8dff54275e525905b9bb84138f9..175f544f7c459d59110ee5b122f5d5fc2ba43027 100644 (file)
@@ -314,8 +314,14 @@ xfs_dquot_disk_alloc(
                return -ESRCH;
        }
 
-       /* Create the block mapping. */
        xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
+
+       error = xfs_iext_count_may_overflow(quotip, XFS_DATA_FORK,
+                       XFS_IEXT_ADD_NOSPLIT_CNT);
+       if (error)
+               return error;
+
+       /* Create the block mapping. */
        error = xfs_bmapi_write(tp, quotip, dqp->q_fileoffset,
                        XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA, 0, &map,
                        &nmaps);
index 7b9ff824e82d48b4040f6442426d4a0e7eacb6e4..32246d90b9cb615f2d8514dbab3d56090275cb10 100644 (file)
@@ -250,6 +250,11 @@ xfs_iomap_write_direct(
        if (error)
                goto out_trans_cancel;
 
+       error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
+                       XFS_IEXT_ADD_NOSPLIT_CNT);
+       if (error)
+               goto out_res_cancel;
+
        xfs_trans_ijoin(tp, ip, 0);
 
        /*
index b4999fb01ff7aa8d3eaefd4f2539ab6cd5058a2b..161b0e8992ba82fad8ecd73289cf978f48937622 100644 (file)
@@ -804,6 +804,11 @@ xfs_growfs_rt_alloc(
                xfs_ilock(ip, XFS_ILOCK_EXCL);
                xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
+               error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
+                               XFS_IEXT_ADD_NOSPLIT_CNT);
+               if (error)
+                       goto out_trans_cancel;
+
                /*
                 * Allocate blocks to the bitmap file.
                 */