📄 resize.c
字号:
ret = *min; *min *= mult; return ret;}/* * Check that all of the backup GDT blocks are held in the primary GDT block. * It is assumed that they are stored in group order. Returns the number of * groups in current filesystem that have BACKUPS, or -ve error code. */static int verify_reserved_gdb(struct super_block *sb, struct buffer_head *primary){ const ext3_fsblk_t blk = primary->b_blocknr; const unsigned long end = EXT3_SB(sb)->s_groups_count; unsigned three = 1; unsigned five = 5; unsigned seven = 7; unsigned grp; __le32 *p = (__le32 *)primary->b_data; int gdbackups = 0; while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) { if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){ ext3_warning(sb, __FUNCTION__, "reserved GDT "E3FSBLK " missing grp %d ("E3FSBLK")", blk, grp, grp * EXT3_BLOCKS_PER_GROUP(sb) + blk); return -EINVAL; } if (++gdbackups > EXT3_ADDR_PER_BLOCK(sb)) return -EFBIG; } return gdbackups;}/* * Called when we need to bring a reserved group descriptor table block into * use from the resize inode. The primary copy of the new GDT block currently * is an indirect block (under the double indirect block in the resize inode). * The new backup GDT blocks will be stored as leaf blocks in this indirect * block, in group order. Even though we know all the block numbers we need, * we check to ensure that the resize inode has actually reserved these blocks. * * Don't need to update the block bitmaps because the blocks are still in use. * * We get all of the error cases out of the way, so that we are sure to not * fail once we start modifying the data on disk, because JBD has no rollback. */static int add_new_gdb(handle_t *handle, struct inode *inode, struct ext3_new_group_data *input, struct buffer_head **primary){ struct super_block *sb = inode->i_sb; struct ext3_super_block *es = EXT3_SB(sb)->s_es; unsigned long gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); ext3_fsblk_t gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; struct buffer_head **o_group_desc, **n_group_desc; struct buffer_head *dind; int gdbackups; struct ext3_iloc iloc; __le32 *data; int err; if (test_opt(sb, DEBUG)) printk(KERN_DEBUG "EXT3-fs: ext3_add_new_gdb: adding group block %lu\n", gdb_num); /* * If we are not using the primary superblock/GDT copy don't resize, * because the user tools have no way of handling this. Probably a * bad time to do it anyways. */ if (EXT3_SB(sb)->s_sbh->b_blocknr != le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) { ext3_warning(sb, __FUNCTION__, "won't resize using backup superblock at %llu", (unsigned long long)EXT3_SB(sb)->s_sbh->b_blocknr); return -EPERM; } *primary = sb_bread(sb, gdblock); if (!*primary) return -EIO; if ((gdbackups = verify_reserved_gdb(sb, *primary)) < 0) { err = gdbackups; goto exit_bh; } data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; dind = sb_bread(sb, le32_to_cpu(*data)); if (!dind) { err = -EIO; goto exit_bh; } data = (__le32 *)dind->b_data; if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) { ext3_warning(sb, __FUNCTION__, "new group %u GDT block "E3FSBLK" not reserved", input->group, gdblock); err = -EINVAL; goto exit_dind; } if ((err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh))) goto exit_dind; if ((err = ext3_journal_get_write_access(handle, *primary))) goto exit_sbh; if ((err = ext3_journal_get_write_access(handle, dind))) goto exit_primary; /* ext3_reserve_inode_write() gets a reference on the iloc */ if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) goto exit_dindj; n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *), GFP_KERNEL); if (!n_group_desc) { err = -ENOMEM; ext3_warning (sb, __FUNCTION__, "not enough memory for %lu groups", gdb_num + 1); goto exit_inode; } /* * Finally, we have all of the possible failures behind us... * * Remove new GDT block from inode double-indirect block and clear out * the new GDT block for use (which also "frees" the backup GDT blocks * from the reserved inode). We don't need to change the bitmaps for * these blocks, because they are marked as in-use from being in the * reserved inode, and will become GDT blocks (primary and backup). */ data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)] = 0; ext3_journal_dirty_metadata(handle, dind); brelse(dind); inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9; ext3_mark_iloc_dirty(handle, inode, &iloc); memset((*primary)->b_data, 0, sb->s_blocksize); ext3_journal_dirty_metadata(handle, *primary); o_group_desc = EXT3_SB(sb)->s_group_desc; memcpy(n_group_desc, o_group_desc, EXT3_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); n_group_desc[gdb_num] = *primary; EXT3_SB(sb)->s_group_desc = n_group_desc; EXT3_SB(sb)->s_gdb_count++; kfree(o_group_desc); es->s_reserved_gdt_blocks = cpu_to_le16(le16_to_cpu(es->s_reserved_gdt_blocks) - 1); ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); return 0;exit_inode: //ext3_journal_release_buffer(handle, iloc.bh); brelse(iloc.bh);exit_dindj: //ext3_journal_release_buffer(handle, dind);exit_primary: //ext3_journal_release_buffer(handle, *primary);exit_sbh: //ext3_journal_release_buffer(handle, *primary);exit_dind: brelse(dind);exit_bh: brelse(*primary); ext3_debug("leaving with error %d\n", err); return err;}/* * Called when we are adding a new group which has a backup copy of each of * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks. * We need to add these reserved backup GDT blocks to the resize inode, so * that they are kept for future resizing and not allocated to files. * * Each reserved backup GDT block will go into a different indirect block. * The indirect blocks are actually the primary reserved GDT blocks, * so we know in advance what their block numbers are. We only get the * double-indirect block to verify it is pointing to the primary reserved * GDT blocks so we don't overwrite a data block by accident. The reserved * backup GDT blocks are stored in their reserved primary GDT block. */static int reserve_backup_gdb(handle_t *handle, struct inode *inode, struct ext3_new_group_data *input){ struct super_block *sb = inode->i_sb; int reserved_gdb =le16_to_cpu(EXT3_SB(sb)->s_es->s_reserved_gdt_blocks); struct buffer_head **primary; struct buffer_head *dind; struct ext3_iloc iloc; ext3_fsblk_t blk; __le32 *data, *end; int gdbackups = 0; int res, i; int err; primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_KERNEL); if (!primary) return -ENOMEM; data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; dind = sb_bread(sb, le32_to_cpu(*data)); if (!dind) { err = -EIO; goto exit_free; } blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count; data = (__le32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count; end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb); /* Get each reserved primary GDT block and verify it holds backups */ for (res = 0; res < reserved_gdb; res++, blk++) { if (le32_to_cpu(*data) != blk) { ext3_warning(sb, __FUNCTION__, "reserved block "E3FSBLK " not at offset %ld", blk, (long)(data - (__le32 *)dind->b_data)); err = -EINVAL; goto exit_bh; } primary[res] = sb_bread(sb, blk); if (!primary[res]) { err = -EIO; goto exit_bh; } if ((gdbackups = verify_reserved_gdb(sb, primary[res])) < 0) { brelse(primary[res]); err = gdbackups; goto exit_bh; } if (++data >= end) data = (__le32 *)dind->b_data; } for (i = 0; i < reserved_gdb; i++) { if ((err = ext3_journal_get_write_access(handle, primary[i]))) { /* int j; for (j = 0; j < i; j++) ext3_journal_release_buffer(handle, primary[j]); */ goto exit_bh; } } if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) goto exit_bh; /* * Finally we can add each of the reserved backup GDT blocks from * the new group to its reserved primary GDT block. */ blk = input->group * EXT3_BLOCKS_PER_GROUP(sb); for (i = 0; i < reserved_gdb; i++) { int err2; data = (__le32 *)primary[i]->b_data; /* printk("reserving backup %lu[%u] = %lu\n", primary[i]->b_blocknr, gdbackups, blk + primary[i]->b_blocknr); */ data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr); err2 = ext3_journal_dirty_metadata(handle, primary[i]); if (!err) err = err2; } inode->i_blocks += reserved_gdb * sb->s_blocksize >> 9; ext3_mark_iloc_dirty(handle, inode, &iloc);exit_bh: while (--res >= 0) brelse(primary[res]); brelse(dind);exit_free: kfree(primary); return err;}/* * Update the backup copies of the ext3 metadata. These don't need to be part * of the main resize transaction, because e2fsck will re-write them if there * is a problem (basically only OOM will cause a problem). However, we * _should_ update the backups if possible, in case the primary gets trashed * for some reason and we need to run e2fsck from a backup superblock. The * important part is that the new block and inode counts are in the backup * superblocks, and the location of the new group metadata in the GDT backups. * * We do not need lock_super() for this, because these blocks are not * otherwise touched by the filesystem code when it is mounted. We don't * need to worry about last changing from sbi->s_groups_count, because the * worst that can happen is that we do not copy the full number of backups * at this time. The resize which changed s_groups_count will backup again. */static void update_backups(struct super_block *sb, int blk_off, char *data, int size){ struct ext3_sb_info *sbi = EXT3_SB(sb); const unsigned long last = sbi->s_groups_count; const int bpg = EXT3_BLOCKS_PER_GROUP(sb); unsigned three = 1; unsigned five = 5; unsigned seven = 7; unsigned group; int rest = sb->s_blocksize - size; handle_t *handle; int err = 0, err2; handle = ext3_journal_start_sb(sb, EXT3_MAX_TRANS_DATA); if (IS_ERR(handle)) { group = 1; err = PTR_ERR(handle); goto exit_err; } while ((group = ext3_list_backups(sb, &three, &five, &seven)) < last) { struct buffer_head *bh; /* Out of journal space, and can't get more - abort - so sad */ if (handle->h_buffer_credits == 0 && ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA) && (err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA))) break; bh = sb_getblk(sb, group * bpg + blk_off); if (!bh) { err = -EIO; break; } ext3_debug("update metadata backup %#04lx\n", (unsigned long)bh->b_blocknr); if ((err = ext3_journal_get_write_access(handle, bh))) break; lock_buffer(bh); memcpy(bh->b_data, data, size); if (rest) memset(bh->b_data + size, 0, rest); set_buffer_uptodate(bh); unlock_buffer(bh); ext3_journal_dirty_metadata(handle, bh); brelse(bh); } if ((err2 = ext3_journal_stop(handle)) && !err) err = err2; /* * Ugh! Need to have e2fsck write the backup copies. It is too * late to revert the resize, we shouldn't fail just because of * the backup copies (they are only needed in case of corruption). *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -