Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=915fb43e43c... Commit: 915fb43e43cc1e3d8f8ba2c7295a0aaa10368882 Parent: 761a035c6ec0ad2b33676da63c2799b10f276a2f Author: Andrew Price anprice@redhat.com AuthorDate: Thu Feb 21 15:51:02 2013 +0000 Committer: Andrew Price anprice@redhat.com CommitterDate: Fri Feb 22 15:16:40 2013 +0000
libgfs2: Rework blk_alloc_i
blk_alloc_i previously chose any resource group with a free block and assumed that the bitmaps were already available in the rgrp_tree. This patch allows us to allocate blocks in a resource group with a given number of free blocks in order to plan ahead and reads in the bitmap data on demand. It also removes some exit()s from blk_alloc_i.
Signed-off-by: Andrew Price anprice@redhat.com --- gfs2/libgfs2/fs_ops.c | 79 ++++++++++++++++++++++++++++++++++++----------- gfs2/libgfs2/libgfs2.h | 1 + 2 files changed, 61 insertions(+), 19 deletions(-)
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c index 3d027e8..b6c268d 100644 --- a/gfs2/libgfs2/fs_ops.c +++ b/gfs2/libgfs2/fs_ops.c @@ -116,32 +116,24 @@ void inode_put(struct gfs2_inode **ip_in) *ip_in = NULL; /* make sure the memory isn't accessed again */ }
-static uint64_t blk_alloc_i(struct gfs2_sbd *sdp, unsigned int type) +static int blk_alloc_in_rg(struct gfs2_sbd *sdp, unsigned int type, struct rgrp_tree *rl, uint64_t *blkno) { - struct osi_node *n, *next = NULL; - struct rgrp_tree *rl = NULL; struct gfs2_rindex *ri; struct gfs2_rgrp *rg; unsigned int block, bn = 0, x = 0, y = 0; unsigned int state; struct gfs2_buffer_head *bh;
- memset(&rg, 0, sizeof(rg)); - for (n = osi_first(&sdp->rgtree); n; n = next) { - next = osi_next(n); - rl = (struct rgrp_tree *)n; - if (rl->rg.rg_free) - break; + if (rl == NULL || rl->rg.rg_free == 0) { + errno = ENOSPC; + return -1; }
- if (n == NULL) { - fprintf(stderr, "Not enough space available on device\n"); - exit(1); - } + if (rl->bh[0] == NULL && gfs2_rgrp_read(sdp, rl) != 0) + return -1;
ri = &rl->ri; rg = &rl->rg; - for (block = 0; block < ri->ri_length; block++) { bh = rl->bh[block]; x = (block) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_rgrp); @@ -157,7 +149,7 @@ static uint64_t blk_alloc_i(struct gfs2_sbd *sdp, unsigned int type)
fprintf(stderr, "allocation is broken (1): %"PRIu64" %u\n", (uint64_t)rl->ri.ri_addr, rl->rg.rg_free); - exit(1); + return -1;
found: if (bn >= ri->ri_bitbytes * GFS2_NBBY) { @@ -165,7 +157,7 @@ found: " (0x%" PRIx64 ") Free:%u\n", bn, ri->ri_bitbytes * GFS2_NBBY, (uint64_t)rl->ri.ri_addr, (uint64_t)rl->ri.ri_addr, rl->rg.rg_free); - exit(1); + return -1; }
switch (type) { @@ -179,7 +171,7 @@ found: break; default: fprintf(stderr, "bad state\n"); - exit(1); + return -1; }
bh->b_data[x] &= ~(0x03 << (GFS2_BIT_SIZE * y)); @@ -193,7 +185,27 @@ found: gfs2_rgrp_out(rg, rl->bh[0]);
sdp->blks_alloced++; - return ri->ri_data0 + bn; + *blkno = ri->ri_data0 + bn; + return 0; +} + +/** + * Do not use this function, it's only here until we can kill it. + * Use blk_alloc_in_rg directly instead. + */ +static uint64_t blk_alloc_i(struct gfs2_sbd *sdp, unsigned int type) +{ + int ret; + uint64_t blkno = 0; + struct osi_node *n = NULL; + for (n = osi_first(&sdp->rgtree); n; n = osi_next(n)) { + if (((struct rgrp_tree *)n)->rg.rg_free) + break; + } + ret = blk_alloc_in_rg(sdp, type, (struct rgrp_tree *)n, &blkno); + if (ret != 0) /* Do what the old blk_alloc_i did */ + exit(1); + return blkno; }
uint64_t data_alloc(struct gfs2_inode *ip) @@ -220,6 +232,33 @@ uint64_t dinode_alloc(struct gfs2_sbd *sdp) return blk_alloc_i(sdp, DINODE); }
+/** + * Allocate a dinode block in a bitmap. In order to plan ahead we look for a + * resource group with blksreq free blocks but only allocate the one dinode block. + * Returns 0 on success with the allocated block number in *blkno or non-zero otherwise. + */ +int lgfs2_dinode_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, uint64_t *blkno) +{ + int ret; + struct rgrp_tree *rgt; + struct osi_node *n = NULL; + for (n = osi_first(&sdp->rgtree); n; n = osi_next(n)) { + rgt = (struct rgrp_tree *)n; + if (rgt->rg.rg_free >= blksreq) + break; + } + if (rgt == NULL) + return -1; + + ret = blk_alloc_in_rg(sdp, DINODE, rgt, blkno); + gfs2_rgrp_relse(rgt); + + if (ret == 0) + sdp->dinodes_alloced++; + + return ret; +} + static __inline__ void buffer_clear_tail(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh, int head) { @@ -1380,7 +1419,9 @@ static struct gfs2_inode *__createi(struct gfs2_inode *dip,
gfs2_lookupi(dip, filename, strlen(filename), &ip); if (!ip) { - bn = dinode_alloc(sdp); + err = lgfs2_dinode_alloc(sdp, 1, &bn); + if (err != 0) + return NULL;
if (if_gfs1) inum.no_formal_ino = bn; diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h index db31a6c..c415745 100644 --- a/gfs2/libgfs2/libgfs2.h +++ b/gfs2/libgfs2/libgfs2.h @@ -440,6 +440,7 @@ extern void inode_put(struct gfs2_inode **ip); extern uint64_t data_alloc(struct gfs2_inode *ip); extern uint64_t meta_alloc(struct gfs2_inode *ip); extern uint64_t dinode_alloc(struct gfs2_sbd *sdp); +extern int lgfs2_dinode_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, uint64_t *blkno); extern int gfs2_readi(struct gfs2_inode *ip, void *buf, uint64_t offset, unsigned int size); #define gfs2_writei(ip, buf, offset, size) \
cluster-commits@lists.fedorahosted.org