diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2012-07-30 06:06:08 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2012-09-13 05:30:58 -0400 |
commit | 62e252eeefda62eb8cae9f4286270317ab8d5a42 (patch) | |
tree | cc7f26be5373eeb7a9489d7d3a17f3a3a88a2f12 | |
parent | 645b2ccc75d3d15928e3dbfc659659c2b8d4d9a6 (diff) |
GFS2: Take account of blockages when using reserved blocks
The claim_reserved_blks() function was not taking account of
the possibility of "blockages" while performing allocation.
This can be caused by another node allocating something in
the same extent which has been reserved locally.
This patch tests for this condition and then skips the remainder
of the reservation in this case. This is a relatively rare event,
so that it should not affect the general performance improvement
which the block reservations provide.
The claim_reserved_blks() function also appears not to be able
to deal with reservations which cross bitmap boundaries, but
that can be dealt with in a future patch since we don't generate
boundary crossing reservations currently.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Reported-by: David Teigland <teigland@redhat.com>
Cc: Bob Peterson <rpeterso@redhat.com>
-rw-r--r-- | fs/gfs2/rgrp.c | 66 |
1 files changed, 28 insertions, 38 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 4d34887a601d..c9ed814eeb6f 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -1961,7 +1961,7 @@ static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd) | |||
1961 | * @dinode: 1 if this block is a dinode block, otherwise data block | 1961 | * @dinode: 1 if this block is a dinode block, otherwise data block |
1962 | * @nblocks: desired extent length | 1962 | * @nblocks: desired extent length |
1963 | * | 1963 | * |
1964 | * Lay claim to previously allocated block reservation blocks. | 1964 | * Lay claim to previously reserved blocks. |
1965 | * Returns: Starting block number of the blocks claimed. | 1965 | * Returns: Starting block number of the blocks claimed. |
1966 | * Sets *nblocks to the actual extent length allocated. | 1966 | * Sets *nblocks to the actual extent length allocated. |
1967 | */ | 1967 | */ |
@@ -1970,19 +1970,17 @@ static u64 claim_reserved_blks(struct gfs2_inode *ip, bool dinode, | |||
1970 | { | 1970 | { |
1971 | struct gfs2_blkreserv *rs = ip->i_res; | 1971 | struct gfs2_blkreserv *rs = ip->i_res; |
1972 | struct gfs2_rgrpd *rgd = rs->rs_rgd; | 1972 | struct gfs2_rgrpd *rgd = rs->rs_rgd; |
1973 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
1974 | struct gfs2_bitmap *bi; | 1973 | struct gfs2_bitmap *bi; |
1975 | u64 start_block = gfs2_rs_startblk(rs); | 1974 | u64 start_block = gfs2_rs_startblk(rs); |
1976 | const unsigned int elen = *nblocks; | 1975 | const unsigned int elen = *nblocks; |
1977 | 1976 | ||
1978 | /*BUG_ON(!gfs2_glock_is_locked_by_me(ip->i_gl));*/ | ||
1979 | gfs2_assert_withdraw(sdp, rgd); | ||
1980 | /*BUG_ON(!gfs2_glock_is_locked_by_me(rgd->rd_gl));*/ | ||
1981 | bi = rs->rs_bi; | 1977 | bi = rs->rs_bi; |
1982 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); | 1978 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); |
1983 | 1979 | ||
1984 | for (*nblocks = 0; *nblocks < elen && rs->rs_free; (*nblocks)++) { | 1980 | for (*nblocks = 0; *nblocks < elen && rs->rs_free; (*nblocks)++) { |
1985 | /* Make sure the bitmap hasn't changed */ | 1981 | if (gfs2_testbit(rgd, bi->bi_bh->b_data + bi->bi_offset, |
1982 | bi->bi_len, rs->rs_biblk) != GFS2_BLKST_FREE) | ||
1983 | break; | ||
1986 | gfs2_setbit(rgd, bi->bi_clone, bi, rs->rs_biblk, | 1984 | gfs2_setbit(rgd, bi->bi_clone, bi, rs->rs_biblk, |
1987 | dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED); | 1985 | dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED); |
1988 | rs->rs_biblk++; | 1986 | rs->rs_biblk++; |
@@ -1991,20 +1989,12 @@ static u64 claim_reserved_blks(struct gfs2_inode *ip, bool dinode, | |||
1991 | BUG_ON(!rgd->rd_reserved); | 1989 | BUG_ON(!rgd->rd_reserved); |
1992 | rgd->rd_reserved--; | 1990 | rgd->rd_reserved--; |
1993 | dinode = false; | 1991 | dinode = false; |
1994 | trace_gfs2_rs(ip, rs, TRACE_RS_CLAIM); | ||
1995 | } | 1992 | } |
1996 | 1993 | ||
1997 | if (!rs->rs_free) { | 1994 | trace_gfs2_rs(ip, rs, TRACE_RS_CLAIM); |
1998 | struct gfs2_rgrpd *rgd = ip->i_res->rs_rgd; | 1995 | if (!rs->rs_free || *nblocks != elen) |
1999 | |||
2000 | gfs2_rs_deltree(rs); | 1996 | gfs2_rs_deltree(rs); |
2001 | /* -nblocks because we haven't returned to do the math yet. | 1997 | |
2002 | I'm doing the math backwards to prevent negative numbers, | ||
2003 | but think of it as: | ||
2004 | if (unclaimed_blocks(rgd) - *nblocks >= RGRP_RSRV_MINBLKS */ | ||
2005 | if (unclaimed_blocks(rgd) >= RGRP_RSRV_MINBLKS + *nblocks) | ||
2006 | rg_mblk_search(rgd, ip); | ||
2007 | } | ||
2008 | return start_block; | 1998 | return start_block; |
2009 | } | 1999 | } |
2010 | 2000 | ||
@@ -2037,34 +2027,34 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks, | |||
2037 | if (ip->i_res->rs_requested == 0) | 2027 | if (ip->i_res->rs_requested == 0) |
2038 | return -ECANCELED; | 2028 | return -ECANCELED; |
2039 | 2029 | ||
2040 | /* Check if we have a multi-block reservation, and if so, claim the | 2030 | /* If we have a reservation, claim blocks from it. */ |
2041 | next free block from it. */ | ||
2042 | if (gfs2_rs_active(ip->i_res)) { | 2031 | if (gfs2_rs_active(ip->i_res)) { |
2043 | BUG_ON(!ip->i_res->rs_free); | 2032 | BUG_ON(!ip->i_res->rs_free); |
2044 | rgd = ip->i_res->rs_rgd; | 2033 | rgd = ip->i_res->rs_rgd; |
2045 | block = claim_reserved_blks(ip, dinode, nblocks); | 2034 | block = claim_reserved_blks(ip, dinode, nblocks); |
2046 | } else { | 2035 | if (*nblocks) |
2047 | rgd = ip->i_rgd; | 2036 | goto found_blocks; |
2037 | } | ||
2048 | 2038 | ||
2049 | if (!dinode && rgrp_contains_block(rgd, ip->i_goal)) | 2039 | rgd = ip->i_rgd; |
2050 | goal = ip->i_goal - rgd->rd_data0; | ||
2051 | else | ||
2052 | goal = rgd->rd_last_alloc; | ||
2053 | |||
2054 | blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, &bi); | ||
2055 | |||
2056 | /* Since all blocks are reserved in advance, this shouldn't | ||
2057 | happen */ | ||
2058 | if (blk == BFITNOENT) { | ||
2059 | printk(KERN_WARNING "BFITNOENT, nblocks=%u\n", | ||
2060 | *nblocks); | ||
2061 | printk(KERN_WARNING "FULL=%d\n", | ||
2062 | test_bit(GBF_FULL, &rgd->rd_bits->bi_flags)); | ||
2063 | goto rgrp_error; | ||
2064 | } | ||
2065 | 2040 | ||
2066 | block = gfs2_alloc_extent(rgd, bi, blk, dinode, nblocks); | 2041 | if (!dinode && rgrp_contains_block(rgd, ip->i_goal)) |
2042 | goal = ip->i_goal - rgd->rd_data0; | ||
2043 | else | ||
2044 | goal = rgd->rd_last_alloc; | ||
2045 | |||
2046 | blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, &bi); | ||
2047 | |||
2048 | /* Since all blocks are reserved in advance, this shouldn't happen */ | ||
2049 | if (blk == BFITNOENT) { | ||
2050 | printk(KERN_WARNING "BFITNOENT, nblocks=%u\n", *nblocks); | ||
2051 | printk(KERN_WARNING "FULL=%d\n", | ||
2052 | test_bit(GBF_FULL, &rgd->rd_bits->bi_flags)); | ||
2053 | goto rgrp_error; | ||
2067 | } | 2054 | } |
2055 | |||
2056 | block = gfs2_alloc_extent(rgd, bi, blk, dinode, nblocks); | ||
2057 | found_blocks: | ||
2068 | ndata = *nblocks; | 2058 | ndata = *nblocks; |
2069 | if (dinode) | 2059 | if (dinode) |
2070 | ndata--; | 2060 | ndata--; |