Rather than having to allocate a single block at a time, this patch
allows the block allocator to allocate an extent. Since there is
no difference (so far as the block allocator is concerned) between
data blocks and indirect blocks, it is posible to allocate a single
extent and for the caller to unrevoke just the blocks required
for indirect blocks.
Currently the only bit of GFS2 to make use of this feature is the
build height function. The intention is that gfs2_block_map will
be changed to make use of this feature in future patches.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
/* Get a free block, fill it with the stuffed data,
and write it out to disk */
/* Get a free block, fill it with the stuffed data,
and write it out to disk */
+ unsigned int n = 1;
+ block = gfs2_alloc_block(ip, &n);
- block = gfs2_alloc_block(ip);
gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), block, 1);
error = gfs2_dir_get_new_buffer(ip, block, &bh);
if (error)
gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), block, 1);
error = gfs2_dir_get_new_buffer(ip, block, &bh);
if (error)
dibh, sizeof(struct gfs2_dinode));
brelse(bh);
} else {
dibh, sizeof(struct gfs2_dinode));
brelse(bh);
} else {
- block = gfs2_alloc_block(ip);
-
error = gfs2_unstuffer_page(ip, dibh, block, page);
if (error)
goto out_brelse;
error = gfs2_unstuffer_page(ip, dibh, block, page);
if (error)
goto out_brelse;
int error;
__be64 *bp;
u64 bn;
int error;
__be64 *bp;
u64 bn;
if (height <= ip->i_height)
return 0;
if (height <= ip->i_height)
return 0;
- for(n = 0; n < new_height; n++) {
- bn = gfs2_alloc_block(ip);
- gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1);
- mp->mp_bh[n] = gfs2_meta_new(ip->i_gl, bn);
- gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[n], 1);
- }
+ do {
+ n = new_height - i;
+ bn = gfs2_alloc_block(ip, &n);
+ gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, n);
+ do {
+ mp->mp_bh[i] = gfs2_meta_new(ip->i_gl, bn++);
+ gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[i], 1);
+ i++;
+ } while(i < n);
+ } while(i < new_height);
n = 0;
bn = mp->mp_bh[0]->b_blocknr;
n = 0;
bn = mp->mp_bh[0]->b_blocknr;
{
int boundary;
__be64 *ptr = metapointer(&boundary, height, mp);
{
int boundary;
__be64 *ptr = metapointer(&boundary, height, mp);
if (*ptr) {
*block = be64_to_cpu(*ptr);
if (*ptr) {
*block = be64_to_cpu(*ptr);
- *block = gfs2_alloc_block(ip);
+ *block = gfs2_alloc_block(ip, &n);
if (height != ip->i_height - 1 || gfs2_is_dir(ip))
gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), *block, 1);
if (height != ip->i_height - 1 || gfs2_is_dir(ip))
gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), *block, 1);
static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth)
{
struct gfs2_inode *ip = GFS2_I(inode);
static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth)
{
struct gfs2_inode *ip = GFS2_I(inode);
- u64 bn = gfs2_alloc_block(ip);
+ unsigned int n = 1;
+ u64 bn = gfs2_alloc_block(ip, &n);
struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn);
struct gfs2_leaf *leaf;
struct gfs2_dirent *dent;
struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn);
struct gfs2_leaf *leaf;
struct gfs2_dirent *dent;
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_ea_header *ea;
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_ea_header *ea;
- block = gfs2_alloc_block(ip);
+ block = gfs2_alloc_block(ip, &n);
gfs2_trans_add_unrevoke(sdp, block, 1);
*bhp = gfs2_meta_new(ip->i_gl, block);
gfs2_trans_add_bh(ip->i_gl, *bhp, 1);
gfs2_trans_add_unrevoke(sdp, block, 1);
*bhp = gfs2_meta_new(ip->i_gl, block);
gfs2_trans_add_bh(ip->i_gl, *bhp, 1);
struct buffer_head *bh;
u64 block;
int mh_size = sizeof(struct gfs2_meta_header);
struct buffer_head *bh;
u64 block;
int mh_size = sizeof(struct gfs2_meta_header);
- block = gfs2_alloc_block(ip);
+ block = gfs2_alloc_block(ip, &n);
gfs2_trans_add_unrevoke(sdp, block, 1);
bh = gfs2_meta_new(ip->i_gl, block);
gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_trans_add_unrevoke(sdp, block, 1);
bh = gfs2_meta_new(ip->i_gl, block);
gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_trans_add_bh(ip->i_gl, indbh, 1);
} else {
u64 blk;
gfs2_trans_add_bh(ip->i_gl, indbh, 1);
} else {
u64 blk;
-
- blk = gfs2_alloc_block(ip);
+ unsigned int n = 1;
+ blk = gfs2_alloc_block(ip, &n);
gfs2_trans_add_unrevoke(sdp, blk, 1);
indbh = gfs2_meta_new(ip->i_gl, blk);
gfs2_trans_add_bh(ip->i_gl, indbh, 1);
gfs2_trans_add_unrevoke(sdp, blk, 1);
indbh = gfs2_meta_new(ip->i_gl, blk);
gfs2_trans_add_bh(ip->i_gl, indbh, 1);
};
static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
};
static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
- unsigned char old_state, unsigned char new_state);
+ unsigned char old_state, unsigned char new_state,
+ unsigned int *n);
/**
* gfs2_setbit - Set a bit in the bitmaps
/**
* gfs2_setbit - Set a bit in the bitmaps
-static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
- unsigned int buflen, u32 block,
- unsigned char new_state)
+static inline void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buf1,
+ unsigned char *buf2, unsigned int offset,
+ unsigned int buflen, u32 block,
+ unsigned char new_state)
- unsigned char *byte, *end, cur_state;
- unsigned int bit;
+ unsigned char *byte1, *byte2, *end, cur_state;
+ const unsigned int bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
- byte = buffer + (block / GFS2_NBBY);
- bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
- end = buffer + buflen;
+ byte1 = buf1 + offset + (block / GFS2_NBBY);
+ end = buf1 + offset + buflen;
- gfs2_assert(rgd->rd_sbd, byte < end);
- cur_state = (*byte >> bit) & GFS2_BIT_MASK;
+ cur_state = (*byte1 >> bit) & GFS2_BIT_MASK;
- if (valid_change[new_state * 4 + cur_state]) {
- *byte ^= cur_state << bit;
- *byte |= new_state << bit;
- } else
+ if (unlikely(!valid_change[new_state * 4 + cur_state])) {
+ return;
+ }
+ *byte1 ^= (cur_state ^ new_state) << bit;
+
+ if (buf2) {
+ byte2 = buf2 + offset + (block / GFS2_NBBY);
+ cur_state = (*byte2 >> bit) & GFS2_BIT_MASK;
+ *byte2 ^= (cur_state ^ new_state) << bit;
+ }
-static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
- unsigned int buflen, u32 block)
+static inline unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd,
+ const unsigned char *buffer,
+ unsigned int buflen, u32 block)
- unsigned char *byte, *end, cur_state;
+ const unsigned char *byte, *end;
+ unsigned char cur_state;
unsigned int bit;
byte = buffer + (block / GFS2_NBBY);
unsigned int bit;
byte = buffer + (block / GFS2_NBBY);
u32 goal = 0, block;
u64 no_addr;
struct gfs2_sbd *sdp = rgd->rd_sbd;
u32 goal = 0, block;
u64 no_addr;
struct gfs2_sbd *sdp = rgd->rd_sbd;
for(;;) {
if (goal >= rgd->rd_data)
break;
down_write(&sdp->sd_log_flush_lock);
for(;;) {
if (goal >= rgd->rd_data)
break;
down_write(&sdp->sd_log_flush_lock);
block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
+ GFS2_BLKST_UNLINKED, &n);
up_write(&sdp->sd_log_flush_lock);
if (block == BFITNOENT)
break;
up_write(&sdp->sd_log_flush_lock);
if (block == BFITNOENT)
break;
* @goal: the goal block within the RG (start here to search for avail block)
* @old_state: GFS2_BLKST_XXX the before-allocation state to find
* @new_state: GFS2_BLKST_XXX the after-allocation block state
* @goal: the goal block within the RG (start here to search for avail block)
* @old_state: GFS2_BLKST_XXX the before-allocation state to find
* @new_state: GFS2_BLKST_XXX the after-allocation block state
+ * @n: The extent length
*
* Walk rgrp's bitmap to find bits that represent a block in @old_state.
* Add the found bitmap buffer to the transaction.
*
* Walk rgrp's bitmap to find bits that represent a block in @old_state.
* Add the found bitmap buffer to the transaction.
*/
static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
*/
static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
- unsigned char old_state, unsigned char new_state)
+ unsigned char old_state, unsigned char new_state,
+ unsigned int *n)
{
struct gfs2_bitmap *bi = NULL;
{
struct gfs2_bitmap *bi = NULL;
- u32 length = rgd->rd_length;
+ const u32 length = rgd->rd_length;
u32 blk = 0;
unsigned int buf, x;
u32 blk = 0;
unsigned int buf, x;
+ const unsigned int elen = *n;
+ const u8 *buffer;
/* Find bitmap block that contains bits for goal block */
for (buf = 0; buf < length; buf++) {
bi = rgd->rd_bits + buf;
/* Find bitmap block that contains bits for goal block */
for (buf = 0; buf < length; buf++) {
bi = rgd->rd_bits + buf;
for (x = 0; x <= length; x++) {
/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
bitmaps, so we must search the originals for that. */
for (x = 0; x <= length; x++) {
/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
bitmaps, so we must search the originals for that. */
- const u8 *buffer = bi->bi_bh->b_data + bi->bi_offset;
+ buffer = bi->bi_bh->b_data + bi->bi_offset;
if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
buffer = bi->bi_clone + bi->bi_offset;
if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
buffer = bi->bi_clone + bi->bi_offset;
}
if (blk != BFITNOENT && old_state != new_state) {
}
if (blk != BFITNOENT && old_state != new_state) {
gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
- gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
+ gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset,
bi->bi_len, blk, new_state);
bi->bi_len, blk, new_state);
- if (bi->bi_clone)
- gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset,
- bi->bi_len, blk, new_state);
+ while(*n < elen) {
+ goal++;
+ if (goal >= (bi->bi_len / GFS2_NBBY))
+ break;
+ if (gfs2_testbit(rgd, buffer, bi->bi_len, goal) !=
+ GFS2_BLKST_FREE)
+ break;
+ (*n)++;
+ gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone,
+ bi->bi_offset, bi->bi_len, blk, new_state);
+ }
}
return (blk == BFITNOENT) ? blk : (bi->bi_start * GFS2_NBBY) + blk;
}
return (blk == BFITNOENT) ? blk : (bi->bi_start * GFS2_NBBY) + blk;
bi->bi_len);
}
gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
bi->bi_len);
}
gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
- gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
+ gfs2_setbit(rgd, bi->bi_bh->b_data, NULL, bi->bi_offset,
bi->bi_len, buf_blk, new_state);
}
bi->bi_len, buf_blk, new_state);
}
* Returns: the allocated block
*/
* Returns: the allocated block
*/
-u64 gfs2_alloc_block(struct gfs2_inode *ip)
+u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = ip->i_alloc;
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = ip->i_alloc;
else
goal = rgd->rd_last_alloc;
else
goal = rgd->rd_last_alloc;
- blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
+ blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED, n);
BUG_ON(blk == BFITNOENT);
BUG_ON(blk == BFITNOENT);
- rgd->rd_last_alloc = blk;
+ rgd->rd_last_alloc = blk;
block = rgd->rd_data0 + blk;
ip->i_goal = block;
block = rgd->rd_data0 + blk;
ip->i_goal = block;
- gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
- rgd->rd_rg.rg_free--;
+ gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free >= *n);
+ rgd->rd_rg.rg_free -= *n;
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
- gfs2_statfs_change(sdp, 0, -1, 0);
- gfs2_quota_change(ip, +1, ip->i_inode.i_uid, ip->i_inode.i_gid);
+ gfs2_statfs_change(sdp, 0, -*n, 0);
+ gfs2_quota_change(ip, *n, ip->i_inode.i_uid, ip->i_inode.i_gid);
spin_lock(&sdp->sd_rindex_spin);
spin_lock(&sdp->sd_rindex_spin);
+ rgd->rd_free_clone -= *n;
spin_unlock(&sdp->sd_rindex_spin);
return block;
spin_unlock(&sdp->sd_rindex_spin);
return block;
struct gfs2_rgrpd *rgd = al->al_rgd;
u32 blk;
u64 block;
struct gfs2_rgrpd *rgd = al->al_rgd;
u32 blk;
u64 block;
blk = rgblk_search(rgd, rgd->rd_last_alloc,
blk = rgblk_search(rgd, rgd->rd_last_alloc,
- GFS2_BLKST_FREE, GFS2_BLKST_DINODE);
+ GFS2_BLKST_FREE, GFS2_BLKST_DINODE, &n);
BUG_ON(blk == BFITNOENT);
rgd->rd_last_alloc = blk;
BUG_ON(blk == BFITNOENT);
rgd->rd_last_alloc = blk;
unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
-u64 gfs2_alloc_block(struct gfs2_inode *ip);
+u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n);
u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);
u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);