[Ocfs2-devel] [PATCH 2/3] ocfs2: implement discontiguous localalloc bitmap
Srinivas Eeda
srinivas.eeda at oracle.com
Mon May 7 16:21:29 PDT 2012
This patch adds supporting functions and modifies localalloc code to implement
discontiguous localalloc bitmap.
Signed-off-by: Srinivas Eeda <srinivas.eeda at oracle.com>
---
fs/ocfs2/localalloc.c | 523 ++++++++++++++++++++++++++++++++-----------------
1 files changed, 342 insertions(+), 181 deletions(-)
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index 4190e53..f63381e 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -48,6 +48,9 @@
#define OCFS2_LOCAL_ALLOC(dinode) (&((dinode)->id2.i_lab))
+/* defines minimum contiguous required */
+#define OCFS2_LOCAL_ALLOC_MIN_BITS 2
+
#define OCFS2_LOCAL_ALLOC_REC_SZ(la) (le16_to_cpu(la->la_rec_count) *\
sizeof(struct ocfs2_local_alloc_rec))
#define OCFS2_LOCAL_ALLOC_BITMAP(la) ((char *)(&(la->la_recs)) +\
@@ -58,7 +61,8 @@
#define OCFS2_MAX_LOCAL_ALLOC_REC_LIMIT 128
-static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc);
+static u32 ocfs2_local_alloc_count_bits(struct ocfs2_super *osb,
+ struct ocfs2_dinode *alloc);
static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
struct ocfs2_dinode *alloc,
@@ -82,8 +86,7 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
handle_t *handle,
struct ocfs2_alloc_context *ac);
-static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
- struct inode *local_alloc_inode);
+static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb);
/*
* ocfs2_la_default_mb() - determine a default size, in megabytes of
@@ -202,6 +205,74 @@ unsigned int ocfs2_la_default_mb(struct ocfs2_super *osb)
return la_mb;
}
+static u32 ocfs2_local_bitmap_to_cluster(struct ocfs2_local_alloc *la, u32 bit)
+{
+ u32 start, prev, offset;
+ int rec;
+
+ rec = start = prev = 0;
+ for (rec = 0; rec < le16_to_cpu(la->la_rec_count); rec++) {
+ prev = start;
+ start += le32_to_cpu(la->la_recs[rec].la_clusters);
+ if (bit < start)
+ break;
+ }
+ offset = le32_to_cpu(la->la_recs[rec].la_start) + (bit - prev);
+
+ return offset;
+}
+
+/*
+ * This function is called before allocating a new chunk for the localalloc
+ * bitmap to make sure there is enough space in the bitmap for the new record
+ */
+static u32 ocfs2_local_alloc_adjust_bits_wanted(struct ocfs2_local_alloc *la,
+ struct ocfs2_alloc_context *ac)
+{
+ u32 required, available, cluster_cnt;
+
+ if (ac->ac_bits_given == ac->ac_bits_wanted)
+ return 0;
+
+ /* total bits available in bitmap */
+ available = le16_to_cpu(la->la_size) << 3;
+ cluster_cnt = ocfs2_local_alloc_cluster_count(la);
+
+ /*
+ * Wanted shouldn't be greater than bitmap size and given should be
+ * equal to cluster count
+ */
+ BUG_ON(ac->ac_bits_given > ac->ac_bits_wanted);
+ BUG_ON(ac->ac_bits_wanted > available);
+ BUG_ON(ac->ac_bits_given != cluster_cnt);
+
+ /* reduce bits taken by each record structure */
+ available -= (le16_to_cpu(la->la_rec_count) *
+ OCFS2_LOCAL_ALLOC_BITS_PER_REC);
+
+ /* reduce space reserved for bitmap for already allocated clusters */
+ available -= cluster_cnt;
+
+ /* if available bits are not enough to fit a new record return 0 */
+ if (available < (OCFS2_LOCAL_ALLOC_BITS_PER_REC + 1))
+ return 0;
+
+ /* Adjust space that will be consumed by new record structure */
+ available -= OCFS2_LOCAL_ALLOC_BITS_PER_REC;
+
+ required = ac->ac_bits_wanted - ac->ac_bits_given;
+
+ /*
+ * we can't allocate clusters more than the bits available. Adjust
+ * bits wanted
+ */
+ if (required > available) {
+ ac->ac_bits_wanted = ac->ac_bits_given + available;
+ return available;
+ } else
+ return required;
+}
+
void ocfs2_la_set_sizes(struct ocfs2_super *osb, int requested_mb)
{
struct super_block *sb = osb->sb;
@@ -239,12 +310,14 @@ void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb,
unsigned int num_clusters)
{
spin_lock(&osb->osb_lock);
- if (osb->local_alloc_state == OCFS2_LA_DISABLED ||
- osb->local_alloc_state == OCFS2_LA_THROTTLED)
- if (num_clusters >= osb->local_alloc_default_bits) {
- cancel_delayed_work(&osb->la_enable_wq);
+ if (osb->local_alloc_state == OCFS2_LA_DISABLED) {
+ cancel_delayed_work(&osb->la_enable_wq);
+ if (num_clusters >= osb->local_alloc_bits)
+ osb->local_alloc_state = OCFS2_LA_THROTTLED;
+
+ if (num_clusters >= osb->local_alloc_default_bits)
osb->local_alloc_state = OCFS2_LA_ENABLED;
- }
+ }
spin_unlock(&osb->osb_lock);
}
@@ -280,7 +353,7 @@ int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
* a new block group. We want to be sure block group
* allocations go through the local alloc, so allow an
* allocation to take up to half the bitmap. */
- if (bits > (la_bits / 2))
+ if ((la_bits > OCFS2_LOCAL_ALLOC_MIN_BITS) && (bits > (la_bits / 2)))
goto bail;
ret = 1;
@@ -348,21 +421,21 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
}
/* do a little verification. */
- num_used = ocfs2_local_alloc_count_bits(alloc);
+ num_used = ocfs2_local_alloc_count_bits(osb, alloc);
/* hopefully the local alloc has always been recovered before
* we load it. */
if (num_used
|| alloc->id1.bitmap1.i_used
|| alloc->id1.bitmap1.i_total
- || la->la_bm_off)
+ || la->la_rec_count)
mlog(ML_ERROR, "Local alloc hasn't been recovered!\n"
- "found = %u, set = %u, taken = %u, off = %u\n",
+ "found = %u, set = %u, taken = %u\n",
num_used, le32_to_cpu(alloc->id1.bitmap1.i_used),
- le32_to_cpu(alloc->id1.bitmap1.i_total),
- OCFS2_LOCAL_ALLOC(alloc)->la_bm_off);
+ le32_to_cpu(alloc->id1.bitmap1.i_total));
- osb->local_alloc_bh = alloc_bh;
+ osb->local_alloc_bh = alloc_bh;
+ osb->local_alloc_inode = inode;
osb->local_alloc_state = OCFS2_LA_ENABLED;
bail:
@@ -389,7 +462,6 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
{
int status;
handle_t *handle;
- struct inode *local_alloc_inode = NULL;
struct buffer_head *bh = NULL;
struct buffer_head *main_bm_bh = NULL;
struct inode *main_bm_inode = NULL;
@@ -402,16 +474,6 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
if (osb->local_alloc_state == OCFS2_LA_UNUSED)
goto out;
- local_alloc_inode =
- ocfs2_get_system_file_inode(osb,
- LOCAL_ALLOC_SYSTEM_INODE,
- osb->slot_num);
- if (!local_alloc_inode) {
- status = -ENOENT;
- mlog_errno(status);
- goto out;
- }
-
osb->local_alloc_state = OCFS2_LA_DISABLED;
ocfs2_resmap_uninit(&osb->osb_la_resmap);
@@ -451,13 +513,19 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
}
memcpy(alloc_copy, alloc, bh->b_size);
- status = ocfs2_journal_access_di(handle, INODE_CACHE(local_alloc_inode),
+ status = ocfs2_journal_access_di(handle,
+ INODE_CACHE(osb->local_alloc_inode),
bh, OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
goto out_commit;
}
+ status = ocfs2_sync_local_to_main(osb, handle, alloc_copy,
+ main_bm_inode, main_bm_bh);
+ if (status < 0)
+ mlog_errno(status);
+
ocfs2_clear_local_alloc(alloc);
ocfs2_journal_dirty(handle, bh);
@@ -465,11 +533,6 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
osb->local_alloc_bh = NULL;
osb->local_alloc_state = OCFS2_LA_UNUSED;
- status = ocfs2_sync_local_to_main(osb, handle, alloc_copy,
- main_bm_inode, main_bm_bh);
- if (status < 0)
- mlog_errno(status);
-
out_commit:
ocfs2_commit_trans(osb, handle);
@@ -483,9 +546,6 @@ out_mutex:
iput(main_bm_inode);
out:
- if (local_alloc_inode)
- iput(local_alloc_inode);
-
if (alloc_copy)
kfree(alloc_copy);
}
@@ -641,22 +701,11 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
{
int status;
struct ocfs2_dinode *alloc;
- struct inode *local_alloc_inode;
unsigned int free_bits;
BUG_ON(!ac);
- local_alloc_inode =
- ocfs2_get_system_file_inode(osb,
- LOCAL_ALLOC_SYSTEM_INODE,
- osb->slot_num);
- if (!local_alloc_inode) {
- status = -ENOENT;
- mlog_errno(status);
- goto bail;
- }
-
- mutex_lock(&local_alloc_inode->i_mutex);
+ mutex_lock(&osb->local_alloc_inode->i_mutex);
/*
* We must double check state and allocator bits because
@@ -675,12 +724,12 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
#ifdef CONFIG_OCFS2_DEBUG_FS
if (le32_to_cpu(alloc->id1.bitmap1.i_used) !=
- ocfs2_local_alloc_count_bits(alloc)) {
+ ocfs2_local_alloc_count_bits(osb, alloc)) {
ocfs2_error(osb->sb, "local alloc inode %llu says it has "
"%u free bits, but a count shows %u",
(unsigned long long)le64_to_cpu(alloc->i_blkno),
le32_to_cpu(alloc->id1.bitmap1.i_used),
- ocfs2_local_alloc_count_bits(alloc));
+ ocfs2_local_alloc_count_bits(osb, alloc));
status = -EIO;
goto bail;
}
@@ -690,8 +739,7 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
le32_to_cpu(alloc->id1.bitmap1.i_used);
if (bits_wanted > free_bits) {
/* uhoh, window change time. */
- status =
- ocfs2_local_alloc_slide_window(osb, local_alloc_inode);
+ status = ocfs2_local_alloc_slide_window(osb);
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
@@ -714,7 +762,7 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
goto bail;
}
- ac->ac_inode = local_alloc_inode;
+ ac->ac_inode = osb->local_alloc_inode;
/* We should never use localalloc from another slot */
ac->ac_alloc_slot = osb->slot_num;
ac->ac_which = OCFS2_AC_USE_LOCAL;
@@ -722,9 +770,8 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
ac->ac_bh = osb->local_alloc_bh;
status = 0;
bail:
- if (status < 0 && local_alloc_inode) {
- mutex_unlock(&local_alloc_inode->i_mutex);
- iput(local_alloc_inode);
+ if (status < 0 && osb->local_alloc_inode) {
+ mutex_unlock(&osb->local_alloc_inode->i_mutex);
}
trace_ocfs2_reserve_local_alloc_bits(
@@ -745,7 +792,7 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,
{
int status, start;
struct inode *local_alloc_inode;
- void *bitmap;
+ u8 *bitmap;
struct ocfs2_dinode *alloc;
struct ocfs2_local_alloc *la;
@@ -764,8 +811,8 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,
goto bail;
}
- bitmap = la->la_bitmap;
- *bit_off = le32_to_cpu(la->la_bm_off) + start;
+ bitmap = OCFS2_LOCAL_ALLOC_BITMAP(la);
+ *bit_off = ocfs2_local_bitmap_to_cluster(la, start);
*num_bits = bits_wanted;
status = ocfs2_journal_access_di(handle,
@@ -792,16 +839,29 @@ bail:
return status;
}
-static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc)
+static u32 ocfs2_local_alloc_count_bits(struct ocfs2_super *osb,
+ struct ocfs2_dinode *alloc)
{
int i;
- u8 *buffer;
+ u8 *bitmap;
u32 count = 0;
struct ocfs2_local_alloc *la = OCFS2_LOCAL_ALLOC(alloc);
- buffer = la->la_bitmap;
- for (i = 0; i < le16_to_cpu(la->la_size); i++)
- count += hweight8(buffer[i]);
+ /*
+ * if discontig is not enabled then lets update the first localalloc
+ * record with the current bitmap block info. We are doing this because
+ * old disk formats are not aware of the records.
+ */
+ if (!ocfs2_supports_discontig_la(osb) && la->la_bm_off) {
+ la->la_rec_count = cpu_to_le16(1);
+ la->la_recs[0].la_start = la->la_bm_off;
+ la->la_recs[0].la_clusters = alloc->id1.bitmap1.i_total;
+ }
+
+ bitmap = OCFS2_LOCAL_ALLOC_BITMAP(la);
+ for (i = 0; i < le32_to_cpu(alloc->id1.bitmap1.i_total); i++)
+ if (ocfs2_test_bit(i, bitmap))
+ count++;
trace_ocfs2_local_alloc_count_bits(count);
return count;
@@ -812,10 +872,11 @@ static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
u32 *numbits,
struct ocfs2_alloc_reservation *resv)
{
- int numfound, bitoff, left, startoff, lastzero;
- int local_resv = 0;
+ int numfound, bitoff, left, startoff;
+ int i, local_resv = 0;
struct ocfs2_alloc_reservation r;
- void *bitmap = NULL;
+ struct ocfs2_local_alloc *la;
+ u8 *bitmap = NULL;
struct ocfs2_reservation_map *resmap = &osb->osb_la_resmap;
if (!alloc->id1.bitmap1.i_total) {
@@ -847,37 +908,44 @@ static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
* Reservations are disabled. Handle this the old way.
*/
- bitmap = OCFS2_LOCAL_ALLOC(alloc)->la_bitmap;
+ la = OCFS2_LOCAL_ALLOC(alloc);
+ bitmap = OCFS2_LOCAL_ALLOC_BITMAP(la);
- numfound = bitoff = startoff = 0;
- lastzero = -1;
- left = le32_to_cpu(alloc->id1.bitmap1.i_total);
- while ((bitoff = ocfs2_find_next_zero_bit(bitmap, left, startoff)) != -1) {
- if (bitoff == left) {
- /* mlog(0, "bitoff (%d) == left", bitoff); */
- break;
- }
- /* mlog(0, "Found a zero: bitoff = %d, startoff = %d, "
- "numfound = %d\n", bitoff, startoff, numfound);*/
-
- /* Ok, we found a zero bit... is it contig. or do we
- * start over?*/
- if (bitoff == startoff) {
- /* we found a zero */
- numfound++;
- startoff++;
- } else {
- /* got a zero after some ones */
- numfound = 1;
- startoff = bitoff+1;
- }
- /* we got everything we needed */
- if (numfound == *numbits) {
- /* mlog(0, "Found it all!\n"); */
- break;
+ left = numfound = bitoff = startoff = 0;
+ for (i = 0; i < le16_to_cpu(la->la_rec_count); i++) {
+
+ numfound = 0;
+ startoff += left;
+ left = le32_to_cpu(la->la_recs[i].la_clusters);
+
+ while ((bitoff = ocfs2_find_next_zero_bit(bitmap, left,
+ startoff)) != -1) {
+ if (bitoff == left) {
+ /* mlog(0, "bitoff (%d) == left", bitoff); */
+ break;
+ }
+ /* mlog(0, "Found a zero: bitoff = %d, startoff = %d, "
+ * "numfound = %d\n", bitoff, startoff, numfound);*/
+
+ /* Ok, we found a zero bit... is it contig. or do we
+ * start over?*/
+ if (bitoff == startoff) {
+ /* we found a zero */
+ numfound++;
+ startoff++;
+ } else {
+ /* got a zero after some ones */
+ numfound = 1;
+ startoff = bitoff+1;
+ }
+ /* we got everything we needed */
+ if (numfound == *numbits) {
+ /* mlog(0, "Found it all!\n"); */
+ goto out;
+ }
}
}
-
+out:
trace_ocfs2_local_alloc_find_clear_bits_search_bitmap(bitoff, numfound);
if (numfound == *numbits)
@@ -900,12 +968,18 @@ static void ocfs2_clear_local_alloc(struct ocfs2_dinode *alloc)
{
struct ocfs2_local_alloc *la = OCFS2_LOCAL_ALLOC(alloc);
int i;
+ u8 *bitmap;
alloc->id1.bitmap1.i_total = 0;
alloc->id1.bitmap1.i_used = 0;
+ la->la_rec_count = 0;
la->la_bm_off = 0;
+
+ /* We reset the rec count so following will clear records as well */
+ bitmap = OCFS2_LOCAL_ALLOC_BITMAP(la);
+ bitmap += sizeof(struct ocfs2_local_alloc);
for(i = 0; i < le16_to_cpu(la->la_size); i++)
- la->la_bitmap[i] = 0;
+ bitmap[i] = 0;
}
#if 0
@@ -933,17 +1007,64 @@ static void ocfs2_verify_zero_bits(unsigned long *bitmap,
* assumes you've already locked the main bitmap -- the bitmap inode
* passed is used for caching.
*/
+static int ocfs2_sync_local_rec_to_main(struct ocfs2_super *osb,
+ handle_t *handle,
+ struct ocfs2_dinode *alloc,
+ struct inode *main_bm_inode,
+ struct buffer_head *main_bm_bh,
+ u8 *bitmap, u64 la_start_blk,
+ int start, int left)
+{
+ int bit_off = 0, status = 0, prev, count;
+ u64 blkno;
+
+ prev = start;
+ count = 0;
+ while ((bit_off = ocfs2_find_next_zero_bit(bitmap, left,
+ start)) != -1) {
+ if ((bit_off < left) && (bit_off == start)) {
+ count++;
+ start++;
+ continue;
+ }
+ if (count) {
+ blkno = la_start_blk +
+ ocfs2_clusters_to_blocks(osb->sb,
+ (start - prev) - count);
+ mlog(0, "\nfreeing %u bits starting at local "
+ "alloc bit %u (la_start_blk = %llu, "
+ "blkno = %llu)\n",
+ count, ((start - prev) - count),
+ (unsigned long long)la_start_blk,
+ (unsigned long long)blkno);
+ status = ocfs2_release_clusters(handle, main_bm_inode,
+ main_bm_bh, blkno,
+ count);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+ }
+ if (bit_off >= left)
+ break;
+ count = 1;
+ start = bit_off + 1;
+ }
+bail:
+ return status;
+}
+
static int ocfs2_sync_local_to_main(struct ocfs2_super *osb,
handle_t *handle,
struct ocfs2_dinode *alloc,
struct inode *main_bm_inode,
struct buffer_head *main_bm_bh)
{
- int status = 0;
- int bit_off, left, count, start;
+ int i, status = 0;
+ int total, start, rec_cnt, credits;
+ u32 clusters;
u64 la_start_blk;
- u64 blkno;
- void *bitmap;
+ u8 *bitmap;
struct ocfs2_local_alloc *la = OCFS2_LOCAL_ALLOC(alloc);
trace_ocfs2_sync_local_to_main(
@@ -954,49 +1075,58 @@ static int ocfs2_sync_local_to_main(struct ocfs2_super *osb,
goto bail;
}
+ /* if all bits are used nothing to sync, just return */
if (le32_to_cpu(alloc->id1.bitmap1.i_used) ==
le32_to_cpu(alloc->id1.bitmap1.i_total)) {
goto bail;
}
- la_start_blk = ocfs2_clusters_to_blocks(osb->sb,
- le32_to_cpu(la->la_bm_off));
- bitmap = la->la_bitmap;
- start = count = bit_off = 0;
- left = le32_to_cpu(alloc->id1.bitmap1.i_total);
+ bitmap = OCFS2_LOCAL_ALLOC_BITMAP(la);
+ rec_cnt = le16_to_cpu(la->la_rec_count) - 1;
- while ((bit_off = ocfs2_find_next_zero_bit(bitmap, left, start))
- != -1) {
- if ((bit_off < left) && (bit_off == start)) {
- count++;
- start++;
- continue;
- }
- if (count) {
- blkno = la_start_blk +
- ocfs2_clusters_to_blocks(osb->sb,
- start - count);
+ for (i = rec_cnt; i >= 0 ; i--) {
+ la_start_blk = ocfs2_clusters_to_blocks(osb->sb,
+ le32_to_cpu(la->la_recs[i].la_start));
- trace_ocfs2_sync_local_to_main_free(
- count, start - count,
- (unsigned long long)la_start_blk,
- (unsigned long long)blkno);
+ total = le32_to_cpu(alloc->id1.bitmap1.i_total);
+ clusters = le32_to_cpu(la->la_recs[i].la_clusters);
+ start = total - clusters;
- status = ocfs2_release_clusters(handle,
- main_bm_inode,
- main_bm_bh, blkno,
- count);
+ status = ocfs2_sync_local_rec_to_main(osb, handle, alloc,
+ main_bm_inode,
+ main_bm_bh, bitmap,
+ la_start_blk, start,
+ total);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+ la->la_bm_off = 0;
+ la->la_recs[i].la_start = 0;
+ la->la_recs[i].la_clusters = 0;
+ le16_add_cpu(&la->la_rec_count, -1);
+ le32_add_cpu(&alloc->id1.bitmap1.i_total, -clusters);
+
+ ocfs2_journal_dirty(handle, osb->local_alloc_bh);
+
+ /* if we need more credits extend the transaction */
+ credits = OCFS2_WINDOW_MOVE_CREDITS - handle->h_buffer_credits;
+ if (credits > 0) {
+ status = ocfs2_extend_trans(handle, credits);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+ status = ocfs2_journal_access_di(handle,
+ INODE_CACHE(osb->local_alloc_inode),
+ osb->local_alloc_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
goto bail;
}
}
- if (bit_off >= left)
- break;
- count = 1;
- start = bit_off + 1;
}
-
bail:
if (status)
mlog_errno(status);
@@ -1046,9 +1176,12 @@ static int ocfs2_recalc_la_window(struct ocfs2_super *osb,
* We ran out of contiguous space in the primary
* bitmap. Drastically reduce the number of bits used
* by local alloc until we have to disable it.
+ * In general we will be seeing atleast few contiguous free
+ * bits. It should be ok to keep local alloc enabled even
+ * in extreme case where max available contiguous free bit is 1
*/
bits = osb->local_alloc_bits >> 1;
- if (bits > ocfs2_megabytes_to_clusters(osb->sb, 1)) {
+ if (bits) {
/*
* By setting state to THROTTLED, we'll keep
* the number of local alloc bits used down
@@ -1096,8 +1229,9 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
goto bail;
}
+ osb->local_alloc_bits = osb->local_alloc_default_bits;
retry_enospc:
- (*ac)->ac_bits_wanted = osb->local_alloc_default_bits;
+ (*ac)->ac_bits_wanted = osb->local_alloc_bits;
status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac);
if (status == -ENOSPC) {
if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_ENOSPC) ==
@@ -1137,9 +1271,11 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
struct ocfs2_alloc_context *ac)
{
int status = 0;
- u32 cluster_off, cluster_count;
+ u32 wanted, cluster_off, cluster_count;
struct ocfs2_dinode *alloc = NULL;
struct ocfs2_local_alloc *la;
+ u8 *bitmap;
+ int i, rec_cnt, credits;
alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
la = OCFS2_LOCAL_ALLOC(alloc);
@@ -1156,72 +1292,97 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
/* we used the generic suballoc reserve function, but we set
* everything up nicely, so there's no reason why we can't use
* the more specific cluster api to claim bits. */
- status = ocfs2_claim_clusters(handle, ac, osb->local_alloc_bits,
- &cluster_off, &cluster_count);
- if (status == -ENOSPC) {
-retry_enospc:
- /*
- * Note: We could also try syncing the journal here to
- * allow use of any free bits which the current
- * transaction can't give us access to. --Mark
- */
- if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_FRAGMENTED) ==
- OCFS2_LA_DISABLED)
- goto bail;
-
- ac->ac_bits_wanted = osb->local_alloc_default_bits;
- status = ocfs2_claim_clusters(handle, ac,
- osb->local_alloc_bits,
- &cluster_off,
+ rec_cnt = 0;
+ wanted = osb->local_alloc_bits;
+ while (1) {
+ status = ocfs2_claim_clusters(handle, ac, wanted, &cluster_off,
&cluster_count);
- if (status == -ENOSPC)
- goto retry_enospc;
- /*
- * We only shrunk the *minimum* number of in our
- * request - it's entirely possible that the allocator
- * might give us more than we asked for.
- */
- if (status == 0) {
- spin_lock(&osb->osb_lock);
- osb->local_alloc_bits = cluster_count;
- spin_unlock(&osb->osb_lock);
+ if (status == -ENOSPC) {
+ /* reduce window size and retry */
+ if (ocfs2_recalc_la_window(osb,
+ OCFS2_LA_EVENT_FRAGMENTED) == OCFS2_LA_DISABLED)
+ break;
+ wanted = osb->local_alloc_bits;
+ continue;
+ } else if (status < 0)
+ break;
+
+ BUG_ON(ac->ac_bits_given > ac->ac_bits_wanted);
+
+ /* found a window */
+ la->la_recs[rec_cnt].la_start = cpu_to_le32(cluster_off);
+ la->la_recs[rec_cnt].la_clusters = cpu_to_le32(cluster_count);
+ rec_cnt++;
+ la->la_rec_count = cpu_to_le16(rec_cnt);
+ le32_add_cpu(&alloc->id1.bitmap1.i_total, cluster_count);
+
+ ocfs2_journal_dirty(handle, osb->local_alloc_bh);
+
+ if (!ocfs2_supports_discontig_la(osb)) {
+ la->la_bm_off = cpu_to_le32(cluster_off);
+ break;
+ }
+
+ /* exit if we can't fit another record */
+ wanted = ocfs2_local_alloc_adjust_bits_wanted(la, ac);
+ if (!wanted)
+ break;
+
+ if (wanted > osb->local_alloc_bits)
+ wanted = osb->local_alloc_bits;
+
+ /* if we need more credits extend the transaction */
+ if (rec_cnt >= OCFS2_MAX_LOCAL_ALLOC_REC_LIMIT)
+ break;
+
+ credits = OCFS2_WINDOW_MOVE_CREDITS - handle->h_buffer_credits;
+ if (credits > 0) {
+ status = ocfs2_extend_trans(handle, credits);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+ status = ocfs2_journal_access_di(handle,
+ INODE_CACHE(osb->local_alloc_inode),
+ osb->local_alloc_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
}
}
- if (status < 0) {
- if (status != -ENOSPC)
- mlog_errno(status);
+ if (!rec_cnt)
goto bail;
- }
+ osb->local_alloc_state = OCFS2_LA_ENABLED;
+ spin_lock(&osb->osb_lock);
+ if (cluster_count > osb->local_alloc_bits)
+ osb->local_alloc_bits = cluster_count;
+ spin_unlock(&osb->osb_lock);
osb->la_last_gd = ac->ac_last_group;
- la->la_bm_off = cpu_to_le32(cluster_off);
- alloc->id1.bitmap1.i_total = cpu_to_le32(cluster_count);
- /* just in case... In the future when we find space ourselves,
- * we don't have to get all contiguous -- but we'll have to
- * set all previously used bits in bitmap and update
- * la_bits_set before setting the bits in the main bitmap. */
- alloc->id1.bitmap1.i_used = 0;
- memset(OCFS2_LOCAL_ALLOC(alloc)->la_bitmap, 0,
- le16_to_cpu(la->la_size));
-
- ocfs2_resmap_restart(&osb->osb_la_resmap, cluster_count,
- OCFS2_LOCAL_ALLOC(alloc)->la_bitmap);
+ bitmap = OCFS2_LOCAL_ALLOC_BITMAP(la);
+ ocfs2_resmap_restart(&osb->osb_la_resmap, rec_cnt,
+ alloc->id1.bitmap1.i_total, bitmap);
+ for (i = 0; i < rec_cnt; i++)
+ ocfs2_resmap_set_ext(&osb->osb_la_resmap, i,
+ le32_to_cpu(la->la_recs[i].la_clusters));
- trace_ocfs2_local_alloc_new_window_result(
- OCFS2_LOCAL_ALLOC(alloc)->la_bm_off,
+ trace_ocfs2_local_alloc_new_window_result
+ (OCFS2_LOCAL_ALLOC(alloc)->la_recs[0].la_start,
le32_to_cpu(alloc->id1.bitmap1.i_total));
bail:
- if (status)
+ if ((status < 0) && (status != -ENOSPC))
mlog_errno(status);
+
return status;
}
/* Note that we do *NOT* lock the local alloc inode here as
* it's been locked already for us. */
-static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
- struct inode *local_alloc_inode)
+static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb)
{
int status = 0;
struct buffer_head *main_bm_bh = NULL;
@@ -1268,7 +1429,7 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
memcpy(alloc_copy, alloc, osb->local_alloc_bh->b_size);
status = ocfs2_journal_access_di(handle,
- INODE_CACHE(local_alloc_inode),
+ INODE_CACHE(osb->local_alloc_inode),
osb->local_alloc_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
--
1.5.4.3
More information about the Ocfs2-devel
mailing list