Quick because it uses ->data pointer. Otherwise it is more complete than the minix conversion because it implements fsb_extentmap but minix doesn't. --- fs/ext2/balloc.c | 173 ++++++++++++---------- fs/ext2/dir.c | 8 - fs/ext2/ext2.h | 11 - fs/ext2/file.c | 16 +- fs/ext2/fsync.c | 4 fs/ext2/ialloc.c | 81 +++++----- fs/ext2/inode.c | 348 ++++++++++++++++++++++++--------------------- fs/ext2/namei.c | 13 - fs/ext2/super.c | 163 +++++---------------- fs/ext2/xattr.c | 144 +++++++++--------- fs/ext2/xip.c | 14 - include/linux/ext2_fs_sb.h | 6 12 files changed, 483 insertions(+), 498 deletions(-) Index: linux-2.6/fs/ext2/file.c =================================================================== --- linux-2.6.orig/fs/ext2/file.c +++ linux-2.6/fs/ext2/file.c @@ -38,6 +38,18 @@ static int ext2_release_file (struct ino return 0; } +static struct vm_operations_struct ext2_file_vm_ops = { + .fault = filemap_fault, + .page_mkwrite = ext2_page_mkwrite, +}; + +static int ext2_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + file_accessed(file); + vma->vm_ops = &ext2_file_vm_ops; + return 0; +} + /* * We have mostly NULL's here: the current defaults are ok for * the ext2 filesystem. @@ -52,7 +64,7 @@ const struct file_operations ext2_file_o #ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, #endif - .mmap = generic_file_mmap, + .mmap = ext2_file_mmap, .open = generic_file_open, .release = ext2_release_file, .fsync = ext2_sync_file, @@ -86,5 +98,5 @@ const struct inode_operations ext2_file_ #endif .setattr = ext2_setattr, .permission = ext2_permission, - .fiemap = ext2_fiemap, +// .fiemap = ext2_fiemap, }; Index: linux-2.6/fs/ext2/namei.c =================================================================== --- linux-2.6.orig/fs/ext2/namei.c +++ linux-2.6/fs/ext2/namei.c @@ -98,9 +98,6 @@ static int ext2_create (struct inode * d if (ext2_use_xip(inode->i_sb)) { inode->i_mapping->a_ops = &ext2_aops_xip; inode->i_fop = &ext2_xip_file_operations; - } else if (test_opt(inode->i_sb, NOBH)) { - inode->i_mapping->a_ops = &ext2_nobh_aops; - inode->i_fop = &ext2_file_operations; } else { inode->i_mapping->a_ops = &ext2_aops; inode->i_fop = &ext2_file_operations; @@ -151,10 +148,7 @@ static int ext2_symlink (struct inode * if (l > sizeof (EXT2_I(inode)->i_data)) { /* slow symlink */ inode->i_op = &ext2_symlink_inode_operations; - if (test_opt(inode->i_sb, NOBH)) - inode->i_mapping->a_ops = &ext2_nobh_aops; - else - inode->i_mapping->a_ops = &ext2_aops; + inode->i_mapping->a_ops = &ext2_aops; err = page_symlink(inode, symname, l); if (err) goto out_fail; @@ -217,10 +211,7 @@ static int ext2_mkdir(struct inode * dir inode->i_op = &ext2_dir_inode_operations; inode->i_fop = &ext2_dir_operations; - if (test_opt(inode->i_sb, NOBH)) - inode->i_mapping->a_ops = &ext2_nobh_aops; - else - inode->i_mapping->a_ops = &ext2_aops; + inode->i_mapping->a_ops = &ext2_aops; inode_inc_link_count(inode); Index: linux-2.6/fs/ext2/balloc.c =================================================================== --- linux-2.6.orig/fs/ext2/balloc.c +++ linux-2.6/fs/ext2/balloc.c @@ -14,7 +14,7 @@ #include "ext2.h" #include <linux/quotaops.h> #include <linux/sched.h> -#include <linux/buffer_head.h> +#include <linux/fsblock.h> #include <linux/capability.h> /* @@ -37,7 +37,7 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, unsigned int block_group, - struct buffer_head ** bh) + struct fsblock_meta ** mb) { unsigned long group_desc; unsigned long offset; @@ -63,16 +63,16 @@ struct ext2_group_desc * ext2_get_group_ return NULL; } - desc = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data; - if (bh) - *bh = sbi->s_group_desc[group_desc]; + desc = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->data; + if (mb) + *mb = sbi->s_group_desc[group_desc]; return desc + offset; } static int ext2_valid_block_bitmap(struct super_block *sb, struct ext2_group_desc *desc, unsigned int block_group, - struct buffer_head *bh) + struct fsblock_meta *mb) { ext2_grpblk_t offset; ext2_grpblk_t next_zero_bit; @@ -84,21 +84,21 @@ static int ext2_valid_block_bitmap(struc /* check whether block bitmap block number is set */ bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); offset = bitmap_blk - group_first_block; - if (!ext2_test_bit(offset, bh->b_data)) + if (!ext2_test_bit(offset, mb->data)) /* bad block bitmap */ goto err_out; /* check whether the inode bitmap block number is set */ bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); offset = bitmap_blk - group_first_block; - if (!ext2_test_bit(offset, bh->b_data)) + if (!ext2_test_bit(offset, mb->data)) /* bad block bitmap */ goto err_out; /* check whether the inode table block number is set */ bitmap_blk = le32_to_cpu(desc->bg_inode_table); offset = bitmap_blk - group_first_block; - next_zero_bit = ext2_find_next_zero_bit(bh->b_data, + next_zero_bit = ext2_find_next_zero_bit(mb->data, offset + EXT2_SB(sb)->s_itb_per_group, offset); if (next_zero_bit >= offset + EXT2_SB(sb)->s_itb_per_group) @@ -117,32 +117,38 @@ err_out: * Read the bitmap for a given block_group,and validate the * bits for block/inode/inode tables are set in the bitmaps * - * Return buffer_head on success or NULL in case of failure. + * Return fsblock_meta on success or NULL in case of failure. */ -static struct buffer_head * +static struct fsblock_meta * read_block_bitmap(struct super_block *sb, unsigned int block_group) { struct ext2_group_desc * desc; - struct buffer_head * bh = NULL; + struct fsblock_meta * mb = NULL; ext2_fsblk_t bitmap_blk; desc = ext2_get_group_desc(sb, block_group, NULL); if (!desc) return NULL; bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); - bh = sb_getblk(sb, bitmap_blk); - if (unlikely(!bh)) { + mb = sb_find_or_create_mblock(&EXT2_SB(sb)->fsb_sb, bitmap_blk); + if (unlikely(!mb)) { ext2_error(sb, __func__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %u", block_group, le32_to_cpu(desc->bg_block_bitmap)); return NULL; } - if (likely(bh_uptodate_or_lock(bh))) - return bh; + if (likely(mb->block.flags & BL_uptodate)) + return mb; + lock_block(mb); /* XXX: may not need to lock */ + if (likely(mb->block.flags & BL_uptodate)) { + unlock_block(mb); + return mb; + } - if (bh_submit_read(bh) < 0) { - brelse(bh); + if (mblock_read_sync(mb) < 0) { + unlock_block(mb); + block_put(mb); ext2_error(sb, __func__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %u", @@ -150,12 +156,13 @@ read_block_bitmap(struct super_block *sb return NULL; } - ext2_valid_block_bitmap(sb, desc, block_group, bh); + unlock_block(mb); + ext2_valid_block_bitmap(sb, desc, block_group, mb); /* * file system mounted not to panic on error, continue with corrupt * bitmap */ - return bh; + return mb; } static void release_blocks(struct super_block *sb, int count) @@ -169,7 +176,7 @@ static void release_blocks(struct super_ } static void group_adjust_blocks(struct super_block *sb, int group_no, - struct ext2_group_desc *desc, struct buffer_head *bh, int count) + struct ext2_group_desc *desc, struct fsblock_meta *mb, int count) { if (count) { struct ext2_sb_info *sbi = EXT2_SB(sb); @@ -180,7 +187,7 @@ static void group_adjust_blocks(struct s desc->bg_free_blocks_count = cpu_to_le16(free_blocks + count); spin_unlock(sb_bgl_lock(sbi, group_no)); sb->s_dirt = 1; - mark_buffer_dirty(bh); + mark_mblock_dirty(mb); } } @@ -486,8 +493,8 @@ void ext2_discard_reservation(struct ino void ext2_free_blocks (struct inode * inode, unsigned long block, unsigned long count) { - struct buffer_head *bitmap_bh = NULL; - struct buffer_head * bh2; + struct fsblock_meta *bitmap_mb = NULL; + struct fsblock_meta *mb; unsigned long block_group; unsigned long bit; unsigned long i; @@ -506,6 +513,8 @@ void ext2_free_blocks (struct inode * in "block = %lu, count = %lu", block, count); goto error_return; } + for (i = 0; i < count; i++) + fbd_discard_block(inode->i_mapping, block + i); ext2_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1); @@ -523,12 +532,13 @@ do_more: overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb); count -= overflow; } - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, block_group); - if (!bitmap_bh) + if (bitmap_mb) + block_put(bitmap_mb); + bitmap_mb = read_block_bitmap(sb, block_group); + if (!bitmap_mb) goto error_return; - desc = ext2_get_group_desc (sb, block_group, &bh2); + desc = ext2_get_group_desc (sb, block_group, &mb); if (!desc) goto error_return; @@ -547,7 +557,7 @@ do_more: for (i = 0, group_freed = 0; i < count; i++) { if (!ext2_clear_bit_atomic(sb_bgl_lock(sbi, block_group), - bit + i, bitmap_bh->b_data)) { + bit + i, bitmap_mb->data)) { ext2_error(sb, __func__, "bit already cleared for block %lu", block + i); } else { @@ -555,11 +565,11 @@ do_more: } } - mark_buffer_dirty(bitmap_bh); + mark_mblock_dirty(bitmap_mb); if (sb->s_flags & MS_SYNCHRONOUS) - sync_dirty_buffer(bitmap_bh); + sync_block(bitmap_mb); - group_adjust_blocks(sb, block_group, desc, bh2, group_freed); + group_adjust_blocks(sb, block_group, desc, mb, group_freed); freed += group_freed; if (overflow) { @@ -568,7 +578,8 @@ do_more: goto do_more; } error_return: - brelse(bitmap_bh); + if (bitmap_mb) + block_put(bitmap_mb); release_blocks(sb, freed); DQUOT_FREE_BLOCK(inode, freed); } @@ -576,19 +587,19 @@ error_return: /** * bitmap_search_next_usable_block() * @start: the starting block (group relative) of the search - * @bh: bufferhead contains the block group bitmap + * @mb: fsblock_meta contains the block group bitmap * @maxblocks: the ending block (group relative) of the reservation * * The bitmap search --- search forward through the actual bitmap on disk until * we find a bit free. */ static ext2_grpblk_t -bitmap_search_next_usable_block(ext2_grpblk_t start, struct buffer_head *bh, +bitmap_search_next_usable_block(ext2_grpblk_t start, struct fsblock_meta *mb, ext2_grpblk_t maxblocks) { ext2_grpblk_t next; - next = ext2_find_next_zero_bit(bh->b_data, maxblocks, start); + next = ext2_find_next_zero_bit(mb->data, maxblocks, start); if (next >= maxblocks) return -1; return next; @@ -598,7 +609,7 @@ bitmap_search_next_usable_block(ext2_grp * find_next_usable_block() * @start: the starting block (group relative) to find next * allocatable block in bitmap. - * @bh: bufferhead contains the block group bitmap + * @mb: fsblock_meta contains the block group bitmap * @maxblocks: the ending block (group relative) for the search * * Find an allocatable block in a bitmap. We perform the "most @@ -607,7 +618,7 @@ bitmap_search_next_usable_block(ext2_grp * then for any free bit in the bitmap. */ static ext2_grpblk_t -find_next_usable_block(int start, struct buffer_head *bh, int maxblocks) +find_next_usable_block(int start, struct fsblock_meta *mb, int maxblocks) { ext2_grpblk_t here, next; char *p, *r; @@ -624,7 +635,7 @@ find_next_usable_block(int start, struct ext2_grpblk_t end_goal = (start + 63) & ~63; if (end_goal > maxblocks) end_goal = maxblocks; - here = ext2_find_next_zero_bit(bh->b_data, end_goal, start); + here = ext2_find_next_zero_bit(mb->data, end_goal, start); if (here < end_goal) return here; ext2_debug("Bit not found near goal\n"); @@ -634,14 +645,14 @@ find_next_usable_block(int start, struct if (here < 0) here = 0; - p = ((char *)bh->b_data) + (here >> 3); + p = ((char *)mb->data) + (here >> 3); r = memscan(p, 0, ((maxblocks + 7) >> 3) - (here >> 3)); - next = (r - ((char *)bh->b_data)) << 3; + next = (r - ((char *)mb->data)) << 3; if (next < maxblocks && next >= here) return next; - here = bitmap_search_next_usable_block(here, bh, maxblocks); + here = bitmap_search_next_usable_block(here, mb, maxblocks); return here; } @@ -650,7 +661,7 @@ find_next_usable_block(int start, struct * @sb: superblock * @handle: handle to this transaction * @group: given allocation block group - * @bitmap_bh: bufferhead holds the block bitmap + * @bitmap_mb: fsblock_meta holds the block bitmap * @grp_goal: given target block within the group * @count: target number of blocks to allocate * @my_rsv: reservation window @@ -670,7 +681,7 @@ find_next_usable_block(int start, struct */ static int ext2_try_to_allocate(struct super_block *sb, int group, - struct buffer_head *bitmap_bh, ext2_grpblk_t grp_goal, + struct fsblock_meta *bitmap_mb, ext2_grpblk_t grp_goal, unsigned long *count, struct ext2_reserve_window *my_rsv) { @@ -706,7 +717,7 @@ ext2_try_to_allocate(struct super_block repeat: if (grp_goal < 0) { - grp_goal = find_next_usable_block(start, bitmap_bh, end); + grp_goal = find_next_usable_block(start, bitmap_mb, end); if (grp_goal < 0) goto fail_access; if (!my_rsv) { @@ -714,7 +725,7 @@ repeat: for (i = 0; i < 7 && grp_goal > start && !ext2_test_bit(grp_goal - 1, - bitmap_bh->b_data); + bitmap_mb->data); i++, grp_goal--) ; } @@ -722,7 +733,7 @@ repeat: start = grp_goal; if (ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), grp_goal, - bitmap_bh->b_data)) { + bitmap_mb->data)) { /* * The block was allocated by another thread, or it was * allocated and then freed by another thread @@ -737,7 +748,7 @@ repeat: grp_goal++; while (num < *count && grp_goal < end && !ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), - grp_goal, bitmap_bh->b_data)) { + grp_goal, bitmap_mb->data)) { num++; grp_goal++; } @@ -900,12 +911,12 @@ static int find_next_reservable_window( * * @sb: the super block * @group: the group we are trying to allocate in - * @bitmap_bh: the block group block bitmap + * @bitmap_mb: the block group block bitmap * */ static int alloc_new_reservation(struct ext2_reserve_window_node *my_rsv, ext2_grpblk_t grp_goal, struct super_block *sb, - unsigned int group, struct buffer_head *bitmap_bh) + unsigned int group, struct fsblock_meta *bitmap_mb) { struct ext2_reserve_window_node *search_head; ext2_fsblk_t group_first_block, group_end_block, start_block; @@ -996,7 +1007,7 @@ retry: spin_unlock(rsv_lock); first_free_block = bitmap_search_next_usable_block( my_rsv->rsv_start - group_first_block, - bitmap_bh, group_end_block - group_first_block + 1); + bitmap_mb, group_end_block - group_first_block + 1); if (first_free_block < 0) { /* @@ -1074,7 +1085,7 @@ static void try_to_extend_reservation(st * ext2_try_to_allocate_with_rsv() * @sb: superblock * @group: given allocation block group - * @bitmap_bh: bufferhead holds the block bitmap + * @bitmap_mb: fsblock_meta holds the block bitmap * @grp_goal: given target block within the group * @count: target number of blocks to allocate * @my_rsv: reservation window @@ -1098,7 +1109,7 @@ static void try_to_extend_reservation(st */ static ext2_grpblk_t ext2_try_to_allocate_with_rsv(struct super_block *sb, unsigned int group, - struct buffer_head *bitmap_bh, ext2_grpblk_t grp_goal, + struct fsblock_meta *bitmap_mb, ext2_grpblk_t grp_goal, struct ext2_reserve_window_node * my_rsv, unsigned long *count) { @@ -1113,7 +1124,7 @@ ext2_try_to_allocate_with_rsv(struct sup * or last attempt to allocate a block with reservation turned on failed */ if (my_rsv == NULL) { - return ext2_try_to_allocate(sb, group, bitmap_bh, + return ext2_try_to_allocate(sb, group, bitmap_mb, grp_goal, count, NULL); } /* @@ -1147,7 +1158,7 @@ ext2_try_to_allocate_with_rsv(struct sup if (my_rsv->rsv_goal_size < *count) my_rsv->rsv_goal_size = *count; ret = alloc_new_reservation(my_rsv, grp_goal, sb, - group, bitmap_bh); + group, bitmap_mb); if (ret < 0) break; /* failed */ @@ -1168,7 +1179,7 @@ ext2_try_to_allocate_with_rsv(struct sup rsv_window_dump(&EXT2_SB(sb)->s_rsv_window_root, 1); BUG(); } - ret = ext2_try_to_allocate(sb, group, bitmap_bh, grp_goal, + ret = ext2_try_to_allocate(sb, group, bitmap_mb, grp_goal, &num, &my_rsv->rsv_window); if (ret >= 0) { my_rsv->rsv_alloc_hit += num; @@ -1217,8 +1228,8 @@ static int ext2_has_free_blocks(struct e ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal, unsigned long *count, int *errp) { - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *gdp_bh; + struct fsblock_meta *bitmap_mb = NULL; + struct fsblock_meta *gdp_mb; int group_no; int goal_group; ext2_grpblk_t grp_target_blk; /* blockgroup relative goal block */ @@ -1285,7 +1296,7 @@ ext2_fsblk_t ext2_new_blocks(struct inod EXT2_BLOCKS_PER_GROUP(sb); goal_group = group_no; retry_alloc: - gdp = ext2_get_group_desc(sb, group_no, &gdp_bh); + gdp = ext2_get_group_desc(sb, group_no, &gdp_mb); if (!gdp) goto io_error; @@ -1302,11 +1313,11 @@ retry_alloc: if (free_blocks > 0) { grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb)); - bitmap_bh = read_block_bitmap(sb, group_no); - if (!bitmap_bh) + bitmap_mb = read_block_bitmap(sb, group_no); + if (!bitmap_mb) goto io_error; grp_alloc_blk = ext2_try_to_allocate_with_rsv(sb, group_no, - bitmap_bh, grp_target_blk, + bitmap_mb, grp_target_blk, my_rsv, &num); if (grp_alloc_blk >= 0) goto allocated; @@ -1323,7 +1334,7 @@ retry_alloc: group_no++; if (group_no >= ngroups) group_no = 0; - gdp = ext2_get_group_desc(sb, group_no, &gdp_bh); + gdp = ext2_get_group_desc(sb, group_no, &gdp_mb); if (!gdp) goto io_error; @@ -1336,15 +1347,16 @@ retry_alloc: if (my_rsv && (free_blocks <= (windowsz/2))) continue; - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, group_no); - if (!bitmap_bh) + if (bitmap_mb) + block_put(bitmap_mb); + bitmap_mb = read_block_bitmap(sb, group_no); + if (!bitmap_mb) goto io_error; /* * try to allocate block(s) from this group, without a goal(-1). */ grp_alloc_blk = ext2_try_to_allocate_with_rsv(sb, group_no, - bitmap_bh, -1, my_rsv, &num); + bitmap_mb, -1, my_rsv, &num); if (grp_alloc_blk >= 0) goto allocated; } @@ -1400,15 +1412,15 @@ allocated: goto out; } - group_adjust_blocks(sb, group_no, gdp, gdp_bh, -num); + group_adjust_blocks(sb, group_no, gdp, gdp_mb, -num); percpu_counter_sub(&sbi->s_freeblocks_counter, num); - mark_buffer_dirty(bitmap_bh); + mark_mblock_dirty(bitmap_mb); if (sb->s_flags & MS_SYNCHRONOUS) - sync_dirty_buffer(bitmap_bh); + sync_block(bitmap_mb); *errp = 0; - brelse(bitmap_bh); + block_put(bitmap_mb); DQUOT_FREE_BLOCK(inode, *count-num); *count = num; return ret_block; @@ -1421,7 +1433,8 @@ out: */ if (!performed_allocation) DQUOT_FREE_BLOCK(inode, *count); - brelse(bitmap_bh); + if (bitmap_mb) + block_put(bitmap_mb); return 0; } @@ -1436,7 +1449,7 @@ ext2_fsblk_t ext2_new_block(struct inode static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; -unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars) +unsigned long ext2_count_free (struct fsblock_meta * map, unsigned int numchars) { unsigned int i; unsigned long sum = 0; @@ -1444,8 +1457,8 @@ unsigned long ext2_count_free (struct bu if (!map) return (0); for (i = 0; i < numchars; i++) - sum += nibblemap[map->b_data[i] & 0xf] + - nibblemap[(map->b_data[i] >> 4) & 0xf]; + sum += nibblemap[map->data[i] & 0xf] + + nibblemap[(map->data[i] >> 4) & 0xf]; return (sum); } @@ -1465,20 +1478,20 @@ unsigned long ext2_count_free_blocks (st bitmap_count = 0; desc = NULL; for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) { - struct buffer_head *bitmap_bh; + struct fsblock_meta *bitmap_mb; desc = ext2_get_group_desc (sb, i, NULL); if (!desc) continue; desc_count += le16_to_cpu(desc->bg_free_blocks_count); - bitmap_bh = read_block_bitmap(sb, i); - if (!bitmap_bh) + bitmap_mb = read_block_bitmap(sb, i); + if (!bitmap_mb) continue; - x = ext2_count_free(bitmap_bh, sb->s_blocksize); + x = ext2_count_free(bitmap_mb, sb->s_blocksize); printk ("group %d: stored = %d, counted = %lu\n", i, le16_to_cpu(desc->bg_free_blocks_count), x); bitmap_count += x; - brelse(bitmap_bh); + block_put(bitmap_mb); } printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n", (long)le32_to_cpu(es->s_free_blocks_count), Index: linux-2.6/fs/ext2/dir.c =================================================================== --- linux-2.6.orig/fs/ext2/dir.c +++ linux-2.6/fs/ext2/dir.c @@ -22,7 +22,7 @@ */ #include "ext2.h" -#include <linux/buffer_head.h> +#include <linux/fsblock.h> #include <linux/pagemap.h> #include <linux/swap.h> @@ -88,7 +88,7 @@ static int ext2_commit_chunk(struct page int err = 0; dir->i_version++; - block_write_end(NULL, mapping, pos, len, len, page, NULL); + __fsblock_write_end(mapping, pos, len, len, page, NULL); if (pos+len > dir->i_size) { i_size_write(dir, pos+len); @@ -201,10 +201,12 @@ static struct page * ext2_get_page(struc ext2_check_page(page, quiet); if (PageError(page)) goto fail; - } + } else + printk("ext2_get_page read_mapping_page error\n"); return page; fail: + printk("ext2_get_page PageError\n"); ext2_put_page(page); return ERR_PTR(-EIO); } Index: linux-2.6/fs/ext2/ext2.h =================================================================== --- linux-2.6.orig/fs/ext2/ext2.h +++ linux-2.6/fs/ext2/ext2.h @@ -1,5 +1,6 @@ #include <linux/fs.h> #include <linux/ext2_fs.h> +#include <linux/fsb_extentmap.h> /* * ext2 mount options @@ -62,6 +63,7 @@ struct ext2_inode_info { struct mutex truncate_mutex; struct inode vfs_inode; struct list_head i_orphan; /* unlinked but open inodes */ + struct fsb_ext_root fsb_ext_root; }; /* @@ -97,7 +99,7 @@ extern unsigned long ext2_count_dirs (st extern void ext2_check_blocks_bitmap (struct super_block *); extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, unsigned int block_group, - struct buffer_head ** bh); + struct fsblock_meta ** mb); extern void ext2_discard_reservation (struct inode *); extern int ext2_should_retry_alloc(struct super_block *sb, int *retries); extern void ext2_init_block_alloc_info(struct inode *); @@ -121,23 +123,24 @@ extern struct inode * ext2_new_inode (st extern void ext2_free_inode (struct inode *); extern unsigned long ext2_count_free_inodes (struct super_block *); extern void ext2_check_inodes_bitmap (struct super_block *); -extern unsigned long ext2_count_free (struct buffer_head *, unsigned); +extern unsigned long ext2_count_free (struct fsblock_meta *, unsigned); /* inode.c */ extern struct inode *ext2_iget (struct super_block *, unsigned long); extern int ext2_write_inode (struct inode *, int); extern void ext2_delete_inode (struct inode *); extern int ext2_sync_inode (struct inode *); -extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int); +extern int ext2_insert_mapping(struct address_space *, loff_t, size_t, int); extern void ext2_truncate (struct inode *); extern int ext2_setattr (struct dentry *, struct iattr *); extern void ext2_set_inode_flags(struct inode *inode); extern void ext2_get_inode_flags(struct ext2_inode_info *); extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len); -int __ext2_write_begin(struct file *file, struct address_space *mapping, +extern int __ext2_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata); +extern int ext2_page_mkwrite(struct vm_area_struct *vma, struct page *page); /* ioctl.c */ extern long ext2_ioctl(struct file *, unsigned int, unsigned long); Index: linux-2.6/fs/ext2/fsync.c =================================================================== --- linux-2.6.orig/fs/ext2/fsync.c +++ linux-2.6/fs/ext2/fsync.c @@ -23,7 +23,7 @@ */ #include "ext2.h" -#include <linux/buffer_head.h> /* for sync_mapping_buffers() */ +#include <linux/fsblock.h> /* for sync_mapping_buffers() */ /* @@ -37,7 +37,7 @@ int ext2_sync_file(struct file *file, st int err; int ret; - ret = sync_mapping_buffers(inode->i_mapping); + ret = fsblock_sync(inode->i_mapping); if (!(inode->i_state & I_DIRTY)) return ret; if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) Index: linux-2.6/fs/ext2/ialloc.c =================================================================== --- linux-2.6.orig/fs/ext2/ialloc.c +++ linux-2.6/fs/ext2/ialloc.c @@ -15,7 +15,7 @@ #include <linux/quotaops.h> #include <linux/sched.h> #include <linux/backing-dev.h> -#include <linux/buffer_head.h> +#include <linux/fsblock.h> #include <linux/random.h> #include "ext2.h" #include "xattr.h" @@ -40,34 +40,34 @@ * Read the inode allocation bitmap for a given block_group, reading * into the specified slot in the superblock's bitmap cache. * - * Return buffer_head of bitmap on success or NULL. + * Return fsblock_meta of bitmap on success or NULL. */ -static struct buffer_head * +static struct fsblock_meta * read_inode_bitmap(struct super_block * sb, unsigned long block_group) { struct ext2_group_desc *desc; - struct buffer_head *bh = NULL; + struct fsblock_meta *mb = NULL; desc = ext2_get_group_desc(sb, block_group, NULL); if (!desc) goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap)); - if (!bh) + mb = sb_mbread(&EXT2_SB(sb)->fsb_sb, le32_to_cpu(desc->bg_inode_bitmap)); + if (!mb) ext2_error(sb, "read_inode_bitmap", "Cannot read inode bitmap - " "block_group = %lu, inode_bitmap = %u", block_group, le32_to_cpu(desc->bg_inode_bitmap)); error_out: - return bh; + return mb; } static void ext2_release_inode(struct super_block *sb, int group, int dir) { struct ext2_group_desc * desc; - struct buffer_head *bh; + struct fsblock_meta *mb; - desc = ext2_get_group_desc(sb, group, &bh); + desc = ext2_get_group_desc(sb, group, &mb); if (!desc) { ext2_error(sb, "ext2_release_inode", "can't get descriptor for group %d", group); @@ -82,7 +82,7 @@ static void ext2_release_inode(struct su if (dir) percpu_counter_dec(&EXT2_SB(sb)->s_dirs_counter); sb->s_dirt = 1; - mark_buffer_dirty(bh); + mark_mblock_dirty(mb); } /* @@ -106,7 +106,7 @@ void ext2_free_inode (struct inode * ino struct super_block * sb = inode->i_sb; int is_directory; unsigned long ino; - struct buffer_head *bitmap_bh = NULL; + struct fsblock_meta *bitmap_mb = NULL; unsigned long block_group; unsigned long bit; struct ext2_super_block * es; @@ -139,23 +139,25 @@ void ext2_free_inode (struct inode * ino } block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb); bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb); - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, block_group); - if (!bitmap_bh) + if (bitmap_mb) + block_put(bitmap_mb); + bitmap_mb = read_inode_bitmap(sb, block_group); + if (!bitmap_mb) goto error_return; /* Ok, now we can actually update the inode bitmaps.. */ if (!ext2_clear_bit_atomic(sb_bgl_lock(EXT2_SB(sb), block_group), - bit, (void *) bitmap_bh->b_data)) + bit, (void *) bitmap_mb->data)) ext2_error (sb, "ext2_free_inode", "bit already cleared for inode %lu", ino); else ext2_release_inode(sb, block_group, is_directory); - mark_buffer_dirty(bitmap_bh); + mark_mblock_dirty(bitmap_mb); if (sb->s_flags & MS_SYNCHRONOUS) - sync_dirty_buffer(bitmap_bh); + sync_block(bitmap_mb); error_return: - brelse(bitmap_bh); + if (bitmap_mb) + block_put(bitmap_mb); } /* @@ -178,6 +180,8 @@ static void ext2_preread_inode(struct in struct ext2_group_desc * gdp; struct backing_dev_info *bdi; + return; /* XXX */ + bdi = inode->i_mapping->backing_dev_info; if (bdi_read_congested(bdi)) return; @@ -196,7 +200,7 @@ static void ext2_preread_inode(struct in EXT2_INODE_SIZE(inode->i_sb); block = le32_to_cpu(gdp->bg_inode_table) + (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)); - sb_breadahead(inode->i_sb, block); +// sb_breadahead(inode->i_sb, block); } /* @@ -438,8 +442,8 @@ found: struct inode *ext2_new_inode(struct inode *dir, int mode) { struct super_block *sb; - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *bh2; + struct fsblock_meta *bitmap_mb = NULL; + struct fsblock_meta *mb; int group, i; ino_t ino = 0; struct inode * inode; @@ -471,17 +475,18 @@ struct inode *ext2_new_inode(struct inod } for (i = 0; i < sbi->s_groups_count; i++) { - gdp = ext2_get_group_desc(sb, group, &bh2); - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, group); - if (!bitmap_bh) { + gdp = ext2_get_group_desc(sb, group, &mb); + if (bitmap_mb) + block_put(bitmap_mb); + bitmap_mb = read_inode_bitmap(sb, group); + if (!bitmap_mb) { err = -EIO; goto fail; } ino = 0; repeat_in_this_group: - ino = ext2_find_next_zero_bit((unsigned long *)bitmap_bh->b_data, + ino = ext2_find_next_zero_bit((unsigned long *)bitmap_mb->data, EXT2_INODES_PER_GROUP(sb), ino); if (ino >= EXT2_INODES_PER_GROUP(sb)) { /* @@ -497,7 +502,7 @@ repeat_in_this_group: continue; } if (ext2_set_bit_atomic(sb_bgl_lock(sbi, group), - ino, bitmap_bh->b_data)) { + ino, bitmap_mb->data)) { /* we lost this inode */ if (++ino >= EXT2_INODES_PER_GROUP(sb)) { /* this group is exhausted, try next group */ @@ -517,10 +522,10 @@ repeat_in_this_group: err = -ENOSPC; goto fail; got: - mark_buffer_dirty(bitmap_bh); + mark_mblock_dirty(bitmap_mb); if (sb->s_flags & MS_SYNCHRONOUS) - sync_dirty_buffer(bitmap_bh); - brelse(bitmap_bh); + sync_block(bitmap_mb); + block_put(bitmap_mb); ino += group * EXT2_INODES_PER_GROUP(sb) + 1; if (ino < EXT2_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { @@ -549,7 +554,7 @@ got: spin_unlock(sb_bgl_lock(sbi, group)); sb->s_dirt = 1; - mark_buffer_dirty(bh2); + mark_mblock_dirty(mb); inode->i_uid = current_fsuid(); if (test_opt (sb, GRPID)) inode->i_gid = dir->i_gid; @@ -630,7 +635,7 @@ unsigned long ext2_count_free_inodes (st #ifdef EXT2FS_DEBUG struct ext2_super_block *es; unsigned long bitmap_count = 0; - struct buffer_head *bitmap_bh = NULL; + struct fsblock_meta *bitmap_mb = NULL; es = EXT2_SB(sb)->s_es; for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) { @@ -640,17 +645,19 @@ unsigned long ext2_count_free_inodes (st if (!desc) continue; desc_count += le16_to_cpu(desc->bg_free_inodes_count); - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, i); - if (!bitmap_bh) + if (bitmap_mb) + block_put(bitmap_mb); + bitmap_mb = read_inode_bitmap(sb, i); + if (!bitmap_mb) continue; - x = ext2_count_free(bitmap_bh, EXT2_INODES_PER_GROUP(sb) / 8); + x = ext2_count_free(bitmap_mb, EXT2_INODES_PER_GROUP(sb) / 8); printk("group %d: stored = %d, counted = %u\n", i, le16_to_cpu(desc->bg_free_inodes_count), x); bitmap_count += x; } - brelse(bitmap_bh); + if (bitmap_mb) + block_put(bitmap_mb); printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n", percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter), desc_count, bitmap_count); Index: linux-2.6/fs/ext2/inode.c =================================================================== --- linux-2.6.orig/fs/ext2/inode.c +++ linux-2.6/fs/ext2/inode.c @@ -29,7 +29,7 @@ #include <linux/quotaops.h> #include <linux/module.h> #include <linux/writeback.h> -#include <linux/buffer_head.h> +#include <linux/fsblock.h> #include <linux/mpage.h> #include <linux/fiemap.h> #include <linux/namei.h> @@ -71,6 +71,7 @@ void ext2_delete_inode (struct inode * i inode->i_size = 0; if (inode->i_blocks) ext2_truncate (inode); + fsblock_release(&inode->i_data, 1); /* XXX: just do this at delete time? (but that goes bug in clear_inode mapping has private check) */ ext2_free_inode (inode); return; @@ -81,13 +82,13 @@ no_delete: typedef struct { __le32 *p; __le32 key; - struct buffer_head *bh; + struct fsblock_meta *mb; } Indirect; -static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) +static inline void add_chain(Indirect *p, struct fsblock_meta *mb, __le32 *v) { p->key = *(p->p = v); - p->bh = bh; + p->mb = mb; } static inline int verify_chain(Indirect *from, Indirect *to) @@ -175,16 +176,16 @@ static int ext2_block_to_path(struct ino * @chain: place to store the result * @err: here we store the error value * - * Function fills the array of triples <key, p, bh> and returns %NULL + * Function fills the array of triples <key, p, mb> and returns %NULL * if everything went OK or the pointer to the last filled triple * (incomplete one) otherwise. Upon the return chain[i].key contains * the number of (i+1)-th block in the chain (as it is stored in memory, * i.e. little-endian 32-bit), chain[i].p contains the address of that - * number (it points into struct inode for i==0 and into the bh->b_data - * for i>0) and chain[i].bh points to the buffer_head of i-th indirect + * number (it points into struct inode for i==0 and into the mb->data + * for i>0) and chain[i].mb points to the fsblock_meta of i-th indirect * block for i>0 and NULL for i==0. In other words, it holds the block * numbers of the chain, addresses they were taken from (and where we can - * verify that chain did not change) and buffer_heads hosting these + * verify that chain did not change) and fsblock_meta hosting these * numbers. * * Function stops when it stumbles upon zero pointer (absent block) @@ -204,7 +205,7 @@ static Indirect *ext2_get_branch(struct { struct super_block *sb = inode->i_sb; Indirect *p = chain; - struct buffer_head *bh; + struct fsblock_meta *mb; *err = 0; /* i_data is not going away, no lock needed */ @@ -212,13 +213,13 @@ static Indirect *ext2_get_branch(struct if (!p->key) goto no_block; while (--depth) { - bh = sb_bread(sb, le32_to_cpu(p->key)); - if (!bh) + mb = sb_mbread(&EXT2_SB(sb)->fsb_sb, le32_to_cpu(p->key)); + if (!mb) goto failure; read_lock(&EXT2_I(inode)->i_meta_lock); if (!verify_chain(chain, p)) goto changed; - add_chain(++p, bh, (__le32*)bh->b_data + *++offsets); + add_chain(++p, mb, (__le32*)mb->data + *++offsets); read_unlock(&EXT2_I(inode)->i_meta_lock); if (!p->key) goto no_block; @@ -227,7 +228,7 @@ static Indirect *ext2_get_branch(struct changed: read_unlock(&EXT2_I(inode)->i_meta_lock); - brelse(bh); + block_put(mb); *err = -EAGAIN; goto no_block; failure: @@ -259,7 +260,7 @@ no_block: static ext2_fsblk_t ext2_find_near(struct inode *inode, Indirect *ind) { struct ext2_inode_info *ei = EXT2_I(inode); - __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data; + __le32 *start = ind->mb ? (__le32 *) ind->mb->data : ei->i_data; __le32 *p; ext2_fsblk_t bg_start; ext2_fsblk_t colour; @@ -270,8 +271,8 @@ static ext2_fsblk_t ext2_find_near(struc return le32_to_cpu(*p); /* No such thing, so let's try location of indirect block */ - if (ind->bh) - return ind->bh->b_blocknr; + if (ind->mb) + return ind->mb->block.block_nr; /* * It is going to be refered from inode itself? OK, just put it into @@ -431,19 +432,19 @@ failed_out: * be placed into *branch->p to fill that gap. * * If allocation fails we free all blocks we've allocated (and forget - * their buffer_heads) and return the error value the from failed + * their fsblock_meta) and return the error value the from failed * ext2_alloc_block() (normally -ENOSPC). Otherwise we set the chain * as described above and return 0. */ -static int ext2_alloc_branch(struct inode *inode, +static noinline int ext2_alloc_branch(struct inode *inode, int indirect_blks, int *blks, ext2_fsblk_t goal, int *offsets, Indirect *branch) { int blocksize = inode->i_sb->s_blocksize; int i, n = 0; int err = 0; - struct buffer_head *bh; + struct fsblock_meta *mb; int num; ext2_fsblk_t new_blocks[4]; ext2_fsblk_t current_block; @@ -459,15 +460,19 @@ static int ext2_alloc_branch(struct inod */ for (n = 1; n <= indirect_blks; n++) { /* - * Get buffer_head for parent block, zero it out + * Get fsblock_meta for parent block, zero it out * and set the pointer to new one, then send * parent to disk. */ - bh = sb_getblk(inode->i_sb, new_blocks[n-1]); - branch[n].bh = bh; - lock_buffer(bh); - memset(bh->b_data, 0, blocksize); - branch[n].p = (__le32 *) bh->b_data + offsets[n]; + mb = sb_find_or_create_mblock(&EXT2_SB(inode->i_sb)->fsb_sb, new_blocks[n-1]); + if (IS_ERR(mb)) { + err = PTR_ERR(mb); + break; /* XXX: proper error handling */ + } + branch[n].mb = mb; + lock_block(mb); + memset(mb->data, 0, blocksize); + branch[n].p = (__le32 *) mb->data + offsets[n]; branch[n].key = cpu_to_le32(new_blocks[n]); *branch[n].p = branch[n].key; if ( n == indirect_blks) { @@ -480,15 +485,15 @@ static int ext2_alloc_branch(struct inod for (i=1; i < num; i++) *(branch[n].p + i) = cpu_to_le32(++current_block); } - set_buffer_uptodate(bh); - unlock_buffer(bh); - mark_buffer_dirty_inode(bh, inode); - /* We used to sync bh here if IS_SYNC(inode). + mark_mblock_uptodate(mb); + unlock_block(mb); + mark_mblock_dirty_inode(mb, inode); + /* We used to sync mb here if IS_SYNC(inode). * But we now rely upon generic_osync_inode() * and b_inode_buffers. But not for directories. */ if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) - sync_dirty_buffer(bh); + sync_block(mb); } *blks = num; return err; @@ -506,7 +511,7 @@ static int ext2_alloc_branch(struct inod * inode (->i_blocks, etc.). In case of success we end up with the full * chain to new block and return 0. */ -static void ext2_splice_branch(struct inode *inode, +static noinline void ext2_splice_branch(struct inode *inode, long block, Indirect *where, int num, int blks) { int i; @@ -521,7 +526,7 @@ static void ext2_splice_branch(struct in *where->p = where->key; /* - * Update the host buffer_head or inode to point to more just allocated + * Update the host fsblock_meta or inode to point to more just allocated * direct blocks blocks */ if (num == 0 && blks > 1) { @@ -544,8 +549,8 @@ static void ext2_splice_branch(struct in /* We are done with atomic stuff, now do the rest of housekeeping */ /* had we spliced it onto indirect block? */ - if (where->bh) - mark_buffer_dirty_inode(where->bh, inode); + if (where->mb) + mark_mblock_dirty_inode(where->mb, inode); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); @@ -569,10 +574,10 @@ static void ext2_splice_branch(struct in * return = 0, if plain lookup failed. * return < 0, error case. */ -static int ext2_get_blocks(struct inode *inode, - sector_t iblock, unsigned long maxblocks, - struct buffer_head *bh_result, - int create) +static int ext2_get_blocks(struct inode *inode, sector_t blocknr, + unsigned long maxblocks, int create, + sector_t *offset, sector_t *block, + unsigned int *size, unsigned int *flags) { int err = -EIO; int offsets[4]; @@ -586,7 +591,11 @@ static int ext2_get_blocks(struct inode int count = 0; ext2_fsblk_t first_block = 0; - depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); + FSB_BUG_ON(create == MAP_BLOCK_ALLOCATE); + + *flags = 0; + + depth = ext2_block_to_path(inode, blocknr, offsets,&blocks_to_boundary); if (depth == 0) return (err); @@ -596,7 +605,6 @@ reread: /* Simplest case - block found, no allocation needed */ if (!partial) { first_block = le32_to_cpu(chain[depth - 1].key); - clear_buffer_new(bh_result); /* What's this do? */ count++; /*map more blocks*/ while (count < maxblocks && count <= blocks_to_boundary) { @@ -622,6 +630,11 @@ reread: } /* Next simple case - plain lookup or failed read of indirect block */ + if (!create && err != -EIO) { + *size = 1; + *offset = blocknr; + *flags |= FE_hole; + } if (!create || err == -EIO) goto cleanup; @@ -634,7 +647,7 @@ reread: if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) ext2_init_block_alloc_info(inode); - goal = ext2_find_goal(inode, iblock, partial); + goal = ext2_find_goal(inode, blocknr, partial); /* the number of blocks need to allocate for [d,t]indirect blocks */ indirect_blks = (chain + depth) - partial - 1; @@ -667,73 +680,117 @@ reread: } } - ext2_splice_branch(inode, iblock, partial, indirect_blks, count); + ext2_splice_branch(inode, blocknr, partial, indirect_blks, count); mutex_unlock(&ei->truncate_mutex); - set_buffer_new(bh_result); + *flags |= FE_new; + *flags &= ~FE_hole; got_it: - map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); - if (count > blocks_to_boundary) - set_buffer_boundary(bh_result); + FSB_BUG_ON(*flags & FE_hole); + *flags |= FE_mapped; + *offset = blocknr; + *size = 1; + *block = le32_to_cpu(chain[depth-1].key); +// if (count > blocks_to_boundary) +// set_buffer_boundary(bh_result); err = count; /* Clean up and exit */ partial = chain + depth - 1; /* the whole chain */ cleanup: while (partial > chain) { - brelse(partial->bh); + block_put(partial->mb); partial--; } return err; changed: while (partial > chain) { - brelse(partial->bh); + block_put(partial->mb); partial--; } goto reread; } -int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) -{ - unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; - int ret = ext2_get_blocks(inode, iblock, max_blocks, - bh_result, create); - if (ret > 0) { - bh_result->b_size = (ret << inode->i_blkbits); +#ifdef EXT2_EXTMAP +static int ext2_map_extent(struct address_space *mapping, loff_t pos, int mode, + sector_t *offset, sector_t *block, + unsigned int *size, unsigned int *flags) +{ + struct inode *inode = mapping->host; + sector_t blocknr; + int ret; + + blocknr = pos >> inode->i_blkbits; + + ret = ext2_get_blocks(inode, blocknr, 1, mode, offset, block, size, flags); + if (ret > 0) ret = 0; - } return ret; - } -int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - u64 start, u64 len) +static int ext2_map_block(struct address_space *mapping, + struct fsblock *block, loff_t pos, int mode) { - return generic_block_fiemap(inode, fieinfo, start, len, - ext2_get_block); + FSB_BUG_ON(block->flags & BL_mapped); + FSB_BUG_ON(mode == MAP_BLOCK_ALLOCATE); + + return fsb_ext_map_fsblock(mapping, pos, block, mode, &EXT2_I(mapping->host)->fsb_ext_root, ext2_map_extent); } +#else -static int ext2_writepage(struct page *page, struct writeback_control *wbc) +static int ext2_map_block(struct address_space *mapping, + struct fsblock *b, loff_t pos, int mode) { - return block_write_full_page(page, ext2_get_block, wbc); + struct inode *inode = mapping->host; + sector_t blocknr; + sector_t offset; + sector_t block = (sector_t)ULLONG_MAX; + unsigned int flags, size; + int ret; + + FSB_BUG_ON(b->flags & BL_mapped); + FSB_BUG_ON(mode == MAP_BLOCK_ALLOCATE); + + blocknr = pos >> inode->i_blkbits; + + ret = ext2_get_blocks(inode, blocknr, 1, mode, &offset, &block, &size, &flags); + if (ret > 0) { + ret = 0; + } + if (!ret) { + if (flags & FE_mapped) { + spin_lock_block_irq(b); + map_fsblock(b, block); + if (flags & FE_new) { + b->flags |= BL_new; + b->flags &= ~BL_hole; + } + FSB_BUG_ON(b->flags & BL_hole); + spin_unlock_block_irq(b); + } else if (flags & FE_hole) { + spin_lock_block_irq(b); + b->flags |= BL_hole; + spin_unlock_block_irq(b); + } + } + return ret; } +#endif -static int ext2_readpage(struct file *file, struct page *page) +static int ext2_writepage(struct page *page, struct writeback_control *wbc) { - return mpage_readpage(page, ext2_get_block); + return fsblock_write_page(page, ext2_map_block, wbc); } -static int -ext2_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) +static int ext2_readpage(struct file *file, struct page *page) { - return mpage_readpages(mapping, pages, nr_pages, ext2_get_block); + return fsblock_read_page(page, ext2_map_block); } int __ext2_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { - return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, - ext2_get_block); + return fsblock_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + ext2_map_block); } static int @@ -745,31 +802,17 @@ ext2_write_begin(struct file *file, stru return __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata); } -static int -ext2_nobh_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - /* - * Dir-in-pagecache still uses ext2_write_begin. Would have to rework - * directory handling code to pass around offsets rather than struct - * pages in order to make this work easily. - */ - return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata, - ext2_get_block); -} - -static int ext2_nobh_writepage(struct page *page, - struct writeback_control *wbc) +static sector_t ext2_bmap(struct address_space *mapping, sector_t block) { - return nobh_writepage(page, ext2_get_block, wbc); + return fsblock_bmap(mapping, block, ext2_map_block); } -static sector_t ext2_bmap(struct address_space *mapping, sector_t block) +int ext2_page_mkwrite(struct vm_area_struct *vma, struct page *page) { - return generic_block_bmap(mapping,block,ext2_get_block); + return fsblock_page_mkwrite(vma, page, ext2_map_block); } +#if 0 static ssize_t ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) @@ -786,19 +829,25 @@ ext2_writepages(struct address_space *ma { return mpage_writepages(mapping, wbc, ext2_get_block); } +#endif const struct address_space_operations ext2_aops = { .readpage = ext2_readpage, - .readpages = ext2_readpages, +// .readpages = ext2_readpages, .writepage = ext2_writepage, - .sync_page = block_sync_page, +// .sync_page = block_sync_page, .write_begin = ext2_write_begin, - .write_end = generic_write_end, + .write_end = fsblock_write_end, .bmap = ext2_bmap, - .direct_IO = ext2_direct_IO, - .writepages = ext2_writepages, - .migratepage = buffer_migrate_page, - .is_partially_uptodate = block_is_partially_uptodate, +// .direct_IO = ext2_direct_IO, +// .writepages = ext2_writepages, +// .migratepage = buffer_migrate_page, +// .is_partially_uptodate = block_is_partially_uptodate, + .set_page_dirty = fsblock_set_page_dirty, + .invalidatepage = fsblock_invalidate_page, + .releasepage = fsblock_releasepage, + .release = fsblock_release, + .sync = fsblock_sync, }; const struct address_space_operations ext2_aops_xip = { @@ -806,19 +855,6 @@ const struct address_space_operations ex .get_xip_mem = ext2_get_xip_mem, }; -const struct address_space_operations ext2_nobh_aops = { - .readpage = ext2_readpage, - .readpages = ext2_readpages, - .writepage = ext2_nobh_writepage, - .sync_page = block_sync_page, - .write_begin = ext2_nobh_write_begin, - .write_end = nobh_write_end, - .bmap = ext2_bmap, - .direct_IO = ext2_direct_IO, - .writepages = ext2_writepages, - .migratepage = buffer_migrate_page, -}; - /* * Probably it should be a library function... search for first non-zero word * or memcmp with zero_page, whatever is better for particular architecture. @@ -853,7 +889,7 @@ static inline int all_zeroes(__le32 *p, * point might try to populate it. * * We atomically detach the top of branch from the tree, store the block - * number of its root in *@top, pointers to buffer_heads of partially + * number of its root in *@top, pointers to fsblock_meta of partially * truncated blocks - in @chain[].bh and pointers to their last elements * that should not be removed - in @chain[].p. Return value is the pointer * to last filled element of @chain. @@ -890,7 +926,7 @@ static Indirect *ext2_find_shared(struct write_unlock(&EXT2_I(inode)->i_meta_lock); goto no_top; } - for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--) + for (p=partial; p>chain && all_zeroes((__le32*)p->mb->data,p->p); p--) ; /* * OK, we've found the last block that must survive. The rest of our @@ -908,7 +944,7 @@ static Indirect *ext2_find_shared(struct while(partial > p) { - brelse(partial->bh); + block_put(partial->mb); partial--; } no_top: @@ -967,7 +1003,7 @@ static inline void ext2_free_data(struct */ static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int depth) { - struct buffer_head * bh; + struct fsblock_meta * mb; unsigned long nr; if (depth--) { @@ -977,22 +1013,22 @@ static void ext2_free_branches(struct in if (!nr) continue; *p = 0; - bh = sb_bread(inode->i_sb, nr); + mb = sb_mbread(&EXT2_SB(inode->i_sb)->fsb_sb, nr); /* * A read failure? Report error and clear slot * (should be rare). */ - if (!bh) { + if (!mb) { ext2_error(inode->i_sb, "ext2_free_branches", "Read failure, inode=%ld, block=%ld", inode->i_ino, nr); continue; } ext2_free_branches(inode, - (__le32*)bh->b_data, - (__le32*)bh->b_data + addr_per_block, + (__le32*)mb->data, + (__le32*)mb->data + addr_per_block, depth); - bforget(bh); + mbforget(mb); ext2_free_blocks(inode, nr, 1); mark_inode_dirty(inode); } @@ -1000,7 +1036,7 @@ static void ext2_free_branches(struct in ext2_free_data(inode, p, q); } -void ext2_truncate(struct inode *inode) +noinline void ext2_truncate(struct inode *inode) { __le32 *i_data = EXT2_I(inode)->i_data; struct ext2_inode_info *ei = EXT2_I(inode); @@ -1027,12 +1063,14 @@ void ext2_truncate(struct inode *inode) if (mapping_is_xip(inode->i_mapping)) xip_truncate_page(inode->i_mapping, inode->i_size); - else if (test_opt(inode->i_sb, NOBH)) - nobh_truncate_page(inode->i_mapping, - inode->i_size, ext2_get_block); - else - block_truncate_page(inode->i_mapping, - inode->i_size, ext2_get_block); + else { + /* XXX: error codes? */ + fsblock_truncate_page(inode->i_mapping, + inode->i_size); +#ifdef EXT2_EXTMAP + fsb_ext_unmap_fsblock(inode->i_mapping, inode->i_size, -1, &EXT2_I(inode)->fsb_ext_root); +#endif + } n = ext2_block_to_path(inode, iblock, offsets, NULL); if (n == 0) @@ -1056,17 +1094,17 @@ void ext2_truncate(struct inode *inode) if (partial == chain) mark_inode_dirty(inode); else - mark_buffer_dirty_inode(partial->bh, inode); + mark_mblock_dirty_inode(partial->mb, inode); ext2_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial); } /* Clear the ends of indirect blocks on the shared branch */ while (partial > chain) { ext2_free_branches(inode, partial->p + 1, - (__le32*)partial->bh->b_data+addr_per_block, + (__le32*)partial->mb->data+addr_per_block, (chain+n-1) - partial); - mark_buffer_dirty_inode(partial->bh, inode); - brelse (partial->bh); + mark_mblock_dirty_inode(partial->mb, inode); + block_put(partial->mb); partial--; } do_indirects: @@ -1102,7 +1140,7 @@ do_indirects: mutex_unlock(&ei->truncate_mutex); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; if (inode_needs_sync(inode)) { - sync_mapping_buffers(inode->i_mapping); + fsblock_sync(inode->i_mapping); ext2_sync_inode (inode); } else { mark_inode_dirty(inode); @@ -1110,9 +1148,9 @@ do_indirects: } static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino, - struct buffer_head **p) + struct fsblock_meta **p) { - struct buffer_head * bh; + struct fsblock_meta * mb; unsigned long block_group; unsigned long block; unsigned long offset; @@ -1133,12 +1171,12 @@ static struct ext2_inode *ext2_get_inode offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb); block = le32_to_cpu(gdp->bg_inode_table) + (offset >> EXT2_BLOCK_SIZE_BITS(sb)); - if (!(bh = sb_bread(sb, block))) + if (!(mb = sb_mbread(&EXT2_SB(sb)->fsb_sb, block))) goto Eio; - *p = bh; + *p = mb; offset &= (EXT2_BLOCK_SIZE(sb) - 1); - return (struct ext2_inode *) (bh->b_data + offset); + return (struct ext2_inode *) (mb->data + offset); Einval: ext2_error(sb, "ext2_get_inode", "bad inode number: %lu", @@ -1191,7 +1229,7 @@ void ext2_get_inode_flags(struct ext2_in struct inode *ext2_iget (struct super_block *sb, unsigned long ino) { struct ext2_inode_info *ei; - struct buffer_head * bh; + struct fsblock_meta * mb; struct ext2_inode *raw_inode; struct inode *inode; long ret = -EIO; @@ -1210,7 +1248,7 @@ struct inode *ext2_iget (struct super_bl #endif ei->i_block_alloc_info = NULL; - raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); + raw_inode = ext2_get_inode(inode->i_sb, ino, &mb); if (IS_ERR(raw_inode)) { ret = PTR_ERR(raw_inode); goto bad_inode; @@ -1237,7 +1275,7 @@ struct inode *ext2_iget (struct super_bl */ if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) { /* this inode is deleted */ - brelse (bh); + block_put(mb); ret = -ESTALE; goto bad_inode; } @@ -1270,9 +1308,6 @@ struct inode *ext2_iget (struct super_bl if (ext2_use_xip(inode->i_sb)) { inode->i_mapping->a_ops = &ext2_aops_xip; inode->i_fop = &ext2_xip_file_operations; - } else if (test_opt(inode->i_sb, NOBH)) { - inode->i_mapping->a_ops = &ext2_nobh_aops; - inode->i_fop = &ext2_file_operations; } else { inode->i_mapping->a_ops = &ext2_aops; inode->i_fop = &ext2_file_operations; @@ -1280,10 +1315,7 @@ struct inode *ext2_iget (struct super_bl } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &ext2_dir_inode_operations; inode->i_fop = &ext2_dir_operations; - if (test_opt(inode->i_sb, NOBH)) - inode->i_mapping->a_ops = &ext2_nobh_aops; - else - inode->i_mapping->a_ops = &ext2_aops; + inode->i_mapping->a_ops = &ext2_aops; } else if (S_ISLNK(inode->i_mode)) { if (ext2_inode_is_fast_symlink(inode)) { inode->i_op = &ext2_fast_symlink_inode_operations; @@ -1291,10 +1323,7 @@ struct inode *ext2_iget (struct super_bl sizeof(ei->i_data) - 1); } else { inode->i_op = &ext2_symlink_inode_operations; - if (test_opt(inode->i_sb, NOBH)) - inode->i_mapping->a_ops = &ext2_nobh_aops; - else - inode->i_mapping->a_ops = &ext2_aops; + inode->i_mapping->a_ops = &ext2_aops; } } else { inode->i_op = &ext2_special_inode_operations; @@ -1305,7 +1334,7 @@ struct inode *ext2_iget (struct super_bl init_special_inode(inode, inode->i_mode, new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); } - brelse (bh); + block_put(mb); ext2_set_inode_flags(inode); unlock_new_inode(inode); return inode; @@ -1315,15 +1344,15 @@ bad_inode: return ERR_PTR(ret); } -static int ext2_update_inode(struct inode * inode, int do_sync) +static noinline int ext2_update_inode(struct inode * inode, int do_sync) { struct ext2_inode_info *ei = EXT2_I(inode); struct super_block *sb = inode->i_sb; ino_t ino = inode->i_ino; uid_t uid = inode->i_uid; gid_t gid = inode->i_gid; - struct buffer_head * bh; - struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh); + struct fsblock_meta * mb; + struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &mb); int n; int err = 0; @@ -1382,11 +1411,9 @@ static int ext2_update_inode(struct inod /* If this is the first large file * created, add a flag to the superblock. */ - lock_kernel(); ext2_update_dynamic_rev(sb); EXT2_SET_RO_COMPAT_FEATURE(sb, EXT2_FEATURE_RO_COMPAT_LARGE_FILE); - unlock_kernel(); ext2_write_super(sb); } } @@ -1406,17 +1433,18 @@ static int ext2_update_inode(struct inod } } else for (n = 0; n < EXT2_N_BLOCKS; n++) raw_inode->i_block[n] = ei->i_data[n]; - mark_buffer_dirty(bh); + mark_mblock_dirty(mb); if (do_sync) { - sync_dirty_buffer(bh); - if (buffer_req(bh) && !buffer_uptodate(bh)) { + sync_block(mb); +// if (buffer_req(bh) && !buffer_uptodate(bh)) { + if (!(mb->block.flags & BL_uptodate)) { printk ("IO error syncing ext2 inode [%s:%08lx]\n", sb->s_id, (unsigned long) ino); err = -EIO; } } ei->i_state &= ~EXT2_STATE_NEW; - brelse (bh); + block_put(mb); return err; } Index: linux-2.6/fs/ext2/super.c =================================================================== --- linux-2.6.orig/fs/ext2/super.c +++ linux-2.6/fs/ext2/super.c @@ -24,7 +24,7 @@ #include <linux/blkdev.h> #include <linux/parser.h> #include <linux/random.h> -#include <linux/buffer_head.h> +#include <linux/fsblock.h> #include <linux/exportfs.h> #include <linux/smp_lock.h> #include <linux/vfs.h> @@ -32,6 +32,7 @@ #include <linux/mount.h> #include <linux/log2.h> #include <linux/quotaops.h> +#include <linux/buffer_head.h> #include <asm/uaccess.h> #include "ext2.h" #include "xattr.h" @@ -121,16 +122,19 @@ static void ext2_put_super (struct super es->s_state = cpu_to_le16(sbi->s_mount_state); ext2_sync_super(sb, es); } + db_count = sbi->s_gdb_count; for (i = 0; i < db_count; i++) if (sbi->s_group_desc[i]) - brelse (sbi->s_group_desc[i]); + block_put(sbi->s_group_desc[i]); kfree(sbi->s_group_desc); kfree(sbi->s_debts); percpu_counter_destroy(&sbi->s_freeblocks_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter); percpu_counter_destroy(&sbi->s_dirs_counter); - brelse (sbi->s_sbh); + if (sbi->s_smb) + block_put(sbi->s_smb); + fsblock_unregister_super(sb, &sbi->fsb_sb); sb->s_fs_info = NULL; kfree(sbi->s_blockgroup_lock); kfree(sbi); @@ -152,11 +156,16 @@ static struct inode *ext2_alloc_inode(st #endif ei->i_block_alloc_info = NULL; ei->vfs_inode.i_version = 1; + fsb_ext_root_init(&ei->fsb_ext_root); return &ei->vfs_inode; } static void ext2_destroy_inode(struct inode *inode) { + fsblock_release(&inode->i_data, 1); +#ifdef EXT2_EXTMAP + fsb_ext_release(inode->i_mapping, &EXT2_I(inode)->fsb_ext_root); +#endif kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); } @@ -739,6 +748,7 @@ static unsigned long descriptor_loc(stru static int ext2_fill_super(struct super_block *sb, void *data, int silent) { struct buffer_head * bh; + struct fsblock_meta * mb; struct ext2_sb_info * sbi; struct ext2_super_block * es; struct inode *root; @@ -803,8 +813,10 @@ static int ext2_fill_super(struct super_ sbi->s_es = es; sb->s_magic = le16_to_cpu(es->s_magic); - if (sb->s_magic != EXT2_SUPER_MAGIC) + if (sb->s_magic != EXT2_SUPER_MAGIC) { + printk("ext2 fill super wrong magic\n"); goto cantfind_ext2; + } /* Set defaults before we parse the mount options */ def_mount_opts = le32_to_cpu(es->s_default_mount_opts); @@ -881,7 +893,7 @@ static int ext2_fill_super(struct super_ /* If the blocksize doesn't match, re-read the thing.. */ if (sb->s_blocksize != blocksize) { - brelse(bh); + put_bh(bh); if (!sb_set_blocksize(sb, blocksize)) { printk(KERN_ERR "EXT2-fs: blocksize too small for device.\n"); @@ -904,6 +916,20 @@ static int ext2_fill_super(struct super_ } } + ret = fsblock_register_super(sb, &sbi->fsb_sb); + if (ret) + goto failed_fsblock; + + mb = sb_mbread(&sbi->fsb_sb, logic_sb_block); + if (!mb) { + printk("EXT2-fs: Could not read fsblock metadata block for superblock\n"); + goto failed_fsblock; + } + + put_bh(bh); + es = (struct ext2_super_block *) (((char *)mb->data) + offset); + sbi->s_es = es; + sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) { @@ -940,7 +966,7 @@ static int ext2_fill_super(struct super_ sbi->s_inodes_per_block; sbi->s_desc_per_block = sb->s_blocksize / sizeof (struct ext2_group_desc); - sbi->s_sbh = bh; + sbi->s_smb = mb; sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_addr_per_block_bits = ilog2 (EXT2_ADDR_PER_BLOCK(sb)); @@ -950,7 +976,7 @@ static int ext2_fill_super(struct super_ if (sb->s_magic != EXT2_SUPER_MAGIC) goto cantfind_ext2; - if (sb->s_blocksize != bh->b_size) { + if (sb->s_blocksize != fsblock_size(mb)) { if (!silent) printk ("VFS: Unsupported blocksize on dev " "%s.\n", sb->s_id); @@ -986,7 +1012,7 @@ static int ext2_fill_super(struct super_ / EXT2_BLOCKS_PER_GROUP(sb)) + 1; db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / EXT2_DESC_PER_BLOCK(sb); - sbi->s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL); + sbi->s_group_desc = kmalloc (db_count * sizeof (struct fsblock_meta *), GFP_KERNEL); if (sbi->s_group_desc == NULL) { printk ("EXT2-fs: not enough memory\n"); goto failed_mount; @@ -999,10 +1025,10 @@ static int ext2_fill_super(struct super_ } for (i = 0; i < db_count; i++) { block = descriptor_loc(sb, logic_sb_block, i); - sbi->s_group_desc[i] = sb_bread(sb, block); + sbi->s_group_desc[i] = sb_mbread(&EXT2_SB(sb)->fsb_sb, block); if (!sbi->s_group_desc[i]) { for (j = 0; j < i; j++) - brelse (sbi->s_group_desc[j]); + block_put(sbi->s_group_desc[j]); printk ("EXT2-fs: unable to read group descriptors\n"); goto failed_mount_group_desc; } @@ -1085,14 +1111,17 @@ failed_mount3: percpu_counter_destroy(&sbi->s_dirs_counter); failed_mount2: for (i = 0; i < db_count; i++) - brelse(sbi->s_group_desc[i]); + block_put(sbi->s_group_desc[i]); failed_mount_group_desc: kfree(sbi->s_group_desc); kfree(sbi->s_debts); failed_mount: - brelse(bh); + put_bh(bh); failed_sbi: + fsblock_unregister_super(sb, &sbi->fsb_sb); sb->s_fs_info = NULL; +failed_fsblock: + block_put(mb); kfree(sbi); return ret; } @@ -1101,7 +1130,7 @@ static void ext2_commit_super (struct su struct ext2_super_block * es) { es->s_wtime = cpu_to_le32(get_seconds()); - mark_buffer_dirty(EXT2_SB(sb)->s_sbh); + mark_mblock_dirty(EXT2_SB(sb)->s_smb); sb->s_dirt = 0; } @@ -1110,8 +1139,8 @@ static void ext2_sync_super(struct super es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); es->s_wtime = cpu_to_le32(get_seconds()); - mark_buffer_dirty(EXT2_SB(sb)->s_sbh); - sync_dirty_buffer(EXT2_SB(sb)->s_sbh); + mark_mblock_dirty(EXT2_SB(sb)->s_smb); + sync_block(EXT2_SB(sb)->s_smb); sb->s_dirt = 0; } @@ -1129,7 +1158,6 @@ static void ext2_sync_super(struct super void ext2_write_super (struct super_block * sb) { struct ext2_super_block * es; - lock_kernel(); if (!(sb->s_flags & MS_RDONLY)) { es = EXT2_SB(sb)->s_es; @@ -1144,7 +1172,6 @@ void ext2_write_super (struct super_bloc ext2_commit_super (sb, es); } sb->s_dirt = 0; - unlock_kernel(); } static int ext2_remount (struct super_block * sb, int * flags, char * data) @@ -1304,107 +1331,7 @@ static int ext2_get_sb(struct file_syste #ifdef CONFIG_QUOTA -/* Read data from quotafile - avoid pagecache and such because we cannot afford - * acquiring the locks... As quota files are never truncated and quota code - * itself serializes the operations (and noone else should touch the files) - * we don't have to be afraid of races */ -static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, - size_t len, loff_t off) -{ - struct inode *inode = sb_dqopt(sb)->files[type]; - sector_t blk = off >> EXT2_BLOCK_SIZE_BITS(sb); - int err = 0; - int offset = off & (sb->s_blocksize - 1); - int tocopy; - size_t toread; - struct buffer_head tmp_bh; - struct buffer_head *bh; - loff_t i_size = i_size_read(inode); - - if (off > i_size) - return 0; - if (off+len > i_size) - len = i_size-off; - toread = len; - while (toread > 0) { - tocopy = sb->s_blocksize - offset < toread ? - sb->s_blocksize - offset : toread; - - tmp_bh.b_state = 0; - err = ext2_get_block(inode, blk, &tmp_bh, 0); - if (err < 0) - return err; - if (!buffer_mapped(&tmp_bh)) /* A hole? */ - memset(data, 0, tocopy); - else { - bh = sb_bread(sb, tmp_bh.b_blocknr); - if (!bh) - return -EIO; - memcpy(data, bh->b_data+offset, tocopy); - brelse(bh); - } - offset = 0; - toread -= tocopy; - data += tocopy; - blk++; - } - return len; -} - -/* Write to quotafile */ -static ssize_t ext2_quota_write(struct super_block *sb, int type, - const char *data, size_t len, loff_t off) -{ - struct inode *inode = sb_dqopt(sb)->files[type]; - sector_t blk = off >> EXT2_BLOCK_SIZE_BITS(sb); - int err = 0; - int offset = off & (sb->s_blocksize - 1); - int tocopy; - size_t towrite = len; - struct buffer_head tmp_bh; - struct buffer_head *bh; - - mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); - while (towrite > 0) { - tocopy = sb->s_blocksize - offset < towrite ? - sb->s_blocksize - offset : towrite; - - tmp_bh.b_state = 0; - err = ext2_get_block(inode, blk, &tmp_bh, 1); - if (err < 0) - goto out; - if (offset || tocopy != EXT2_BLOCK_SIZE(sb)) - bh = sb_bread(sb, tmp_bh.b_blocknr); - else - bh = sb_getblk(sb, tmp_bh.b_blocknr); - if (!bh) { - err = -EIO; - goto out; - } - lock_buffer(bh); - memcpy(bh->b_data+offset, data, tocopy); - flush_dcache_page(bh->b_page); - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - unlock_buffer(bh); - brelse(bh); - offset = 0; - towrite -= tocopy; - data += tocopy; - blk++; - } -out: - if (len == towrite) - return err; - if (inode->i_size < off+len-towrite) - i_size_write(inode, off+len-towrite); - inode->i_version++; - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - mutex_unlock(&inode->i_mutex); - return len - towrite; -} - +#error "not yet supported" #endif static struct file_system_type ext2_fs_type = { Index: linux-2.6/fs/ext2/xattr.c =================================================================== --- linux-2.6.orig/fs/ext2/xattr.c +++ linux-2.6/fs/ext2/xattr.c @@ -53,7 +53,7 @@ * to avoid deadlocks. */ -#include <linux/buffer_head.h> +#include <linux/fsblock.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -64,9 +64,9 @@ #include "xattr.h" #include "acl.h" -#define HDR(bh) ((struct ext2_xattr_header *)((bh)->b_data)) +#define HDR(fsb) ((struct ext2_xattr_header *)((fsb)->data)) #define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr)) -#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) +#define FIRST_ENTRY(fsb) ENTRY(HDR(fsb)+1) #define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) #ifdef EXT2_XATTR_DEBUG @@ -76,11 +76,11 @@ printk(f); \ printk("\n"); \ } while (0) -# define ea_bdebug(bh, f...) do { \ +# define ea_bdebug(fsb, f...) do { \ char b[BDEVNAME_SIZE]; \ - printk(KERN_DEBUG "block %s:%lu: ", \ - bdevname(bh->b_bdev, b), \ - (unsigned long) bh->b_blocknr); \ + printk(KERN_DEBUG "block %s:%llu: ", \ + bdevname(fsb->page->mapping->host->i_sb->sb_bdev, b), \ + (unsigned long long) fsb->blocknr); \ printk(f); \ printk("\n"); \ } while (0) @@ -89,11 +89,11 @@ # define ea_bdebug(f...) #endif -static int ext2_xattr_set2(struct inode *, struct buffer_head *, +static int ext2_xattr_set2(struct inode *, struct fsblock *, struct ext2_xattr_header *); -static int ext2_xattr_cache_insert(struct buffer_head *); -static struct buffer_head *ext2_xattr_cache_find(struct inode *, +static int ext2_xattr_cache_insert(struct fsblock *); +static struct fsblock *ext2_xattr_cache_find(struct inode *, struct ext2_xattr_header *); static void ext2_xattr_rehash(struct ext2_xattr_header *, struct ext2_xattr_entry *); @@ -149,7 +149,7 @@ int ext2_xattr_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t buffer_size) { - struct buffer_head *bh = NULL; + struct fsblock *fsb = NULL; struct ext2_xattr_entry *entry; size_t name_len, size; char *end; @@ -165,15 +165,15 @@ ext2_xattr_get(struct inode *inode, int if (!EXT2_I(inode)->i_file_acl) goto cleanup; ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); + fsb = sb_mbread(inode->i_sb, EXT2_I(inode)->i_file_acl); error = -EIO; - if (!bh) + if (!fsb) goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); - end = bh->b_data + bh->b_size; - if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || - HDR(bh)->h_blocks != cpu_to_le32(1)) { + ea_bdebug(fsb, "count=%d, refcount=%d", + atomic_read(&(fsb->count)), le32_to_cpu(HDR(fsb)->h_refcount)); + end = fsb->data + fsblock_size(fsb); + if (HDR(fsb)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || + HDR(fsb)->h_blocks != cpu_to_le32(1)) { bad_block: ext2_error(inode->i_sb, "ext2_xattr_get", "inode %ld: bad block %d", inode->i_ino, EXT2_I(inode)->i_file_acl); @@ -186,7 +186,7 @@ bad_block: ext2_error(inode->i_sb, "ext2 error = -ERANGE; if (name_len > 255) goto cleanup; - entry = FIRST_ENTRY(bh); + entry = FIRST_ENTRY(fsb); while (!IS_LAST_ENTRY(entry)) { struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry); @@ -206,7 +206,7 @@ bad_block: ext2_error(inode->i_sb, "ext2 goto bad_block; entry = next; } - if (ext2_xattr_cache_insert(bh)) + if (ext2_xattr_cache_insert(fsb)) ea_idebug(inode, "cache insert failed"); error = -ENODATA; goto cleanup; @@ -219,20 +219,20 @@ found: le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) goto bad_block; - if (ext2_xattr_cache_insert(bh)) + if (ext2_xattr_cache_insert(fsb)) ea_idebug(inode, "cache insert failed"); if (buffer) { error = -ERANGE; if (size > buffer_size) goto cleanup; /* return value of attribute */ - memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), + memcpy(buffer, fsb->data + le16_to_cpu(entry->e_value_offs), size); } error = size; cleanup: - brelse(bh); + mbrelse(fsb); up_read(&EXT2_I(inode)->xattr_sem); return error; @@ -251,7 +251,7 @@ cleanup: static int ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) { - struct buffer_head *bh = NULL; + struct fsblock *fsb = NULL; struct ext2_xattr_entry *entry; char *end; size_t rest = buffer_size; @@ -265,15 +265,15 @@ ext2_xattr_list(struct inode *inode, cha if (!EXT2_I(inode)->i_file_acl) goto cleanup; ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); + fsb = sb_mbread(inode->i_sb, EXT2_I(inode)->i_file_acl); error = -EIO; - if (!bh) + if (!fsb) goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); - end = bh->b_data + bh->b_size; - if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || - HDR(bh)->h_blocks != cpu_to_le32(1)) { + ea_bdebug(fsb, "count=%d, refcount=%d", + atomic_read(&(fsb->count)), le32_to_cpu(HDR(bh)->h_refcount)); + end = fsb->data + fsblock_size(fsb); + if (HDR(fsb)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || + HDR(fsb)->h_blocks != cpu_to_le32(1)) { bad_block: ext2_error(inode->i_sb, "ext2_xattr_list", "inode %ld: bad block %d", inode->i_ino, EXT2_I(inode)->i_file_acl); @@ -282,7 +282,7 @@ bad_block: ext2_error(inode->i_sb, "ext2 } /* check the on-disk data structure */ - entry = FIRST_ENTRY(bh); + entry = FIRST_ENTRY(fsb); while (!IS_LAST_ENTRY(entry)) { struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry); @@ -290,11 +290,11 @@ bad_block: ext2_error(inode->i_sb, "ext2 goto bad_block; entry = next; } - if (ext2_xattr_cache_insert(bh)) + if (ext2_xattr_cache_insert(fsb)) ea_idebug(inode, "cache insert failed"); /* list the attribute names */ - for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); + for (entry = FIRST_ENTRY(fsb); !IS_LAST_ENTRY(entry); entry = EXT2_XATTR_NEXT(entry)) { struct xattr_handler *handler = ext2_xattr_handler(entry->e_name_index); @@ -316,7 +316,7 @@ bad_block: ext2_error(inode->i_sb, "ext2 error = buffer_size - rest; /* total size */ cleanup: - brelse(bh); + mbrelse(fsb); up_read(&EXT2_I(inode)->xattr_sem); return error; @@ -344,7 +344,7 @@ static void ext2_xattr_update_super_bloc EXT2_SET_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR); sb->s_dirt = 1; - mark_buffer_dirty(EXT2_SB(sb)->s_sbh); + mark_mblock_dirty(EXT2_SB(sb)->s_smb); } /* @@ -364,7 +364,7 @@ ext2_xattr_set(struct inode *inode, int const void *value, size_t value_len, int flags) { struct super_block *sb = inode->i_sb; - struct buffer_head *bh = NULL; + struct fsblock *fsb = NULL; struct ext2_xattr_header *header = NULL; struct ext2_xattr_entry *here, *last; size_t name_len, free, min_offs = sb->s_blocksize; @@ -372,7 +372,7 @@ ext2_xattr_set(struct inode *inode, int char *end; /* - * header -- Points either into bh, or to a temporarily + * header -- Points either into fsb, or to a temporarily * allocated buffer. * here -- The named entry found, or the place for inserting, within * the block pointed to by header. @@ -396,15 +396,15 @@ ext2_xattr_set(struct inode *inode, int down_write(&EXT2_I(inode)->xattr_sem); if (EXT2_I(inode)->i_file_acl) { /* The inode already has an extended attribute block. */ - bh = sb_bread(sb, EXT2_I(inode)->i_file_acl); + fsb = sb_mbread(sb, EXT2_I(inode)->i_file_acl); error = -EIO; - if (!bh) + if (!fsb) goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), - le32_to_cpu(HDR(bh)->h_refcount)); - header = HDR(bh); - end = bh->b_data + bh->b_size; + ea_bdebug(fsb, "count=%d, refcount=%d", + atomic_read(&(fsb->count)), + le32_to_cpu(HDR(fsb)->h_refcount)); + header = HDR(fsb); + end = fsb->data + fsblock_size(fsb); if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || header->h_blocks != cpu_to_le32(1)) { bad_block: ext2_error(sb, "ext2_xattr_set", @@ -414,7 +414,7 @@ bad_block: ext2_error(sb, "ext2_xattr_s goto cleanup; } /* Find the named attribute. */ - here = FIRST_ENTRY(bh); + here = FIRST_ENTRY(fsb); while (!IS_LAST_ENTRY(here)) { struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(here); if ((char *)next >= end) @@ -488,12 +488,12 @@ bad_block: ext2_error(sb, "ext2_xattr_s if (header) { struct mb_cache_entry *ce; - /* assert(header == HDR(bh)); */ - ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, - bh->b_blocknr); - lock_buffer(bh); + /* assert(header == HDR(fsb)); */ + ce = mb_cache_entry_get(ext2_xattr_cache, fsb->b_bdev, + fsb->blocknr); + lock_block(fsb); if (header->h_refcount == cpu_to_le32(1)) { - ea_bdebug(bh, "modifying in-place"); + ea_bdebug(fsb, "modifying in-place"); if (ce) mb_cache_entry_free(ce); /* keep the buffer locked while modifying it. */ @@ -502,18 +502,18 @@ bad_block: ext2_error(sb, "ext2_xattr_s if (ce) mb_cache_entry_release(ce); - unlock_buffer(bh); - ea_bdebug(bh, "cloning"); - header = kmalloc(bh->b_size, GFP_KERNEL); + unlock_block(fsb); + ea_bdebug(fsb, "cloning"); + header = kmalloc(fsb->b_size, GFP_KERNEL); error = -ENOMEM; if (header == NULL) goto cleanup; - memcpy(header, HDR(bh), bh->b_size); + memcpy(header, HDR(fsb), fsb->b_size); header->h_refcount = cpu_to_le32(1); - offset = (char *)here - bh->b_data; + offset = (char *)here - fsb->data; here = ENTRY((char *)header + offset); - offset = (char *)last - bh->b_data; + offset = (char *)last - fsb->data; last = ENTRY((char *)header + offset); } } else { @@ -528,7 +528,7 @@ bad_block: ext2_error(sb, "ext2_xattr_s last = here = ENTRY(header+1); } - /* Iff we are modifying the block in-place, bh is locked here. */ + /* Iff we are modifying the block in-place, fsb is locked here. */ if (not_found) { /* Insert the new name. */ @@ -600,19 +600,19 @@ bad_block: ext2_error(sb, "ext2_xattr_s skip_replace: if (IS_LAST_ENTRY(ENTRY(header+1))) { /* This block is now empty. */ - if (bh && header == HDR(bh)) - unlock_buffer(bh); /* we were modifying in-place. */ - error = ext2_xattr_set2(inode, bh, NULL); + if (fsb && header == HDR(fsb)) + unlock_buffer(fsb); /* we were modifying in-place. */ + error = ext2_xattr_set2(inode, fsb, NULL); } else { ext2_xattr_rehash(header, here); - if (bh && header == HDR(bh)) - unlock_buffer(bh); /* we were modifying in-place. */ - error = ext2_xattr_set2(inode, bh, header); + if (fsb && header == HDR(fsb)) + unlock_buffer(fsb); /* we were modifying in-place. */ + error = ext2_xattr_set2(inode, fsb, header); } cleanup: - brelse(bh); - if (!(bh && header == HDR(bh))) + mbrelse(fsb); + if (!(fsb && header == HDR(fsb))) kfree(header); up_write(&EXT2_I(inode)->xattr_sem); @@ -623,11 +623,11 @@ cleanup: * Second half of ext2_xattr_set(): Update the file system. */ static int -ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, +ext2_xattr_set2(struct inode *inode, struct fsblock *old_fsb, struct ext2_xattr_header *header) { struct super_block *sb = inode->i_sb; - struct buffer_head *new_bh = NULL; + struct fsblock *new_fsb = NULL; int error; if (header) { @@ -754,7 +754,7 @@ cleanup: void ext2_xattr_delete_inode(struct inode *inode) { - struct buffer_head *bh = NULL; + struct fsblock *fsb = NULL; struct mb_cache_entry *ce; down_write(&EXT2_I(inode)->xattr_sem); @@ -824,7 +824,7 @@ ext2_xattr_put_super(struct super_block * Returns 0, or a negative error number on failure. */ static int -ext2_xattr_cache_insert(struct buffer_head *bh) +ext2_xattr_cache_insert(struct fsblock *fsb) { __u32 hash = le32_to_cpu(HDR(bh)->h_hash); struct mb_cache_entry *ce; @@ -897,7 +897,7 @@ ext2_xattr_cmp(struct ext2_xattr_header * Returns a locked buffer head to the block found, or NULL if such * a block was not found or an error occurred. */ -static struct buffer_head * +static struct fsblock * ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) { __u32 hash = le32_to_cpu(header->h_hash); @@ -910,7 +910,7 @@ again: ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, inode->i_sb->s_bdev, hash); while (ce) { - struct buffer_head *bh; + struct fsblock *fsb; if (IS_ERR(ce)) { if (PTR_ERR(ce) == -EAGAIN) Index: linux-2.6/fs/ext2/xip.c =================================================================== --- linux-2.6.orig/fs/ext2/xip.c +++ linux-2.6/fs/ext2/xip.c @@ -8,7 +8,7 @@ #include <linux/mm.h> #include <linux/fs.h> #include <linux/genhd.h> -#include <linux/buffer_head.h> +#include <linux/fsblock.h> #include <linux/ext2_fs_sb.h> #include <linux/ext2_fs.h> #include <linux/blkdev.h> @@ -33,16 +33,16 @@ static inline int __ext2_get_block(struct inode *inode, pgoff_t pgoff, int create, sector_t *result) { - struct buffer_head tmp; + struct fsblock tmp; int rc; - memset(&tmp, 0, sizeof(struct buffer_head)); - rc = ext2_get_block(inode, pgoff, &tmp, create); - *result = tmp.b_blocknr; + memset(&tmp, 0, sizeof(struct fsblock)); + rc = ext2_map_block(inode, pgoff, &tmp, create); + *result = tmp.blocknr; /* did we get a sparse block (hole in the file)? */ - if (!tmp.b_blocknr && !rc) { - BUG_ON(create); + if (!tmp.blocknr && !rc) { + WARN_ON(create); rc = -ENODATA; } Index: linux-2.6/include/linux/ext2_fs_sb.h =================================================================== --- linux-2.6.orig/include/linux/ext2_fs_sb.h +++ linux-2.6/include/linux/ext2_fs_sb.h @@ -19,6 +19,7 @@ #include <linux/blockgroup_lock.h> #include <linux/percpu_counter.h> #include <linux/rbtree.h> +#include <linux/fsblock.h> /* XXX Here for now... not interested in restructing headers JUST now */ @@ -81,9 +82,9 @@ struct ext2_sb_info { unsigned long s_groups_count; /* Number of groups in the fs */ unsigned long s_overhead_last; /* Last calculated overhead */ unsigned long s_blocks_last; /* Last seen block count */ - struct buffer_head * s_sbh; /* Buffer containing the super block */ + struct fsblock_meta * s_smb; /* Buffer containing the super block */ struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */ - struct buffer_head ** s_group_desc; + struct fsblock_meta ** s_group_desc; unsigned long s_mount_opt; unsigned long s_sb_block; uid_t s_resuid; @@ -106,6 +107,7 @@ struct ext2_sb_info { spinlock_t s_rsv_window_lock; struct rb_root s_rsv_window_root; struct ext2_reserve_window_node s_rsv_window_head; + struct fsblock_sb fsb_sb; }; static inline spinlock_t * -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html