⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 resize.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -