xfs: convert growfs AG header init to use buffer lists
[platform/kernel/linux-rpi.git] / fs / xfs / xfs_fsops.c
index 391d193..4b560ca 100644 (file)
@@ -81,7 +81,8 @@ xfs_grow_ag_headers(
        struct xfs_mount        *mp,
        xfs_agnumber_t          agno,
        xfs_extlen_t            agsize,
-       xfs_rfsblock_t          *nfree)
+       xfs_rfsblock_t          *nfree,
+       struct list_head        *buffer_list)
 {
        struct xfs_agf          *agf;
        struct xfs_agi          *agi;
@@ -135,11 +136,8 @@ xfs_grow_ag_headers(
                agf->agf_refcount_level = cpu_to_be32(1);
                agf->agf_refcount_blocks = cpu_to_be32(1);
        }
-
-       error = xfs_bwrite(bp);
+       xfs_buf_delwri_queue(bp, buffer_list);
        xfs_buf_relse(bp);
-       if (error)
-               goto out_error;
 
        /*
         * AG freelist header block
@@ -164,10 +162,8 @@ xfs_grow_ag_headers(
        for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++)
                agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
 
-       error = xfs_bwrite(bp);
+       xfs_buf_delwri_queue(bp, buffer_list);
        xfs_buf_relse(bp);
-       if (error)
-               goto out_error;
 
        /*
         * AG inode header block
@@ -201,10 +197,8 @@ xfs_grow_ag_headers(
        for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
                agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
 
-       error = xfs_bwrite(bp);
+       xfs_buf_delwri_queue(bp, buffer_list);
        xfs_buf_relse(bp);
-       if (error)
-               goto out_error;
 
        /*
         * BNO btree root block
@@ -226,10 +220,8 @@ xfs_grow_ag_headers(
        arec->ar_blockcount = cpu_to_be32(
                agsize - be32_to_cpu(arec->ar_startblock));
 
-       error = xfs_bwrite(bp);
+       xfs_buf_delwri_queue(bp, buffer_list);
        xfs_buf_relse(bp);
-       if (error)
-               goto out_error;
 
        /*
         * CNT btree root block
@@ -251,10 +243,8 @@ xfs_grow_ag_headers(
                agsize - be32_to_cpu(arec->ar_startblock));
        *nfree += be32_to_cpu(arec->ar_blockcount);
 
-       error = xfs_bwrite(bp);
+       xfs_buf_delwri_queue(bp, buffer_list);
        xfs_buf_relse(bp);
-       if (error)
-               goto out_error;
 
        /* RMAP btree root block */
        if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
@@ -326,10 +316,8 @@ xfs_grow_ag_headers(
                        be16_add_cpu(&block->bb_numrecs, 1);
                }
 
-               error = xfs_bwrite(bp);
+               xfs_buf_delwri_queue(bp, buffer_list);
                xfs_buf_relse(bp);
-               if (error)
-                       goto out_error;
        }
 
        /*
@@ -345,11 +333,8 @@ xfs_grow_ag_headers(
        }
 
        xfs_btree_init_block(mp, bp, XFS_BTNUM_INO , 0, 0, agno, 0);
-
-       error = xfs_bwrite(bp);
+       xfs_buf_delwri_queue(bp, buffer_list);
        xfs_buf_relse(bp);
-       if (error)
-               goto out_error;
 
        /*
         * FINO btree root block
@@ -364,13 +349,9 @@ xfs_grow_ag_headers(
                        goto out_error;
                }
 
-               xfs_btree_init_block(mp, bp, XFS_BTNUM_FINO,
-                                            0, 0, agno, 0);
-
-               error = xfs_bwrite(bp);
+               xfs_btree_init_block(mp, bp, XFS_BTNUM_FINO, 0, 0, agno, 0);
+               xfs_buf_delwri_queue(bp, buffer_list);
                xfs_buf_relse(bp);
-               if (error)
-                       goto out_error;
        }
 
        /*
@@ -386,13 +367,9 @@ xfs_grow_ag_headers(
                        goto out_error;
                }
 
-               xfs_btree_init_block(mp, bp, XFS_BTNUM_REFC,
-                                    0, 0, agno, 0);
-
-               error = xfs_bwrite(bp);
+               xfs_btree_init_block(mp, bp, XFS_BTNUM_REFC, 0, 0, agno, 0);
+               xfs_buf_delwri_queue(bp, buffer_list);
                xfs_buf_relse(bp);
-               if (error)
-                       goto out_error;
        }
 
 out_error:
@@ -419,6 +396,7 @@ xfs_growfs_data_private(
        xfs_agnumber_t          oagcount;
        int                     pct;
        xfs_trans_t             *tp;
+       LIST_HEAD               (buffer_list);
 
        nb = in->newblocks;
        pct = in->imaxpct;
@@ -459,9 +437,16 @@ xfs_growfs_data_private(
                return error;
 
        /*
-        * Write new AG headers to disk. Non-transactional, but written
-        * synchronously so they are completed prior to the growfs transaction
-        * being logged.
+        * Write new AG headers to disk. Non-transactional, but need to be
+        * written and completed prior to the growfs transaction being logged.
+        * To do this, we use a delayed write buffer list and wait for
+        * submission and IO completion of the list as a whole. This allows the
+        * IO subsystem to merge all the AG headers in a single AG into a single
+        * IO and hide most of the latency of the IO from us.
+        *
+        * This also means that if we get an error whilst building the buffer
+        * list to write, we can cancel the entire list without having written
+        * anything.
         */
        nfree = 0;
        for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) {
@@ -472,10 +457,17 @@ xfs_growfs_data_private(
                else
                        agsize = mp->m_sb.sb_agblocks;
 
-               error = xfs_grow_ag_headers(mp, agno, agsize, &nfree);
-               if (error)
+               error = xfs_grow_ag_headers(mp, agno, agsize, &nfree,
+                                           &buffer_list);
+               if (error) {
+                       xfs_buf_delwri_cancel(&buffer_list);
                        goto error0;
+               }
        }
+       error = xfs_buf_delwri_submit(&buffer_list);
+       if (error)
+               goto error0;
+
        xfs_trans_agblocks_delta(tp, nfree);
 
        /*