diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2009-01-05 21:36:19 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-01-05 21:36:19 -0500 |
commit | 920313a726e04fef0f2c0bcb04ad8229c0e700d8 (patch) | |
tree | 7e7644a2fd48586ec2f455e56525565174798e4a /fs/ext4/resize.c | |
parent | e21675d4b63975d09eb75c443c48ebe663d23e18 (diff) |
ext4: Use EXT4_GROUP_INFO_NEED_INIT_BIT during resize
The new groups added during resize are flagged as
need_init group. Make sure we properly initialize these
groups. When we have block size < page size and we are adding
new groups the page may still be marked uptodate even though
we haven't initialized the group. While forcing the init
of buddy cache we need to make sure other groups part of the
same page of buddy cache is not using the cache.
group_info->alloc_sem is added to ensure the same.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
cc: stable@kernel.org
Diffstat (limited to 'fs/ext4/resize.c')
-rw-r--r-- | fs/ext4/resize.c | 49 |
1 files changed, 8 insertions, 41 deletions
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 526db73701b4..92034d2c8a73 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -748,6 +748,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
748 | struct inode *inode = NULL; | 748 | struct inode *inode = NULL; |
749 | handle_t *handle; | 749 | handle_t *handle; |
750 | int gdb_off, gdb_num; | 750 | int gdb_off, gdb_num; |
751 | int num_grp_locked = 0; | ||
751 | int err, err2; | 752 | int err, err2; |
752 | 753 | ||
753 | gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb); | 754 | gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb); |
@@ -788,6 +789,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
788 | } | 789 | } |
789 | } | 790 | } |
790 | 791 | ||
792 | |||
791 | if ((err = verify_group_input(sb, input))) | 793 | if ((err = verify_group_input(sb, input))) |
792 | goto exit_put; | 794 | goto exit_put; |
793 | 795 | ||
@@ -856,6 +858,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
856 | * using the new disk blocks. | 858 | * using the new disk blocks. |
857 | */ | 859 | */ |
858 | 860 | ||
861 | num_grp_locked = ext4_mb_get_buddy_cache_lock(sb, input->group); | ||
859 | /* Update group descriptor block for new group */ | 862 | /* Update group descriptor block for new group */ |
860 | gdp = (struct ext4_group_desc *)((char *)primary->b_data + | 863 | gdp = (struct ext4_group_desc *)((char *)primary->b_data + |
861 | gdb_off * EXT4_DESC_SIZE(sb)); | 864 | gdb_off * EXT4_DESC_SIZE(sb)); |
@@ -872,9 +875,11 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
872 | * We can allocate memory for mb_alloc based on the new group | 875 | * We can allocate memory for mb_alloc based on the new group |
873 | * descriptor | 876 | * descriptor |
874 | */ | 877 | */ |
875 | err = ext4_mb_add_more_groupinfo(sb, input->group, gdp); | 878 | err = ext4_mb_add_groupinfo(sb, input->group, gdp); |
876 | if (err) | 879 | if (err) { |
880 | ext4_mb_put_buddy_cache_lock(sb, input->group, num_grp_locked); | ||
877 | goto exit_journal; | 881 | goto exit_journal; |
882 | } | ||
878 | 883 | ||
879 | /* | 884 | /* |
880 | * Make the new blocks and inodes valid next. We do this before | 885 | * Make the new blocks and inodes valid next. We do this before |
@@ -916,6 +921,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
916 | 921 | ||
917 | /* Update the global fs size fields */ | 922 | /* Update the global fs size fields */ |
918 | sbi->s_groups_count++; | 923 | sbi->s_groups_count++; |
924 | ext4_mb_put_buddy_cache_lock(sb, input->group, num_grp_locked); | ||
919 | 925 | ||
920 | ext4_handle_dirty_metadata(handle, NULL, primary); | 926 | ext4_handle_dirty_metadata(handle, NULL, primary); |
921 | 927 | ||
@@ -1082,45 +1088,6 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, | |||
1082 | if ((err = ext4_journal_stop(handle))) | 1088 | if ((err = ext4_journal_stop(handle))) |
1083 | goto exit_put; | 1089 | goto exit_put; |
1084 | 1090 | ||
1085 | /* | ||
1086 | * Mark mballoc pages as not up to date so that they will be updated | ||
1087 | * next time they are loaded by ext4_mb_load_buddy. | ||
1088 | * | ||
1089 | * XXX Bad, Bad, BAD!!! We should not be overloading the | ||
1090 | * Uptodate flag, particularly on thte bitmap bh, as way of | ||
1091 | * hinting to ext4_mb_load_buddy() that it needs to be | ||
1092 | * overloaded. A user could take a LVM snapshot, then do an | ||
1093 | * on-line fsck, and clear the uptodate flag, and this would | ||
1094 | * not be a bug in userspace, but a bug in the kernel. FIXME!!! | ||
1095 | */ | ||
1096 | { | ||
1097 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
1098 | struct inode *inode = sbi->s_buddy_cache; | ||
1099 | int blocks_per_page; | ||
1100 | int block; | ||
1101 | int pnum; | ||
1102 | struct page *page; | ||
1103 | |||
1104 | /* Set buddy page as not up to date */ | ||
1105 | blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; | ||
1106 | block = group * 2; | ||
1107 | pnum = block / blocks_per_page; | ||
1108 | page = find_get_page(inode->i_mapping, pnum); | ||
1109 | if (page != NULL) { | ||
1110 | ClearPageUptodate(page); | ||
1111 | page_cache_release(page); | ||
1112 | } | ||
1113 | |||
1114 | /* Set bitmap page as not up to date */ | ||
1115 | block++; | ||
1116 | pnum = block / blocks_per_page; | ||
1117 | page = find_get_page(inode->i_mapping, pnum); | ||
1118 | if (page != NULL) { | ||
1119 | ClearPageUptodate(page); | ||
1120 | page_cache_release(page); | ||
1121 | } | ||
1122 | } | ||
1123 | |||
1124 | if (test_opt(sb, DEBUG)) | 1091 | if (test_opt(sb, DEBUG)) |
1125 | printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n", | 1092 | printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n", |
1126 | ext4_blocks_count(es)); | 1093 | ext4_blocks_count(es)); |