gfs2: Fix loop in gfs2_rbm_find (v2)
Fix the resource group wrap-around logic in gfs2_rbm_find that commite579ed4f44
broke. The bug can lead to unnecessary repeated scanning of the same bitmaps; there is a risk that future changes will turn this into an endless loop. This is an updated version of commit2d29f6b96d
("gfs2: Fix loop in gfs2_rbm_find") which ended up being reverted because it introduced a performance regression in iozone (see commite74c98ca2d
). Changes since v1: - Simplify the wrap-around logic. - Handle the case where each resource group only has a single bitmap block (small filesystem). - Update rd_extfail_pt whenever we scan the entire bitmap, even when we don't start the scan at the very beginning of the bitmap. Fixes:e579ed4f44
("GFS2: Introduce rbm field bii") Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
parent
b4b52b881c
commit
71921ef859
@ -1729,25 +1729,22 @@ fail:
|
||||
static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
|
||||
const struct gfs2_inode *ip, bool nowrap)
|
||||
{
|
||||
bool scan_from_start = rbm->bii == 0 && rbm->offset == 0;
|
||||
struct buffer_head *bh;
|
||||
int initial_bii;
|
||||
u32 initial_offset;
|
||||
int first_bii = rbm->bii;
|
||||
u32 first_offset = rbm->offset;
|
||||
int last_bii;
|
||||
u32 offset;
|
||||
u8 *buffer;
|
||||
int n = 0;
|
||||
int iters = rbm->rgd->rd_length;
|
||||
bool wrapped = false;
|
||||
int ret;
|
||||
struct gfs2_bitmap *bi;
|
||||
struct gfs2_extent maxext = { .rbm.rgd = rbm->rgd, };
|
||||
|
||||
/* If we are not starting at the beginning of a bitmap, then we
|
||||
* need to add one to the bitmap count to ensure that we search
|
||||
* the starting bitmap twice.
|
||||
/*
|
||||
* Determine the last bitmap to search. If we're not starting at the
|
||||
* beginning of a bitmap, we need to search that bitmap twice to scan
|
||||
* the entire resource group.
|
||||
*/
|
||||
if (rbm->offset != 0)
|
||||
iters++;
|
||||
last_bii = rbm->bii - (rbm->offset == 0);
|
||||
|
||||
while(1) {
|
||||
bi = rbm_bi(rbm);
|
||||
@ -1761,47 +1758,46 @@ static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
|
||||
WARN_ON(!buffer_uptodate(bh));
|
||||
if (state != GFS2_BLKST_UNLINKED && bi->bi_clone)
|
||||
buffer = bi->bi_clone + bi->bi_offset;
|
||||
initial_offset = rbm->offset;
|
||||
offset = gfs2_bitfit(buffer, bi->bi_bytes, rbm->offset, state);
|
||||
if (offset == BFITNOENT)
|
||||
goto bitmap_full;
|
||||
if (offset == BFITNOENT) {
|
||||
if (state == GFS2_BLKST_FREE && rbm->offset == 0)
|
||||
set_bit(GBF_FULL, &bi->bi_flags);
|
||||
goto next_bitmap;
|
||||
}
|
||||
rbm->offset = offset;
|
||||
if (ip == NULL)
|
||||
return 0;
|
||||
|
||||
initial_bii = rbm->bii;
|
||||
ret = gfs2_reservation_check_and_update(rbm, ip,
|
||||
minext ? *minext : 0,
|
||||
&maxext);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
if (ret > 0) {
|
||||
n += (rbm->bii - initial_bii);
|
||||
if (ret > 0)
|
||||
goto next_iter;
|
||||
}
|
||||
if (ret == -E2BIG) {
|
||||
rbm->bii = 0;
|
||||
rbm->offset = 0;
|
||||
n += (rbm->bii - initial_bii);
|
||||
goto res_covered_end_of_rgrp;
|
||||
}
|
||||
return ret;
|
||||
|
||||
bitmap_full: /* Mark bitmap as full and fall through */
|
||||
if ((state == GFS2_BLKST_FREE) && initial_offset == 0)
|
||||
set_bit(GBF_FULL, &bi->bi_flags);
|
||||
|
||||
next_bitmap: /* Find next bitmap in the rgrp */
|
||||
rbm->offset = 0;
|
||||
rbm->bii++;
|
||||
if (rbm->bii == rbm->rgd->rd_length)
|
||||
rbm->bii = 0;
|
||||
res_covered_end_of_rgrp:
|
||||
if ((rbm->bii == 0) && nowrap)
|
||||
break;
|
||||
n++;
|
||||
if (rbm->bii == 0) {
|
||||
if (wrapped)
|
||||
break;
|
||||
wrapped = true;
|
||||
if (nowrap)
|
||||
break;
|
||||
}
|
||||
next_iter:
|
||||
if (n >= iters)
|
||||
/* Have we scanned the entire resource group? */
|
||||
if (wrapped && rbm->bii > last_bii)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1811,8 +1807,8 @@ next_iter:
|
||||
/* If the extent was too small, and it's smaller than the smallest
|
||||
to have failed before, remember for future reference that it's
|
||||
useless to search this rgrp again for this amount or more. */
|
||||
if ((first_offset == 0) && (first_bii == 0) &&
|
||||
(*minext < rbm->rgd->rd_extfail_pt))
|
||||
if (wrapped && (scan_from_start || rbm->bii > last_bii) &&
|
||||
*minext < rbm->rgd->rd_extfail_pt)
|
||||
rbm->rgd->rd_extfail_pt = *minext;
|
||||
|
||||
/* If the maximum extent we found is big enough to fulfill the
|
||||
|
Loading…
Reference in New Issue
Block a user