aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/resize.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/resize.c')
-rw-r--r--fs/ext4/resize.c59
1 files changed, 41 insertions, 18 deletions
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index 472fc0d3e1c0..bd8a52bb3999 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -16,6 +16,7 @@
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/slab.h> 17#include <linux/slab.h>
18 18
19#include "group.h"
19 20
20#define outside(b, first, last) ((b) < (first) || (b) >= (last)) 21#define outside(b, first, last) ((b) < (first) || (b) >= (last))
21#define inside(b, first, last) ((b) >= (first) && (b) < (last)) 22#define inside(b, first, last) ((b) >= (first) && (b) < (last))
@@ -140,22 +141,29 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
140} 141}
141 142
142/* 143/*
143 * To avoid calling the atomic setbit hundreds or thousands of times, we only 144 * If we have fewer than thresh credits, extend by EXT4_MAX_TRANS_DATA.
144 * need to use it within a single byte (to ensure we get endianness right). 145 * If that fails, restart the transaction & regain write access for the
145 * We can use memset for the rest of the bitmap as there are no other users. 146 * buffer head which is used for block_bitmap modifications.
146 */ 147 */
147static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) 148static int extend_or_restart_transaction(handle_t *handle, int thresh,
149 struct buffer_head *bh)
148{ 150{
149 int i; 151 int err;
152
153 if (handle->h_buffer_credits >= thresh)
154 return 0;
150 155
151 if (start_bit >= end_bit) 156 err = ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA);
152 return; 157 if (err < 0)
158 return err;
159 if (err) {
160 if ((err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA)))
161 return err;
162 if ((err = ext4_journal_get_write_access(handle, bh)))
163 return err;
164 }
153 165
154 ext4_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); 166 return 0;
155 for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
156 ext4_set_bit(i, bitmap);
157 if (i < end_bit)
158 memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
159} 167}
160 168
161/* 169/*
@@ -180,8 +188,9 @@ static int setup_new_group_blocks(struct super_block *sb,
180 int i; 188 int i;
181 int err = 0, err2; 189 int err = 0, err2;
182 190
183 handle = ext4_journal_start_sb(sb, reserved_gdb + gdblocks + 191 /* This transaction may be extended/restarted along the way */
184 2 + sbi->s_itb_per_group); 192 handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA);
193
185 if (IS_ERR(handle)) 194 if (IS_ERR(handle))
186 return PTR_ERR(handle); 195 return PTR_ERR(handle);
187 196
@@ -208,6 +217,9 @@ static int setup_new_group_blocks(struct super_block *sb,
208 217
209 ext4_debug("update backup group %#04lx (+%d)\n", block, bit); 218 ext4_debug("update backup group %#04lx (+%d)\n", block, bit);
210 219
220 if ((err = extend_or_restart_transaction(handle, 1, bh)))
221 goto exit_bh;
222
211 gdb = sb_getblk(sb, block); 223 gdb = sb_getblk(sb, block);
212 if (!gdb) { 224 if (!gdb) {
213 err = -EIO; 225 err = -EIO;
@@ -217,10 +229,10 @@ static int setup_new_group_blocks(struct super_block *sb,
217 brelse(gdb); 229 brelse(gdb);
218 goto exit_bh; 230 goto exit_bh;
219 } 231 }
220 lock_buffer(bh); 232 lock_buffer(gdb);
221 memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, bh->b_size); 233 memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size);
222 set_buffer_uptodate(gdb); 234 set_buffer_uptodate(gdb);
223 unlock_buffer(bh); 235 unlock_buffer(gdb);
224 ext4_journal_dirty_metadata(handle, gdb); 236 ext4_journal_dirty_metadata(handle, gdb);
225 ext4_set_bit(bit, bh->b_data); 237 ext4_set_bit(bit, bh->b_data);
226 brelse(gdb); 238 brelse(gdb);
@@ -233,6 +245,9 @@ static int setup_new_group_blocks(struct super_block *sb,
233 245
234 ext4_debug("clear reserved block %#04lx (+%d)\n", block, bit); 246 ext4_debug("clear reserved block %#04lx (+%d)\n", block, bit);
235 247
248 if ((err = extend_or_restart_transaction(handle, 1, bh)))
249 goto exit_bh;
250
236 if (IS_ERR(gdb = bclean(handle, sb, block))) { 251 if (IS_ERR(gdb = bclean(handle, sb, block))) {
237 err = PTR_ERR(bh); 252 err = PTR_ERR(bh);
238 goto exit_bh; 253 goto exit_bh;
@@ -254,6 +269,10 @@ static int setup_new_group_blocks(struct super_block *sb,
254 struct buffer_head *it; 269 struct buffer_head *it;
255 270
256 ext4_debug("clear inode block %#04lx (+%d)\n", block, bit); 271 ext4_debug("clear inode block %#04lx (+%d)\n", block, bit);
272
273 if ((err = extend_or_restart_transaction(handle, 1, bh)))
274 goto exit_bh;
275
257 if (IS_ERR(it = bclean(handle, sb, block))) { 276 if (IS_ERR(it = bclean(handle, sb, block))) {
258 err = PTR_ERR(it); 277 err = PTR_ERR(it);
259 goto exit_bh; 278 goto exit_bh;
@@ -262,6 +281,10 @@ static int setup_new_group_blocks(struct super_block *sb,
262 brelse(it); 281 brelse(it);
263 ext4_set_bit(bit, bh->b_data); 282 ext4_set_bit(bit, bh->b_data);
264 } 283 }
284
285 if ((err = extend_or_restart_transaction(handle, 2, bh)))
286 goto exit_bh;
287
265 mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb), 288 mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb),
266 bh->b_data); 289 bh->b_data);
267 ext4_journal_dirty_metadata(handle, bh); 290 ext4_journal_dirty_metadata(handle, bh);
@@ -289,7 +312,6 @@ exit_journal:
289 return err; 312 return err;
290} 313}
291 314
292
293/* 315/*
294 * Iterate through the groups which hold BACKUP superblock/GDT copies in an 316 * Iterate through the groups which hold BACKUP superblock/GDT copies in an
295 * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before 317 * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before
@@ -842,6 +864,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
842 ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */ 864 ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */
843 gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); 865 gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);
844 gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb)); 866 gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb));
867 gdp->bg_checksum = ext4_group_desc_csum(sbi, input->group, gdp);
845 868
846 /* 869 /*
847 * Make the new blocks and inodes valid next. We do this before 870 * Make the new blocks and inodes valid next. We do this before