Commit 71921ef8 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher

gfs2: Fix loop in gfs2_rbm_find (v2)

Fix the resource group wrap-around logic in gfs2_rbm_find that commit
e579ed4f 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 commit 2d29f6b9 ("gfs2: Fix loop in
gfs2_rbm_find") which ended up being reverted because it introduced a
performance regression in iozone (see commit e74c98ca).  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: e579ed4f ("GFS2: Introduce rbm field bii")
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
parent b4b52b88
...@@ -1729,25 +1729,22 @@ static int gfs2_reservation_check_and_update(struct gfs2_rbm *rbm, ...@@ -1729,25 +1729,22 @@ static int gfs2_reservation_check_and_update(struct gfs2_rbm *rbm,
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, ...@@ -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 @@ static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext, ...@@ -1811,8 +1807,8 @@ static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
/* 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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment