Srinivas Eeda
2012-Sep-19 00:10 UTC
[Ocfs2-devel] ocfs2 discontig localalloc patches (ver 2)
Hi Joel, et al, sorry for the delay in resending discontiguous localalloc patches. Can you please review when you get a chance. I'll email the tools patches once kernel patches are approved. I came across two use cases where this feature will help. 1. On a customer site, after running an application that creates, deletes ~200 hundred files per second, filesystem got fragmented which impacts localalloc bitmap. Filesystem usage was about 52%. The fragmentation significantly reduces localalloc bitmap size from about 256 mb to closer to 1M and eventually gets disabled. 2. A filesystem of 2TB has a cluster size of 4K which divides filesystem into about 16000 subgroups. In the begining, localalloc bitmap looks for about 2048 contiguous clusters(8mb). In the begining customer was seeing about 600Mb/sec throughput. But once the filesystem was used to about 51% usage, there are very few contiguous chunks that are larger than 2048 clusters(but are scattered). So everytime localalloc bitmap needs to be refilled, it has to scan quite a bit of subgroups before finding one big chunk.This behavior brought down throughput from 600mb/sec down to around < 15mb/sec. When I reduced the bitmap to half, performance was back up. Changes: 1. Allow localalloc bitmap to use multiple contiguous chunks. 2. Each localalloc extent is 128K to start with. This doesn't limit the bitmap from getting one big chunk to fill the bitmap. I have recreated customer filesystem on an iscsi storage with the o2image captured from the customer system. When ran a test of creating 100Mb files, I see a throughput of ~70M/sec without the discontig-la feature and about 280M/sec with discontig-la. Thanks, --Srini
Srinivas Eeda
2012-Sep-19 00:10 UTC
[Ocfs2-devel] [PATCH 1/5] ocfs2: modifiy reservation code to support discontiguous allocations
Currently reservation code assumes that bitmap given to it is one contigous chunk. This patch enhances it to handle a discontigous chunks. It adds new fields m_bitmap_ext_cnt and m_bitmap_ext_arr. m_bitmap_ext_arr tracks the sizes of each contigous chunk and m_bitmap_ext_cnt trackes size of m_bitmap_ext_arr Callers should pass number of discontiguous chunks during ocfs2_resmap_restart and later call ocfs2_resmap_set_extent_size for every chunk. Signed-off-by: Srinivas Eeda <srinivas.eeda at oracle.com> --- fs/ocfs2/localalloc.c | 4 +++- fs/ocfs2/reservations.c | 39 ++++++++++++++++++++++++++++++++++----- fs/ocfs2/reservations.h | 7 ++++++- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index a9f78c7..53a162f 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -1191,9 +1191,11 @@ retry_enospc: memset(OCFS2_LOCAL_ALLOC(alloc)->la_bitmap, 0, le16_to_cpu(la->la_size)); - ocfs2_resmap_restart(&osb->osb_la_resmap, cluster_count, + ocfs2_resmap_restart(&osb->osb_la_resmap, 1, cluster_count, OCFS2_LOCAL_ALLOC(alloc)->la_bitmap); + ocfs2_resmap_set_extent_size(&osb->osb_la_resmap, 0, cluster_count); + trace_ocfs2_local_alloc_new_window_result( OCFS2_LOCAL_ALLOC(alloc)->la_bm_off, le32_to_cpu(alloc->id1.bitmap1.i_total)); diff --git a/fs/ocfs2/reservations.c b/fs/ocfs2/reservations.c index 41ffd36..e1034ed 100644 --- a/fs/ocfs2/reservations.c +++ b/fs/ocfs2/reservations.c @@ -291,7 +291,7 @@ static void ocfs2_resmap_clear_all_resv(struct ocfs2_reservation_map *resmap) } } -void ocfs2_resmap_restart(struct ocfs2_reservation_map *resmap, +void ocfs2_resmap_restart(struct ocfs2_reservation_map *resmap, u32 ext_cnt, unsigned int clen, char *disk_bitmap) { if (ocfs2_resmap_disabled(resmap)) @@ -300,12 +300,32 @@ void ocfs2_resmap_restart(struct ocfs2_reservation_map *resmap, spin_lock(&resv_lock); ocfs2_resmap_clear_all_resv(resmap); + + /* free existing extent array */ + kfree(resmap->m_bitmap_ext_arr); + resmap->m_bitmap_len = clen; resmap->m_disk_bitmap = disk_bitmap; + resmap->m_bitmap_ext_cnt = ext_cnt; + resmap->m_bitmap_ext_arr = kmalloc((sizeof(u32) * ext_cnt), GFP_NOFS); + if (!resmap->m_bitmap_ext_arr) { + mlog_errno(-ENOMEM); + resmap->m_osb->osb_resv_level = 0; /* disable reservations */ + } + spin_unlock(&resv_lock); } +void ocfs2_resmap_set_extent_size(struct ocfs2_reservation_map *resmap, + int indx, u32 sz) +{ + if (ocfs2_resmap_disabled(resmap)) + return; + + resmap->m_bitmap_ext_arr[indx] = sz; +} + void ocfs2_resmap_uninit(struct ocfs2_reservation_map *resmap) { /* Does nothing for now. Keep this around for API symmetry */ @@ -419,21 +439,30 @@ static int ocfs2_resmap_find_free_bits(struct ocfs2_reservation_map *resmap, unsigned int *rlen) { void *bitmap = resmap->m_disk_bitmap; - unsigned int best_start, best_len = 0; + unsigned int best_start, len, ext, best_len = 0; int offset, start, found; trace_ocfs2_resmap_find_free_bits_begin(search_start, search_len, wanted, resmap->m_bitmap_len); - found = best_start = best_len = 0; - + found = best_start = best_len = ext = 0; start = search_start; + len = resmap->m_bitmap_ext_arr[ext++]; + while ((offset = ocfs2_find_next_zero_bit(bitmap, resmap->m_bitmap_len, - start)) != -1) { + start)) != -1) { /* Search reached end of the region */ if (offset >= (search_start + search_len)) break; + if (offset >= len) { + if (ext >= resmap->m_bitmap_ext_cnt) + break; + len += resmap->m_bitmap_ext_arr[ext++]; + found = 1; + start = offset + 1; + } + if (offset == start) { /* we found a zero */ found++; diff --git a/fs/ocfs2/reservations.h b/fs/ocfs2/reservations.h index 42c2b80..fed3aae 100644 --- a/fs/ocfs2/reservations.h +++ b/fs/ocfs2/reservations.h @@ -56,6 +56,8 @@ struct ocfs2_reservation_map { u32 m_bitmap_len; /* Number of valid * bits available */ + u32 m_bitmap_ext_cnt; + u32 *m_bitmap_ext_arr; struct list_head m_lru; /* LRU of reservations * structures. */ @@ -94,6 +96,9 @@ void ocfs2_resv_discard(struct ocfs2_reservation_map *resmap, int ocfs2_resmap_init(struct ocfs2_super *osb, struct ocfs2_reservation_map *resmap); +void ocfs2_resmap_set_extent_size(struct ocfs2_reservation_map *resmap, + int indx, u32 sz); + /** * ocfs2_resmap_restart() - "restart" a reservation bitmap * @resmap: reservations bitmap @@ -107,7 +112,7 @@ int ocfs2_resmap_init(struct ocfs2_super *osb, * reservations. A future version will recalculate existing * reservations based on the new bitmap. */ -void ocfs2_resmap_restart(struct ocfs2_reservation_map *resmap, +void ocfs2_resmap_restart(struct ocfs2_reservation_map *resmap, u32 ext_cnt, unsigned int clen, char *disk_bitmap); /** -- 1.5.4.3
Srinivas Eeda
2012-Sep-19 00:11 UTC
[Ocfs2-devel] [PATCH 2/5] ocfs2: move ocfs2-local-alloc-inode to ocfs2-super
ocfs2_local_alloc_inode is used in multiple functions. It is convenient if we move ocfs2_local_alloc_inode to ocfs2 super. Signed-off-by: Srinivas Eeda <srinivas.eeda at oracle.com> --- fs/ocfs2/localalloc.c | 53 ++++++++++++------------------------------------- fs/ocfs2/ocfs2.h | 1 + 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index 53a162f..45818df 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -72,8 +72,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 @@ -352,7 +351,8 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb) le32_to_cpu(alloc->id1.bitmap1.i_total), OCFS2_LOCAL_ALLOC(alloc)->la_bm_off); - 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: @@ -379,7 +379,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; @@ -392,16 +391,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); @@ -441,7 +430,8 @@ 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); @@ -473,9 +463,6 @@ out_mutex: iput(main_bm_inode); out: - if (local_alloc_inode) - iput(local_alloc_inode); - if (alloc_copy) kfree(alloc_copy); } @@ -631,22 +618,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 @@ -680,8 +656,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); @@ -704,7 +679,8 @@ 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; + igrab(ac->ac_inode); /* We should never use localalloc from another slot */ ac->ac_alloc_slot = osb->slot_num; ac->ac_which = OCFS2_AC_USE_LOCAL; @@ -712,10 +688,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) + mutex_unlock(&osb->local_alloc_inode->i_mutex); trace_ocfs2_reserve_local_alloc_bits( (unsigned long long)ac->ac_max_block, @@ -1208,8 +1182,7 @@ bail: /* 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; @@ -1256,7 +1229,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) { diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index d355e6e..836a647 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -367,6 +367,7 @@ struct ocfs2_super * by osb_lock */ struct buffer_head *local_alloc_bh; + struct inode *local_alloc_inode; u64 la_last_gd; -- 1.5.4.3
Srinivas Eeda
2012-Sep-19 00:11 UTC
[Ocfs2-devel] [PATCH 3/5] ocfs2: new structure to implement discontiguous localalloc bitmap
Currently localalloc bitmap uses single contiguous free chunk of clusters. It's size gets reduced as the contiguous free chunks gets smaller. This ultimately gets disabled if the largest contiguous free chunk is smaller than 1Mb. This patch localalloc bitmap to use space from multiple contiguous free chunk clusters. This patch introduces new ocfs2_local_alloc_rec structure which tracks a single contiguous free chunk. When discontigous localalloc is enabled, ocfs2_local_alloc now holds an array of these records each pointing to a free chunk on the disk. In best case there is one record and as the filesystem gets fragmented you may see multipe records. This feature can be enabled/disabled when the file system is offline. Signed-off-by: Srinivas Eeda <srinivas.eeda at oracle.com> --- fs/ocfs2/localalloc.c | 22 ++++++++++++++-- fs/ocfs2/ocfs2.h | 7 +++++ fs/ocfs2/ocfs2_fs.h | 65 ++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index 45818df..98961f4 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -48,6 +48,13 @@ #define OCFS2_LOCAL_ALLOC(dinode) (&((dinode)->id2.i_lab)) +#define OCFS2_LOCAL_ALLOC_REC_SZ(la) (le16_to_cpu(la->la_rec_count) *\ + sizeof(struct ocfs2_local_alloc_rec)) +#define OCFS2_LOCAL_ALLOC_BITS_PER_REC (sizeof(struct ocfs2_local_alloc_rec)*8) + +#define OCFS2_LOCAL_ALLOC_SIZE(osb) ocfs2_local_alloc_size(osb->sb,\ + osb->s_feature_incompat) + static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc); static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb, @@ -74,6 +81,15 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb); +static inline u8 *ocfs2_local_alloc_bitmap(struct ocfs2_super *osb, + struct ocfs2_local_alloc *la) +{ + if (ocfs2_supports_discontig_la(osb)) + return (u8 *)la->la_recs + le16_to_cpu(la->la_bm_start); + else + return la->la_bitmap; +} + /* * ocfs2_la_default_mb() - determine a default size, in megabytes of * the local alloc. @@ -184,7 +200,7 @@ unsigned int ocfs2_la_default_mb(struct ocfs2_super *osb) /* We can't store more bits than we can in a block. */ la_max_mb = ocfs2_clusters_to_megabytes(osb->sb, - ocfs2_local_alloc_size(sb) * 8); + OCFS2_LOCAL_ALLOC_SIZE(osb) * 8); if (la_mb > la_max_mb) la_mb = la_max_mb; @@ -198,7 +214,7 @@ void ocfs2_la_set_sizes(struct ocfs2_super *osb, int requested_mb) unsigned int la_max_mb; la_max_mb = ocfs2_clusters_to_megabytes(sb, - ocfs2_local_alloc_size(sb) * 8); + OCFS2_LOCAL_ALLOC_SIZE(osb) * 8); trace_ocfs2_la_set_sizes(requested_mb, la_max_mb, la_default_mb); @@ -329,7 +345,7 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb) } if ((la->la_size == 0) || - (le16_to_cpu(la->la_size) > ocfs2_local_alloc_size(inode->i_sb))) { + (le16_to_cpu(la->la_size) > OCFS2_LOCAL_ALLOC_SIZE(osb))) { mlog(ML_ERROR, "Local alloc size is invalid (la_size = %u)\n", le16_to_cpu(la->la_size)); status = -EINVAL; diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 836a647..7ab1afe 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -523,6 +523,13 @@ static inline int ocfs2_supports_discontig_bg(struct ocfs2_super *osb) return 0; } +static inline int ocfs2_supports_discontig_la(struct ocfs2_super *osb) +{ + if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_DISCONTIG_LA) + return 1; + return 0; +} + static inline unsigned int ocfs2_link_max(struct ocfs2_super *osb) { if (ocfs2_supports_indexed_dirs(osb)) diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index 938387a..409b2b0 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h @@ -102,7 +102,8 @@ | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS \ | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE \ | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG \ - | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO) + | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO \ + | OCFS2_FEATURE_INCOMPAT_DISCONTIG_LA) #define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \ | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \ | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA) @@ -177,6 +178,9 @@ */ #define OCFS2_FEATURE_INCOMPAT_CLUSTERINFO 0x4000 +/* Discontiguous local alloc */ +#define OCFS2_FEATURE_INCOMPAT_DISCONTIG_LA 0x8000 + /* * backup superblock flag is used to indicate that this volume * has backup superblocks. @@ -661,17 +665,44 @@ struct ocfs2_super_block { }; /* + * LocalAlloc record used when discontig-la is enabled. Each record points + * to one contiguous chunk + */ +#define OCFS2_MAX_LOCAL_ALLOC_REC_LIMIT 128 /* Max localalloc records */ + +struct ocfs2_local_alloc_rec { + __le32 la_start; /* 1st cluster in this extent */ + __le32 la_clusters; /* Number of contiguous clusters */ +}; + +/* * Local allocation bitmap for OCFS2 slots * Note that it exists inside an ocfs2_dinode, so all offsets are * relative to the start of ocfs2_dinode.id2. + * Each ocfs2_local_alloc_rec tracks one contigous chunk of clusters. */ struct ocfs2_local_alloc { -/*00*/ __le32 la_bm_off; /* Starting bit offset in main bitmap */ - __le16 la_size; /* Size of included bitmap, in bytes */ - __le16 la_reserved1; - __le64 la_reserved2; -/*10*/ __u8 la_bitmap[0]; + union { + /* struct used when localalloc is contiguous */ + struct { + /*00*/ __le32 la_bm_off; /* offset in main bitmap */ + __le16 la_size; /* Size of bitmap, in bytes */ + __le16 la_reserved1; + __le64 la_reserved2; + /*10*/ __u8 la_bitmap[0]; + }; + + /* struct used when localalloc can be discontigous */ + struct { + /*00*/ __le16 la_bm_start; /* start offset to the bitmap */ + __le16 la_rec_count; /* number of localalloc recs */ + __le16 la_dc_size; /* space for records & bitmap */ + __le16 la_reserved3; + __le64 la_reserved4; + /*10*/ struct ocfs2_local_alloc_rec la_recs[0]; + }; + }; }; /* @@ -1375,12 +1406,17 @@ static inline int ocfs2_dx_entries_per_root(struct super_block *sb) return size / sizeof(struct ocfs2_dx_entry); } -static inline u16 ocfs2_local_alloc_size(struct super_block *sb) +static inline u16 ocfs2_local_alloc_size(struct super_block *sb, + u32 feature_incompat) { u16 size; - size = sb->s_blocksize - - offsetof(struct ocfs2_dinode, id2.i_lab.la_bitmap); + if (feature_incompat & OCFS2_FEATURE_INCOMPAT_DISCONTIG_LA) + size = sb->s_blocksize - + offsetof(struct ocfs2_dinode, id2.i_lab.la_bitmap); + else + size = sb->s_blocksize - + offsetof(struct ocfs2_dinode, id2.i_lab.la_bitmap); return size; } @@ -1523,12 +1559,17 @@ static inline int ocfs2_extent_recs_per_gd(int blocksize) return size / sizeof(struct ocfs2_extent_rec); } -static inline int ocfs2_local_alloc_size(int blocksize) +static inline int ocfs2_local_alloc_size(int blocksize, + u32 feature_incompat) { int size; - size = blocksize - - offsetof(struct ocfs2_dinode, id2.i_lab.la_bitmap); + if (feature_incompat & OCFS2_FEATURE_INCOMPAT_DISCONTIG_LA) + size = blocksize - + offsetof(struct ocfs2_dinode, id2.i_lab.la_recs); + else + size = blocksize - + offsetof(struct ocfs2_dinode, id2.i_lab.la_bitmap); return size; } -- 1.5.4.3
Srinivas Eeda
2012-Sep-19 00:11 UTC
[Ocfs2-devel] [PATCH 4/5] ocfs2: implement discontiguous localalloc bitmap
This patch adds code to support discontiguous localalloc bitmap. At any given time there can be a combination of volumes that have discontigous feature enabled or disabled. Signed-off-by: Srinivas Eeda <srinivas.eeda at oracle.com> --- fs/ocfs2/localalloc.c | 478 +++++++++++++++++++++++++++++++++++-------------- 1 files changed, 341 insertions(+), 137 deletions(-) diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index 98961f4..82653f2 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -55,14 +55,16 @@ #define OCFS2_LOCAL_ALLOC_SIZE(osb) ocfs2_local_alloc_size(osb->sb,\ osb->s_feature_incompat) -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, u32 *numbits, struct ocfs2_alloc_reservation *resv); -static void ocfs2_clear_local_alloc(struct ocfs2_dinode *alloc); +static void ocfs2_clear_local_alloc(struct ocfs2_super *osb, + struct ocfs2_dinode *alloc); static int ocfs2_sync_local_to_main(struct ocfs2_super *osb, handle_t *handle, @@ -207,6 +209,68 @@ unsigned int ocfs2_la_default_mb(struct ocfs2_super *osb) return la_mb; } +static inline u32 ocfs2_local_bitmap_to_cluster(struct ocfs2_super *osb, + struct ocfs2_local_alloc *la, + u32 bit) +{ + u32 start, prev, offset; + int rec; + + if (!ocfs2_supports_discontig_la(osb)) + return le32_to_cpu(la->la_bm_off) + bit; + + 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. + * It adjusts bits wanted and returns 0(if full) or a possitive + * number(bits required) + */ +static unsigned int +ocfs2_local_alloc_adjust_bits_wanted(struct ocfs2_dinode *alloc, + struct ocfs2_alloc_context *ac) +{ + unsigned int wanted, bits_used, total_bits; + struct ocfs2_local_alloc *la; + int bits_left; + + BUG_ON(ac->ac_bits_given > ac->ac_bits_wanted); + wanted = ac->ac_bits_wanted - ac->ac_bits_given; + if (wanted == 0) + return 0; + + la = OCFS2_LOCAL_ALLOC(alloc); + total_bits = le16_to_cpu(la->la_dc_size) << 3; + + /* space for localalloc bitmap + space used for extent records */ + bits_used = le32_to_cpu(alloc->id1.bitmap1.i_total) + + (le16_to_cpu(la->la_rec_count) * + OCFS2_LOCAL_ALLOC_BITS_PER_REC); + + bits_left = total_bits - bits_used; + if (bits_left <= OCFS2_LOCAL_ALLOC_BITS_PER_REC) + return 0; + + /* space fore new record */ + bits_left -= OCFS2_LOCAL_ALLOC_BITS_PER_REC; + if (wanted > bits_left) { + wanted = bits_left; + ac->ac_bits_wanted = ac->ac_bits_given + bits_left; + } + return wanted; +} + void ocfs2_la_set_sizes(struct ocfs2_super *osb, int requested_mb) { struct super_block *sb = osb->sb; @@ -344,28 +408,38 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb) goto bail; } - if ((la->la_size == 0) || - (le16_to_cpu(la->la_size) > OCFS2_LOCAL_ALLOC_SIZE(osb))) { + if (!ocfs2_supports_discontig_la(osb) && + (!la->la_size || + (le16_to_cpu(la->la_size) > OCFS2_LOCAL_ALLOC_SIZE(osb)))) { mlog(ML_ERROR, "Local alloc size is invalid (la_size = %u)\n", le16_to_cpu(la->la_size)); status = -EINVAL; goto bail; } + if (ocfs2_supports_discontig_la(osb) && + (!la->la_dc_size || + (le16_to_cpu(la->la_dc_size) > OCFS2_LOCAL_ALLOC_SIZE(osb)))) { + mlog(ML_ERROR, "Local alloc size is invalid " + "(la_dc_size = %u)\n", le16_to_cpu(la->la_dc_size)); + status = -EINVAL; + goto bail; + } + /* 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) + || (ocfs2_supports_discontig_la(osb) && la->la_rec_count) + || (!ocfs2_supports_discontig_la(osb) && la->la_bm_off)) 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_inode = inode; @@ -454,11 +528,12 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb) goto out_commit; } - ocfs2_clear_local_alloc(alloc); + ocfs2_clear_local_alloc(osb, alloc); ocfs2_journal_dirty(handle, bh); brelse(bh); osb->local_alloc_bh = NULL; + osb->local_alloc_inode = NULL; osb->local_alloc_state = OCFS2_LA_UNUSED; status = ocfs2_sync_local_to_main(osb, handle, alloc_copy, @@ -529,7 +604,7 @@ int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb, memcpy((*alloc_copy), alloc_bh->b_data, alloc_bh->b_size); alloc = (struct ocfs2_dinode *) alloc_bh->b_data; - ocfs2_clear_local_alloc(alloc); + ocfs2_clear_local_alloc(osb, alloc); ocfs2_compute_meta_ecc(osb->sb, alloc_bh->b_data, &alloc->i_check); status = ocfs2_write_block(osb, alloc_bh, INODE_CACHE(inode)); @@ -657,12 +732,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; } @@ -744,8 +819,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(osb, la); + *bit_off = ocfs2_local_bitmap_to_cluster(osb, la, start); *num_bits = bits_wanted; status = ocfs2_journal_access_di(handle, @@ -772,12 +847,19 @@ 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) { - u32 count; + u32 size, count; + u8 *bitmap; struct ocfs2_local_alloc *la = OCFS2_LOCAL_ALLOC(alloc); - count = memweight(la->la_bitmap, le16_to_cpu(la->la_size)); + size = OCFS2_LOCAL_ALLOC_SIZE(osb); + if (ocfs2_supports_discontig_la(osb)) + size -= le16_to_cpu(la->la_bm_start); + + bitmap = ocfs2_local_alloc_bitmap(osb, la); + count = memweight(bitmap, size); trace_ocfs2_local_alloc_count_bits(count); return count; @@ -788,10 +870,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, rec_cnt, 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) { @@ -823,37 +906,47 @@ 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(osb, 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; + if (ocfs2_supports_discontig_la(osb)) + rec_cnt = le16_to_cpu(la->la_rec_count); + else + rec_cnt = 1; + + left = numfound = bitoff = startoff = 0; + for (i = 0; i < rec_cnt; i++) { + + numfound = 0; + startoff += left; + if (ocfs2_supports_discontig_la(osb)) + left = le32_to_cpu(la->la_recs[i].la_clusters); + else + left = le32_to_cpu(alloc->id1.bitmap1.i_total); + + while ((bitoff = ocfs2_find_next_zero_bit(bitmap, left, + startoff)) != -1) { + if (bitoff == left) + break; + + /* 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) + goto out; } } - +out: trace_ocfs2_local_alloc_find_clear_bits_search_bitmap(bitoff, numfound); if (numfound == *numbits) @@ -872,16 +965,25 @@ bail: return bitoff; } -static void ocfs2_clear_local_alloc(struct ocfs2_dinode *alloc) +static void ocfs2_clear_local_alloc(struct ocfs2_super *osb, + struct ocfs2_dinode *alloc) { struct ocfs2_local_alloc *la = OCFS2_LOCAL_ALLOC(alloc); - int i; + int i, size; + u8 *bitmap; alloc->id1.bitmap1.i_total = 0; alloc->id1.bitmap1.i_used = 0; - la->la_bm_off = 0; - for(i = 0; i < le16_to_cpu(la->la_size); i++) - la->la_bitmap[i] = 0; + if (ocfs2_supports_discontig_la(osb)) { + la->la_bm_start = 0; + la->la_rec_count = 0; + } else + la->la_bm_off = 0; + + size = OCFS2_LOCAL_ALLOC_SIZE(osb); + bitmap = ocfs2_local_alloc_bitmap(osb, la); + for (i = 0; i < size; i++) + bitmap[i] = 0; } #if 0 @@ -909,17 +1011,59 @@ 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 inode *main_bm_inode, + struct buffer_head *main_bm_bh, + u8 *bitmap, u64 la_start_blk, + int startoff, int left) +{ + int bit_off = 0, status = 0, prev, count; + u64 blkno; + + BUG_ON(left < startoff); + prev = startoff; + count = 0; + while ((bit_off = ocfs2_find_next_zero_bit(bitmap, left, + startoff)) != -1) { + if ((bit_off < left) && (bit_off == startoff)) { + count++; + startoff++; + continue; + } + if (count) { + blkno = la_start_blk + + ocfs2_clusters_to_blocks(osb->sb, + (startoff - prev) - count); + 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; + startoff = 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( @@ -935,44 +1079,60 @@ static int ocfs2_sync_local_to_main(struct ocfs2_super *osb, 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(osb, la); + if (ocfs2_supports_discontig_la(osb)) + rec_cnt = le16_to_cpu(la->la_rec_count); + else + rec_cnt = 1; - while ((bit_off = ocfs2_find_next_zero_bit(bitmap, left, start)) - != -1) { - if ((bit_off < left) && (bit_off == start)) { - count++; - start++; - continue; + for (i = rec_cnt - 1; i >= 0; i--) { + if (ocfs2_supports_discontig_la(osb)) { + clusters = le32_to_cpu(la->la_recs[i].la_clusters); + la_start_blk = ocfs2_clusters_to_blocks(osb->sb, + le32_to_cpu(la->la_recs[i].la_start)); + } else { + clusters = le32_to_cpu(alloc->id1.bitmap1.i_total); + la_start_blk = ocfs2_clusters_to_blocks(osb->sb, + le32_to_cpu(la->la_bm_off)); } - if (count) { - blkno = la_start_blk + - ocfs2_clusters_to_blocks(osb->sb, - start - count); - - trace_ocfs2_sync_local_to_main_free( - count, start - count, - (unsigned long long)la_start_blk, - (unsigned long long)blkno); - - status = ocfs2_release_clusters(handle, - main_bm_inode, - main_bm_bh, blkno, - count); + total = le32_to_cpu(alloc->id1.bitmap1.i_total); + start = total - clusters; + status = ocfs2_sync_local_rec_to_main(osb, handle, + main_bm_inode, + main_bm_bh, bitmap, + la_start_blk, start, + total); + if (status < 0) { + mlog_errno(status); + goto bail; + } + 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(main_bm_inode), + main_bm_bh, + OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } } - if (bit_off >= left) + + le32_add_cpu(&alloc->id1.bitmap1.i_total, -clusters); + if (!ocfs2_supports_discontig_la(osb)) { + la->la_bm_off = 0; break; - count = 1; - start = bit_off + 1; + } + le16_add_cpu(&la->la_rec_count, -1); } + if (ocfs2_supports_discontig_la(osb)) + la->la_bm_start = 0; bail: if (status) mlog_errno(status); @@ -1014,17 +1174,27 @@ static int ocfs2_recalc_la_window(struct ocfs2_super *osb, } /* - * ENOSPC and fragmentation are treated similarly for now. + * ENOSPC means there are not enough free clusters in global bitmap. + * So disable localalloc. */ - if (event == OCFS2_LA_EVENT_ENOSPC || - event == OCFS2_LA_EVENT_FRAGMENTED) { + if (event == OCFS2_LA_EVENT_ENOSPC) { + osb->local_alloc_state = OCFS2_LA_DISABLED; + queue_delayed_work(ocfs2_wq, &osb->la_enable_wq, + OCFS2_LA_ENABLE_INTERVAL); + goto out_unlock; + } + + if (event == OCFS2_LA_EVENT_FRAGMENTED) { /* * 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. + * If discontigous localalloc is enabled, we try to fill the + * bitmap until it's disabled */ bits = osb->local_alloc_bits >> 1; - if (bits > ocfs2_megabytes_to_clusters(osb->sb, 1)) { + if (ocfs2_supports_discontig_la(osb) || + (bits > ocfs2_megabytes_to_clusters(osb->sb, 1))) { /* * By setting state to THROTTLED, we'll keep * the number of local alloc bits used down @@ -1113,9 +1283,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); @@ -1132,59 +1304,91 @@ 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); + + 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; + } + + 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); + la->la_bm_start += sizeof(struct ocfs2_local_alloc_rec); + + if (rec_cnt >= OCFS2_MAX_LOCAL_ALLOC_REC_LIMIT) + break; + + /* exit if we can't fit another record */ + wanted = ocfs2_local_alloc_adjust_bits_wanted(alloc, ac); + if (!wanted) + break; + + /* we start from max bits seen instead of max bits needed */ + if (wanted > osb->local_alloc_bits) + wanted = osb->local_alloc_bits; + + /* if we need more credits extend 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 (status < 0) { - if (status != -ENOSPC) - mlog_errno(status); + + if (!alloc->id1.bitmap1.i_total) goto bail; - } + 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, 1, cluster_count, - OCFS2_LOCAL_ALLOC(alloc)->la_bitmap); + bitmap = ocfs2_local_alloc_bitmap(osb, la); - ocfs2_resmap_set_extent_size(&osb->osb_la_resmap, 0, cluster_count); + if (!ocfs2_supports_discontig_la(osb)) { + ocfs2_resmap_restart(&osb->osb_la_resmap, 1, cluster_count, + bitmap); + ocfs2_resmap_set_extent_size(&osb->osb_la_resmap, 0, + cluster_count); + } else { + 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_extent_size(&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, @@ -1253,7 +1457,7 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb) goto bail; } - ocfs2_clear_local_alloc(alloc); + ocfs2_clear_local_alloc(osb, alloc); ocfs2_journal_dirty(handle, osb->local_alloc_bh); status = ocfs2_sync_local_to_main(osb, handle, alloc_copy, -- 1.5.4.3
Srinivas Eeda
2012-Sep-19 00:11 UTC
[Ocfs2-devel] [PATCH 5/5] ocfs2 set min default contig localalloc size
When discontiguous localalloc is enabled, localalloc should just try for a minimum smaller contiguous chunk. This will improve performance when the file system is fragmented. This setting doesn't stop localalloc from getting bigger chunk. The default chunk size is set to fill 128Kb. localalloc will try to look for atleast that big of chunk. If it's not available then it reduces the size by half and retries. #define OCFS2_DEFAULT_LOCALALLOC_CHUNK_SIZE (128*1024) /* 128kb */ Signed-off-by: Srinivas Eeda <srinivas.eeda at oracle.com> --- fs/ocfs2/localalloc.c | 28 +++++++++++++++++++++------- 1 files changed, 21 insertions(+), 7 deletions(-) diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index 82653f2..569e131 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -271,6 +271,19 @@ ocfs2_local_alloc_adjust_bits_wanted(struct ocfs2_dinode *alloc, return wanted; } +#define OCFS2_DEFAULT_LOCALALLOC_CHUNK_SIZE (128*1024) /* 128kb */ + +void ocfs2_set_default_min_alloc_size(struct ocfs2_super *osb) +{ + if (ocfs2_supports_discontig_la(osb)) { + osb->local_alloc_bits = OCFS2_DEFAULT_LOCALALLOC_CHUNK_SIZE / + osb->s_clustersize; + if (!osb->local_alloc_bits) + osb->local_alloc_bits = 1; + } else + osb->local_alloc_bits = osb->local_alloc_default_bits; +} + void ocfs2_la_set_sizes(struct ocfs2_super *osb, int requested_mb) { struct super_block *sb = osb->sb; @@ -294,8 +307,7 @@ void ocfs2_la_set_sizes(struct ocfs2_super *osb, int requested_mb) osb->local_alloc_default_bits ocfs2_megabytes_to_clusters(sb, requested_mb); } - - osb->local_alloc_bits = osb->local_alloc_default_bits; + ocfs2_set_default_min_alloc_size(osb); } static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb) @@ -1219,7 +1231,7 @@ static int ocfs2_recalc_la_window(struct ocfs2_super *osb, * low space. */ if (osb->local_alloc_state != OCFS2_LA_THROTTLED) - osb->local_alloc_bits = osb->local_alloc_default_bits; + ocfs2_set_default_min_alloc_size(osb); out_unlock: state = osb->local_alloc_state; @@ -1369,10 +1381,12 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, if (!alloc->id1.bitmap1.i_total) goto bail; - spin_lock(&osb->osb_lock); - if (cluster_count > osb->local_alloc_bits) - osb->local_alloc_bits = cluster_count; - spin_unlock(&osb->osb_lock); + if (!ocfs2_supports_discontig_la(osb)) { + 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; bitmap = ocfs2_local_alloc_bitmap(osb, la); -- 1.5.4.3