aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/rgrp.c
diff options
context:
space:
mode:
authorBob Peterson <rpeterso@redhat.com>2013-11-06 10:55:52 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2014-01-03 04:57:02 -0500
commit5ce13431dd3365d5dd4f3890394dac59b687c0ed (patch)
tree075a5a73e1fd5e121ec68c75f323aeba53869633 /fs/gfs2/rgrp.c
parent7a262d2ed9fa42fad8c4f243f8025580b58cf2f6 (diff)
GFS2: If requested is too large, use the largest extent in the rgrp
Here is a second try at a patch I posted earlier, which also implements suggestions Steve made: Before this patch, GFS2 would keep searching through all the rgrps until it found one that had a chunk of free blocks big enough to satisfy the size hint, which is based on the file write size, regardless of whether the chunk was big enough to perform the write. However, when doing big writes there may not be a large enough chunk of free blocks in any rgrp, due to file system fragmentation. The largest chunk may be big enough to satisfy the write request, but it may not meet the ideal reservation size from the "size hint". The writes would slow to a crawl because every write would search every rgrp, then finally give up and default to a single-block write. In my case, performance would drop from 425MB/s to 18KB/s, or 24000 times slower. This patch basically makes it so that if we can't find a contiguous chunk of blocks big enough to satisfy the sizehint, we'll use the largest chunk of blocks we found that will still contain the write. It does so by keeping track of the largest run of blocks within the rgrp. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r--fs/gfs2/rgrp.c64
1 files changed, 49 insertions, 15 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index c8d6161bd682..809fecd82970 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -57,6 +57,11 @@
57 * 3 = Used (metadata) 57 * 3 = Used (metadata)
58 */ 58 */
59 59
60struct gfs2_extent {
61 struct gfs2_rbm rbm;
62 u32 len;
63};
64
60static const char valid_change[16] = { 65static const char valid_change[16] = {
61 /* current */ 66 /* current */
62 /* n */ 0, 1, 1, 1, 67 /* n */ 0, 1, 1, 1,
@@ -65,8 +70,9 @@ static const char valid_change[16] = {
65 1, 0, 0, 0 70 1, 0, 0, 0
66}; 71};
67 72
68static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 minext, 73static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
69 const struct gfs2_inode *ip, bool nowrap); 74 const struct gfs2_inode *ip, bool nowrap,
75 const struct gfs2_alloc_parms *ap);
70 76
71 77
72/** 78/**
@@ -1455,7 +1461,7 @@ static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip,
1455 if (WARN_ON(gfs2_rbm_from_block(&rbm, goal))) 1461 if (WARN_ON(gfs2_rbm_from_block(&rbm, goal)))
1456 return; 1462 return;
1457 1463
1458 ret = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, extlen, ip, true); 1464 ret = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, &extlen, ip, true, ap);
1459 if (ret == 0) { 1465 if (ret == 0) {
1460 rs->rs_rbm = rbm; 1466 rs->rs_rbm = rbm;
1461 rs->rs_free = extlen; 1467 rs->rs_free = extlen;
@@ -1520,6 +1526,7 @@ static u64 gfs2_next_unreserved_block(struct gfs2_rgrpd *rgd, u64 block,
1520 * @rbm: The current position in the resource group 1526 * @rbm: The current position in the resource group
1521 * @ip: The inode for which we are searching for blocks 1527 * @ip: The inode for which we are searching for blocks
1522 * @minext: The minimum extent length 1528 * @minext: The minimum extent length
1529 * @maxext: A pointer to the maximum extent structure
1523 * 1530 *
1524 * This checks the current position in the rgrp to see whether there is 1531 * This checks the current position in the rgrp to see whether there is
1525 * a reservation covering this block. If not then this function is a 1532 * a reservation covering this block. If not then this function is a
@@ -1532,7 +1539,8 @@ static u64 gfs2_next_unreserved_block(struct gfs2_rgrpd *rgd, u64 block,
1532 1539
1533static int gfs2_reservation_check_and_update(struct gfs2_rbm *rbm, 1540static int gfs2_reservation_check_and_update(struct gfs2_rbm *rbm,
1534 const struct gfs2_inode *ip, 1541 const struct gfs2_inode *ip,
1535 u32 minext) 1542 u32 minext,
1543 struct gfs2_extent *maxext)
1536{ 1544{
1537 u64 block = gfs2_rbm_to_block(rbm); 1545 u64 block = gfs2_rbm_to_block(rbm);
1538 u32 extlen = 1; 1546 u32 extlen = 1;
@@ -1545,8 +1553,7 @@ static int gfs2_reservation_check_and_update(struct gfs2_rbm *rbm,
1545 */ 1553 */
1546 if (minext) { 1554 if (minext) {
1547 extlen = gfs2_free_extlen(rbm, minext); 1555 extlen = gfs2_free_extlen(rbm, minext);
1548 nblock = block + extlen; 1556 if (extlen <= maxext->len)
1549 if (extlen < minext)
1550 goto fail; 1557 goto fail;
1551 } 1558 }
1552 1559
@@ -1555,9 +1562,17 @@ static int gfs2_reservation_check_and_update(struct gfs2_rbm *rbm,
1555 * and skip if parts of it are already reserved 1562 * and skip if parts of it are already reserved
1556 */ 1563 */
1557 nblock = gfs2_next_unreserved_block(rbm->rgd, block, extlen, ip); 1564 nblock = gfs2_next_unreserved_block(rbm->rgd, block, extlen, ip);
1558 if (nblock == block) 1565 if (nblock == block) {
1559 return 0; 1566 if (!minext || extlen >= minext)
1567 return 0;
1568
1569 if (extlen > maxext->len) {
1570 maxext->len = extlen;
1571 maxext->rbm = *rbm;
1572 }
1560fail: 1573fail:
1574 nblock = block + extlen;
1575 }
1561 ret = gfs2_rbm_from_block(rbm, nblock); 1576 ret = gfs2_rbm_from_block(rbm, nblock);
1562 if (ret < 0) 1577 if (ret < 0)
1563 return ret; 1578 return ret;
@@ -1568,10 +1583,12 @@ fail:
1568 * gfs2_rbm_find - Look for blocks of a particular state 1583 * gfs2_rbm_find - Look for blocks of a particular state
1569 * @rbm: Value/result starting position and final position 1584 * @rbm: Value/result starting position and final position
1570 * @state: The state which we want to find 1585 * @state: The state which we want to find
1571 * @minext: The requested extent length (0 for a single block) 1586 * @minext: Pointer to the requested extent length (NULL for a single block)
1587 * This is updated to be the actual reservation size.
1572 * @ip: If set, check for reservations 1588 * @ip: If set, check for reservations
1573 * @nowrap: Stop looking at the end of the rgrp, rather than wrapping 1589 * @nowrap: Stop looking at the end of the rgrp, rather than wrapping
1574 * around until we've reached the starting point. 1590 * around until we've reached the starting point.
1591 * @ap: the allocation parameters
1575 * 1592 *
1576 * Side effects: 1593 * Side effects:
1577 * - If looking for free blocks, we set GBF_FULL on each bitmap which 1594 * - If looking for free blocks, we set GBF_FULL on each bitmap which
@@ -1580,8 +1597,9 @@ fail:
1580 * Returns: 0 on success, -ENOSPC if there is no block of the requested state 1597 * Returns: 0 on success, -ENOSPC if there is no block of the requested state
1581 */ 1598 */
1582 1599
1583static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 minext, 1600static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
1584 const struct gfs2_inode *ip, bool nowrap) 1601 const struct gfs2_inode *ip, bool nowrap,
1602 const struct gfs2_alloc_parms *ap)
1585{ 1603{
1586 struct buffer_head *bh; 1604 struct buffer_head *bh;
1587 int initial_bii; 1605 int initial_bii;
@@ -1592,6 +1610,7 @@ static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 minext,
1592 int iters = rbm->rgd->rd_length; 1610 int iters = rbm->rgd->rd_length;
1593 int ret; 1611 int ret;
1594 struct gfs2_bitmap *bi; 1612 struct gfs2_bitmap *bi;
1613 struct gfs2_extent maxext = { .rbm.rgd = rbm->rgd, };
1595 1614
1596 /* If we are not starting at the beginning of a bitmap, then we 1615 /* If we are not starting at the beginning of a bitmap, then we
1597 * need to add one to the bitmap count to ensure that we search 1616 * need to add one to the bitmap count to ensure that we search
@@ -1620,7 +1639,9 @@ static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 minext,
1620 return 0; 1639 return 0;
1621 1640
1622 initial_bii = rbm->bii; 1641 initial_bii = rbm->bii;
1623 ret = gfs2_reservation_check_and_update(rbm, ip, minext); 1642 ret = gfs2_reservation_check_and_update(rbm, ip,
1643 minext ? *minext : 0,
1644 &maxext);
1624 if (ret == 0) 1645 if (ret == 0)
1625 return 0; 1646 return 0;
1626 if (ret > 0) { 1647 if (ret > 0) {
@@ -1655,6 +1676,17 @@ next_iter:
1655 break; 1676 break;
1656 } 1677 }
1657 1678
1679 if (minext == NULL || state != GFS2_BLKST_FREE)
1680 return -ENOSPC;
1681
1682 /* If the maximum extent we found is big enough to fulfill the
1683 minimum requirements, use it anyway. */
1684 if (maxext.len) {
1685 *rbm = maxext.rbm;
1686 *minext = maxext.len;
1687 return 0;
1688 }
1689
1658 return -ENOSPC; 1690 return -ENOSPC;
1659} 1691}
1660 1692
@@ -1680,7 +1712,8 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
1680 1712
1681 while (1) { 1713 while (1) {
1682 down_write(&sdp->sd_log_flush_lock); 1714 down_write(&sdp->sd_log_flush_lock);
1683 error = gfs2_rbm_find(&rbm, GFS2_BLKST_UNLINKED, 0, NULL, true); 1715 error = gfs2_rbm_find(&rbm, GFS2_BLKST_UNLINKED, NULL, NULL,
1716 true, NULL);
1684 up_write(&sdp->sd_log_flush_lock); 1717 up_write(&sdp->sd_log_flush_lock);
1685 if (error == -ENOSPC) 1718 if (error == -ENOSPC)
1686 break; 1719 break;
@@ -2184,11 +2217,12 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
2184 int error; 2217 int error;
2185 2218
2186 gfs2_set_alloc_start(&rbm, ip, dinode); 2219 gfs2_set_alloc_start(&rbm, ip, dinode);
2187 error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, 0, ip, false); 2220 error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, NULL, ip, false, NULL);
2188 2221
2189 if (error == -ENOSPC) { 2222 if (error == -ENOSPC) {
2190 gfs2_set_alloc_start(&rbm, ip, dinode); 2223 gfs2_set_alloc_start(&rbm, ip, dinode);
2191 error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, 0, NULL, false); 2224 error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, NULL, NULL, false,
2225 NULL);
2192 } 2226 }
2193 2227
2194 /* Since all blocks are reserved in advance, this shouldn't happen */ 2228 /* Since all blocks are reserved in advance, this shouldn't happen */