diff options
author | Bob Peterson <rpeterso@redhat.com> | 2011-11-18 10:58:32 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2011-11-21 05:04:09 -0500 |
commit | 6e87ed0fc93ffbe2aec296e6912b1dcb19034d6c (patch) | |
tree | 4f4ac522d34f35de3e3671996ddc35977aaa49ad /fs/gfs2 | |
parent | 4442f2e03ed9646664c94e197e637b03324a6664 (diff) |
GFS2: move toward a generic multi-block allocator
This patch is a revision of the one I previously posted.
I tried to integrate all the suggestions Steve gave.
The purpose of the patch is to change function gfs2_alloc_block
(allocate either a dinode block or an extent of data blocks)
to a more generic gfs2_alloc_blocks function that can
allocate both a dinode _and_ an extent of data blocks in the
same call. This will ultimately help us create a multi-block
reservation scheme to reduce file fragmentation.
This patch moves more toward a generic multi-block allocator that
takes a pointer to the number of data blocks to allocate, plus whether
or not to allocate a dinode. In theory, it could be called to allocate
(1) a single dinode block, (2) a group of one or more data blocks, or
(3) a dinode plus several data blocks.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/bmap.c | 4 | ||||
-rw-r--r-- | fs/gfs2/dir.c | 2 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 3 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 59 | ||||
-rw-r--r-- | fs/gfs2/rgrp.h | 4 | ||||
-rw-r--r-- | fs/gfs2/xattr.c | 6 |
6 files changed, 39 insertions, 39 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index b69235ba2251..cb74312eb270 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -133,7 +133,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) | |||
133 | and write it out to disk */ | 133 | and write it out to disk */ |
134 | 134 | ||
135 | unsigned int n = 1; | 135 | unsigned int n = 1; |
136 | error = gfs2_alloc_block(ip, &block, &n, 0, NULL); | 136 | error = gfs2_alloc_blocks(ip, &block, &n, 0, NULL); |
137 | if (error) | 137 | if (error) |
138 | goto out_brelse; | 138 | goto out_brelse; |
139 | if (isdir) { | 139 | if (isdir) { |
@@ -503,7 +503,7 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock, | |||
503 | do { | 503 | do { |
504 | int error; | 504 | int error; |
505 | n = blks - alloced; | 505 | n = blks - alloced; |
506 | error = gfs2_alloc_block(ip, &bn, &n, 0, NULL); | 506 | error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); |
507 | if (error) | 507 | if (error) |
508 | return error; | 508 | return error; |
509 | alloced += n; | 509 | alloced += n; |
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index ae75319b65e8..f8485da3b853 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c | |||
@@ -823,7 +823,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, | |||
823 | struct gfs2_dirent *dent; | 823 | struct gfs2_dirent *dent; |
824 | struct qstr name = { .name = "", .len = 0, .hash = 0 }; | 824 | struct qstr name = { .name = "", .len = 0, .hash = 0 }; |
825 | 825 | ||
826 | error = gfs2_alloc_block(ip, &bn, &n, 0, NULL); | 826 | error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); |
827 | if (error) | 827 | if (error) |
828 | return NULL; | 828 | return NULL; |
829 | bh = gfs2_meta_new(ip->i_gl, bn); | 829 | bh = gfs2_meta_new(ip->i_gl, bn); |
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index de2668f5c974..3ab192bac7d3 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -389,6 +389,7 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) | |||
389 | { | 389 | { |
390 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 390 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
391 | int error; | 391 | int error; |
392 | int dblocks = 0; | ||
392 | 393 | ||
393 | if (gfs2_alloc_get(dip) == NULL) | 394 | if (gfs2_alloc_get(dip) == NULL) |
394 | return -ENOMEM; | 395 | return -ENOMEM; |
@@ -402,7 +403,7 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) | |||
402 | if (error) | 403 | if (error) |
403 | goto out_ipreserv; | 404 | goto out_ipreserv; |
404 | 405 | ||
405 | error = gfs2_alloc_block(dip, no_addr, NULL, 1, generation); | 406 | error = gfs2_alloc_blocks(dip, no_addr, &dblocks, 1, generation); |
406 | 407 | ||
407 | gfs2_trans_end(sdp); | 408 | gfs2_trans_end(sdp); |
408 | 409 | ||
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 855597abc5e7..b8935afab20b 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -65,8 +65,8 @@ 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, unsigned char new_state, | 68 | unsigned char old_state, bool dinode, |
69 | unsigned int *n); | 69 | unsigned int *ndata); |
70 | 70 | ||
71 | /** | 71 | /** |
72 | * gfs2_setbit - Set a bit in the bitmaps | 72 | * gfs2_setbit - Set a bit in the bitmaps |
@@ -921,8 +921,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip | |||
921 | while (goal < rgd->rd_data) { | 921 | while (goal < rgd->rd_data) { |
922 | down_write(&sdp->sd_log_flush_lock); | 922 | down_write(&sdp->sd_log_flush_lock); |
923 | n = 1; | 923 | n = 1; |
924 | block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, | 924 | block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, 0, &n); |
925 | GFS2_BLKST_UNLINKED, &n); | ||
926 | up_write(&sdp->sd_log_flush_lock); | 925 | up_write(&sdp->sd_log_flush_lock); |
927 | if (block == BFITNOENT) | 926 | if (block == BFITNOENT) |
928 | break; | 927 | break; |
@@ -1115,7 +1114,7 @@ static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) | |||
1115 | * @rgd: the resource group descriptor | 1114 | * @rgd: the resource group descriptor |
1116 | * @goal: the goal block within the RG (start here to search for avail block) | 1115 | * @goal: the goal block within the RG (start here to search for avail block) |
1117 | * @old_state: GFS2_BLKST_XXX the before-allocation state to find | 1116 | * @old_state: GFS2_BLKST_XXX the before-allocation state to find |
1118 | * @new_state: GFS2_BLKST_XXX the after-allocation block state | 1117 | * @dinode: TRUE if the first block we allocate is for a dinode |
1119 | * @n: The extent length | 1118 | * @n: The extent length |
1120 | * | 1119 | * |
1121 | * Walk rgrp's bitmap to find bits that represent a block in @old_state. | 1120 | * Walk rgrp's bitmap to find bits that represent a block in @old_state. |
@@ -1132,8 +1131,7 @@ static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) | |||
1132 | */ | 1131 | */ |
1133 | 1132 | ||
1134 | static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, | 1133 | static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, |
1135 | unsigned char old_state, unsigned char new_state, | 1134 | unsigned char old_state, bool dinode, unsigned int *n) |
1136 | unsigned int *n) | ||
1137 | { | 1135 | { |
1138 | struct gfs2_bitmap *bi = NULL; | 1136 | struct gfs2_bitmap *bi = NULL; |
1139 | const u32 length = rgd->rd_length; | 1137 | const u32 length = rgd->rd_length; |
@@ -1192,13 +1190,14 @@ skip: | |||
1192 | if (blk == BFITNOENT) | 1190 | if (blk == BFITNOENT) |
1193 | return blk; | 1191 | return blk; |
1194 | 1192 | ||
1195 | *n = 1; | 1193 | if (old_state == GFS2_BLKST_UNLINKED) |
1196 | if (old_state == new_state) | ||
1197 | goto out; | 1194 | goto out; |
1198 | 1195 | ||
1199 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); | 1196 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); |
1200 | gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, | 1197 | gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, |
1201 | bi, blk, new_state); | 1198 | bi, blk, dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED); |
1199 | if (!dinode) | ||
1200 | (*n)++; | ||
1202 | goal = blk; | 1201 | goal = blk; |
1203 | while (*n < elen) { | 1202 | while (*n < elen) { |
1204 | goal++; | 1203 | goal++; |
@@ -1208,7 +1207,7 @@ skip: | |||
1208 | GFS2_BLKST_FREE) | 1207 | GFS2_BLKST_FREE) |
1209 | break; | 1208 | break; |
1210 | gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, | 1209 | gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, |
1211 | bi, goal, new_state); | 1210 | bi, goal, GFS2_BLKST_USED); |
1212 | (*n)++; | 1211 | (*n)++; |
1213 | } | 1212 | } |
1214 | out: | 1213 | out: |
@@ -1300,28 +1299,26 @@ static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd) | |||
1300 | } | 1299 | } |
1301 | 1300 | ||
1302 | /** | 1301 | /** |
1303 | * gfs2_alloc_block - Allocate one or more blocks | 1302 | * gfs2_alloc_blocks - Allocate one or more blocks of data and/or a dinode |
1304 | * @ip: the inode to allocate the block for | 1303 | * @ip: the inode to allocate the block for |
1305 | * @bn: Used to return the starting block number | 1304 | * @bn: Used to return the starting block number |
1306 | * @n: requested number of blocks/extent length (value/result) | 1305 | * @ndata: requested number of data blocks/extent length (value/result) |
1307 | * dinode: 1 if we're allocating a dinode, 0 if it's a data block | 1306 | * @dinode: 1 if we're allocating a dinode block, else 0 |
1308 | * @generation: the generation number of the inode | 1307 | * @generation: the generation number of the inode |
1309 | * | 1308 | * |
1310 | * Returns: 0 or error | 1309 | * Returns: 0 or error |
1311 | */ | 1310 | */ |
1312 | 1311 | ||
1313 | int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n, | 1312 | int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *ndata, |
1314 | int dinode, u64 *generation) | 1313 | bool dinode, u64 *generation) |
1315 | { | 1314 | { |
1316 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1315 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1317 | struct buffer_head *dibh; | 1316 | struct buffer_head *dibh; |
1318 | struct gfs2_alloc *al = ip->i_alloc; | 1317 | struct gfs2_alloc *al = ip->i_alloc; |
1319 | struct gfs2_rgrpd *rgd; | 1318 | struct gfs2_rgrpd *rgd; |
1320 | u32 goal, blk; /* block, within the rgrp scope */ | 1319 | u32 goal, extlen, blk; /* block, within the rgrp scope */ |
1321 | u64 block; /* block, within the file system scope */ | 1320 | u64 block; /* block, within the file system scope */ |
1322 | unsigned int extn = 1; | ||
1323 | int error; | 1321 | int error; |
1324 | unsigned char blk_type = dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED; | ||
1325 | 1322 | ||
1326 | /* Only happens if there is a bug in gfs2, return something distinctive | 1323 | /* Only happens if there is a bug in gfs2, return something distinctive |
1327 | * to ensure that it is noticed. | 1324 | * to ensure that it is noticed. |
@@ -1329,8 +1326,6 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n, | |||
1329 | if (al == NULL) | 1326 | if (al == NULL) |
1330 | return -ECANCELED; | 1327 | return -ECANCELED; |
1331 | 1328 | ||
1332 | if (n == NULL) | ||
1333 | n = &extn; | ||
1334 | rgd = ip->i_rgd; | 1329 | rgd = ip->i_rgd; |
1335 | 1330 | ||
1336 | if (!dinode && rgrp_contains_block(rgd, ip->i_goal)) | 1331 | if (!dinode && rgrp_contains_block(rgd, ip->i_goal)) |
@@ -1338,7 +1333,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n, | |||
1338 | else | 1333 | else |
1339 | goal = rgd->rd_last_alloc; | 1334 | goal = rgd->rd_last_alloc; |
1340 | 1335 | ||
1341 | blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, blk_type, n); | 1336 | blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, dinode, ndata); |
1342 | 1337 | ||
1343 | /* Since all blocks are reserved in advance, this shouldn't happen */ | 1338 | /* Since all blocks are reserved in advance, this shouldn't happen */ |
1344 | if (blk == BFITNOENT) | 1339 | if (blk == BFITNOENT) |
@@ -1347,7 +1342,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n, | |||
1347 | rgd->rd_last_alloc = blk; | 1342 | rgd->rd_last_alloc = blk; |
1348 | block = rgd->rd_data0 + blk; | 1343 | block = rgd->rd_data0 + blk; |
1349 | if (!dinode) { | 1344 | if (!dinode) { |
1350 | ip->i_goal = block + *n - 1; | 1345 | ip->i_goal = block + *ndata - 1; |
1351 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1346 | error = gfs2_meta_inode_buffer(ip, &dibh); |
1352 | if (error == 0) { | 1347 | if (error == 0) { |
1353 | struct gfs2_dinode *di = | 1348 | struct gfs2_dinode *di = |
@@ -1358,10 +1353,13 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n, | |||
1358 | brelse(dibh); | 1353 | brelse(dibh); |
1359 | } | 1354 | } |
1360 | } | 1355 | } |
1361 | if (rgd->rd_free < *n) | 1356 | extlen = *ndata; |
1357 | if (dinode) | ||
1358 | extlen++; | ||
1359 | if (rgd->rd_free < extlen) | ||
1362 | goto rgrp_error; | 1360 | goto rgrp_error; |
1363 | 1361 | ||
1364 | rgd->rd_free -= *n; | 1362 | rgd->rd_free -= extlen; |
1365 | if (dinode) { | 1363 | if (dinode) { |
1366 | rgd->rd_dinodes++; | 1364 | rgd->rd_dinodes++; |
1367 | *generation = rgd->rd_igeneration++; | 1365 | *generation = rgd->rd_igeneration++; |
@@ -1372,15 +1370,16 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n, | |||
1372 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); | 1370 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); |
1373 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); | 1371 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); |
1374 | 1372 | ||
1375 | gfs2_statfs_change(sdp, 0, -(s64)*n, dinode ? 1 : 0); | 1373 | gfs2_statfs_change(sdp, 0, -(s64)extlen, dinode ? 1 : 0); |
1376 | if (dinode) | 1374 | if (dinode) |
1377 | gfs2_trans_add_unrevoke(sdp, block, 1); | 1375 | gfs2_trans_add_unrevoke(sdp, block, 1); |
1378 | else | 1376 | if (*ndata) |
1379 | gfs2_quota_change(ip, *n, ip->i_inode.i_uid, | 1377 | gfs2_quota_change(ip, *ndata, ip->i_inode.i_uid, |
1380 | ip->i_inode.i_gid); | 1378 | ip->i_inode.i_gid); |
1381 | 1379 | ||
1382 | rgd->rd_free_clone -= *n; | 1380 | rgd->rd_free_clone -= extlen; |
1383 | trace_gfs2_block_alloc(ip, block, *n, blk_type); | 1381 | trace_gfs2_block_alloc(ip, block, *ndata, |
1382 | dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED); | ||
1384 | *bn = block; | 1383 | *bn = block; |
1385 | return 0; | 1384 | return 0; |
1386 | 1385 | ||
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 4cb560813973..b3b61b8f6d8f 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h | |||
@@ -39,8 +39,8 @@ static inline void gfs2_alloc_put(struct gfs2_inode *ip) | |||
39 | extern int gfs2_inplace_reserve(struct gfs2_inode *ip); | 39 | extern int gfs2_inplace_reserve(struct gfs2_inode *ip); |
40 | extern void gfs2_inplace_release(struct gfs2_inode *ip); | 40 | extern void gfs2_inplace_release(struct gfs2_inode *ip); |
41 | 41 | ||
42 | extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n, | 42 | extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, |
43 | int dinode, u64 *generation); | 43 | bool dinode, u64 *generation); |
44 | 44 | ||
45 | extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta); | 45 | extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta); |
46 | extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); | 46 | extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); |
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index e4794a5b0a16..ef74e1591b89 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c | |||
@@ -610,7 +610,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) | |||
610 | u64 block; | 610 | u64 block; |
611 | int error; | 611 | int error; |
612 | 612 | ||
613 | error = gfs2_alloc_block(ip, &block, &n, 0, NULL); | 613 | error = gfs2_alloc_blocks(ip, &block, &n, 0, NULL); |
614 | if (error) | 614 | if (error) |
615 | return error; | 615 | return error; |
616 | gfs2_trans_add_unrevoke(sdp, block, 1); | 616 | gfs2_trans_add_unrevoke(sdp, block, 1); |
@@ -672,7 +672,7 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, | |||
672 | int mh_size = sizeof(struct gfs2_meta_header); | 672 | int mh_size = sizeof(struct gfs2_meta_header); |
673 | unsigned int n = 1; | 673 | unsigned int n = 1; |
674 | 674 | ||
675 | error = gfs2_alloc_block(ip, &block, &n, 0, NULL); | 675 | error = gfs2_alloc_blocks(ip, &block, &n, 0, NULL); |
676 | if (error) | 676 | if (error) |
677 | return error; | 677 | return error; |
678 | gfs2_trans_add_unrevoke(sdp, block, 1); | 678 | gfs2_trans_add_unrevoke(sdp, block, 1); |
@@ -992,7 +992,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
992 | } else { | 992 | } else { |
993 | u64 blk; | 993 | u64 blk; |
994 | unsigned int n = 1; | 994 | unsigned int n = 1; |
995 | error = gfs2_alloc_block(ip, &blk, &n, 0, NULL); | 995 | error = gfs2_alloc_blocks(ip, &blk, &n, 0, NULL); |
996 | if (error) | 996 | if (error) |
997 | return error; | 997 | return error; |
998 | gfs2_trans_add_unrevoke(sdp, blk, 1); | 998 | gfs2_trans_add_unrevoke(sdp, blk, 1); |