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

📄 resize.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/fs/ext4/resize.c * * Support for resizing an ext4 filesystem while it is mounted. * * Copyright (C) 2001, 2002 Andreas Dilger <adilger@clusterfs.com> * * This could probably be made into a module, because it is not often in use. */#define EXT4FS_DEBUG#include <linux/ext4_jbd2.h>#include <linux/errno.h>#include <linux/slab.h>#include "group.h"#define outside(b, first, last)	((b) < (first) || (b) >= (last))#define inside(b, first, last)	((b) >= (first) && (b) < (last))static int verify_group_input(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;	ext4_fsblk_t start = ext4_blocks_count(es);	ext4_fsblk_t end = start + input->blocks_count;	unsigned group = input->group;	ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group;	unsigned overhead = ext4_bg_has_super(sb, group) ?		(1 + ext4_bg_num_gdb(sb, group) +		 le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;	ext4_fsblk_t metaend = start + overhead;	struct buffer_head *bh = NULL;	ext4_grpblk_t free_blocks_count, offset;	int err = -EINVAL;	input->free_blocks_count = free_blocks_count =		input->blocks_count - 2 - overhead - sbi->s_itb_per_group;	if (test_opt(sb, DEBUG))		printk(KERN_DEBUG "EXT4-fs: adding %s group %u: %u blocks "		       "(%d free, %u reserved)\n",		       ext4_bg_has_super(sb, input->group) ? "normal" :		       "no-super", input->group, input->blocks_count,		       free_blocks_count, input->reserved_blocks);	ext4_get_group_no_and_offset(sb, start, NULL, &offset);	if (group != sbi->s_groups_count)		ext4_warning(sb, __FUNCTION__,			     "Cannot add at group %u (only %lu groups)",			     input->group, sbi->s_groups_count);	else if (offset != 0)			ext4_warning(sb, __FUNCTION__, "Last group not full");	else if (input->reserved_blocks > input->blocks_count / 5)		ext4_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)",			     input->reserved_blocks);	else if (free_blocks_count < 0)		ext4_warning(sb, __FUNCTION__, "Bad blocks count %u",			     input->blocks_count);	else if (!(bh = sb_bread(sb, end - 1)))		ext4_warning(sb, __FUNCTION__,			     "Cannot read last block (%llu)",			     end - 1);	else if (outside(input->block_bitmap, start, end))		ext4_warning(sb, __FUNCTION__,			     "Block bitmap not in group (block %llu)",			     (unsigned long long)input->block_bitmap);	else if (outside(input->inode_bitmap, start, end))		ext4_warning(sb, __FUNCTION__,			     "Inode bitmap not in group (block %llu)",			     (unsigned long long)input->inode_bitmap);	else if (outside(input->inode_table, start, end) ||	         outside(itend - 1, start, end))		ext4_warning(sb, __FUNCTION__,			     "Inode table not in group (blocks %llu-%llu)",			     (unsigned long long)input->inode_table, itend - 1);	else if (input->inode_bitmap == input->block_bitmap)		ext4_warning(sb, __FUNCTION__,			     "Block bitmap same as inode bitmap (%llu)",			     (unsigned long long)input->block_bitmap);	else if (inside(input->block_bitmap, input->inode_table, itend))		ext4_warning(sb, __FUNCTION__,			     "Block bitmap (%llu) in inode table (%llu-%llu)",			     (unsigned long long)input->block_bitmap,			     (unsigned long long)input->inode_table, itend - 1);	else if (inside(input->inode_bitmap, input->inode_table, itend))		ext4_warning(sb, __FUNCTION__,			     "Inode bitmap (%llu) in inode table (%llu-%llu)",			     (unsigned long long)input->inode_bitmap,			     (unsigned long long)input->inode_table, itend - 1);	else if (inside(input->block_bitmap, start, metaend))		ext4_warning(sb, __FUNCTION__,			     "Block bitmap (%llu) in GDT table"			     " (%llu-%llu)",			     (unsigned long long)input->block_bitmap,			     start, metaend - 1);	else if (inside(input->inode_bitmap, start, metaend))		ext4_warning(sb, __FUNCTION__,			     "Inode bitmap (%llu) in GDT table"			     " (%llu-%llu)",			     (unsigned long long)input->inode_bitmap,			     start, metaend - 1);	else if (inside(input->inode_table, start, metaend) ||	         inside(itend - 1, start, metaend))		ext4_warning(sb, __FUNCTION__,			     "Inode table (%llu-%llu) overlaps"			     "GDT table (%llu-%llu)",			     (unsigned long long)input->inode_table,			     itend - 1, start, metaend - 1);	else		err = 0;	brelse(bh);	return err;}static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,				  ext4_fsblk_t blk){	struct buffer_head *bh;	int err;	bh = sb_getblk(sb, blk);	if (!bh)		return ERR_PTR(-EIO);	if ((err = ext4_journal_get_write_access(handle, bh))) {		brelse(bh);		bh = ERR_PTR(err);	} else {		lock_buffer(bh);		memset(bh->b_data, 0, sb->s_blocksize);		set_buffer_uptodate(bh);		unlock_buffer(bh);	}	return bh;}/* * If we have fewer than thresh credits, extend by EXT4_MAX_TRANS_DATA. * If that fails, restart the transaction & regain write access for the * buffer head which is used for block_bitmap modifications. */static int extend_or_restart_transaction(handle_t *handle, int thresh,					 struct buffer_head *bh){	int err;	if (handle->h_buffer_credits >= thresh)		return 0;	err = ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA);	if (err < 0)		return err;	if (err) {		if ((err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA)))			return err;	        if ((err = ext4_journal_get_write_access(handle, bh)))			return err;        }	return 0;}/* * Set up the block and inode bitmaps, and the inode table for the new group. * This doesn't need to be part of the main transaction, since we are only * changing blocks outside the actual filesystem.  We still do journaling to * ensure the recovery is correct in case of a failure just after resize. * If any part of this fails, we simply abort the resize. */static int setup_new_group_blocks(struct super_block *sb,				  struct ext4_new_group_data *input){	struct ext4_sb_info *sbi = EXT4_SB(sb);	ext4_fsblk_t start = ext4_group_first_block_no(sb, input->group);	int reserved_gdb = ext4_bg_has_super(sb, input->group) ?		le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0;	unsigned long gdblocks = ext4_bg_num_gdb(sb, input->group);	struct buffer_head *bh;	handle_t *handle;	ext4_fsblk_t block;	ext4_grpblk_t bit;	int i;	int err = 0, err2;	/* This transaction may be extended/restarted along the way */	handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA);	if (IS_ERR(handle))		return PTR_ERR(handle);	lock_super(sb);	if (input->group != sbi->s_groups_count) {		err = -EBUSY;		goto exit_journal;	}	if (IS_ERR(bh = bclean(handle, sb, input->block_bitmap))) {		err = PTR_ERR(bh);		goto exit_journal;	}	if (ext4_bg_has_super(sb, input->group)) {		ext4_debug("mark backup superblock %#04lx (+0)\n", start);		ext4_set_bit(0, bh->b_data);	}	/* Copy all of the GDT blocks into the backup in this group */	for (i = 0, bit = 1, block = start + 1;	     i < gdblocks; i++, block++, bit++) {		struct buffer_head *gdb;		ext4_debug("update backup group %#04lx (+%d)\n", block, bit);		if ((err = extend_or_restart_transaction(handle, 1, bh)))			goto exit_bh;		gdb = sb_getblk(sb, block);		if (!gdb) {			err = -EIO;			goto exit_bh;		}		if ((err = ext4_journal_get_write_access(handle, gdb))) {			brelse(gdb);			goto exit_bh;		}		lock_buffer(gdb);		memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size);		set_buffer_uptodate(gdb);		unlock_buffer(gdb);		ext4_journal_dirty_metadata(handle, gdb);		ext4_set_bit(bit, bh->b_data);		brelse(gdb);	}	/* Zero out all of the reserved backup group descriptor table blocks */	for (i = 0, bit = gdblocks + 1, block = start + bit;	     i < reserved_gdb; i++, block++, bit++) {		struct buffer_head *gdb;		ext4_debug("clear reserved block %#04lx (+%d)\n", block, bit);		if ((err = extend_or_restart_transaction(handle, 1, bh)))			goto exit_bh;		if (IS_ERR(gdb = bclean(handle, sb, block))) {			err = PTR_ERR(bh);			goto exit_bh;		}		ext4_journal_dirty_metadata(handle, gdb);		ext4_set_bit(bit, bh->b_data);		brelse(gdb);	}	ext4_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap,		   input->block_bitmap - start);	ext4_set_bit(input->block_bitmap - start, bh->b_data);	ext4_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap,		   input->inode_bitmap - start);	ext4_set_bit(input->inode_bitmap - start, bh->b_data);	/* Zero out all of the inode table blocks */	for (i = 0, block = input->inode_table, bit = block - start;	     i < sbi->s_itb_per_group; i++, bit++, block++) {		struct buffer_head *it;		ext4_debug("clear inode block %#04lx (+%d)\n", block, bit);		if ((err = extend_or_restart_transaction(handle, 1, bh)))			goto exit_bh;		if (IS_ERR(it = bclean(handle, sb, block))) {			err = PTR_ERR(it);			goto exit_bh;		}		ext4_journal_dirty_metadata(handle, it);		brelse(it);		ext4_set_bit(bit, bh->b_data);	}	if ((err = extend_or_restart_transaction(handle, 2, bh)))		goto exit_bh;	mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb),			bh->b_data);	ext4_journal_dirty_metadata(handle, bh);	brelse(bh);	/* Mark unused entries in inode bitmap used */	ext4_debug("clear inode bitmap %#04x (+%ld)\n",		   input->inode_bitmap, input->inode_bitmap - start);	if (IS_ERR(bh = bclean(handle, sb, input->inode_bitmap))) {		err = PTR_ERR(bh);		goto exit_journal;	}	mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb),			bh->b_data);	ext4_journal_dirty_metadata(handle, bh);exit_bh:	brelse(bh);exit_journal:	unlock_super(sb);	if ((err2 = ext4_journal_stop(handle)) && !err)		err = err2;	return err;}/* * Iterate through the groups which hold BACKUP superblock/GDT copies in an * ext4 filesystem.  The counters should be initialized to 1, 5, and 7 before * calling this for the first time.  In a sparse filesystem it will be the * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... */static unsigned ext4_list_backups(struct super_block *sb, unsigned *three,				  unsigned *five, unsigned *seven){	unsigned *min = three;	int mult = 3;	unsigned ret;	if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,					EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {		ret = *min;		*min += 1;		return ret;	}	if (*five < *min) {		min = five;		mult = 5;	}	if (*seven < *min) {		min = seven;		mult = 7;	}	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){

⌨️ 快捷键说明

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