diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2011-11-22 07:18:51 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2011-11-22 07:18:51 -0500 |
commit | 6a8099ed5677ac1bb2c74b74a31fecb8282f56c2 (patch) | |
tree | a6baa1fa5a8a9f140b76210fb5f8eb3fb68906c5 /fs/gfs2/rgrp.c | |
parent | 564e12b1157215171e7f3af5b70611ec7154327c (diff) |
GFS2: Fix multi-block allocation
Clean up gfs2_alloc_blocks so that it takes the full extent length
rather than just the number of non-inode blocks as an argument. That
will only make a difference in the inode allocation case for now.
Also, this fixes the extent length handling around gfs2_alloc_extent() so
that multi block allocations will work again.
The rd_last_alloc block is set to the final block in the allocated
extent (as per the update to i_goal, but referenced to a different
start point).
This also removes the dinode argument to rgblk_search() which is no
longer used.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r-- | fs/gfs2/rgrp.c | 65 |
1 files changed, 35 insertions, 30 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index f6e05d63e8ab..22234627f684 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -65,7 +65,7 @@ static const char valid_change[16] = { | |||
65 | }; | 65 | }; |
66 | 66 | ||
67 | static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, | 67 | static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, |
68 | unsigned char old_state, bool dinode, | 68 | unsigned char old_state, |
69 | struct gfs2_bitmap **rbi); | 69 | struct gfs2_bitmap **rbi); |
70 | 70 | ||
71 | /** | 71 | /** |
@@ -939,7 +939,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip | |||
939 | 939 | ||
940 | while (goal < rgd->rd_data) { | 940 | while (goal < rgd->rd_data) { |
941 | down_write(&sdp->sd_log_flush_lock); | 941 | down_write(&sdp->sd_log_flush_lock); |
942 | block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, 0, &bi); | 942 | block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, &bi); |
943 | up_write(&sdp->sd_log_flush_lock); | 943 | up_write(&sdp->sd_log_flush_lock); |
944 | if (block == BFITNOENT) | 944 | if (block == BFITNOENT) |
945 | break; | 945 | break; |
@@ -1147,14 +1147,14 @@ static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) | |||
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | /** | 1149 | /** |
1150 | * rgblk_search - find a block in @old_state | 1150 | * rgblk_search - find a block in @state |
1151 | * @rgd: the resource group descriptor | 1151 | * @rgd: the resource group descriptor |
1152 | * @goal: the goal block within the RG (start here to search for avail block) | 1152 | * @goal: the goal block within the RG (start here to search for avail block) |
1153 | * @old_state: GFS2_BLKST_XXX the before-allocation state to find | 1153 | * @state: GFS2_BLKST_XXX the before-allocation state to find |
1154 | * @dinode: TRUE if the first block we allocate is for a dinode | 1154 | * @dinode: TRUE if the first block we allocate is for a dinode |
1155 | * @rbi: address of the pointer to the bitmap containing the block found | 1155 | * @rbi: address of the pointer to the bitmap containing the block found |
1156 | * | 1156 | * |
1157 | * Walk rgrp's bitmap to find bits that represent a block in @old_state. | 1157 | * Walk rgrp's bitmap to find bits that represent a block in @state. |
1158 | * | 1158 | * |
1159 | * This function never fails, because we wouldn't call it unless we | 1159 | * This function never fails, because we wouldn't call it unless we |
1160 | * know (from reservation results, etc.) that a block is available. | 1160 | * know (from reservation results, etc.) that a block is available. |
@@ -1166,7 +1166,7 @@ static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) | |||
1166 | */ | 1166 | */ |
1167 | 1167 | ||
1168 | static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, | 1168 | static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, |
1169 | unsigned char old_state, bool dinode, | 1169 | unsigned char state, |
1170 | struct gfs2_bitmap **rbi) | 1170 | struct gfs2_bitmap **rbi) |
1171 | { | 1171 | { |
1172 | struct gfs2_bitmap *bi = NULL; | 1172 | struct gfs2_bitmap *bi = NULL; |
@@ -1198,21 +1198,21 @@ do_search: | |||
1198 | bi = rgd->rd_bits + buf; | 1198 | bi = rgd->rd_bits + buf; |
1199 | 1199 | ||
1200 | if (test_bit(GBF_FULL, &bi->bi_flags) && | 1200 | if (test_bit(GBF_FULL, &bi->bi_flags) && |
1201 | (old_state == GFS2_BLKST_FREE)) | 1201 | (state == GFS2_BLKST_FREE)) |
1202 | goto skip; | 1202 | goto skip; |
1203 | 1203 | ||
1204 | /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone | 1204 | /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone |
1205 | bitmaps, so we must search the originals for that. */ | 1205 | bitmaps, so we must search the originals for that. */ |
1206 | buffer = bi->bi_bh->b_data + bi->bi_offset; | 1206 | buffer = bi->bi_bh->b_data + bi->bi_offset; |
1207 | WARN_ON(!buffer_uptodate(bi->bi_bh)); | 1207 | WARN_ON(!buffer_uptodate(bi->bi_bh)); |
1208 | if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) | 1208 | if (state != GFS2_BLKST_UNLINKED && bi->bi_clone) |
1209 | buffer = bi->bi_clone + bi->bi_offset; | 1209 | buffer = bi->bi_clone + bi->bi_offset; |
1210 | 1210 | ||
1211 | blk = gfs2_bitfit(buffer, bi->bi_len, goal, old_state); | 1211 | blk = gfs2_bitfit(buffer, bi->bi_len, goal, state); |
1212 | if (blk != BFITNOENT) | 1212 | if (blk != BFITNOENT) |
1213 | break; | 1213 | break; |
1214 | 1214 | ||
1215 | if ((goal == 0) && (old_state == GFS2_BLKST_FREE)) | 1215 | if ((goal == 0) && (state == GFS2_BLKST_FREE)) |
1216 | set_bit(GBF_FULL, &bi->bi_flags); | 1216 | set_bit(GBF_FULL, &bi->bi_flags); |
1217 | 1217 | ||
1218 | /* Try next bitmap block (wrap back to rgrp header if at end) */ | 1218 | /* Try next bitmap block (wrap back to rgrp header if at end) */ |
@@ -1247,12 +1247,12 @@ static u64 gfs2_alloc_extent(struct gfs2_rgrpd *rgd, struct gfs2_bitmap *bi, | |||
1247 | u32 goal; | 1247 | u32 goal; |
1248 | const u8 *buffer = NULL; | 1248 | const u8 *buffer = NULL; |
1249 | 1249 | ||
1250 | *n = 0; | ||
1250 | buffer = bi->bi_bh->b_data + bi->bi_offset; | 1251 | buffer = bi->bi_bh->b_data + bi->bi_offset; |
1251 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); | 1252 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); |
1252 | gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, | 1253 | gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, |
1253 | bi, blk, dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED); | 1254 | bi, blk, dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED); |
1254 | if (!dinode) | 1255 | (*n)++; |
1255 | (*n)++; | ||
1256 | goal = blk; | 1256 | goal = blk; |
1257 | while (*n < elen) { | 1257 | while (*n < elen) { |
1258 | goal++; | 1258 | goal++; |
@@ -1266,7 +1266,7 @@ static u64 gfs2_alloc_extent(struct gfs2_rgrpd *rgd, struct gfs2_bitmap *bi, | |||
1266 | (*n)++; | 1266 | (*n)++; |
1267 | } | 1267 | } |
1268 | blk = gfs2_bi2rgd_blk(bi, blk); | 1268 | blk = gfs2_bi2rgd_blk(bi, blk); |
1269 | rgd->rd_last_alloc = blk; | 1269 | rgd->rd_last_alloc = blk + *n - 1; |
1270 | return rgd->rd_data0 + blk; | 1270 | return rgd->rd_data0 + blk; |
1271 | } | 1271 | } |
1272 | 1272 | ||
@@ -1358,20 +1358,21 @@ static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd) | |||
1358 | * gfs2_alloc_blocks - Allocate one or more blocks of data and/or a dinode | 1358 | * gfs2_alloc_blocks - Allocate one or more blocks of data and/or a dinode |
1359 | * @ip: the inode to allocate the block for | 1359 | * @ip: the inode to allocate the block for |
1360 | * @bn: Used to return the starting block number | 1360 | * @bn: Used to return the starting block number |
1361 | * @ndata: requested number of data blocks/extent length (value/result) | 1361 | * @ndata: requested number of blocks/extent length (value/result) |
1362 | * @dinode: 1 if we're allocating a dinode block, else 0 | 1362 | * @dinode: 1 if we're allocating a dinode block, else 0 |
1363 | * @generation: the generation number of the inode | 1363 | * @generation: the generation number of the inode |
1364 | * | 1364 | * |
1365 | * Returns: 0 or error | 1365 | * Returns: 0 or error |
1366 | */ | 1366 | */ |
1367 | 1367 | ||
1368 | int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *ndata, | 1368 | int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks, |
1369 | bool dinode, u64 *generation) | 1369 | bool dinode, u64 *generation) |
1370 | { | 1370 | { |
1371 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1371 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1372 | struct buffer_head *dibh; | 1372 | struct buffer_head *dibh; |
1373 | struct gfs2_rgrpd *rgd; | 1373 | struct gfs2_rgrpd *rgd; |
1374 | u32 goal, extlen, blk; /* block, within the rgrp scope */ | 1374 | unsigned int ndata; |
1375 | u32 goal, blk; /* block, within the rgrp scope */ | ||
1375 | u64 block; /* block, within the file system scope */ | 1376 | u64 block; /* block, within the file system scope */ |
1376 | int error; | 1377 | int error; |
1377 | struct gfs2_bitmap *bi; | 1378 | struct gfs2_bitmap *bi; |
@@ -1389,17 +1390,19 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *ndata, | |||
1389 | else | 1390 | else |
1390 | goal = rgd->rd_last_alloc; | 1391 | goal = rgd->rd_last_alloc; |
1391 | 1392 | ||
1392 | blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, dinode, &bi); | 1393 | blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, &bi); |
1393 | 1394 | ||
1394 | *ndata = 0; | ||
1395 | /* Since all blocks are reserved in advance, this shouldn't happen */ | 1395 | /* Since all blocks are reserved in advance, this shouldn't happen */ |
1396 | if (blk == BFITNOENT) | 1396 | if (blk == BFITNOENT) |
1397 | goto rgrp_error; | 1397 | goto rgrp_error; |
1398 | 1398 | ||
1399 | block = gfs2_alloc_extent(rgd, bi, blk, dinode, ndata); | 1399 | block = gfs2_alloc_extent(rgd, bi, blk, dinode, nblocks); |
1400 | ndata = *nblocks; | ||
1401 | if (dinode) | ||
1402 | ndata--; | ||
1400 | 1403 | ||
1401 | if (!dinode) { | 1404 | if (!dinode) { |
1402 | ip->i_goal = block + *ndata - 1; | 1405 | ip->i_goal = block + ndata - 1; |
1403 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1406 | error = gfs2_meta_inode_buffer(ip, &dibh); |
1404 | if (error == 0) { | 1407 | if (error == 0) { |
1405 | struct gfs2_dinode *di = | 1408 | struct gfs2_dinode *di = |
@@ -1410,13 +1413,10 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *ndata, | |||
1410 | brelse(dibh); | 1413 | brelse(dibh); |
1411 | } | 1414 | } |
1412 | } | 1415 | } |
1413 | extlen = *ndata; | 1416 | if (rgd->rd_free < *nblocks) |
1414 | if (dinode) | ||
1415 | extlen++; | ||
1416 | if (rgd->rd_free < extlen) | ||
1417 | goto rgrp_error; | 1417 | goto rgrp_error; |
1418 | 1418 | ||
1419 | rgd->rd_free -= extlen; | 1419 | rgd->rd_free -= *nblocks; |
1420 | if (dinode) { | 1420 | if (dinode) { |
1421 | rgd->rd_dinodes++; | 1421 | rgd->rd_dinodes++; |
1422 | *generation = rgd->rd_igeneration++; | 1422 | *generation = rgd->rd_igeneration++; |
@@ -1427,15 +1427,20 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *ndata, | |||
1427 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); | 1427 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); |
1428 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); | 1428 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); |
1429 | 1429 | ||
1430 | gfs2_statfs_change(sdp, 0, -(s64)extlen, dinode ? 1 : 0); | 1430 | gfs2_statfs_change(sdp, 0, -(s64)*nblocks, dinode ? 1 : 0); |
1431 | if (dinode) | 1431 | if (dinode) |
1432 | gfs2_trans_add_unrevoke(sdp, block, 1); | 1432 | gfs2_trans_add_unrevoke(sdp, block, 1); |
1433 | if (*ndata) | 1433 | |
1434 | gfs2_quota_change(ip, *ndata, ip->i_inode.i_uid, | 1434 | /* |
1435 | * This needs reviewing to see why we cannot do the quota change | ||
1436 | * at this point in the dinode case. | ||
1437 | */ | ||
1438 | if (ndata) | ||
1439 | gfs2_quota_change(ip, ndata, ip->i_inode.i_uid, | ||
1435 | ip->i_inode.i_gid); | 1440 | ip->i_inode.i_gid); |
1436 | 1441 | ||
1437 | rgd->rd_free_clone -= extlen; | 1442 | rgd->rd_free_clone -= *nblocks; |
1438 | trace_gfs2_block_alloc(ip, block, extlen, | 1443 | trace_gfs2_block_alloc(ip, block, *nblocks, |
1439 | dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED); | 1444 | dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED); |
1440 | *bn = block; | 1445 | *bn = block; |
1441 | return 0; | 1446 | return 0; |