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

📄 resize.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (err) {		ext4_warning(sb, __FUNCTION__,			     "can't update backup for group %d (err %d), "			     "forcing fsck on next reboot", group, err);		sbi->s_mount_state &= ~EXT4_VALID_FS;		sbi->s_es->s_state &= cpu_to_le16(~EXT4_VALID_FS);		mark_buffer_dirty(sbi->s_sbh);	}}/* Add group descriptor data to an existing or new group descriptor block. * Ensure we handle all possible error conditions _before_ we start modifying * the filesystem, because we cannot abort the transaction and not have it * write the data to disk. * * If we are on a GDT block boundary, we need to get the reserved GDT block. * Otherwise, we may need to add backup GDT blocks for a sparse group. * * We only need to hold the superblock lock while we are actually adding * in the new group's counts to the superblock.  Prior to that we have * not really "added" the group at all.  We re-check that we are still * adding in the last group in case things have changed since verifying. */int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input){	struct ext4_sb_info *sbi = EXT4_SB(sb);	struct ext4_super_block *es = sbi->s_es;	int reserved_gdb = ext4_bg_has_super(sb, input->group) ?		le16_to_cpu(es->s_reserved_gdt_blocks) : 0;	struct buffer_head *primary = NULL;	struct ext4_group_desc *gdp;	struct inode *inode = NULL;	handle_t *handle;	int gdb_off, gdb_num;	int err, err2;	gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb);	gdb_off = input->group % EXT4_DESC_PER_BLOCK(sb);	if (gdb_off == 0 && !EXT4_HAS_RO_COMPAT_FEATURE(sb,					EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {		ext4_warning(sb, __FUNCTION__,			     "Can't resize non-sparse filesystem further");		return -EPERM;	}	if (ext4_blocks_count(es) + input->blocks_count <	    ext4_blocks_count(es)) {		ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n");		return -EINVAL;	}	if (le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb) <	    le32_to_cpu(es->s_inodes_count)) {		ext4_warning(sb, __FUNCTION__, "inodes_count overflow\n");		return -EINVAL;	}	if (reserved_gdb || gdb_off == 0) {		if (!EXT4_HAS_COMPAT_FEATURE(sb,					     EXT4_FEATURE_COMPAT_RESIZE_INODE)){			ext4_warning(sb, __FUNCTION__,				     "No reserved GDT blocks, can't resize");			return -EPERM;		}		inode = iget(sb, EXT4_RESIZE_INO);		if (!inode || is_bad_inode(inode)) {			ext4_warning(sb, __FUNCTION__,				     "Error opening resize inode");			iput(inode);			return -ENOENT;		}	}	if ((err = verify_group_input(sb, input)))		goto exit_put;	if ((err = setup_new_group_blocks(sb, input)))		goto exit_put;	/*	 * We will always be modifying at least the superblock and a GDT	 * block.  If we are adding a group past the last current GDT block,	 * we will also modify the inode and the dindirect block.  If we	 * are adding a group with superblock/GDT backups  we will also	 * modify each of the reserved GDT dindirect blocks.	 */	handle = ext4_journal_start_sb(sb,				       ext4_bg_has_super(sb, input->group) ?				       3 + reserved_gdb : 4);	if (IS_ERR(handle)) {		err = PTR_ERR(handle);		goto exit_put;	}	lock_super(sb);	if (input->group != sbi->s_groups_count) {		ext4_warning(sb, __FUNCTION__,			     "multiple resizers run on filesystem!");		err = -EBUSY;		goto exit_journal;	}	if ((err = ext4_journal_get_write_access(handle, sbi->s_sbh)))		goto exit_journal;	/*	 * We will only either add reserved group blocks to a backup group	 * or remove reserved blocks for the first group in a new group block.	 * Doing both would be mean more complex code, and sane people don't	 * use non-sparse filesystems anymore.  This is already checked above.	 */	if (gdb_off) {		primary = sbi->s_group_desc[gdb_num];		if ((err = ext4_journal_get_write_access(handle, primary)))			goto exit_journal;		if (reserved_gdb && ext4_bg_num_gdb(sb, input->group) &&		    (err = reserve_backup_gdb(handle, inode, input)))			goto exit_journal;	} else if ((err = add_new_gdb(handle, inode, input, &primary)))		goto exit_journal;	/*	 * OK, now we've set up the new group.  Time to make it active.	 *	 * Current kernels don't lock all allocations via lock_super(),	 * so we have to be safe wrt. concurrent accesses the group	 * data.  So we need to be careful to set all of the relevant	 * group descriptor data etc. *before* we enable the group.	 *	 * The key field here is sbi->s_groups_count: as long as	 * that retains its old value, nobody is going to access the new	 * group.	 *	 * So first we update all the descriptor metadata for the new	 * group; then we update the total disk blocks count; then we	 * update the groups count to enable the group; then finally we	 * update the free space counts so that the system can start	 * using the new disk blocks.	 */	/* Update group descriptor block for new group */	gdp = (struct ext4_group_desc *)primary->b_data + gdb_off;	ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */	ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */	ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */	gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);	gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb));	gdp->bg_checksum = ext4_group_desc_csum(sbi, input->group, gdp);	/*	 * Make the new blocks and inodes valid next.  We do this before	 * increasing the group count so that once the group is enabled,	 * all of its blocks and inodes are already valid.	 *	 * We always allocate group-by-group, then block-by-block or	 * inode-by-inode within a group, so enabling these	 * blocks/inodes before the group is live won't actually let us	 * allocate the new space yet.	 */	ext4_blocks_count_set(es, ext4_blocks_count(es) +		input->blocks_count);	es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) +		EXT4_INODES_PER_GROUP(sb));	/*	 * We need to protect s_groups_count against other CPUs seeing	 * inconsistent state in the superblock.	 *	 * The precise rules we use are:	 *	 * * Writers of s_groups_count *must* hold lock_super	 * AND	 * * Writers must perform a smp_wmb() after updating all dependent	 *   data and before modifying the groups count	 *	 * * Readers must hold lock_super() over the access	 * OR	 * * Readers must perform an smp_rmb() after reading the groups count	 *   and before reading any dependent data.	 *	 * NB. These rules can be relaxed when checking the group count	 * while freeing data, as we can only allocate from a block	 * group after serialising against the group count, and we can	 * only then free after serialising in turn against that	 * allocation.	 */	smp_wmb();	/* Update the global fs size fields */	sbi->s_groups_count++;	ext4_journal_dirty_metadata(handle, primary);	/* Update the reserved block counts only once the new group is	 * active. */	ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) +		input->reserved_blocks);	/* Update the free space counts */	percpu_counter_add(&sbi->s_freeblocks_counter,			   input->free_blocks_count);	percpu_counter_add(&sbi->s_freeinodes_counter,			   EXT4_INODES_PER_GROUP(sb));	ext4_journal_dirty_metadata(handle, sbi->s_sbh);	sb->s_dirt = 1;exit_journal:	unlock_super(sb);	if ((err2 = ext4_journal_stop(handle)) && !err)		err = err2;	if (!err) {		update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es,			       sizeof(struct ext4_super_block));		update_backups(sb, primary->b_blocknr, primary->b_data,			       primary->b_size);	}exit_put:	iput(inode);	return err;} /* ext4_group_add *//* Extend the filesystem to the new number of blocks specified.  This entry * point is only used to extend the current filesystem to the end of the last * existing group.  It can be accessed via ioctl, or by "remount,resize=<size>" * for emergencies (because it has no dependencies on reserved blocks). * * If we _really_ wanted, we could use default values to call ext4_group_add() * allow the "remount" trick to work for arbitrary resizing, assuming enough * GDT blocks are reserved to grow to the desired size. */int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,		      ext4_fsblk_t n_blocks_count){	ext4_fsblk_t o_blocks_count;	unsigned long o_groups_count;	ext4_grpblk_t last;	ext4_grpblk_t add;	struct buffer_head * bh;	handle_t *handle;	int err;	unsigned long freed_blocks;	/* We don't need to worry about locking wrt other resizers just	 * yet: we're going to revalidate es->s_blocks_count after	 * taking lock_super() below. */	o_blocks_count = ext4_blocks_count(es);	o_groups_count = EXT4_SB(sb)->s_groups_count;	if (test_opt(sb, DEBUG))		printk(KERN_DEBUG "EXT4-fs: extending last group from %llu uto %llu blocks\n",		       o_blocks_count, n_blocks_count);	if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)		return 0;	if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {		printk(KERN_ERR "EXT4-fs: filesystem on %s:"			" too large to resize to %llu blocks safely\n",			sb->s_id, n_blocks_count);		if (sizeof(sector_t) < 8)			ext4_warning(sb, __FUNCTION__,			"CONFIG_LBD not enabled\n");		return -EINVAL;	}	if (n_blocks_count < o_blocks_count) {		ext4_warning(sb, __FUNCTION__,			     "can't shrink FS - resize aborted");		return -EBUSY;	}	/* Handle the remaining blocks in the last group only. */	ext4_get_group_no_and_offset(sb, o_blocks_count, NULL, &last);	if (last == 0) {		ext4_warning(sb, __FUNCTION__,			     "need to use ext2online to resize further");		return -EPERM;	}	add = EXT4_BLOCKS_PER_GROUP(sb) - last;	if (o_blocks_count + add < o_blocks_count) {		ext4_warning(sb, __FUNCTION__, "blocks_count overflow");		return -EINVAL;	}	if (o_blocks_count + add > n_blocks_count)		add = n_blocks_count - o_blocks_count;	if (o_blocks_count + add < n_blocks_count)		ext4_warning(sb, __FUNCTION__,			     "will only finish group (%llu"			     " blocks, %u new)",			     o_blocks_count + add, add);	/* See if the device is actually as big as what was requested */	bh = sb_bread(sb, o_blocks_count + add -1);	if (!bh) {		ext4_warning(sb, __FUNCTION__,			     "can't read last block, resize aborted");		return -ENOSPC;	}	brelse(bh);	/* We will update the superblock, one block bitmap, and	 * one group descriptor via ext4_free_blocks().	 */	handle = ext4_journal_start_sb(sb, 3);	if (IS_ERR(handle)) {		err = PTR_ERR(handle);		ext4_warning(sb, __FUNCTION__, "error %d on journal start",err);		goto exit_put;	}	lock_super(sb);	if (o_blocks_count != ext4_blocks_count(es)) {		ext4_warning(sb, __FUNCTION__,			     "multiple resizers run on filesystem!");		unlock_super(sb);		err = -EBUSY;		goto exit_put;	}	if ((err = ext4_journal_get_write_access(handle,						 EXT4_SB(sb)->s_sbh))) {		ext4_warning(sb, __FUNCTION__,			     "error %d on journal write access", err);		unlock_super(sb);		ext4_journal_stop(handle);		goto exit_put;	}	ext4_blocks_count_set(es, o_blocks_count + add);	ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);	sb->s_dirt = 1;	unlock_super(sb);	ext4_debug("freeing blocks %lu through %llu\n", o_blocks_count,		   o_blocks_count + add);	ext4_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks);	ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,		   o_blocks_count + add);	if ((err = ext4_journal_stop(handle)))		goto exit_put;	if (test_opt(sb, DEBUG))		printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n",		       ext4_blocks_count(es));	update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es,		       sizeof(struct ext4_super_block));exit_put:	return err;} /* ext4_group_extend */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -