set_blocksize: Allow to set a larger block size than PAGE_SIZE set_blocksize is changed to allow to specify a blocksize larger than a page. If that occurs then we switch the device to use compound pages. Signed-off-by: Christoph Lameter --- fs/block_dev.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++------- fs/buffer.c | 12 +++++------- fs/inode.c | 7 +++++++ 3 files changed, 60 insertions(+), 14 deletions(-) Index: linux-2.6.21-rc7-mm2/fs/block_dev.c =================================================================== --- linux-2.6.21-rc7-mm2.orig/fs/block_dev.c 2007-04-27 15:27:37.000000000 -0700 +++ linux-2.6.21-rc7-mm2/fs/block_dev.c 2007-04-27 16:04:58.000000000 -0700 @@ -65,12 +65,41 @@ static void kill_bdev(struct block_devic return; invalidate_bh_lrus(); truncate_inode_pages(bdev->bd_inode->i_mapping, 0); -} +} + +#ifdef CONFIG_LARGE_BLOCKSIZE + +static int page_cache_min_order = 0; +static int page_cache_max_order = 4; /* 64k */ + +static int __init setup_page_cache_min_order(char *str) +{ + get_option (&str, &page_cache_min_order); + return 1; +} + +__setup("page_cache_min_order=", setup_page_cache_min_order); + +static int __init setup_page_cache_max_order(char *str) +{ + get_option (&str, &page_cache_max_order); + return 1; +} + +__setup("page_cache_max_order=", setup_page_cache_max_order); +#else + +#define page_cache_min_order 0 +#define page_cache_max_order 0 + +#endif int set_blocksize(struct block_device *bdev, int size) { - /* Size must be a power of two, and between 512 and PAGE_SIZE */ - if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size)) + if (size < 512 || !is_power_of_2(size)) + return -EINVAL; + + if (size > (PAGE_SIZE << page_cache_max_order)) return -EINVAL; /* Size cannot be smaller than the size supported by the device */ @@ -79,10 +108,20 @@ int set_blocksize(struct block_device *b /* Don't change the size if it is same as current */ if (bdev->bd_block_size != size) { + int bits = blksize_bits(size); + int order; + struct address_space *mapping = + bdev->bd_inode->i_mapping; + sync_blockdev(bdev); - bdev->bd_block_size = size; - bdev->bd_inode->i_blkbits = blksize_bits(size); kill_bdev(bdev); + bdev->bd_block_size = size; + bdev->bd_inode->i_blkbits = bits; + if (bits < PAGE_SHIFT + page_cache_min_order) + order = page_cache_min_order; + else + order = bits - PAGE_SHIFT; + set_mapping_order(mapping, order); } return 0; } @@ -93,8 +132,10 @@ int sb_set_blocksize(struct super_block { if (set_blocksize(sb->s_bdev, size)) return 0; - /* If we get here, we know size is power of two - * and it's value is between 512 and PAGE_SIZE */ + /* + * If we get here, we know size is power of two + * and it's value is valid for the page cache + */ sb->s_blocksize = size; sb->s_blocksize_bits = blksize_bits(size); return sb->s_blocksize; Index: linux-2.6.21-rc7-mm2/fs/buffer.c =================================================================== --- linux-2.6.21-rc7-mm2.orig/fs/buffer.c 2007-04-27 15:44:41.000000000 -0700 +++ linux-2.6.21-rc7-mm2/fs/buffer.c 2007-04-27 15:52:06.000000000 -0700 @@ -1086,7 +1086,7 @@ __getblk_slow(struct block_device *bdev, { /* Size must be multiple of hard sectorsize */ if (unlikely(size & (bdev_hardsect_size(bdev)-1) || - (size < 512 || size > PAGE_SIZE))) { + !page_cache_valid_blocksize(size))) { printk(KERN_ERR "getblk(): invalid block size %d requested\n", size); printk(KERN_ERR "hardsect size: %d\n", @@ -2101,20 +2101,18 @@ int cont_prepare_write(struct page *page page_cache_release(new_page); continue; } - zerofrom = page_cache_offset(*bytes); + zerofrom = page_cache_offset(mapping, *bytes); if (zerofrom & (blocksize-1)) { *bytes |= (blocksize-1); (*bytes)++; } status = __block_prepare_write(inode, new_page, zerofrom, - page_cache_size(mapping), get_block); + page_size, get_block); if (status) goto out_unmap; zero_user_page(page, zerofrom, - page_cache_size(mapping) - zerofrom, - KM_USER0); - generic_commit_write(NULL, new_page, zerofrom, - page_cache_size(mapping)); + page_size - zerofrom, KM_USER0); + generic_commit_write(NULL, new_page, zerofrom, page_size); unlock_page(new_page); page_cache_release(new_page); } Index: linux-2.6.21-rc7-mm2/fs/inode.c =================================================================== --- linux-2.6.21-rc7-mm2.orig/fs/inode.c 2007-04-27 15:27:37.000000000 -0700 +++ linux-2.6.21-rc7-mm2/fs/inode.c 2007-04-27 15:52:06.000000000 -0700 @@ -155,6 +155,13 @@ static struct inode *alloc_inode(struct mapping->host = inode; mapping->flags = 0; mapping_set_gfp_mask(mapping, GFP_HIGH_MOVABLE); + + if (inode->i_blkbits > PAGE_SHIFT) + set_mapping_order(mapping, + inode->i_blkbits - PAGE_SHIFT); + else + set_mapping_order(mapping, 0); + mapping->assoc_mapping = NULL; mapping->backing_dev_info = &default_backing_dev_info;