gfs2: Fix loop in gfs2_rbm_find (v2)
Fix the resource group wrap-around logic in gfs2_rbm_find that commithifive-unleashed-5.2e579ed4f44
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>
parent
b4b52b881c
commit
71921ef859
|
@ -1729,25 +1729,22 @@ fail:
|
||||||
static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
|
static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
|
||||||
const struct gfs2_inode *ip, bool nowrap)
|
const struct gfs2_inode *ip, bool nowrap)
|
||||||
{
|
{
|
||||||
|
bool scan_from_start = rbm->bii == 0 && rbm->offset == 0;
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
int initial_bii;
|
int last_bii;
|
||||||
u32 initial_offset;
|
|
||||||
int first_bii = rbm->bii;
|
|
||||||
u32 first_offset = rbm->offset;
|
|
||||||
u32 offset;
|
u32 offset;
|
||||||
u8 *buffer;
|
u8 *buffer;
|
||||||
int n = 0;
|
bool wrapped = false;
|
||||||
int iters = rbm->rgd->rd_length;
|
|
||||||
int ret;
|
int ret;
|
||||||
struct gfs2_bitmap *bi;
|
struct gfs2_bitmap *bi;
|
||||||
struct gfs2_extent maxext = { .rbm.rgd = rbm->rgd, };
|
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
|
* Determine the last bitmap to search. If we're not starting at the
|
||||||
* the starting bitmap twice.
|
* beginning of a bitmap, we need to search that bitmap twice to scan
|
||||||
|
* the entire resource group.
|
||||||
*/
|
*/
|
||||||
if (rbm->offset != 0)
|
last_bii = rbm->bii - (rbm->offset == 0);
|
||||||
iters++;
|
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
bi = rbm_bi(rbm);
|
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));
|
WARN_ON(!buffer_uptodate(bh));
|
||||||
if (state != GFS2_BLKST_UNLINKED && bi->bi_clone)
|
if (state != GFS2_BLKST_UNLINKED && bi->bi_clone)
|
||||||
buffer = bi->bi_clone + bi->bi_offset;
|
buffer = bi->bi_clone + bi->bi_offset;
|
||||||
initial_offset = rbm->offset;
|
|
||||||
offset = gfs2_bitfit(buffer, bi->bi_bytes, rbm->offset, state);
|
offset = gfs2_bitfit(buffer, bi->bi_bytes, rbm->offset, state);
|
||||||
if (offset == BFITNOENT)
|
if (offset == BFITNOENT) {
|
||||||
goto bitmap_full;
|
if (state == GFS2_BLKST_FREE && rbm->offset == 0)
|
||||||
|
set_bit(GBF_FULL, &bi->bi_flags);
|
||||||
|
goto next_bitmap;
|
||||||
|
}
|
||||||
rbm->offset = offset;
|
rbm->offset = offset;
|
||||||
if (ip == NULL)
|
if (ip == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
initial_bii = rbm->bii;
|
|
||||||
ret = gfs2_reservation_check_and_update(rbm, ip,
|
ret = gfs2_reservation_check_and_update(rbm, ip,
|
||||||
minext ? *minext : 0,
|
minext ? *minext : 0,
|
||||||
&maxext);
|
&maxext);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (ret > 0) {
|
if (ret > 0)
|
||||||
n += (rbm->bii - initial_bii);
|
|
||||||
goto next_iter;
|
goto next_iter;
|
||||||
}
|
|
||||||
if (ret == -E2BIG) {
|
if (ret == -E2BIG) {
|
||||||
rbm->bii = 0;
|
rbm->bii = 0;
|
||||||
rbm->offset = 0;
|
rbm->offset = 0;
|
||||||
n += (rbm->bii - initial_bii);
|
|
||||||
goto res_covered_end_of_rgrp;
|
goto res_covered_end_of_rgrp;
|
||||||
}
|
}
|
||||||
return ret;
|
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 */
|
next_bitmap: /* Find next bitmap in the rgrp */
|
||||||
rbm->offset = 0;
|
rbm->offset = 0;
|
||||||
rbm->bii++;
|
rbm->bii++;
|
||||||
if (rbm->bii == rbm->rgd->rd_length)
|
if (rbm->bii == rbm->rgd->rd_length)
|
||||||
rbm->bii = 0;
|
rbm->bii = 0;
|
||||||
res_covered_end_of_rgrp:
|
res_covered_end_of_rgrp:
|
||||||
if ((rbm->bii == 0) && nowrap)
|
if (rbm->bii == 0) {
|
||||||
break;
|
if (wrapped)
|
||||||
n++;
|
break;
|
||||||
|
wrapped = true;
|
||||||
|
if (nowrap)
|
||||||
|
break;
|
||||||
|
}
|
||||||
next_iter:
|
next_iter:
|
||||||
if (n >= iters)
|
/* Have we scanned the entire resource group? */
|
||||||
|
if (wrapped && rbm->bii > last_bii)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1811,8 +1807,8 @@ next_iter:
|
||||||
/* If the extent was too small, and it's smaller than the smallest
|
/* If the extent was too small, and it's smaller than the smallest
|
||||||
to have failed before, remember for future reference that it's
|
to have failed before, remember for future reference that it's
|
||||||
useless to search this rgrp again for this amount or more. */
|
useless to search this rgrp again for this amount or more. */
|
||||||
if ((first_offset == 0) && (first_bii == 0) &&
|
if (wrapped && (scan_from_start || rbm->bii > last_bii) &&
|
||||||
(*minext < rbm->rgd->rd_extfail_pt))
|
*minext < rbm->rgd->rd_extfail_pt)
|
||||||
rbm->rgd->rd_extfail_pt = *minext;
|
rbm->rgd->rd_extfail_pt = *minext;
|
||||||
|
|
||||||
/* If the maximum extent we found is big enough to fulfill the
|
/* If the maximum extent we found is big enough to fulfill the
|
||||||
|
|
Loading…
Reference in New Issue