gfs2-utils: master - libgfs2: Add functions for finding free extents
Andrew Price
andyp at fedoraproject.org
Fri Sep 5 13:39:26 UTC 2014
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=5cc5a173c606a85cb8d07b6d28d112b05caeb2f6
Commit: 5cc5a173c606a85cb8d07b6d28d112b05caeb2f6
Parent: ecdbf2b46fecfce5d21f654d8b9d414811ff0bac
Author: Andrew Price <anprice at redhat.com>
AuthorDate: Fri Jun 20 23:07:47 2014 +0100
Committer: Andrew Price <anprice at redhat.com>
CommitterDate: Mon Sep 1 11:28:52 2014 +0100
libgfs2: Add functions for finding free extents
Port gfs2_rbm_find and some functions which it depends on from the gfs2
kernel code. This will set the base for allocation of single-extent
files. The functions have been simplified where possible as libgfs2
doesn't have a concept of reservations for the time being.
Signed-off-by: Andrew Price <anprice at redhat.com>
---
gfs2/libgfs2/rgrp.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++
gfs2/libgfs2/rgrp.h | 2 +
2 files changed, 199 insertions(+), 0 deletions(-)
diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c
index 0f36b86..7063288 100644
--- a/gfs2/libgfs2/rgrp.c
+++ b/gfs2/libgfs2/rgrp.c
@@ -638,3 +638,200 @@ static int lgfs2_rbm_incr(struct lgfs2_rbm *rbm)
rbm->bii++;
return 0;
}
+
+/**
+ * lgfs2_testbit - test a bit in the bitmaps
+ * @rbm: The bit to test
+ *
+ * Returns: The two bit block state of the requested bit
+ */
+static inline uint8_t lgfs2_testbit(const struct lgfs2_rbm *rbm)
+{
+ struct gfs2_bitmap *bi = rbm_bi(rbm);
+ const uint8_t *buffer = (uint8_t *)bi->bi_bh->b_data + bi->bi_offset;
+ const uint8_t *byte;
+ unsigned int bit;
+
+ byte = buffer + (rbm->offset / GFS2_NBBY);
+ bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE;
+
+ return (*byte >> bit) & GFS2_BIT_MASK;
+}
+
+/**
+ * lgfs2_unaligned_extlen - Look for free blocks which are not byte aligned
+ * @rbm: Position to search (value/result)
+ * @n_unaligned: Number of unaligned blocks to check
+ * @len: Decremented for each block found (terminate on zero)
+ *
+ * Returns: true if a non-free block is encountered
+ */
+static int lgfs2_unaligned_extlen(struct lgfs2_rbm *rbm, uint32_t n_unaligned, uint32_t *len)
+{
+ uint32_t n;
+ uint8_t res;
+
+ for (n = 0; n < n_unaligned; n++) {
+ res = lgfs2_testbit(rbm);
+ if (res != GFS2_BLKST_FREE)
+ return 1;
+ (*len)--;
+ if (*len == 0)
+ return 1;
+ if (lgfs2_rbm_incr(rbm))
+ return 1;
+ }
+
+ return 0;
+}
+
+static uint8_t *check_bytes8(const uint8_t *start, uint8_t value, unsigned bytes)
+{
+ while (bytes) {
+ if (*start != value)
+ return (void *)start;
+ start++;
+ bytes--;
+ }
+ return NULL;
+}
+
+/**
+ * lgfs2_free_extlen - Return extent length of free blocks
+ * @rbm: Starting position
+ * @len: Max length to check
+ *
+ * Starting at the block specified by the rbm, see how many free blocks
+ * there are, not reading more than len blocks ahead. This can be done
+ * using check_bytes8 when the blocks are byte aligned, but has to be done
+ * on a block by block basis in case of unaligned blocks. Also this
+ * function can cope with bitmap boundaries (although it must stop on
+ * a resource group boundary)
+ *
+ * Returns: Number of free blocks in the extent
+ */
+static uint32_t lgfs2_free_extlen(const struct lgfs2_rbm *rrbm, uint32_t len)
+{
+ struct lgfs2_rbm rbm = *rrbm;
+ uint32_t n_unaligned = rbm.offset & 3;
+ uint32_t size = len;
+ uint32_t bytes;
+ uint32_t chunk_size;
+ uint8_t *ptr, *start, *end;
+ uint64_t block;
+ struct gfs2_bitmap *bi;
+
+ if (n_unaligned &&
+ lgfs2_unaligned_extlen(&rbm, 4 - n_unaligned, &len))
+ goto out;
+
+ n_unaligned = len & 3;
+ /* Start is now byte aligned */
+ while (len > 3) {
+ bi = rbm_bi(&rbm);
+ start = (uint8_t *)bi->bi_bh->b_data;
+ end = start + bi->bi_bh->sdp->bsize;
+ start += bi->bi_offset;
+ start += (rbm.offset / GFS2_NBBY);
+ bytes = (len / GFS2_NBBY) < (end - start) ? (len / GFS2_NBBY):(end - start);
+ ptr = check_bytes8(start, 0, bytes);
+ chunk_size = ((ptr == NULL) ? bytes : (ptr - start));
+ chunk_size *= GFS2_NBBY;
+ len -= chunk_size;
+ block = lgfs2_rbm_to_block(&rbm);
+ if (lgfs2_rbm_from_block(&rbm, block + chunk_size)) {
+ n_unaligned = 0;
+ break;
+ }
+ if (ptr) {
+ n_unaligned = 3;
+ break;
+ }
+ n_unaligned = len & 3;
+ }
+
+ /* Deal with any bits left over at the end */
+ if (n_unaligned)
+ lgfs2_unaligned_extlen(&rbm, n_unaligned, &len);
+out:
+ return size - len;
+}
+
+/**
+ * gfs2_rbm_find - Look for blocks of a particular state
+ * @rbm: Value/result starting position and final position
+ * @state: The state which we want to find
+ * @minext: Pointer to the requested extent length (NULL for a single block)
+ * This is updated to be the actual reservation size.
+ *
+ * Returns: 0 on success, non-zero with errno == ENOSPC if there is no block of the requested state
+ */
+int lgfs2_rbm_find(struct lgfs2_rbm *rbm, uint8_t state, uint32_t *minext)
+{
+ int initial_bii;
+ uint32_t offset;
+ int n = 0;
+ int iters = rbm->rgd->ri.ri_length;
+ uint32_t extlen;
+
+ /* If we are not starting at the beginning of a bitmap, then we
+ * need to add one to the bitmap count to ensure that we search
+ * the starting bitmap twice.
+ */
+ if (rbm->offset != 0)
+ iters++;
+
+ for (n = 0; n < iters; n++) {
+ struct gfs2_bitmap *bi = rbm_bi(rbm);
+ struct gfs2_buffer_head *bh = bi->bi_bh;
+ uint8_t *buf = (uint8_t *)bh->b_data + bi->bi_offset;
+ uint64_t block;
+ int ret;
+
+ if ((rbm->rgd->rg.rg_free < *minext) && (state == GFS2_BLKST_FREE))
+ goto next_bitmap;
+
+ offset = gfs2_bitfit(buf, bi->bi_len, rbm->offset, state);
+ if (offset == BFITNOENT)
+ goto next_bitmap;
+
+ rbm->offset = offset;
+ initial_bii = rbm->bii;
+ block = lgfs2_rbm_to_block(rbm);
+ extlen = 1;
+
+ if (*minext != 0)
+ extlen = lgfs2_free_extlen(rbm, *minext);
+
+ if (extlen >= *minext)
+ return 0;
+
+ ret = lgfs2_rbm_from_block(rbm, block + extlen);
+ if (ret == 0) {
+ n += (rbm->bii - initial_bii);
+ continue;
+ }
+
+ if (errno == E2BIG) {
+ rbm->bii = 0;
+ rbm->offset = 0;
+ n += (rbm->bii - initial_bii);
+ goto res_covered_end_of_rgrp;
+ }
+
+ return ret;
+
+next_bitmap: /* Find next bitmap in the rgrp */
+ rbm->offset = 0;
+ rbm->bii++;
+ if (rbm->bii == rbm->rgd->ri.ri_length)
+ rbm->bii = 0;
+
+res_covered_end_of_rgrp:
+ if (rbm->bii == 0)
+ break;
+ }
+
+ errno = ENOSPC;
+ return 1;
+}
diff --git a/gfs2/libgfs2/rgrp.h b/gfs2/libgfs2/rgrp.h
index 384231e..1634fbc 100644
--- a/gfs2/libgfs2/rgrp.h
+++ b/gfs2/libgfs2/rgrp.h
@@ -44,4 +44,6 @@ static inline int lgfs2_rbm_eq(const struct lgfs2_rbm *rbm1, const struct lgfs2_
(rbm1->offset == rbm2->offset);
}
+extern int lgfs2_rbm_find(struct lgfs2_rbm *rbm, uint8_t state, uint32_t *minext);
+
#endif /* __RGRP_DOT_H__ */
More information about the cluster-commits
mailing list