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

📄 resize.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/fs/ext3/resize.c * * Support for resizing an ext3 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 EXT3FS_DEBUG#include <linux/ext3_jbd.h>#include <linux/errno.h>#include <linux/slab.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 ext3_new_group_data *input){	struct ext3_sb_info *sbi = EXT3_SB(sb);	struct ext3_super_block *es = sbi->s_es;	ext3_fsblk_t start = le32_to_cpu(es->s_blocks_count);	ext3_fsblk_t end = start + input->blocks_count;	unsigned group = input->group;	ext3_fsblk_t itend = input->inode_table + sbi->s_itb_per_group;	unsigned overhead = ext3_bg_has_super(sb, group) ?		(1 + ext3_bg_num_gdb(sb, group) +		 le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;	ext3_fsblk_t metaend = start + overhead;	struct buffer_head *bh = NULL;	ext3_grpblk_t free_blocks_count;	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 "EXT3-fs: adding %s group %u: %u blocks "		       "(%d free, %u reserved)\n",		       ext3_bg_has_super(sb, input->group) ? "normal" :		       "no-super", input->group, input->blocks_count,		       free_blocks_count, input->reserved_blocks);	if (group != sbi->s_groups_count)		ext3_warning(sb, __FUNCTION__,			     "Cannot add at group %u (only %lu groups)",			     input->group, sbi->s_groups_count);	else if ((start - le32_to_cpu(es->s_first_data_block)) %		 EXT3_BLOCKS_PER_GROUP(sb))		ext3_warning(sb, __FUNCTION__, "Last group not full");	else if (input->reserved_blocks > input->blocks_count / 5)		ext3_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)",			     input->reserved_blocks);	else if (free_blocks_count < 0)		ext3_warning(sb, __FUNCTION__, "Bad blocks count %u",			     input->blocks_count);	else if (!(bh = sb_bread(sb, end - 1)))		ext3_warning(sb, __FUNCTION__,			     "Cannot read last block ("E3FSBLK")",			     end - 1);	else if (outside(input->block_bitmap, start, end))		ext3_warning(sb, __FUNCTION__,			     "Block bitmap not in group (block %u)",			     input->block_bitmap);	else if (outside(input->inode_bitmap, start, end))		ext3_warning(sb, __FUNCTION__,			     "Inode bitmap not in group (block %u)",			     input->inode_bitmap);	else if (outside(input->inode_table, start, end) ||	         outside(itend - 1, start, end))		ext3_warning(sb, __FUNCTION__,			     "Inode table not in group (blocks %u-"E3FSBLK")",			     input->inode_table, itend - 1);	else if (input->inode_bitmap == input->block_bitmap)		ext3_warning(sb, __FUNCTION__,			     "Block bitmap same as inode bitmap (%u)",			     input->block_bitmap);	else if (inside(input->block_bitmap, input->inode_table, itend))		ext3_warning(sb, __FUNCTION__,			     "Block bitmap (%u) in inode table (%u-"E3FSBLK")",			     input->block_bitmap, input->inode_table, itend-1);	else if (inside(input->inode_bitmap, input->inode_table, itend))		ext3_warning(sb, __FUNCTION__,			     "Inode bitmap (%u) in inode table (%u-"E3FSBLK")",			     input->inode_bitmap, input->inode_table, itend-1);	else if (inside(input->block_bitmap, start, metaend))		ext3_warning(sb, __FUNCTION__,			     "Block bitmap (%u) in GDT table"			     " ("E3FSBLK"-"E3FSBLK")",			     input->block_bitmap, start, metaend - 1);	else if (inside(input->inode_bitmap, start, metaend))		ext3_warning(sb, __FUNCTION__,			     "Inode bitmap (%u) in GDT table"			     " ("E3FSBLK"-"E3FSBLK")",			     input->inode_bitmap, start, metaend - 1);	else if (inside(input->inode_table, start, metaend) ||	         inside(itend - 1, start, metaend))		ext3_warning(sb, __FUNCTION__,			     "Inode table (%u-"E3FSBLK") overlaps"			     "GDT table ("E3FSBLK"-"E3FSBLK")",			     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,				  ext3_fsblk_t blk){	struct buffer_head *bh;	int err;	bh = sb_getblk(sb, blk);	if (!bh)		return ERR_PTR(-EIO);	if ((err = ext3_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;}/* * To avoid calling the atomic setbit hundreds or thousands of times, we only * need to use it within a single byte (to ensure we get endianness right). * We can use memset for the rest of the bitmap as there are no other users. */static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap){	int i;	if (start_bit >= end_bit)		return;	ext3_debug("mark end bits +%d through +%d used\n", start_bit, end_bit);	for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)		ext3_set_bit(i, bitmap);	if (i < end_bit)		memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);}/* * If we have fewer than thresh credits, extend by EXT3_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 = ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA);	if (err < 0)		return err;	if (err) {		err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA);		if (err)			return err;		err = ext3_journal_get_write_access(handle, bh);		if (err)			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 ext3_new_group_data *input){	struct ext3_sb_info *sbi = EXT3_SB(sb);	ext3_fsblk_t start = ext3_group_first_block_no(sb, input->group);	int reserved_gdb = ext3_bg_has_super(sb, input->group) ?		le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0;	unsigned long gdblocks = ext3_bg_num_gdb(sb, input->group);	struct buffer_head *bh;	handle_t *handle;	ext3_fsblk_t block;	ext3_grpblk_t bit;	int i;	int err = 0, err2;	/* This transaction may be extended/restarted along the way */	handle = ext3_journal_start_sb(sb, EXT3_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 (ext3_bg_has_super(sb, input->group)) {		ext3_debug("mark backup superblock %#04lx (+0)\n", start);		ext3_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;		ext3_debug("update backup group %#04lx (+%d)\n", block, bit);		err = extend_or_restart_transaction(handle, 1, bh);		if (err)			goto exit_bh;		gdb = sb_getblk(sb, block);		if (!gdb) {			err = -EIO;			goto exit_bh;		}		if ((err = ext3_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);		ext3_journal_dirty_metadata(handle, gdb);		ext3_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;		ext3_debug("clear reserved block %#04lx (+%d)\n", block, bit);		err = extend_or_restart_transaction(handle, 1, bh);		if (err)			goto exit_bh;		if (IS_ERR(gdb = bclean(handle, sb, block))) {			err = PTR_ERR(bh);			goto exit_bh;		}		ext3_journal_dirty_metadata(handle, gdb);		ext3_set_bit(bit, bh->b_data);		brelse(gdb);	}	ext3_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap,		   input->block_bitmap - start);	ext3_set_bit(input->block_bitmap - start, bh->b_data);	ext3_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap,		   input->inode_bitmap - start);	ext3_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;		ext3_debug("clear inode block %#04lx (+%d)\n", block, bit);		err = extend_or_restart_transaction(handle, 1, bh);		if (err)			goto exit_bh;		if (IS_ERR(it = bclean(handle, sb, block))) {			err = PTR_ERR(it);			goto exit_bh;		}		ext3_journal_dirty_metadata(handle, it);		brelse(it);		ext3_set_bit(bit, bh->b_data);	}	err = extend_or_restart_transaction(handle, 2, bh);	if (err)		goto exit_bh;	mark_bitmap_end(input->blocks_count, EXT3_BLOCKS_PER_GROUP(sb),			bh->b_data);	ext3_journal_dirty_metadata(handle, bh);	brelse(bh);	/* Mark unused entries in inode bitmap used */	ext3_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(EXT3_INODES_PER_GROUP(sb), EXT3_BLOCKS_PER_GROUP(sb),			bh->b_data);	ext3_journal_dirty_metadata(handle, bh);exit_bh:	brelse(bh);exit_journal:	unlock_super(sb);	if ((err2 = ext3_journal_stop(handle)) && !err)		err = err2;	return err;}/* * Iterate through the groups which hold BACKUP superblock/GDT copies in an * ext3 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 ext3_list_backups(struct super_block *sb, unsigned *three,				  unsigned *five, unsigned *seven){	unsigned *min = three;	int mult = 3;	unsigned ret;	if (!EXT3_HAS_RO_COMPAT_FEATURE(sb,					EXT3_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;	}

⌨️ 快捷键说明

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