11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/fs/ext3/resize.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Support for resizing an ext3 filesystem while it is mounted. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 Andreas Dilger <adilger@clusterfs.com> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This could probably be made into a module, because it is not often in use. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EXT3FS_DEBUG 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 144613ad180d19082f99551477dcb13cb23d23661bAl Viro#include "ext3.h" 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define outside(b, first, last) ((b) < (first) || (b) >= (last)) 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define inside(b, first, last) ((b) >= (first) && (b) < (last)) 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int verify_group_input(struct super_block *sb, 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_new_group_data *input) 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_sb_info *sbi = EXT3_SB(sb); 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_super_block *es = sbi->s_es; 251c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao ext3_fsblk_t start = le32_to_cpu(es->s_blocks_count); 261c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao ext3_fsblk_t end = start + input->blocks_count; 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned group = input->group; 281c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao ext3_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned overhead = ext3_bg_has_super(sb, group) ? 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1 + ext3_bg_num_gdb(sb, group) + 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; 321c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao ext3_fsblk_t metaend = start + overhead; 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh = NULL; 341c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao ext3_grpblk_t free_blocks_count; 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -EINVAL; 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->free_blocks_count = free_blocks_count = 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->blocks_count - 2 - overhead - sbi->s_itb_per_group; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_opt(sb, DEBUG)) 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "EXT3-fs: adding %s group %u: %u blocks " 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(%d free, %u reserved)\n", 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_bg_has_super(sb, input->group) ? "normal" : 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "no-super", input->group, input->blocks_count, 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_blocks_count, input->reserved_blocks); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (group != sbi->s_groups_count) 48e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Cannot add at group %u (only %lu groups)", 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->group, sbi->s_groups_count); 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if ((start - le32_to_cpu(es->s_first_data_block)) % 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT3_BLOCKS_PER_GROUP(sb)) 53e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, "Last group not full"); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (input->reserved_blocks > input->blocks_count / 5) 55e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, "Reserved blocks too high (%u)", 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->reserved_blocks); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (free_blocks_count < 0) 58e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, "Bad blocks count %u", 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->blocks_count); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (!(bh = sb_bread(sb, end - 1))) 61e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 621c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao "Cannot read last block ("E3FSBLK")", 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end - 1); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (outside(input->block_bitmap, start, end)) 65e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Block bitmap not in group (block %u)", 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->block_bitmap); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (outside(input->inode_bitmap, start, end)) 69e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Inode bitmap not in group (block %u)", 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->inode_bitmap); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (outside(input->inode_table, start, end) || 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outside(itend - 1, start, end)) 74e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 751c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao "Inode table not in group (blocks %u-"E3FSBLK")", 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->inode_table, itend - 1); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (input->inode_bitmap == input->block_bitmap) 78e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Block bitmap same as inode bitmap (%u)", 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->block_bitmap); 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (inside(input->block_bitmap, input->inode_table, itend)) 82e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 831c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao "Block bitmap (%u) in inode table (%u-"E3FSBLK")", 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->block_bitmap, input->inode_table, itend-1); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (inside(input->inode_bitmap, input->inode_table, itend)) 86e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 871c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao "Inode bitmap (%u) in inode table (%u-"E3FSBLK")", 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->inode_bitmap, input->inode_table, itend-1); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (inside(input->block_bitmap, start, metaend)) 90e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 911c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao "Block bitmap (%u) in GDT table" 921c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao " ("E3FSBLK"-"E3FSBLK")", 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->block_bitmap, start, metaend - 1); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (inside(input->inode_bitmap, start, metaend)) 95e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 961c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao "Inode bitmap (%u) in GDT table" 971c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao " ("E3FSBLK"-"E3FSBLK")", 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->inode_bitmap, start, metaend - 1); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (inside(input->inode_table, start, metaend) || 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inside(itend - 1, start, metaend)) 101e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 1021c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao "Inode table (%u-"E3FSBLK") overlaps" 1031c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao "GDT table ("E3FSBLK"-"E3FSBLK")", 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->inode_table, itend - 1, start, metaend - 1); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = 0; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct buffer_head *bclean(handle_t *handle, struct super_block *sb, 11343d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao ext3_fsblk_t blk) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = sb_getblk(sb, blk); 1191b7d76e9b1106f2be062f915b05d47658dd4fc63Wang Shilong if (unlikely(!bh)) 120c04e88e271ab67de1409c3b4a4e80dbe13eac7b0Wang Shilong return ERR_PTR(-ENOMEM); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_get_write_access(handle, bh))) { 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = ERR_PTR(err); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_buffer(bh); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(bh->b_data, 0, sb->s_blocksize); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_buffer_uptodate(bh); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(bh); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bh; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To avoid calling the atomic setbit hundreds or thousands of times, we only 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to use it within a single byte (to ensure we get endianness right). 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can use memset for the rest of the bitmap as there are no other users. 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (start_bit >= end_bit) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_set_bit(i, bitmap); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i < end_bit) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1541ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen * If we have fewer than thresh credits, extend by EXT3_MAX_TRANS_DATA. 1551ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen * If that fails, restart the transaction & regain write access for the 1561ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen * buffer head which is used for block_bitmap modifications. 1571ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen */ 1581ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeenstatic int extend_or_restart_transaction(handle_t *handle, int thresh, 1591ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen struct buffer_head *bh) 1601ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen{ 1611ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen int err; 1621ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 1631ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen if (handle->h_buffer_credits >= thresh) 1641ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen return 0; 1651ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 1661ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen err = ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA); 1671ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen if (err < 0) 1681ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen return err; 1691ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen if (err) { 1701ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA); 1711ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen if (err) 1721ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen return err; 1731ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen err = ext3_journal_get_write_access(handle, bh); 1741ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen if (err) 1751ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen return err; 1761ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen } 1771ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 1781ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen return 0; 1791ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen} 1801ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 1811ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen/* 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up the block and inode bitmaps, and the inode table for the new group. 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This doesn't need to be part of the main transaction, since we are only 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * changing blocks outside the actual filesystem. We still do journaling to 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ensure the recovery is correct in case of a failure just after resize. 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If any part of this fails, we simply abort the resize. 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int setup_new_group_blocks(struct super_block *sb, 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_new_group_data *input) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_sb_info *sbi = EXT3_SB(sb); 19243d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao ext3_fsblk_t start = ext3_group_first_block_no(sb, input->group); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reserved_gdb = ext3_bg_has_super(sb, input->group) ? 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long gdblocks = ext3_bg_num_gdb(sb, input->group); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_t *handle; 19843d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao ext3_fsblk_t block; 1991c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao ext3_grpblk_t bit; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0, err2; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen /* This transaction may be extended/restarted along the way */ 2041ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen handle = ext3_journal_start_sb(sb, EXT3_MAX_TRANS_DATA); 2051ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(handle)) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PTR_ERR(handle); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20996d2a495c25d525873529b736cdb63ad502b101cEric Sandeen mutex_lock(&sbi->s_resize_lock); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (input->group != sbi->s_groups_count) { 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EBUSY; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_journal; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(bh = bclean(handle, sb, input->block_bitmap))) { 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = PTR_ERR(bh); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_journal; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ext3_bg_has_super(sb, input->group)) { 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_debug("mark backup superblock %#04lx (+0)\n", start); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_set_bit(0, bh->b_data); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy all of the GDT blocks into the backup in this group */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0, bit = 1, block = start + 1; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i < gdblocks; i++, block++, bit++) { 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *gdb; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_debug("update backup group %#04lx (+%d)\n", block, bit); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen err = extend_or_restart_transaction(handle, 1, bh); 2331ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen if (err) 2341ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen goto exit_bh; 2351ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdb = sb_getblk(sb, block); 2371b7d76e9b1106f2be062f915b05d47658dd4fc63Wang Shilong if (unlikely(!gdb)) { 238c04e88e271ab67de1409c3b4a4e80dbe13eac7b0Wang Shilong err = -ENOMEM; 2392973dfdb877c17b36c27ba66d71028ff1eb2f32eGlauber de Oliveira Costa goto exit_bh; 2402973dfdb877c17b36c27ba66d71028ff1eb2f32eGlauber de Oliveira Costa } 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_get_write_access(handle, gdb))) { 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(gdb); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24542a2b6ad71b011144d21d88a124140bb2bf1023fEric Sandeen lock_buffer(gdb); 24642a2b6ad71b011144d21d88a124140bb2bf1023fEric Sandeen memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_buffer_uptodate(gdb); 24842a2b6ad71b011144d21d88a124140bb2bf1023fEric Sandeen unlock_buffer(gdb); 24941dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, gdb); 25041dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) { 25141dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim brelse(gdb); 25241dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_bh; 25341dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim } 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_set_bit(bit, bh->b_data); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(gdb); 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Zero out all of the reserved backup group descriptor table blocks */ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0, bit = gdblocks + 1, block = start + bit; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i < reserved_gdb; i++, block++, bit++) { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *gdb; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_debug("clear reserved block %#04lx (+%d)\n", block, bit); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen err = extend_or_restart_transaction(handle, 1, bh); 2661ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen if (err) 2671ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen goto exit_bh; 2681ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(gdb = bclean(handle, sb, block))) { 2708e0eb4011bd73d5f91b215b532f74eef478ef795Roel Kluin err = PTR_ERR(gdb); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27341dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, gdb); 27441dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) { 27541dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim brelse(gdb); 27641dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_bh; 27741dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim } 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_set_bit(bit, bh->b_data); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(gdb); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap, 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->block_bitmap - start); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_set_bit(input->block_bitmap - start, bh->b_data); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap, 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->inode_bitmap - start); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_set_bit(input->inode_bitmap - start, bh->b_data); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Zero out all of the inode table blocks */ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0, block = input->inode_table, bit = block - start; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i < sbi->s_itb_per_group; i++, bit++, block++) { 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *it; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2938bdac5d1ed892da54b6b2069e50a47b3aa39460fGlauber de Oliveira Costa ext3_debug("clear inode block %#04lx (+%d)\n", block, bit); 2941ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 2951ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen err = extend_or_restart_transaction(handle, 1, bh); 2961ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen if (err) 2971ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen goto exit_bh; 2981ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(it = bclean(handle, sb, block))) { 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = PTR_ERR(it); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30341dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, it); 30441dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) { 30541dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim brelse(it); 30641dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_bh; 30741dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim } 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(it); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_set_bit(bit, bh->b_data); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3111ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 3121ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen err = extend_or_restart_transaction(handle, 2, bh); 3131ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen if (err) 3141ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen goto exit_bh; 3151ad6ecf9146e85ccb4e0bce70b91a93f57145c72Eric Sandeen 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_bitmap_end(input->blocks_count, EXT3_BLOCKS_PER_GROUP(sb), 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->b_data); 31841dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, bh); 31941dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) 32041dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_bh; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Mark unused entries in inode bitmap used */ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_debug("clear inode bitmap %#04x (+%ld)\n", 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->inode_bitmap, input->inode_bitmap - start); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(bh = bclean(handle, sb, input->inode_bitmap))) { 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = PTR_ERR(bh); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_journal; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_bitmap_end(EXT3_INODES_PER_GROUP(sb), EXT3_BLOCKS_PER_GROUP(sb), 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->b_data); 33341dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, bh); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_bh: 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_journal: 33896d2a495c25d525873529b736cdb63ad502b101cEric Sandeen mutex_unlock(&sbi->s_resize_lock); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err2 = ext3_journal_stop(handle)) && !err) 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = err2; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Iterate through the groups which hold BACKUP superblock/GDT copies in an 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * calling this for the first time. In a sparse filesystem it will be the 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned ext3_list_backups(struct super_block *sb, unsigned *three, 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned *five, unsigned *seven) 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned *min = three; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mult = 3; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned ret; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = *min; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *min += 1; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*five < *min) { 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min = five; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mult = 5; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*seven < *min) { 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min = seven; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mult = 7; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = *min; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *min *= mult; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check that all of the backup GDT blocks are held in the primary GDT block. 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It is assumed that they are stored in group order. Returns the number of 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * groups in current filesystem that have BACKUPS, or -ve error code. 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int verify_reserved_gdb(struct super_block *sb, 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *primary) 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38943d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao const ext3_fsblk_t blk = primary->b_blocknr; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned long end = EXT3_SB(sb)->s_groups_count; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned three = 1; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned five = 5; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned seven = 7; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned grp; 395a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp __le32 *p = (__le32 *)primary->b_data; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int gdbackups = 0; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) { 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){ 400e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 40143d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao "reserved GDT "E3FSBLK 40243d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao " missing grp %d ("E3FSBLK")", 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk, grp, 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds grp * EXT3_BLOCKS_PER_GROUP(sb) + blk); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++gdbackups > EXT3_ADDR_PER_BLOCK(sb)) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFBIG; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return gdbackups; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called when we need to bring a reserved group descriptor table block into 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use from the resize inode. The primary copy of the new GDT block currently 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is an indirect block (under the double indirect block in the resize inode). 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The new backup GDT blocks will be stored as leaf blocks in this indirect 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * block, in group order. Even though we know all the block numbers we need, 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we check to ensure that the resize inode has actually reserved these blocks. 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't need to update the block bitmaps because the blocks are still in use. 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We get all of the error cases out of the way, so that we are sure to not 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fail once we start modifying the data on disk, because JBD has no rollback. 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int add_new_gdb(handle_t *handle, struct inode *inode, 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_new_group_data *input, 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head **primary) 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb = inode->i_sb; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_super_block *es = EXT3_SB(sb)->s_es; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); 43443d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao ext3_fsblk_t gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head **o_group_desc, **n_group_desc; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *dind; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int gdbackups; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_iloc iloc; 439a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp __le32 *data; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_opt(sb, DEBUG)) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "EXT3-fs: ext3_add_new_gdb: adding group block %lu\n", 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdb_num); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are not using the primary superblock/GDT copy don't resize, 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * because the user tools have no way of handling this. Probably a 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bad time to do it anyways. 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (EXT3_SB(sb)->s_sbh->b_blocknr != 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) { 454e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 4559f40668d7d14d4d16cedc2104bfb63a43584dacfGlauber de Oliveira Costa "won't resize using backup superblock at %llu", 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long)EXT3_SB(sb)->s_sbh->b_blocknr); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *primary = sb_bread(sb, gdblock); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!*primary) 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((gdbackups = verify_reserved_gdb(sb, *primary)) < 0) { 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = gdbackups; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dind = sb_bread(sb, le32_to_cpu(*data)); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dind) { 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EIO; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 476a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp data = (__le32 *)dind->b_data; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) { 478e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 47943d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao "new group %u GDT block "E3FSBLK" not reserved", 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->group, gdblock); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_dind; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh))) 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_dind; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_get_write_access(handle, *primary))) 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_sbh; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_get_write_access(handle, dind))) 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_primary; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ext3_reserve_inode_write() gets a reference on the iloc */ 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_dindj; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 498f52720ca5f48574e347dff35ffe6b389ace61537Panagiotis Issaris n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *), 499c587f0c0a69227587baaa12e75815b6644457c0aJosef Bacik GFP_NOFS); 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!n_group_desc) { 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENOMEM; 502e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning (sb, __func__, 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "not enough memory for %lu groups", gdb_num + 1); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_inode; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finally, we have all of the possible failures behind us... 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove new GDT block from inode double-indirect block and clear out 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the new GDT block for use (which also "frees" the backup GDT blocks 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from the reserved inode). We don't need to change the bitmaps for 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * these blocks, because they are marked as in-use from being in the 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reserved inode, and will become GDT blocks (primary and backup). 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)] = 0; 51741dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, dind); 51841dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) 51941dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_group_desc; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(dind); 52141dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim dind = NULL; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9; 52341dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_mark_iloc_dirty(handle, inode, &iloc); 52441dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) 52541dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_group_desc; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset((*primary)->b_data, 0, sb->s_blocksize); 52741dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, *primary); 52841dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) 52941dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_group_desc; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds o_group_desc = EXT3_SB(sb)->s_group_desc; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(n_group_desc, o_group_desc, 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT3_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n_group_desc[gdb_num] = *primary; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT3_SB(sb)->s_group_desc = n_group_desc; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT3_SB(sb)->s_gdb_count++; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(o_group_desc); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53950e8a2890ed0eeb7a11ae0c39144fcdd1cad1cf8Marcin Slusarz le16_add_cpu(&es->s_reserved_gdt_blocks, -1); 54041dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); 54141dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) 54241dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_inode; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54641dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kimexit_group_desc: 54741dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim kfree(n_group_desc); 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_inode: 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds //ext3_journal_release_buffer(handle, iloc.bh); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(iloc.bh); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_dindj: 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds //ext3_journal_release_buffer(handle, dind); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_primary: 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds //ext3_journal_release_buffer(handle, *primary); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_sbh: 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds //ext3_journal_release_buffer(handle, *primary); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_dind: 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(dind); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_bh: 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(*primary); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_debug("leaving with error %d\n", err); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called when we are adding a new group which has a backup copy of each of 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks. 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to add these reserved backup GDT blocks to the resize inode, so 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that they are kept for future resizing and not allocated to files. 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Each reserved backup GDT block will go into a different indirect block. 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The indirect blocks are actually the primary reserved GDT blocks, 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so we know in advance what their block numbers are. We only get the 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * double-indirect block to verify it is pointing to the primary reserved 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GDT blocks so we don't overwrite a data block by accident. The reserved 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * backup GDT blocks are stored in their reserved primary GDT block. 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int reserve_backup_gdb(handle_t *handle, struct inode *inode, 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_new_group_data *input) 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb = inode->i_sb; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reserved_gdb =le16_to_cpu(EXT3_SB(sb)->s_es->s_reserved_gdt_blocks); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head **primary; 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *dind; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_iloc iloc; 58743d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao ext3_fsblk_t blk; 588a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp __le32 *data, *end; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int gdbackups = 0; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res, i; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 593c587f0c0a69227587baaa12e75815b6644457c0aJosef Bacik primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_NOFS); 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!primary) 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dind = sb_bread(sb, le32_to_cpu(*data)); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dind) { 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EIO; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_free; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count; 6059bb91784de6618c955994b2d5be332fb68c87ef1Josef Bacik data = (__le32 *)dind->b_data + (EXT3_SB(sb)->s_gdb_count % 6069bb91784de6618c955994b2d5be332fb68c87ef1Josef Bacik EXT3_ADDR_PER_BLOCK(sb)); 607a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get each reserved primary GDT block and verify it holds backups */ 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (res = 0; res < reserved_gdb; res++, blk++) { 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (le32_to_cpu(*data) != blk) { 612e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 61343d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao "reserved block "E3FSBLK 61443d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao " not at offset %ld", 615a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp blk, 616a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp (long)(data - (__le32 *)dind->b_data)); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds primary[res] = sb_bread(sb, blk); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!primary[res]) { 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EIO; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((gdbackups = verify_reserved_gdb(sb, primary[res])) < 0) { 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(primary[res]); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = gdbackups; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++data >= end) 631a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp data = (__le32 *)dind->b_data; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < reserved_gdb; i++) { 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_get_write_access(handle, primary[i]))) { 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < i; j++) 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_journal_release_buffer(handle, primary[j]); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_bh; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finally we can add each of the reserved backup GDT blocks from 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the new group to its reserved primary GDT block. 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk = input->group * EXT3_BLOCKS_PER_GROUP(sb); 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < reserved_gdb; i++) { 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err2; 655a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp data = (__le32 *)primary[i]->b_data; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* printk("reserving backup %lu[%u] = %lu\n", 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds primary[i]->b_blocknr, gdbackups, 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk + primary[i]->b_blocknr); */ 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err2 = ext3_journal_dirty_metadata(handle, primary[i]); 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!err) 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = err2; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_blocks += reserved_gdb * sb->s_blocksize >> 9; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_mark_iloc_dirty(handle, inode, &iloc); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_bh: 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (--res >= 0) 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(primary[res]); 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(dind); 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_free: 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(primary); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the backup copies of the ext3 metadata. These don't need to be part 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the main resize transaction, because e2fsck will re-write them if there 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is a problem (basically only OOM will cause a problem). However, we 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * _should_ update the backups if possible, in case the primary gets trashed 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for some reason and we need to run e2fsck from a backup superblock. The 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * important part is that the new block and inode counts are in the backup 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * superblocks, and the location of the new group metadata in the GDT backups. 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 68796d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * We do not need take the s_resize_lock for this, because these 68896d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * blocks are not otherwise touched by the filesystem code when it is 68996d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * mounted. We don't need to worry about last changing from 69096d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * sbi->s_groups_count, because the worst that can happen is that we 69196d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * do not copy the full number of backups at this time. The resize 69296d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * which changed s_groups_count will backup again. 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_backups(struct super_block *sb, 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int blk_off, char *data, int size) 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_sb_info *sbi = EXT3_SB(sb); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned long last = sbi->s_groups_count; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const int bpg = EXT3_BLOCKS_PER_GROUP(sb); 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned three = 1; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned five = 5; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned seven = 7; 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned group; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rest = sb->s_blocksize - size; 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_t *handle; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0, err2; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle = ext3_journal_start_sb(sb, EXT3_MAX_TRANS_DATA); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(handle)) { 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds group = 1; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = PTR_ERR(handle); 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_err; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((group = ext3_list_backups(sb, &three, &five, &seven)) < last) { 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Out of journal space, and can't get more - abort - so sad */ 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (handle->h_buffer_credits == 0 && 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA) && 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA))) 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = sb_getblk(sb, group * bpg + blk_off); 7251b7d76e9b1106f2be062f915b05d47658dd4fc63Wang Shilong if (unlikely(!bh)) { 726c04e88e271ab67de1409c3b4a4e80dbe13eac7b0Wang Shilong err = -ENOMEM; 7272973dfdb877c17b36c27ba66d71028ff1eb2f32eGlauber de Oliveira Costa break; 7282973dfdb877c17b36c27ba66d71028ff1eb2f32eGlauber de Oliveira Costa } 7298bdac5d1ed892da54b6b2069e50a47b3aa39460fGlauber de Oliveira Costa ext3_debug("update metadata backup %#04lx\n", 7308bdac5d1ed892da54b6b2069e50a47b3aa39460fGlauber de Oliveira Costa (unsigned long)bh->b_blocknr); 73141dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if ((err = ext3_journal_get_write_access(handle, bh))) { 73241dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim brelse(bh); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 73441dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim } 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_buffer(bh); 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(bh->b_data, data, size); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rest) 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(bh->b_data + size, 0, rest); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_buffer_uptodate(bh); 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(bh); 74141dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, bh); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 74341dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) 74441dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim break; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err2 = ext3_journal_stop(handle)) && !err) 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = err2; 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ugh! Need to have e2fsck write the backup copies. It is too 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * late to revert the resize, we shouldn't fail just because of 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the backup copies (they are only needed in case of corruption). 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * However, if we got here we have a journal problem too, so we 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can't really start a transaction to mark the superblock. 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Chicken out and just set the flag on the hope it will be written 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to disk, and if not - we will simply wait until next fsck. 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_err: 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 761e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "can't update backup for group %d (err %d), " 7639f40668d7d14d4d16cedc2104bfb63a43584dacfGlauber de Oliveira Costa "forcing fsck on next reboot", group, err); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sbi->s_mount_state &= ~EXT3_VALID_FS; 765a4e4de36dc446b2193bdc8ebb96a96e44b69dd94Dave Kleikamp sbi->s_es->s_state &= cpu_to_le16(~EXT3_VALID_FS); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_buffer_dirty(sbi->s_sbh); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Add group descriptor data to an existing or new group descriptor block. 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure we handle all possible error conditions _before_ we start modifying 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the filesystem, because we cannot abort the transaction and not have it 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write the data to disk. 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are on a GDT block boundary, we need to get the reserved GDT block. 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, we may need to add backup GDT blocks for a sparse group. 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We only need to hold the superblock lock while we are actually adding 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the new group's counts to the superblock. Prior to that we have 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not really "added" the group at all. We re-check that we are still 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adding in the last group in case things have changed since verifying. 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_sb_info *sbi = EXT3_SB(sb); 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_super_block *es = sbi->s_es; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reserved_gdb = ext3_bg_has_super(sb, input->group) ? 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpu(es->s_reserved_gdt_blocks) : 0; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *primary = NULL; 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext3_group_desc *gdp; 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct inode *inode = NULL; 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_t *handle; 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int gdb_off, gdb_num; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err, err2; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdb_off = input->group % EXT3_DESC_PER_BLOCK(sb); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gdb_off == 0 && !EXT3_HAS_RO_COMPAT_FEATURE(sb, 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { 801e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 8029f40668d7d14d4d16cedc2104bfb63a43584dacfGlauber de Oliveira Costa "Can't resize non-sparse filesystem further"); 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80632c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen if (le32_to_cpu(es->s_blocks_count) + input->blocks_count < 80732c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen le32_to_cpu(es->s_blocks_count)) { 808e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, "blocks_count overflow\n"); 80932c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen return -EINVAL; 81032c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen } 81132c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen 81232c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen if (le32_to_cpu(es->s_inodes_count) + EXT3_INODES_PER_GROUP(sb) < 81332c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen le32_to_cpu(es->s_inodes_count)) { 814e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, "inodes_count overflow\n"); 81532c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen return -EINVAL; 81632c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen } 81732c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reserved_gdb || gdb_off == 0) { 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!EXT3_HAS_COMPAT_FEATURE(sb, 820972fbf779832e5ad15effa7712789aeff9224c37Josef Bacik EXT3_FEATURE_COMPAT_RESIZE_INODE) 821972fbf779832e5ad15effa7712789aeff9224c37Josef Bacik || !le16_to_cpu(es->s_reserved_gdt_blocks)) { 822e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 8239f40668d7d14d4d16cedc2104bfb63a43584dacfGlauber de Oliveira Costa "No reserved GDT blocks, can't resize"); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 826473043dcee1874aab99f66b0362b344618eb3790David Howells inode = ext3_iget(sb, EXT3_RESIZE_INO); 827473043dcee1874aab99f66b0362b344618eb3790David Howells if (IS_ERR(inode)) { 828e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 8299f40668d7d14d4d16cedc2104bfb63a43584dacfGlauber de Oliveira Costa "Error opening resize inode"); 830473043dcee1874aab99f66b0362b344618eb3790David Howells return PTR_ERR(inode); 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = verify_group_input(sb, input))) 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_put; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = setup_new_group_blocks(sb, input))) 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_put; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We will always be modifying at least the superblock and a GDT 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * block. If we are adding a group past the last current GDT block, 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we will also modify the inode and the dindirect block. If we 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are adding a group with superblock/GDT backups we will also 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify each of the reserved GDT dindirect blocks. 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle = ext3_journal_start_sb(sb, 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_bg_has_super(sb, input->group) ? 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3 + reserved_gdb : 4); 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(handle)) { 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = PTR_ERR(handle); 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_put; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85596d2a495c25d525873529b736cdb63ad502b101cEric Sandeen mutex_lock(&sbi->s_resize_lock); 85629ba17231222c42ca3df5424f43949e2a6fddec2Glauber de Oliveira Costa if (input->group != sbi->s_groups_count) { 857e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 8589f40668d7d14d4d16cedc2104bfb63a43584dacfGlauber de Oliveira Costa "multiple resizers run on filesystem!"); 859aa877b3dc9f2a1fdffac4ea36bee97c21db11a69Glauber de Oliveira Costa err = -EBUSY; 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_journal; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_get_write_access(handle, sbi->s_sbh))) 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_journal; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We will only either add reserved group blocks to a backup group 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or remove reserved blocks for the first group in a new group block. 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Doing both would be mean more complex code, and sane people don't 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use non-sparse filesystems anymore. This is already checked above. 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gdb_off) { 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds primary = sbi->s_group_desc[gdb_num]; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_get_write_access(handle, primary))) 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_journal; 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reserved_gdb && ext3_bg_num_gdb(sb, input->group) && 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (err = reserve_backup_gdb(handle, inode, input))) 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_journal; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((err = add_new_gdb(handle, inode, input, &primary))) 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_journal; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OK, now we've set up the new group. Time to make it active. 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 88696d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * We do not lock all allocations via s_resize_lock 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so we have to be safe wrt. concurrent accesses the group 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data. So we need to be careful to set all of the relevant 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * group descriptor data etc. *before* we enable the group. 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 89129ba17231222c42ca3df5424f43949e2a6fddec2Glauber de Oliveira Costa * The key field here is sbi->s_groups_count: as long as 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that retains its old value, nobody is going to access the new 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * group. 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So first we update all the descriptor metadata for the new 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * group; then we update the total disk blocks count; then we 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * update the groups count to enable the group; then finally we 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * update the free space counts so that the system can start 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * using the new disk blocks. 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Update group descriptor block for new group */ 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdp = (struct ext3_group_desc *)primary->b_data + gdb_off; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdp->bg_block_bitmap = cpu_to_le32(input->block_bitmap); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdp->bg_inode_bitmap = cpu_to_le32(input->inode_bitmap); 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdp->bg_inode_table = cpu_to_le32(input->inode_table); 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb)); 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make the new blocks and inodes valid next. We do this before 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * increasing the group count so that once the group is enabled, 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all of its blocks and inodes are already valid. 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We always allocate group-by-group, then block-by-block or 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inode-by-inode within a group, so enabling these 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * blocks/inodes before the group is live won't actually let us 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocate the new space yet. 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 92150e8a2890ed0eeb7a11ae0c39144fcdd1cad1cf8Marcin Slusarz le32_add_cpu(&es->s_blocks_count, input->blocks_count); 92250e8a2890ed0eeb7a11ae0c39144fcdd1cad1cf8Marcin Slusarz le32_add_cpu(&es->s_inodes_count, EXT3_INODES_PER_GROUP(sb)); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to protect s_groups_count against other CPUs seeing 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inconsistent state in the superblock. 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The precise rules we use are: 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 93096d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * * Writers of s_groups_count *must* hold s_resize_lock 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * AND 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * * Writers must perform a smp_wmb() after updating all dependent 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data and before modifying the groups count 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 93596d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * * Readers must hold s_resize_lock over the access 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OR 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * * Readers must perform an smp_rmb() after reading the groups count 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and before reading any dependent data. 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NB. These rules can be relaxed when checking the group count 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * while freeing data, as we can only allocate from a block 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * group after serialising against the group count, and we can 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * only then free after serialising in turn against that 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocation. 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds smp_wmb(); 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Update the global fs size fields */ 94929ba17231222c42ca3df5424f43949e2a6fddec2Glauber de Oliveira Costa sbi->s_groups_count++; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95141dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, primary); 95241dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) 95341dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_journal; 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Update the reserved block counts only once the new group is 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * active. */ 95750e8a2890ed0eeb7a11ae0c39144fcdd1cad1cf8Marcin Slusarz le32_add_cpu(&es->s_r_blocks_count, input->reserved_blocks); 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Update the free space counts */ 960aa0dff2d09bfa50b7d02714a45920c64568e699dPeter Zijlstra percpu_counter_add(&sbi->s_freeblocks_counter, 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input->free_blocks_count); 962aa0dff2d09bfa50b7d02714a45920c64568e699dPeter Zijlstra percpu_counter_add(&sbi->s_freeinodes_counter, 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT3_INODES_PER_GROUP(sb)); 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96541dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, sbi->s_sbh); 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_journal: 96896d2a495c25d525873529b736cdb63ad502b101cEric Sandeen mutex_unlock(&sbi->s_resize_lock); 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err2 = ext3_journal_stop(handle)) && !err) 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = err2; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!err) { 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct ext3_super_block)); 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_backups(sb, primary->b_blocknr, primary->b_data, 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds primary->b_size); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_put: 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iput(inode); 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* ext3_group_add */ 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Extend the filesystem to the new number of blocks specified. This entry 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * point is only used to extend the current filesystem to the end of the last 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * existing group. It can be accessed via ioctl, or by "remount,resize=<size>" 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for emergencies (because it has no dependencies on reserved blocks). 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we _really_ wanted, we could use default values to call ext3_group_add() 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allow the "remount" trick to work for arbitrary resizing, assuming enough 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GDT blocks are reserved to grow to the desired size. 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, 99243d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao ext3_fsblk_t n_blocks_count) 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 99443d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao ext3_fsblk_t o_blocks_count; 9951c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao ext3_grpblk_t last; 9961c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao ext3_grpblk_t add; 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head * bh; 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_t *handle; 9991c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao int err; 10001c2bf374a4b8c2e1a3e6ff3a64fb67272a8cd2e2Mingming Cao unsigned long freed_blocks; 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We don't need to worry about locking wrt other resizers just 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * yet: we're going to revalidate es->s_blocks_count after 100496d2a495c25d525873529b736cdb63ad502b101cEric Sandeen * taking the s_resize_lock below. */ 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds o_blocks_count = le32_to_cpu(es->s_blocks_count); 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_opt(sb, DEBUG)) 1008db50d20b1da6ebb62bc28172de142efd9e7b5d89Namhyung Kim printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK 100925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi " up to "E3FSBLK" blocks\n", 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds o_blocks_count, n_blocks_count); 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n_blocks_count == 0 || n_blocks_count == o_blocks_count) 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1015fcd5df35882b128ef3e160fab3074e6fe7ae501bMingming Cao if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { 1016fcd5df35882b128ef3e160fab3074e6fe7ae501bMingming Cao printk(KERN_ERR "EXT3-fs: filesystem on %s:" 1017db50d20b1da6ebb62bc28172de142efd9e7b5d89Namhyung Kim " too large to resize to "E3FSBLK" blocks safely\n", 1018fcd5df35882b128ef3e160fab3074e6fe7ae501bMingming Cao sb->s_id, n_blocks_count); 1019fcd5df35882b128ef3e160fab3074e6fe7ae501bMingming Cao if (sizeof(sector_t) < 8) 1020e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 102190c699a9ee4be165966d40f1837909ccb8890a68Bartlomiej Zolnierkiewicz "CONFIG_LBDAF not enabled\n"); 1022fcd5df35882b128ef3e160fab3074e6fe7ae501bMingming Cao return -EINVAL; 1023fcd5df35882b128ef3e160fab3074e6fe7ae501bMingming Cao } 1024fcd5df35882b128ef3e160fab3074e6fe7ae501bMingming Cao 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n_blocks_count < o_blocks_count) { 1026e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "can't shrink FS - resize aborted"); 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle the remaining blocks in the last group only. */ 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = (o_blocks_count - le32_to_cpu(es->s_first_data_block)) % 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT3_BLOCKS_PER_GROUP(sb); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (last == 0) { 1036e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 10379f40668d7d14d4d16cedc2104bfb63a43584dacfGlauber de Oliveira Costa "need to use ext2online to resize further"); 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add = EXT3_BLOCKS_PER_GROUP(sb) - last; 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104332c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen if (o_blocks_count + add < o_blocks_count) { 1044e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, "blocks_count overflow"); 104532c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen return -EINVAL; 104632c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen } 104732c2d2bc4bed61323f14f2a7d69ccbd567253d8aEric Sandeen 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (o_blocks_count + add > n_blocks_count) 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add = n_blocks_count - o_blocks_count; 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (o_blocks_count + add < n_blocks_count) 1052e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 105343d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao "will only finish group ("E3FSBLK 105443d23f9039fc810ecd621f1e4f9d578eadce058aMingming Cao " blocks, %u new)", 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds o_blocks_count + add, add); 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* See if the device is actually as big as what was requested */ 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = sb_bread(sb, o_blocks_count + add -1); 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bh) { 1060e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "can't read last block, resize aborted"); 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOSPC; 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We will update the superblock, one block bitmap, and 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one group descriptor via ext3_free_blocks(). 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle = ext3_journal_start_sb(sb, 3); 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(handle)) { 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = PTR_ERR(handle); 1072e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, "error %d on journal start",err); 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_put; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107696d2a495c25d525873529b736cdb63ad502b101cEric Sandeen mutex_lock(&EXT3_SB(sb)->s_resize_lock); 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) { 1078e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 10799f40668d7d14d4d16cedc2104bfb63a43584dacfGlauber de Oliveira Costa "multiple resizers run on filesystem!"); 108096d2a495c25d525873529b736cdb63ad502b101cEric Sandeen mutex_unlock(&EXT3_SB(sb)->s_resize_lock); 108122a5daf5375a900e1a4efe8ffe2daef9be01e873Akinobu Mita ext3_journal_stop(handle); 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EBUSY; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_put; 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_get_write_access(handle, 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT3_SB(sb)->s_sbh))) { 1088e05b6b524bd5c5c2bae1b64a7cbe08d46d57a6feHarvey Harrison ext3_warning(sb, __func__, 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "error %d on journal write access", err); 109096d2a495c25d525873529b736cdb63ad502b101cEric Sandeen mutex_unlock(&EXT3_SB(sb)->s_resize_lock); 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_journal_stop(handle); 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_put; 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds es->s_blocks_count = cpu_to_le32(o_blocks_count + add); 109541dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); 109696d2a495c25d525873529b736cdb63ad502b101cEric Sandeen mutex_unlock(&EXT3_SB(sb)->s_resize_lock); 109741dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim if (err) { 109841dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim ext3_warning(sb, __func__, 109941dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim "error %d on journal dirty metadata", err); 110041dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim ext3_journal_stop(handle); 110141dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim goto exit_put; 110241dc6385bd6cd3366c1b4bede33688521eb21db9Namhyung Kim } 1103db50d20b1da6ebb62bc28172de142efd9e7b5d89Namhyung Kim ext3_debug("freeing blocks "E3FSBLK" through "E3FSBLK"\n", 1104db50d20b1da6ebb62bc28172de142efd9e7b5d89Namhyung Kim o_blocks_count, o_blocks_count + add); 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext3_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks); 1106db50d20b1da6ebb62bc28172de142efd9e7b5d89Namhyung Kim ext3_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", 1107db50d20b1da6ebb62bc28172de142efd9e7b5d89Namhyung Kim o_blocks_count, o_blocks_count + add); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = ext3_journal_stop(handle))) 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_put; 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_opt(sb, DEBUG)) 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "EXT3-fs: extended group to %u blocks\n", 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(es->s_blocks_count)); 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_backups(sb, EXT3_SB(sb)->s_sbh->b_blocknr, (char *)es, 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct ext3_super_block)); 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_put: 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* ext3_group_extend */ 1118