Multiple block allocation for ext3
Subsystems (8)
A message that is not in the archive (sent off-list or not yet received): [email protected]
RFC PATCH 1/4 Multiple block allocation for ext3
Here is the patch support multiple block allocation for ext3. Current ext3 allocates one block at a time, not efficient for large sequential write IO.
This patch implements a simply multiple block allocation with current ext3. The basic idea is allocating the 1st block in the existing way, and attempting to allocate the next adjacent blocks on a best effort basis. If contiguous allocation is blocked by an already allocated block, the current number of free blocks are allocated and no futhur search is tried.
This implementation makes uses of block reservation. With the knowledge of how many blocks to allocate, the reservation window size is being enlargedaccordin before block allocation to increase the chance to get contiguous blocks.
Previous post of this patch with more description could be found here:
http://marc.theaimsgroup.com/?l=ext2-devel&m=111471578328685&w=2
---
linux-2.6.12-ming/fs/ext3/balloc.c | 121 +++++++-- linux-2.6.12-ming/fs/ext3/inode.c | 380 ++++++++++++++++++++++++++++-- linux-2.6.12-ming/fs/ext3/xattr.c | 3 linux-2.6.12-ming/include/linux/ext3_fs.h | 2 4 files changed, 458 insertions(+), 48 deletions(-)
fs/ext3/balloc.c renamed from fs/ext3/balloc.c~ext3-get-blocks +90 -31
@@ -20,6 +20,7 @@#include <linux/quotaops.h> #include <linux/buffer_head.h> +#define NBS_DEBUG 0/* * balloc.c contains the blocks allocation and deallocation routines */
@@ -652,9 +653,11 @@ claim_block(spinlock_t *lock, int block,*/ static int ext3_try_to_allocate (struct super_block *sb,handle_t *handle,int group, -struct buffer_head *bitmap_bh,int goal,struct ext3_reserve_window *my_rsv) +struct buffer_head *bitmap_bh,int goal,unsigned long *count, +struct ext3_reserve_window *my_rsv) {int group_first_block, start, end; +unsigned long num =0 ;/* we do allocation within the reservation window if we have a window */ if (my_rsv) {
@@ -712,8 +715,22 @@ repeat: goto fail_access; goto repeat; } -return goal; + num++; + goal++; +if (NBS_DEBUG ) +printk ("ext3_new_block: first block allocated:block %d,num %d\n" , goal, num); +while (num < *count && goal < end + &&ext3_test_allocatable (goal, bitmap_bh) + &&claim_block (sb_bgl_lock (EXT3_SB (sb), group), goal, bitmap_bh)) { + num++; + goal++; + } + *count = num; +if (NBS_DEBUG ) +printk ("ext3_new_block: additional block allocated:block %d,num %d,goal-num %d\n" , goal, num, goal-num); +return goal - num; fail_access: + *count = num;return -1 ; }
@@ -998,6 +1015,28 @@ retry: goto retry; } +static void try_to_extend_reservation (struct ext3_reserve_window_node *my_rsv, +struct super_block *sb,int size) +{ +struct ext3_reserve_window_node *next_rsv; +struct rb_node *next; +spinlock_t *rsv_lock = &EXT3_SB (sb)->s_rsv_window_lock; + +spin_lock (rsv_lock); + next =rb_next (&my_rsv->rsv_node); + +if (!next) + my_rsv->rsv_end += size; +else { + next_rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node); + +if ((next_rsv->rsv_start - my_rsv->rsv_end) > size) + my_rsv->rsv_end += size; +else + my_rsv->rsv_end = next_rsv->rsv_start -1 ; + } +spin_unlock (rsv_lock); +}/* * This is the main function used to allocate a new block and its reservation * window.
@@ -1023,11 +1062,12 @@ static int ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, unsigned int group, struct buffer_head *bitmap_bh, int goal, struct ext3_reserve_window_node * my_rsv, - int *errp) + unsigned long *count, int *errp) { unsigned long group_first_block;int ret =0 ;int fatal; +unsigned long num = *count; *errp =0 ;
@@ -1050,7 +1090,8 @@ ext3_try_to_allocate_with_rsv(struct sup* or last attempt to allocate a block with reservation turned on failed */ if (my_rsv ==NULL ) { - ret =ext3_try_to_allocate (sb, handle, group, bitmap_bh, goal,NULL ); + ret =ext3_try_to_allocate (sb, handle, group, bitmap_bh, goal, + count,NULL ); goto out; }/*
@@ -1080,6 +1121,10 @@ ext3_try_to_allocate_with_rsv(struct supwhile (1 ) {if (rsv_is_empty (&my_rsv->rsv_window) || (ret <0 ) || !goal_in_my_reservation (&my_rsv->rsv_window, goal, group, sb)) { +if (my_rsv->rsv_goal_size < *count) + my_rsv->rsv_goal_size = *count; + + ret =alloc_new_reservation (my_rsv, goal, sb, group, bitmap_bh);if (ret <0 )
@@ -1088,15 +1133,21 @@ ext3_try_to_allocate_with_rsv(struct supif (!goal_in_my_reservation (&my_rsv->rsv_window, goal, group, sb)) goal =-1 ; } +else { +if (goal >0 && (my_rsv->rsv_end - goal +1 ) < *count) +try_to_extend_reservation (my_rsv, sb, + *count-my_rsv->rsv_end+goal-1 ); + }if ((my_rsv->rsv_start >= group_first_block +EXT3_BLOCKS_PER_GROUP (sb)) || (my_rsv->rsv_end < group_first_block))BUG (); ret =ext3_try_to_allocate (sb, handle, group, bitmap_bh, goal, - &my_rsv->rsv_window); + &num, &my_rsv->rsv_window);if (ret >=0 ) { - my_rsv->rsv_alloc_hit++; + my_rsv->rsv_alloc_hit += num;break ;/* succeed */ } + num = *count; } out:if (ret >=0 ) {
@@ -1153,8 +1204,8 @@ int ext3_should_retry_alloc(struct super* bitmap, and then for any free bit if that fails. * This function also updates quota and i_blocks field. */ -int ext3_new_block (handle_t *handle,struct inode *inode, -unsigned long goal,int *errp) +int ext3_new_blocks (handle_t *handle,struct inode *inode, +unsigned long goal,unsigned long * count,int *errp) {struct buffer_head *bitmap_bh =NULL ;struct buffer_head *gdp_bh;
@@ -1177,7 +1228,8 @@ int ext3_new_block(handle_t *handle, strstatic int goal_hits, goal_attempts;#endif unsigned long ngroups; - +unsigned long num = *count; +int i; *errp = -ENOSPC ; sb = inode->i_sb;if (!sb) {
@@ -1188,7 +1240,7 @@ int ext3_new_block(handle_t *handle, str/* * Check quota for allocation of this block. */ -if (DQUOT_ALLOC_BLOCK (inode,1 )) { +if (DQUOT_ALLOC_BLOCK (inode, num)) { *errp = -EDQUOT ;return 0 ; }
@@ -1243,7 +1295,7 @@ retry:if (!bitmap_bh) goto io_error; ret_block =ext3_try_to_allocate_with_rsv (sb, handle, group_no, - bitmap_bh, ret_block, my_rsv, &fatal); + bitmap_bh, ret_block, my_rsv, &num, &fatal);if (fatal) goto out;if (ret_block >=0 )
@@ -1280,7 +1332,7 @@ retry:if (!bitmap_bh) goto io_error; ret_block =ext3_try_to_allocate_with_rsv (sb, handle, group_no, - bitmap_bh,-1 , my_rsv, &fatal); + bitmap_bh,-1 , my_rsv, &num, &fatal);if (fatal) goto out;if (ret_block >=0 )
@@ -1315,14 +1367,17 @@ allocated: target_block = ret_block + group_no *EXT3_BLOCKS_PER_GROUP (sb) +le32_to_cpu (es->s_first_data_block); -if (target_block ==le32_to_cpu (gdp->bg_block_bitmap) || - target_block ==le32_to_cpu (gdp->bg_inode_bitmap) || -in_range (target_block,le32_to_cpu (gdp->bg_inode_table), -EXT3_SB (sb)->s_itb_per_group)) -ext3_error (sb,"ext3_new_block" , -"Allocating block in system zone - " -"block = %u" , target_block); - +for (i =0 ; i < num; i++, target_block++) { +if (target_block ==le32_to_cpu (gdp->bg_block_bitmap) || + target_block ==le32_to_cpu (gdp->bg_inode_bitmap) || +in_range (target_block,le32_to_cpu (gdp->bg_inode_table), +EXT3_SB (sb)->s_itb_per_group)) { +ext3_error (sb,"ext3_new_block" , +"Allocating block in system zone - " +"block = %u" , target_block); + goto out; + } + } performed_allocation =1 ;#ifdef CONFIG_JBD_DEBUG
@@ -1340,10 +1395,12 @@ allocated:jbd_lock_bh_state (bitmap_bh);spin_lock (sb_bgl_lock (sbi, group_no));if (buffer_jbd (bitmap_bh) &&bh2jh (bitmap_bh)->b_committed_data) { -if (ext3_test_bit (ret_block, -bh2jh (bitmap_bh)->b_committed_data)) { -printk ("%s: block was unexpectedly set in " -"b_committed_data\n" , __FUNCTION__); +for (i =0 ; i < num ; i++) { +if (ext3_test_bit (ret_block++, +bh2jh (bitmap_bh)->b_committed_data)) { +printk ("%s: block was unexpectedly set in " +"b_committed_data\n" , __FUNCTION__); + } } }ext3_debug ("found bit %d\n" , ret_block);
@@ -1352,12 +1409,12 @@ allocated:#endif /* ret_block was blockgroup-relative. Now it becomes fs-relative */ - ret_block = target_block; + ret_block = target_block - num; -if (ret_block >=le32_to_cpu (es->s_blocks_count)) { +if (target_block -1 >=le32_to_cpu (es->s_blocks_count)) {ext3_error (sb,"ext3_new_block" , -"block(%d) >= blocks count(%d) - " -"block_group = %d, es == %p " , ret_block, +"block(%d) >= fs blocks count(%d) - " +"block_group = %d, es == %p " , target_block -1 ,le32_to_cpu (es->s_blocks_count), group_no, es); goto out; }
@@ -1372,9 +1429,9 @@ allocated:spin_lock (sb_bgl_lock (sbi, group_no)); gdp->bg_free_blocks_count = -cpu_to_le16 (le16_to_cpu (gdp->bg_free_blocks_count) -1 ); +cpu_to_le16 (le16_to_cpu (gdp->bg_free_blocks_count)-num);spin_unlock (sb_bgl_lock (sbi, group_no)); -percpu_counter_mod (&sbi->s_freeblocks_counter,-1 ); +percpu_counter_mod (&sbi->s_freeblocks_counter, -num);BUFFER_TRACE (gdp_bh,"journal_dirty_metadata for group descriptor" ); err =ext3_journal_dirty_metadata (handle, gdp_bh);
@@ -1386,6 +1443,8 @@ allocated: goto out; *errp =0 ; +DQUOT_FREE_BLOCK (inode, *count-num); + *count = num;brelse (bitmap_bh);return ret_block;
@@ -1400,7 +1459,7 @@ out:* Undo the block allocation */ if (!performed_allocation) -DQUOT_FREE_BLOCK (inode,1 ); +DQUOT_FREE_BLOCK (inode, *count);brelse (bitmap_bh);return 0 ; }
fs/ext3/inode.c renamed from fs/ext3/inode.c~ext3-get-blocks +365 -15
449 lines not on this page · raw message
fs/ext3/xattr.c renamed from fs/ext3/xattr.c~ext3-get-blocks +2 -1
@@ -796,7 +796,8 @@ inserted: EXT3_SB(sb)->s_es->s_first_data_block) +EXT3_I (inode)->i_block_group *EXT3_BLOCKS_PER_GROUP (sb); -int block =ext3_new_block (handle, inode, goal, &error); +unsigned long count =1 ; +int block =ext3_new_blocks (handle, inode, goal, &count, &error);if (error) goto cleanup;ea_idebug (inode,"creating block %d" , block);
include/linux/ext3_fs.h renamed from include/linux/ext3_fs.h~ext3-get-blocks +1 -1
@@ -729,7 +729,7 @@ struct dir_private_info {/* balloc.c */ extern int ext3_bg_has_super (struct super_block *sb,int group);extern unsigned long ext3_bg_num_gdb (struct super_block *sb,int group); -extern int ext3_new_block (handle_t *,struct inode *,unsigned long ,int *); +extern int ext3_new_blocks (handle_t *,struct inode *,unsigned long ,unsigned long *,int *);extern void ext3_free_blocks (handle_t *,struct inode *,unsigned long ,unsigned long ); extern void ext3_free_blocks_sb (handle_t *, struct super_block *,
_
-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies from IBM. Find simple to follow Roadmaps, straightforward articles, informative Webcasts and more! Get everything you need to get up to speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
cover Multiple block allocation and delayed allocation for ext3
In reply to a message not in the archiveHi All,
Here are the updated patches to support multiple block allocation and delayed allocation for ext3 done by me, Badari and Suparna.
[PATCH 1/4] -- multiple block allocation for current ext3. (ext3_get_blocks()).
[PATCH 2/4] -- adding delayed allocation for writeback mode
[PATCH 3/4] -- generic support for cluster pages together in mapge_writepages() to make use of getblocks()
[PATCH 4/4] -- support multiple block allocation for ext3 writeback mode through writepages().
Have done initial testing on dbench and tiobench on a 2.6.11 version of this patch set. Dbench 8 thread throughput result is increased by 20% with this patch set.
dbench comparison: (ext3-dm represents ext3+thispatchset)
http://www.sudhaa.com/~ram/ols2005presentation/dbench.jpg
tiobench comparison:
http://www.sudhaa.com/~ram/ols2005presentation/tio_seq_write.jpg
Todo:
- bmap() support for delayed allocation
- page reserve flag to indicate the delayed allocation
- ordered mode support for delayed allocation
- "bh" support to enable blocksize = 1k/2k filesystems
Cheers,
Mingming
Re: [RFC] [PATCH 0/4]Multiple block allocation and delayed allocation for ext3
Quoted 4 lines · Mingming Cao
Hi All,
Here are the updated patches to support multiple block allocation and delayed allocation for ext3 done by me, Badari and Suparna.
Patches are against 2.6.13-rc3.
Mingming
-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies from IBM. Find simple to follow Roadmaps, straightforward articles, informative Webcasts and more! Get everything you need to get up to speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
RFC PATCH 2/4 delayed allocation for ext3
In reply to a message not in the archiveHere is the updated patch from Badari for delayed allocation for ext3. Delayed allocation defers block allocation from prepare-write time to page writeout time.
---
linux-2.6.12-ming/fs/buffer.c | 13 +++++++++---- linux-2.6.12-ming/fs/ext3/inode.c | 6 ++++++ linux-2.6.12-ming/fs/ext3/super.c | 14 +++++++++++++- linux-2.6.12-ming/include/linux/ext3_fs.h | 1 + 4 files changed, 29 insertions(+), 5 deletions(-)
include/linux/ext3_fs.h renamed from include/linux/ext3_fs.h~ext3-delalloc +1 -0
@@ -373,6 +373,7 @@ struct ext3_inode {#define EXT3_MOUNT_BARRIER 0x20000/* Use block barriers */ #define EXT3_MOUNT_NOBH 0x40000/* No bufferheads */ #define EXT3_MOUNT_QUOTA 0x80000/* Some quota option set */ +#define EXT3_MOUNT_DELAYED_ALLOC 0xC0000/* Delayed Allocation */ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H
fs/ext3/inode.c renamed from fs/ext3/inode.c~ext3-delalloc +6 -0
@@ -1340,6 +1340,9 @@ static int ext3_prepare_write(struct filhandle_t *handle;int retries =0 ; + +if (test_opt (inode->i_sb,DELAYED_ALLOC )) +return __nobh_prepare_write (page, from, to, ext3_get_block,0 ); retry: handle =ext3_journal_start (inode, needed_blocks);if (IS_ERR (handle)) {
@@ -1439,6 +1442,9 @@ static int ext3_writeback_commit_write(selse ret =generic_commit_write (file, page, from, to); +if (test_opt (inode->i_sb,DELAYED_ALLOC )) +return ret; + ret2 =ext3_journal_stop (handle);if (!ret) ret = ret2;
fs/ext3/super.c renamed from fs/ext3/super.c~ext3-delalloc +13 -1
@@ -585,7 +585,7 @@ enum { Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, - Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, + Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_delayed_alloc, Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
@@ -621,6 +621,7 @@ static match_table_t tokens = { {Opt_noreservation, "noreservation"}, {Opt_noload, "noload"}, {Opt_nobh, "nobh"}, + {Opt_delayed_alloc, "delalloc"}, {Opt_commit, "commit=%u"}, {Opt_journal_update, "journal=update"}, {Opt_journal_inum, "journal=%u"},
@@ -954,6 +955,10 @@ clear_qf_name:case Opt_nobh:set_opt (sbi->s_mount_opt,NOBH );break ; +case Opt_delayed_alloc: +set_opt (sbi->s_mount_opt,NOBH ); +set_opt (sbi->s_mount_opt,DELAYED_ALLOC ); +break ;default :printk (KERN_ERR "EXT3-fs: Unrecognized mount option \"%s\" "
@@ -1612,6 +1617,13 @@ static int ext3_fill_super (struct superclear_opt (sbi->s_mount_opt,NOBH ); } } +if (test_opt (sb,DELAYED_ALLOC )) { +if (!(test_opt (sb,DATA_FLAGS ) ==EXT3_MOUNT_WRITEBACK_DATA )) { +printk (KERN_WARNING "EXT3-fs: Ignoring delall option - " +"its supported only with writeback mode\n" ); +clear_opt (sbi->s_mount_opt,DELAYED_ALLOC ); + } + }/* * The journal_load will have done any necessary log recovery, * so we can safely mount the rest of the filesystem now.
fs/buffer.c renamed from fs/buffer.c~ext3-delalloc +9 -4
@@ -2337,8 +2337,8 @@ static void end_buffer_read_nobh(struct* On entry, the page is fully not uptodate. * On exit the page is fully uptodate in the areas outside (from,to) */ -int nobh_prepare_write (struct page *page,unsigned from,unsigned to, -get_block_t *get_block) +int __nobh_prepare_write (struct page *page,unsigned from,unsigned to, +get_block_t *get_block,int create) {struct inode *inode = page->mapping->host;const unsigned blkbits = inode->i_blkbits;
@@ -2370,10 +2370,8 @@ int nobh_prepare_write(struct page *page block_start <PAGE_CACHE_SIZE ; block_in_page++, block_start += blocksize) {unsigned block_end = block_start + blocksize; -int create; map_bh.b_state =0 ; - create =1 ;if (block_start >= to) create =0 ; ret = get_block(inode, block_in_file + block_in_page,
@@ -2482,6 +2480,13 @@ failed:set_page_dirty (page);return ret; } + +int nobh_prepare_write (struct page *page,unsigned from,unsigned to, +get_block_t *get_block) +{ +return __nobh_prepare_write (page, from, to, get_block,1 ); +} +EXPORT_SYMBOL (nobh_prepare_write); int nobh_commit_write(struct file *file, struct page *page,
_
Re: [Ext2-devel] [RFC] [PATCH 2/4]delayed allocation for ext3
include/linux/ext3_fs.h struct ext3_inode { · line 376
Quoted 5 lines · Mingming Cao
include/linux/ext3_fs.h renamed from include/linux/ext3_fs.h~ext3-delalloc +1
-0@@ -373,6 +373,7 @@ struct ext3_inode {#define EXT3_MOUNT_BARRIER 0x20000/* Use block barriers */ #define EXT3_MOUNT_NOBH 0x40000/* No bufferheads */ #define EXT3_MOUNT_QUOTA 0x80000/* Some quota option set */ +#define EXT3_MOUNT_DELAYED_ALLOC 0xC0000/* Delayed Allocation */
This doesn't make sense. DELAYED_ALLOC == QUOTA | NOBH?
fs/ext3/super.c static match_table_t tokens = { · line 624
Quoted 1 line
fs/ext3/super.c renamed from fs/ext3/super.c~ext3-delalloc +1
-0+ {Opt_delayed_alloc, "delalloc"},
Is this a replacement for Alex's delalloc code? We also use delalloc for that code and if they are not interchangeable it will cause confusion about which one is in use.
fs/ext3/super.c static int ext3_fill_super (struct super · line 1623
Quoted 4 lines
fs/ext3/super.c renamed from fs/ext3/super.c~ext3-delalloc +4
-0+if (test_opt (sb,DELAYED_ALLOC )) { +if (!(test_opt (sb,DATA_FLAGS ) ==EXT3_MOUNT_WRITEBACK_DATA )) { +printk (KERN_WARNING "EXT3-fs: Ignoring delall option - " +"its supported only with writeback mode\n" );
Should be "ignoring delalloc option".
Cheers, Andreas
--
Andreas Dilger
Principal Software Engineer
Cluster File Systems, Inc.
Re: [Ext2-devel] [RFC] [PATCH 2/4]delayed allocation for ext3
Quoted 9 lines · Andreas Dilger
include/linux/ext3_fs.h struct ext3_inode { · line 376
Quoted 5 lines · Mingming Cao
include/linux/ext3_fs.h renamed from include/linux/ext3_fs.h~ext3-delalloc +1
-0@@ -373,6 +373,7 @@ struct ext3_inode {#define EXT3_MOUNT_BARRIER 0x20000/* Use block barriers */ #define EXT3_MOUNT_NOBH 0x40000/* No bufferheads */ #define EXT3_MOUNT_QUOTA 0x80000/* Some quota option set */ +#define EXT3_MOUNT_DELAYED_ALLOC 0xC0000/* Delayed Allocation */ This doesn't make sense.
DELAYED_ALLOC== QUOTA | NOBH?
Ah...:-) Badari used 0x80000 for DELAYED_ALLOC in the previous patch (2.6.11 based).When moving those patches forward to 2.6.13-rc3, we found the conflict with QUOTA, and obviously picked up a wrong value.
Quoted 6 lines
fs/ext3/super.c static match_table_t tokens = { · line 624
Quoted 1 line
fs/ext3/super.c renamed from fs/ext3/super.c~ext3-delalloc +1
-0+ {Opt_delayed_alloc, "delalloc"},Is this a replacement for Alex's delalloc code? We also use delalloc for that code and if they are not interchangeable it will cause confusion about which one is in use.
Okey, will think a new name for this feature to avoid confusion. Alex's delalloc is bond to extent tree structure so it's hard to be adopted directly to the current ext3 layout, so, I'd say this work done by Badari(inspired by Alex's work) is a different implementation.
Quoted 7 lines
fs/ext3/super.c static int ext3_fill_super (struct super · line 1623
Quoted 4 lines
fs/ext3/super.c renamed from fs/ext3/super.c~ext3-delalloc +4
-0+if (test_opt (sb,DELAYED_ALLOC )) { +if (!(test_opt (sb,DATA_FLAGS ) ==EXT3_MOUNT_WRITEBACK_DATA )) { +printk (KERN_WARNING "EXT3-fs: Ignoring delall option - " +"its supported only with writeback mode\n" );Should be "ignoring delalloc option".
Fixed.
Thanks for looking at this.
Mingming
Re: [Ext2-devel] [RFC] [PATCH 2/4]delayed allocation for ext3
In reply to Andreas DilgerQuoted 8 lines · Andreas Dilger
include/linux/ext3_fs.h struct ext3_inode { · line 376
Quoted 5 lines · Mingming Cao
include/linux/ext3_fs.h renamed from include/linux/ext3_fs.h~ext3-delalloc +1
-0@@ -373,6 +373,7 @@ struct ext3_inode {#define EXT3_MOUNT_BARRIER 0x20000/* Use block barriers */ #define EXT3_MOUNT_NOBH 0x40000/* No bufferheads */ #define EXT3_MOUNT_QUOTA 0x80000/* Some quota option set */ +#define EXT3_MOUNT_DELAYED_ALLOC 0xC0000/* Delayed Allocation */ This doesn't make sense.
DELAYED_ALLOC== QUOTA | NOBH?
My fault. I will fix it.
Quoted 7 lines
fs/ext3/super.c static match_table_t tokens = { · line 624
Quoted 2 lines
fs/ext3/super.c renamed from fs/ext3/super.c~ext3-delalloc +1
-0+ {Opt_delayed_alloc, "delalloc"},Is this a replacement for Alex's delalloc code? We also use delalloc for that code and if they are not interchangeable it will cause confusion about which one is in use.
Well, basically "delalloc" concept is same - whether we use it on current ext3 layout or with new extent layout doesn't matter.
Quoted 6 lines
fs/ext3/super.c static int ext3_fill_super (struct super · line 1623
Quoted 4 lines
fs/ext3/super.c renamed from fs/ext3/super.c~ext3-delalloc +4
-0+if (test_opt (sb,DELAYED_ALLOC )) { +if (!(test_opt (sb,DATA_FLAGS ) ==EXT3_MOUNT_WRITEBACK_DATA )) { +printk (KERN_WARNING "EXT3-fs: Ignoring delall option - " +"its supported only with writeback mode\n" );Should be "ignoring delalloc option".
Yep.
Thanks,
Badari
Re: [RFC] [PATCH 2/4]delayed allocation for ext3
In reply to Mingming CaoQuoted 4 lines · Mingming Cao
Here is the updated patch from Badari for delayed allocation for ext3. Delayed allocation defers block allocation from prepare-write time to page writeout time.
For data=writeback only, yes?
fs/ext3/inode.c static int ext3_prepare_write(struct fil · line 1345
Quoted 10 lines
...
fs/ext3/inode.c renamed from fs/ext3/inode.c~ext3-delalloc +3
-0@@ -1340,6 +1340,9 @@ static int ext3_prepare_write(struct filhandle_t *handle;int retries =0 ; + +if (test_opt (inode->i_sb,DELAYED_ALLOC )) +return __nobh_prepare_write (page, from, to, ext3_get_block,0 );
Rather than performing this test on each ->prepare_write(), would it not be better to set up a new set of address_space_operations for this mode?
__nobh_prepare_write() seems like a poor choice of name?
fs/ext3/inode.c static int ext3_writeback_commit_write(s · line 1447
Quoted 10 lines
fs/ext3/inode.c renamed from fs/ext3/inode.c~ext3-delalloc +3
-0retry: handle =ext3_journal_start (inode, needed_blocks);if (IS_ERR (handle)) {@@ -1439,6 +1442,9 @@ static int ext3_writeback_commit_write(selse ret =generic_commit_write (file, page, from, to); +if (test_opt (inode->i_sb,DELAYED_ALLOC )) +return ret; +
Here too, perhaps.
Quoted 9 lines
fs/ext3/inode.c renamed from fs/ext3/inode.c~ext3-delalloc +2
-0+ } + }/* * The journal_load will have done any necessary log recovery, * so we can safely mount the rest of the filesystem now. diff -puN
fs/buffer.c~ext3-delallocfs/buffer.c
fs/buffer.c static void end_buffer_read_nobh(struct · line 2341
Quoted 7 lines
fs/buffer.c renamed from fs/buffer.c~ext3-delalloc +2
-2@@ -2337,8 +2337,8 @@ static void end_buffer_read_nobh(struct* On entry, the page is fully not uptodate. * On exit the page is fully uptodate in the areas outside (from,to) */ -int nobh_prepare_write (struct page *page,unsigned from,unsigned to, -get_block_t *get_block) +int __nobh_prepare_write (struct page *page,unsigned from,unsigned to, +get_block_t *get_block,int create)
Suggest you make this static and update the comment.
Quoted 4 lines
fs/buffer.c renamed from fs/buffer.c~ext3-delalloc +0
-0{struct inode *inode = page->mapping->host;const unsigned blkbits = inode->i_blkbits;
fs/buffer.c int nobh_prepare_write(struct page *page · line 2377
Quoted 10 lines
fs/buffer.c renamed from fs/buffer.c~ext3-delalloc +0
-2@@ -2370,10 +2370,8 @@ int nobh_prepare_write(struct page *page block_start <PAGE_CACHE_SIZE ; block_in_page++, block_start += blocksize) {unsigned block_end = block_start + blocksize; -int create; map_bh.b_state =0 ; - create =1 ;if (block_start >= to) create =0 ; ret = get_block(inode, block_in_file + block_in_page,
What's going on here? Seems that we'll call get_block() with `create=0'. Is there any point in doing that? For delayed allocation we shuld be able to skip get_block() altogether here and, err, delay it.
Quoted 7 lines
fs/buffer.c renamed from fs/buffer.c~ext3-delalloc +6
-0+int nobh_prepare_write (struct page *page,unsigned from,unsigned +get_block_t *get_block) +{ +return __nobh_prepare_write (page, from, to, get_block,1 ); +} +
EXPORT_SYMBOL(nobh_prepare_write);
Here you add nobh_dalloc_prepare_write() and remember to export it to modules this time ;)
Re: [RFC] [PATCH 2/4]delayed allocation for ext3
Quoted 7 lines · Andrew Morton
Quoted 4 lines · Mingming Cao
Here is the updated patch from Badari for delayed allocation for ext3. Delayed allocation defers block allocation from prepare-write time to page writeout time.
For data=writeback only, yes?
Yes.
Quoted 8 lines
Quoted 8 lines
...
fs/ext3/inode.c renamed from fs/ext3/inode.c~ext3-delalloc +0
-0@@ -1340,6 +1340,9 @@ static int ext3_prepare_write(struct filhandle_t *handle;int retries =0 ;
Quoted 8 lines
fs/ext3/inode.c static int ext3_prepare_write(struct fil · line 1345
Quoted 3 lines
fs/ext3/inode.c renamed from fs/ext3/inode.c~ext3-delalloc +3
-0+ +if (test_opt (inode->i_sb,DELAYED_ALLOC )) +return __nobh_prepare_write (page, from, to, ext3_get_block,0 );Rather than performing this test on each ->prepare_write(), would it not be better to set up a new set of
address_space_operationsfor this mode?
__nobh_prepare_write()seems like a poor choice of name?
You are correct. I was trying to minimize the changes to interfaces. Once we get it working, I will do it as part of cleanups.
Quoted 24 lines
fs/ext3/inode.c static int ext3_writeback_commit_write(s · line 1447
Quoted 11 lines
fs/ext3/inode.c renamed from fs/ext3/inode.c~ext3-delalloc +3
-0retry: handle =ext3_journal_start (inode, needed_blocks);if (IS_ERR (handle)) {@@ -1439,6 +1442,9 @@ static int ext3_writeback_commit_write(selse ret =generic_commit_write (file, page, from, to); +if (test_opt (inode->i_sb,DELAYED_ALLOC )) +return ret; +Here too, perhaps.
Quoted 10 lines
fs/ext3/inode.c renamed from fs/ext3/inode.c~ext3-delalloc +2
-0+ } + }/* * The journal_load will have done any necessary log recovery, * so we can safely mount the rest of the filesystem now. diff -puN
fs/buffer.c~ext3-delallocfs/buffer.cfs/buffer.c renamed from fs/buffer.c~ext3-delalloc +0
-0@@ -2337,8 +2337,8 @@ static void end_buffer_read_nobh(struct* On entry, the page is fully not uptodate.
Quoted 9 lines
fs/buffer.c static void end_buffer_read_nobh(struct · line 2341
Quoted 6 lines
fs/buffer.c renamed from fs/buffer.c~ext3-delalloc +2
-2* On exit the page is fully uptodate in the areas outside (from,to) */ -int nobh_prepare_write (struct page *page,unsigned from,unsigned to, -get_block_t *get_block) +int __nobh_prepare_write (struct page *page,unsigned from,unsigned to, +get_block_t *get_block,int create)Suggest you make this static and update the comment.
Sure.
Quoted 9 lines
Quoted 9 lines
fs/buffer.c renamed from fs/buffer.c~ext3-delalloc +0
-1{struct inode *inode = page->mapping->host;const unsigned blkbits = inode->i_blkbits;@@ -2370,10 +2370,8 @@ int nobh_prepare_write(struct page *page block_start <PAGE_CACHE_SIZE ; block_in_page++, block_start += blocksize) {unsigned block_end = block_start + blocksize; -int create;
Quoted 9 lines
fs/buffer.c int nobh_prepare_write(struct page *page · line 2377
Quoted 5 lines
fs/buffer.c renamed from fs/buffer.c~ext3-delalloc +0
-1map_bh.b_state =0 ; - create =1 ;if (block_start >= to) create =0 ; ret = get_block(inode, block_in_file + block_in_page,What's going on here? Seems that we'll call
get_block()with `create=0'. Is there any point in doing that? For delayed allocation we shuld be able to skipget_block()altogether here and, err, delay it.
For delayed allocation, I need to delay the block allocation - but I still need to do get_block(READ) and read the data from the block - if the block already exists.
Quoted 12 lines
Quoted 8 lines
fs/buffer.c renamed from fs/buffer.c~ext3-delalloc +6
-0+int nobh_prepare_write (struct page *page,unsigned from,unsigned +get_block_t *get_block) +{ +return __nobh_prepare_write (page, from, to, get_block,1 ); +} +
EXPORT_SYMBOL(nobh_prepare_write);Here you add
nobh_dalloc_prepare_write()and remember to export it to modules this time ;)
Will do.
Thanks,
Badari
-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies from IBM. Find simple to follow Roadmaps, straightforward articles, informative Webcasts and more! Get everything you need to get up to speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
RFC PATCH 3/4 generic getblocks() support in mpage_writepages
In reply to a message not in the archiveUpdated patch from Suparna for generic support for cluster pages together in mapge_writepages() to make use of getblocks()
---
linux-2.6.12-ming/fs/buffer.c | 49 ----- linux-2.6.12-ming/fs/ext2/inode.c | 15 - linux-2.6.12-ming/fs/ext3/inode.c | 15 + linux-2.6.12-ming/fs/ext3/super.c | 3 linux-2.6.12-ming/fs/hfs/inode.c | 2 linux-2.6.12-ming/fs/hfsplus/inode.c | 2 linux-2.6.12-ming/fs/jfs/inode.c | 24 ++ linux-2.6.12-ming/fs/mpage.c | 214 ++++++++++++++++++-------- linux-2.6.12-ming/include/linux/buffer_head.h | 4 linux-2.6.12-ming/include/linux/fs.h | 2 linux-2.6.12-ming/include/linux/mpage.h | 11 - linux-2.6.12-ming/include/linux/pagemap.h | 3 linux-2.6.12-ming/include/linux/pagevec.h | 3 linux-2.6.12-ming/include/linux/radix-tree.h | 14 + linux-2.6.12-ming/lib/radix-tree.c | 25 ++- linux-2.6.12-ming/mm/filemap.c | 9 - linux-2.6.12-ming/mm/swap.c | 11 + 17 files changed, 270 insertions(+), 136 deletions(-)
fs/buffer.c renamed from fs/buffer.c~mpage_writepages_getblocks +3 -46
@@ -2509,53 +2509,10 @@ EXPORT_SYMBOL(nobh_commit_write);* that it tries to operate without attaching bufferheads to * the page. */ -int nobh_writepage (struct page *page,get_block_t *get_block, -struct writeback_control *wbc) +int nobh_writepage (struct page *page,get_blocks_t *get_blocks, +struct writeback_control *wbc,writepage_t bh_writepage_fn) { -struct inode *const inode = page->mapping->host; -loff_t i_size =i_size_read (inode); -const pgoff_t end_index = i_size >>PAGE_CACHE_SHIFT ; -unsigned offset; -void *kaddr; -int ret; - -/* Is the page fully inside i_size? */ -if (page->index < end_index) - goto out; - -/* Is the page fully outside i_size? (truncate in progress) */ - offset = i_size & (PAGE_CACHE_SIZE -1 ); -if (page->index >= end_index+1 || !offset) { -/* -* The page may have dirty, unmapped buffers. For example, -* they may have been added in ext3_writepage(). Make them -* freeable here, so the page does not leak. -*/ -#if 0 -/* Not really sure about this - do we need this ? */ -if (page->mapping->a_ops->invalidatepage) - page->mapping->a_ops->invalidatepage (page, offset); -#endif -unlock_page (page); -return 0 ;/* don't care */ - } - -/* -* The page straddles i_size. It must be zeroed out on each and every -* writepage invocation because it may be mmapped. "A file is mapped -* in multiples of the page size. For a file that is not a multiple of -* the page size, the remaining memory is zeroed when mapped, and -* writes to that region are not written out to the file." -*/ - kaddr =kmap_atomic (page,KM_USER0 ); -memset (kaddr + offset,0 ,PAGE_CACHE_SIZE - offset); -flush_dcache_page (page); -kunmap_atomic (kaddr,KM_USER0 ); -out: - ret =mpage_writepage (page, get_block, wbc); -if (ret == -EAGAIN ) - ret =__block_write_full_page (inode, page, get_block, wbc); -return ret; +return mpage_writepage (page, get_blocks, wbc, bh_writepage_fn); }EXPORT_SYMBOL (nobh_writepage);
fs/ext2/inode.c renamed from fs/ext2/inode.c~mpage_writepages_getblocks +8 -7
@@ -650,12 +650,6 @@ ext2_nobh_prepare_write(struct file *filreturn nobh_prepare_write (page,from,to,ext2_get_block); } -static int ext2_nobh_writepage (struct page *page, -struct writeback_control *wbc) -{ -return nobh_writepage (page, ext2_get_block, wbc); -} -static sector_t ext2_bmap (struct address_space *mapping,sector_t block) {return generic_block_bmap (mapping,block,ext2_get_block);
@@ -673,6 +667,12 @@ ext2_get_blocks(struct inode *inode, secreturn ret; } +static int ext2_nobh_writepage (struct page *page, +struct writeback_control *wbc) +{ +return nobh_writepage (page, ext2_get_blocks, wbc, ext2_writepage); +} +static ssize_t ext2_direct_IO (int rw,struct kiocb *iocb,const struct iovec *iov,loff_t offset,unsigned long nr_segs)
@@ -687,7 +687,8 @@ ext2_direct_IO(int rw, struct kiocb *iocstatic int ext2_writepages (struct address_space *mapping,struct writeback_control *wbc) { -return mpage_writepages (mapping, wbc, ext2_get_block); +return __mpage_writepages (mapping, wbc, ext2_get_blocks, + ext2_writepage); }struct address_space_operations ext2_aops = {
fs/ext3/super.c renamed from fs/ext3/super.c~mpage_writepages_getblocks +3 -0
@@ -1353,6 +1353,7 @@ static int ext3_fill_super (struct super sbi->s_resgid =le16_to_cpu (es->s_def_resgid);set_opt (sbi->s_mount_opt,RESERVATION ); +set_opt (sbi->s_mount_opt,NOBH );/* temp: set nobh default */ if (!parse_options ((char *) data, sb, &journal_inum,NULL ,0 )) goto failed_mount;
@@ -1599,6 +1600,7 @@ static int ext3_fill_super (struct superprintk (KERN_ERR "EXT3-fs: Journal does not support " "requested data journaling mode\n" ); goto failed_mount3; +set_opt (sbi->s_mount_opt,NOBH );/* temp: set nobh default */ }default :break ;
@@ -1616,6 +1618,7 @@ static int ext3_fill_super (struct super "its supported only with writeback mode\n");clear_opt (sbi->s_mount_opt,NOBH ); } +printk ("NOBH option set\n" ); }if (test_opt (sb,DELAYED_ALLOC )) {if (!(test_opt (sb,DATA_FLAGS ) ==EXT3_MOUNT_WRITEBACK_DATA )) {
fs/ext3/inode.c renamed from fs/ext3/inode.c~mpage_writepages_getblocks +14 -1
@@ -1195,6 +1195,11 @@ get_block: } +static int ext3_writepages_get_blocks (struct inode *inode,sector_t iblock, +unsigned long max_blocks,struct buffer_head *bh,int create) +{ +return ext3_direct_io_get_blocks (inode, iblock, max_blocks, bh, create); +}/* * `handle' can be NULL if create is zero */
@@ -1674,6 +1679,13 @@ out_fail:return ret; } +static int +ext3_writeback_writepage_helper (struct page *page, +struct writeback_control *wbc) +{ +return block_write_full_page (page, ext3_get_block, wbc); +} +static int ext3_writeback_writepage (struct page *page,struct writeback_control *wbc) {
@@ -1692,7 +1704,8 @@ static int ext3_writeback_writepage(stru }if (test_opt (inode->i_sb,NOBH )) - ret =nobh_writepage (page, ext3_get_block, wbc); + ret =nobh_writepage (page, ext3_writepages_get_blocks, wbc, + ext3_writeback_writepage_helper);else ret =block_write_full_page (page, ext3_get_block, wbc);
fs/hfs/inode.c renamed from fs/hfs/inode.c~mpage_writepages_getblocks +1 -1
@@ -124,7 +124,7 @@ static ssize_t hfs_direct_IO(int rw, strstatic int hfs_writepages (struct address_space *mapping,struct writeback_control *wbc) { -return mpage_writepages (mapping, wbc, hfs_get_block); +return mpage_writepages (mapping, wbc, hfs_get_blocks); }struct address_space_operations hfs_btree_aops = {
fs/hfsplus/inode.c renamed from fs/hfsplus/inode.c~mpage_writepages_getblocks +1 -1
@@ -121,7 +121,7 @@ static ssize_t hfsplus_direct_IO(int rw,static int hfsplus_writepages (struct address_space *mapping,struct writeback_control *wbc) { -return mpage_writepages (mapping, wbc, hfsplus_get_block); +return mpage_writepages (mapping, wbc, hfsplus_get_blocks); }struct address_space_operations hfsplus_btree_aops = {
fs/jfs/inode.c renamed from fs/jfs/inode.c~mpage_writepages_getblocks +22 -2
@@ -249,21 +249,41 @@ jfs_get_blocks(struct inode *ip, sector_return rc; } +static int +jfs_mpage_get_blocks (struct inode *ip,sector_t lblock,unsigned long + max_blocks,struct buffer_head *bh_result,int create) +{ +/* +* fixme: temporary workaround: return one block at a time until +* we figure out why we see exposures with truncate on +* allocating multiple blocks in one shot. +*/ +return jfs_get_blocks (ip, lblock,1 , bh_result, create); +} +static int jfs_get_block (struct inode *ip,sector_t lblock,struct buffer_head *bh_result,int create) {return jfs_get_blocks (ip, lblock,1 , bh_result, create); } +static int jfs_bh_writepage (struct page *page, +struct writeback_control *wbc) +{ +return block_write_full_page (page, jfs_get_block, wbc); +} + +static int jfs_writepage (struct page *page,struct writeback_control *wbc) { -return nobh_writepage (page, jfs_get_block, wbc); +return nobh_writepage (page, jfs_mpage_get_blocks, wbc, jfs_bh_writepage); }static int jfs_writepages (struct address_space *mapping,struct writeback_control *wbc) { -return mpage_writepages (mapping, wbc, jfs_get_block); +return __mpage_writepages (mapping, wbc, jfs_mpage_get_blocks, + jfs_bh_writepage); }static int jfs_readpage (struct file *file,struct page *page)
fs/mpage.c renamed from fs/mpage.c~mpage_writepages_getblocks +155 -59
353 lines not on this page · raw message
include/linux/buffer_head.h renamed from include/linux/buffer_head.h~mpage_writepages_getblocks +2 -2
@@ -206,8 +206,8 @@ int file_fsync(struct file *, struct denint nobh_prepare_write (struct page *,unsigned ,unsigned ,get_block_t *);int nobh_commit_write (struct file *,struct page *,unsigned ,unsigned );int nobh_truncate_page (struct address_space *,loff_t ); -int nobh_writepage (struct page *page,get_block_t *get_block, -struct writeback_control *wbc); +int nobh_writepage (struct page *page,get_blocks_t *get_blocks, +struct writeback_control *wbc,writepage_t bh_writepage);/*
include/linux/fs.h renamed from include/linux/fs.h~mpage_writepages_getblocks +2 -0
@@ -305,6 +305,8 @@ struct page;struct address_space ;struct writeback_control ; +typedef int (writepage_t )(struct page *page,struct writeback_control *wbc); +struct address_space_operations {int (*writepage)(struct page *page,struct writeback_control *wbc);int (*readpage)(struct file *,struct page *);
include/linux/mpage.h renamed from include/linux/mpage.h~mpage_writepages_getblocks +7 -4
@@ -11,15 +11,18 @@*/ struct writeback_control ; -typedef int (writepage_t )(struct page *page,struct writeback_control *wbc);int mpage_readpages (struct address_space *mapping,struct list_head *pages,unsigned nr_pages,get_block_t get_block);int mpage_readpage (struct page *page,get_block_t get_block); +int mpage_writepages (struct address_space *mapping, -struct writeback_control *wbc,get_block_t get_block); -int mpage_writepage (struct page *page,get_block_t *get_block, -struct writeback_control *wbc); +struct writeback_control *wbc,get_blocks_t get_blocks); +int mpage_writepage (struct page *page,get_blocks_t *get_blocks, +struct writeback_control *wbc,writepage_t writepage); +int __mpage_writepages (struct address_space *mapping, +struct writeback_control *wbc,get_blocks_t get_blocks, +writepage_t writepage);static inline int generic_writepages (struct address_space *mapping,struct writeback_control *wbc)
include/linux/pagemap.h renamed from include/linux/pagemap.h~mpage_writepages_getblocks +2 -1
@@ -73,7 +73,8 @@ extern struct page * find_or_create_pageunsigned find_get_pages (struct address_space *mapping,pgoff_t start,unsigned int nr_pages,struct page **pages);unsigned find_get_pages_tag (struct address_space *mapping,pgoff_t *index, -int tag,unsigned int nr_pages,struct page **pages); +int tag,unsigned int nr_pages,struct page **pages, +int contig);/* * Returns locked page at given index in given cache, creating it if needed.
include/linux/pagevec.h renamed from include/linux/pagevec.h~mpage_writepages_getblocks +3 -0
@@ -28,6 +28,9 @@ unsigned pagevec_lookup(struct pagevec *unsigned pagevec_lookup_tag (struct pagevec *pvec,struct address_space *mapping,pgoff_t *index,int tag,unsigned nr_pages); +unsigned pagevec_contig_lookup_tag (struct pagevec *pvec, +struct address_space *mapping,pgoff_t *index,int tag, +unsigned nr_pages);static inline void pagevec_init (struct pagevec *pvec,int cold) {
include/linux/radix-tree.h renamed from include/linux/radix-tree.h~mpage_writepages_getblocks +12 -2
@@ -59,8 +59,18 @@ void *radix_tree_tag_clear(struct radix_int radix_tree_tag_get (struct radix_tree_root *root,unsigned long index,int tag);unsigned int -radix_tree_gang_lookup_tag (struct radix_tree_root *root,void **results, -unsigned long first_index,unsigned int max_items,int tag); +__radix_tree_gang_lookup_tag (struct radix_tree_root *root,void **results, +unsigned long first_index,unsigned int max_items,int tag, +int contig); + +static inline unsigned int radix_tree_gang_lookup_tag (struct radix_tree_root + *root,void **results,unsigned long first_index, +unsigned int max_items,int tag) +{ +return __radix_tree_gang_lookup_tag (root, results, first_index, + max_items, tag,0 ); +} +int radix_tree_tagged (struct radix_tree_root *root,int tag);static inline void radix_tree_preload_end (void )
lib/radix-tree.c renamed from lib/radix-tree.c~mpage_writepages_getblocks +19 -6
@@ -557,12 +557,13 @@ EXPORT_SYMBOL(radix_tree_gang_lookup);*/ static unsigned int __lookup_tag (struct radix_tree_root *root,void **results,unsigned long index, -unsigned int max_items,unsigned long *next_index,int tag) +unsigned int max_items,unsigned long *next_index,int tag,int contig) {unsigned int nr_found =0 ;unsigned int shift;unsigned int height = root->height;struct radix_tree_node *slot; +unsigned long cindex = (contig && (*next_index)) ? *next_index :-1 ; shift = (height -1 ) *RADIX_TREE_MAP_SHIFT ; slot = root->rnode;
@@ -575,6 +576,11 @@ __lookup_tag(struct radix_tree_root *rooBUG_ON (slot->slots[i] ==NULL );break ; } +if (contig && index >= cindex) { +/* break in contiguity */ + index =0 ; + goto out; + } index &= ~((1UL << shift) -1 ); index +=1UL << shift;if (index ==0 )
@@ -593,6 +599,10 @@ __lookup_tag(struct radix_tree_root *roo results[nr_found++] = slot->slots[j];if (nr_found == max_items) goto out; + }else if (contig && nr_found) { +/* break in contiguity */ + index =0 ; + goto out; } } }
@@ -618,29 +628,32 @@ out:* returns the number of items which were placed at *@results. */ unsigned int -radix_tree_gang_lookup_tag (struct radix_tree_root *root,void **results, -unsigned long first_index,unsigned int max_items,int tag) +__radix_tree_gang_lookup_tag (struct radix_tree_root *root,void **results, +unsigned long first_index,unsigned int max_items,int tag, +int contig) {const unsigned long max_index =radix_tree_maxindex (root->height);unsigned long cur_index = first_index; +unsigned long next_index =0 ;/* Index of next contiguous search */ unsigned int ret =0 ;while (ret < max_items) {unsigned int nr_found; -unsigned long next_index;/* Index of next search */ if (cur_index > max_index)break ; nr_found =__lookup_tag (root, results + ret, cur_index, - max_items - ret, &next_index, tag); + max_items - ret, &next_index, tag, contig); ret += nr_found;if (next_index ==0 )break ; cur_index = next_index; +if (!nr_found) + next_index =0 ; }return ret; } -EXPORT_SYMBOL (radix_tree_gang_lookup_tag); +EXPORT_SYMBOL (__radix_tree_gang_lookup_tag);/** * radix_tree_delete - delete an item from a radix tree
mm/filemap.c renamed from mm/filemap.c~mpage_writepages_getblocks +6 -3
@@ -649,16 +649,19 @@ unsigned find_get_pages(struct address_s/* * Like find_get_pages, except we only return pages which are tagged with * `tag'. We update *index to index the next page for the traversal. +* If 'contig' is 1, then we return only pages which are contiguous in the +* file. */ unsigned find_get_pages_tag (struct address_space *mapping,pgoff_t *index, -int tag,unsigned int nr_pages,struct page **pages) +int tag,unsigned int nr_pages,struct page **pages, +int contig) {unsigned int i;unsigned int ret;read_lock_irq (&mapping->tree_lock); - ret =radix_tree_gang_lookup_tag (&mapping->page_tree, - (void **)pages, *index, nr_pages, tag); + ret =__radix_tree_gang_lookup_tag (&mapping->page_tree, + (void **)pages, *index, nr_pages, tag, contig);for (i =0 ; i < ret; i++)page_cache_get (pages[i]);if (ret)
mm/swap.c renamed from mm/swap.c~mpage_writepages_getblocks +10 -1
@@ -384,7 +384,16 @@ unsigned pagevec_lookup_tag(struct pagev pgoff_t *index, int tag, unsigned nr_pages) { pvec->nr = find_get_pages_tag(mapping, index, tag, - nr_pages, pvec->pages); + nr_pages, pvec->pages,0 ); +return pagevec_count (pvec); +} + +unsigned int +pagevec_contig_lookup_tag (struct pagevec *pvec,struct address_space *mapping, +pgoff_t *index,int tag,unsigned nr_pages) +{ + pvec->nr =find_get_pages_tag (mapping, index, tag, + nr_pages, pvec->pages,1 );return pagevec_count (pvec); }
_
-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies from IBM. Find simple to follow Roadmaps, straightforward articles, informative Webcasts and more! Get everything you need to get up to speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
RFC PATCH 4/4 add ext3 writeback writpages
In reply to a message not in the archivesupport multiple block allocation for ext3 writeback mode through writepages().
---
linux-2.6.12-ming/fs/ext3/inode.c | 131 ++++++++++++++++++++++++++++++++ linux-2.6.12-ming/fs/mpage.c | 8 + linux-2.6.12-ming/include/linux/mpage.h | 17 ++++ 3 files changed, 153 insertions(+), 3 deletions(-)
fs/ext3/inode.c renamed from fs/ext3/inode.c~writepages +131 -0
@@ -36,6 +36,7 @@#include <linux/writeback.h> #include <linux/mpage.h> #include <linux/uio.h> +#include <linux/pagevec.h> #include "xattr.h" #include "acl.h"
@@ -1719,6 +1720,135 @@ out_fail:return ret; } +static int +ext3_writeback_writepages (struct address_space *mapping, +struct writeback_control *wbc) +{ +struct inode *inode = mapping->host; +const unsigned blkbits = inode->i_blkbits; +int err =0 ; +int ret =0 ; +int done =0 ; +unsigned int max_pages_to_cluster =0 ; +struct pagevec pvec; +int nr_pages; +pgoff_t index; +pgoff_t end =-1 ;/* Inclusive */ +int scanned =0 ; +int is_range =0 ; +struct page *page; +struct mpageio mio = { + .bio =NULL + }; + +pagevec_init (&pvec,0 ); +if (wbc->sync_mode ==WB_SYNC_NONE ) { + index = mapping->writeback_index;/* Start from prev offset */ + }else { + index =0 ;/* whole-file sweep */ + scanned =1 ; + } +if (wbc->start || wbc->end) { + index = wbc->start >>PAGE_CACHE_SHIFT ; + end = wbc->end >>PAGE_CACHE_SHIFT ; + is_range =1 ; + scanned =1 ; + } + max_pages_to_cluster =min (EXT3_MAX_TRANS_DATA , (pgoff_t )PAGEVEC_SIZE ); + +retry: +down_read (&inode->i_alloc_sem); +while (!done && (index <= end) && + (nr_pages =pagevec_contig_lookup_tag (&pvec, mapping, + &index,PAGECACHE_TAG_DIRTY , +min (end - index, max_pages_to_cluster-1 ) +1 ))) { +unsigned i; + + scanned =1 ; +for (i =0 ; i < nr_pages; i++) { + page = pvec.pages[i]; + +lock_page (page); + +if (unlikely (page->mapping != mapping)) { +unlock_page (page); +break ; + } + +if (unlikely (is_range) && page->index > end) { +unlock_page (page); +break ; + } + +if (wbc->sync_mode !=WB_SYNC_NONE ) +wait_on_page_writeback (page); + +if (PageWriteback (page) || + !clear_page_dirty_for_io (page)) { +unlock_page (page); +break ; + } + } + +if (i) { +unsigned j; +handle_t *handle; + + page = pvec.pages[i-1 ]; + index = page->index +1 ; + mio.final_block_in_request = +min (index, end) << (PAGE_CACHE_SHIFT - blkbits); + + handle =ext3_journal_start (inode, + i +ext3_writepage_trans_blocks (inode)); + +if (IS_ERR (handle)) { + err =PTR_ERR (handle); + done =1 ; + } +for (j =0 ; j < i; j++) { + page = pvec.pages[j]; +if (!done) { + ret =__mpage_writepage (&mio, page, + ext3_writepages_get_blocks, wbc, + ext3_writeback_writepage_helper); +if (ret || (--(wbc->nr_to_write) <=0 )) + done =1 ; + }else { +redirty_page_for_writepage (wbc, page); +unlock_page (page); + } + } +if (!err && mio.bio) + mio.bio =mpage_bio_submit (WRITE , mio.bio); +if (!err) + err =ext3_journal_stop (handle); +if (!ret) { + ret = err; +if (ret) + done =1 ; + } + } +pagevec_release (&pvec); +cond_resched (); + } + +up_read (&inode->i_alloc_sem); + +if (!scanned && !done) { +/* +* We hit the last page and there is more work to be done: wrap +* back to the start of the file +*/ + scanned =1 ; + index =0 ; + goto retry; + } +if (!is_range) + mapping->writeback_index = index; +return ret; +} +static int ext3_journalled_writepage (struct page *page,struct writeback_control *wbc) {
@@ -1923,6 +2053,7 @@ static struct address_space_operations e .readpage = ext3_readpage, .readpages = ext3_readpages, .writepage = ext3_writeback_writepage, + .writepages = ext3_writeback_writepages, .sync_page = block_sync_page, .prepare_write = ext3_prepare_write, .commit_write = ext3_writeback_commit_write,
fs/mpage.c renamed from fs/mpage.c~writepages +5 -3
@@ -90,7 +90,7 @@ static int mpage_end_io_write(struct bioreturn 0 ; } -static struct bio *mpage_bio_submit (int rw,struct bio *bio) +struct bio *mpage_bio_submit (int rw,struct bio *bio) { bio->bi_end_io = mpage_end_io_read;if (rw ==WRITE )
@@ -373,6 +373,7 @@ int mpage_readpage(struct page *page, ge }EXPORT_SYMBOL (mpage_readpage); +#if 0 struct mpageio { struct bio *bio; struct buffer_head map_bh;
@@ -383,6 +384,7 @@ struct mpageio {sector_t boundary_block; struct block_device *boundary_bdev; }; +#endif /* * Maps as many contiguous disk blocks as it can within the range of
@@ -450,7 +452,7 @@ static unsigned long mpage_get_more_bloc* written, so it can intelligently allocate a suitably-sized BIO. For now, * just allocate full-size (16-page) BIOs. */ -static int +int __mpage_writepage (struct mpageio *mio,struct page *page,get_blocks_t get_blocks,struct writeback_control *wbc,writepage_t writepage_fn)
@@ -532,7 +534,7 @@ __mpage_writepage(struct mpageio *mio, s*/ BUG_ON (!PageUptodate (page)); block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits); - last_block = (i_size -1 ) >> blkbits; + last_block = (i_size) >> blkbits; blocks_to_skip = block_in_file - mio->block_in_file; mio->block_in_file = block_in_file;if (blocks_to_skip < (map_bh->b_size >> blkbits)) {
include/linux/mpage.h renamed from include/linux/mpage.h~writepages +17 -0
@@ -9,9 +9,23 @@* (And no, it doesn't do the #ifdef __MPAGE_H thing, and it doesn't do * nested includes. Get it right in the .c file). */ +#ifndef _LINUX_BUFFER_HEAD_H +#include <linux/buffer_head.h> +#endif struct writeback_control ; +struct mpageio { +struct bio *bio; +struct buffer_head map_bh; +unsigned long block_in_file; +unsigned long final_block_in_request; +sector_t block_in_bio; +int boundary; +sector_t boundary_block; +struct block_device *boundary_bdev; +}; +int mpage_readpages (struct address_space *mapping,struct list_head *pages,unsigned nr_pages,get_block_t get_block);int mpage_readpage (struct page *page,get_block_t get_block);
@@ -23,6 +37,9 @@ int mpage_writepage(struct page *page, gint __mpage_writepages (struct address_space *mapping,struct writeback_control *wbc,get_blocks_t get_blocks,writepage_t writepage); +int __mpage_writepage (struct mpageio *mio,struct page *page, +get_blocks_t get_blocks,struct writeback_control *wbc, +writepage_t writepage_fn);static inline int generic_writepages (struct address_space *mapping,struct writeback_control *wbc)
_
-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies from IBM. Find simple to follow Roadmaps, straightforward articles, informative Webcasts and more! Get everything you need to get up to speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click