diff mbox

[RFC,v1,2/4] resize2fs: add option -I for reserving more special inodes

Message ID 20150312162013.17173.71244.stgit@buzz
State Accepted, archived
Headers show

Commit Message

Konstantin Khlebnikov March 12, 2015, 4:20 p.m. UTC
Resize2fs relocates last inodes when it shinks filesystem.
This patch reuses this code for relocating first inodes,
it adds option '-I' for changing first normal inode.

Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
---
 resize/main.c         |   38 ++++++++++++++++++++++++++++++++----
 resize/resize2fs.8.in |    8 ++++++++
 resize/resize2fs.c    |   52 +++++++++++++++++++++++++++++++++++++++++++++++--
 resize/resize2fs.h    |    3 +++
 4 files changed, 95 insertions(+), 6 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Darrick Wong March 12, 2015, 7:26 p.m. UTC | #1
On Thu, Mar 12, 2015 at 07:20:13PM +0300, Konstantin Khlebnikov wrote:
> Resize2fs relocates last inodes when it shinks filesystem.
> This patch reuses this code for relocating first inodes,
> it adds option '-I' for changing first normal inode.
> 
> Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
> ---
>  resize/main.c         |   38 ++++++++++++++++++++++++++++++++----
>  resize/resize2fs.8.in |    8 ++++++++
>  resize/resize2fs.c    |   52 +++++++++++++++++++++++++++++++++++++++++++++++--
>  resize/resize2fs.h    |    3 +++
>  4 files changed, 95 insertions(+), 6 deletions(-)
> 
> diff --git a/resize/main.c b/resize/main.c
> index 16f48d438cb0..eae7146f41ab 100644
> --- a/resize/main.c
> +++ b/resize/main.c
> @@ -41,8 +41,9 @@ static char *device_name, *io_options;
>  
>  static void usage (char *prog)
>  {
> -	fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] "
> -			   "[-p] device [-b|-s|new_size]\n\n"), prog);
> +	fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P]"
> +			   "[-p] [-I first_inode] device [-b|-s|new_size]\n\n"),
> +			prog);
>  
>  	exit (1);
>  }
> @@ -213,7 +214,7 @@ int main (int argc, char ** argv)
>  		exit(1);
>  	}
>  
> -	while ((c = getopt(argc, argv, "d:fFhMPpS:bs")) != EOF) {
> +	while ((c = getopt(argc, argv, "d:fFhMPpS:bsI:")) != EOF) {
>  		switch (c) {
>  		case 'h':
>  			usage(program_name);
> @@ -245,6 +246,10 @@ int main (int argc, char ** argv)
>  		case 's':
>  			flags |= RESIZE_DISABLE_64BIT;
>  			break;
> +		case 'I':
> +			flags |= RESIZE_SPECIAL_INODES;
> +			rfs->first_ino = atoi(optarg);
> +			break;
>  		default:
>  			usage(program_name);
>  		}
> @@ -430,7 +435,8 @@ int main (int argc, char ** argv)
>  			new_size &= ~((sys_page_size / blocksize)-1);
>  	}
>  	/* If changing 64bit, don't change the filesystem size. */
> -	if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) {
> +	if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT |
> +		     RESIZE_SPECIAL_INODES)) {
>  		new_size = ext2fs_blocks_count(fs->super);
>  	}
>  	if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
> @@ -507,6 +513,28 @@ int main (int argc, char ** argv)
>  				"feature.\n"));
>  			exit(1);
>  		}
> +	} else if (flags & RESIZE_SPECIAL_INODES) {
> +		if (rfs->first_ino > fs->super->s_inodes_count) {

An FS with rfs->first_ino == fs->super->s_inodes_count isn't going to be
very useful... presumably you'd want at least one regular inode, right?

> +			fprintf(stderr, _("First inode too big\n"));

"Cannot reserve more than ($s_inodes_count - 1) inodes"?

> +			exit(1);
> +		}
> +		if (rfs->first_ino < EXT2_FIRST_INO(fs->super)) {
> +			fprintf(stderr, _("The filesystem has %d special inodes."
> +					  "Reducing isn't supported.\n\n"),
> +					EXT2_FIRST_INO(fs->super));
> +			exit(1);
> +		}
> +		if (rfs->first_ino == EXT2_FIRST_INO(fs->super)) {
> +			fprintf(stderr, _("The filesystem already has %d "
> +					  "special inodes. Nothing to do!\n\n"),
> +					EXT2_FIRST_INO(fs->super));
> +			exit(0);
> +		}
> +		if (mount_flags & EXT2_MF_MOUNTED) {
> +			fprintf(stderr, _("Cannot change count of special "
> +				"inodes while the filesystem is mounted.\n"));
> +			exit(1);
> +		}
>  	} else if (new_size == ext2fs_blocks_count(fs->super)) {
>  		fprintf(stderr, _("The filesystem is already %llu (%dk) "
>  			"blocks long.  Nothing to do!\n\n"), new_size,
> @@ -532,6 +560,8 @@ int main (int argc, char ** argv)
>  			printf(_("Converting the filesystem to 64-bit.\n"));
>  		else if (flags & RESIZE_DISABLE_64BIT)
>  			printf(_("Converting the filesystem to 32-bit.\n"));
> +		else if (flags & RESIZE_SPECIAL_INODES)
> +			printf(_("Reserving special inodes.\n"));
>  		else
>  			printf(_("Resizing the filesystem on "
>  				 "%s to %llu (%dk) blocks.\n"),
> diff --git a/resize/resize2fs.8.in b/resize/resize2fs.8.in
> index 0129bfcafa3b..f22563fe07e1 100644
> --- a/resize/resize2fs.8.in
> +++ b/resize/resize2fs.8.in
> @@ -18,6 +18,10 @@ resize2fs \- ext2/ext3/ext4 file system resizer
>  .B \-S
>  .I RAID-stride
>  ]
> +[
> +.B \-I
> +.I first-inode
> +]
>  .I device
>  [
>  .I size
> @@ -101,6 +105,10 @@ to resize the filesystem concurrent with changing the 64bit status.
>  Turns on the 64bit feature, resizes the group descriptors as necessary, and
>  moves other metadata out of the way.
>  .TP
> +.B \-I \fI <first-inode>
> +This changes first normal inode and relocates inuse inodes into vacant slots.
> +Inodes below that are reserved for internal use. Reducing isn't supported.

"Increases the number of reserved inodes, moving any in-use inodes into vacant
slots."?

--D

> +.TP
>  .B \-d \fIdebug-flags
>  Turns on various resize2fs debugging features, if they have been compiled
>  into the binary.
> diff --git a/resize/resize2fs.c b/resize/resize2fs.c
> index dead364bf4bf..2fb653b76dd8 100644
> --- a/resize/resize2fs.c
> +++ b/resize/resize2fs.c
> @@ -48,6 +48,7 @@ static errcode_t block_mover(ext2_resize_t rfs);
>  static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
>  static errcode_t inode_ref_fix(ext2_resize_t rfs);
>  static errcode_t move_itables(ext2_resize_t rfs);
> +static errcode_t zero_new_special_inodes(ext2_resize_t rfs);
>  static errcode_t fix_resize_inode(ext2_filsys fs);
>  static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
>  static errcode_t fix_sb_journal_backup(ext2_filsys fs);
> @@ -112,6 +113,11 @@ errcode_t resize_fs(ext2_filsys fs, ext2_resize_t rfs)
>  	if (retval)
>  		goto errout;
>  
> +	if (flags & RESIZE_SPECIAL_INODES) {
> +		ext2fs_update_dynamic_rev(rfs->new_fs);
> +		EXT2_SB(rfs->new_fs->super)->s_first_ino = rfs->first_ino;
> +	}
> +
>  	init_resource_track(&rtrack, "resize_group_descriptors", fs->io);
>  	retval = resize_group_descriptors(rfs);
>  	if (retval)
> @@ -177,6 +183,12 @@ errcode_t resize_fs(ext2_filsys fs, ext2_resize_t rfs)
>  		goto errout;
>  	print_resource_track(rfs, &rtrack, fs->io);
>  
> +	init_resource_track(&rtrack, "zero_new_special_inodes", fs->io);
> +	retval = zero_new_special_inodes(rfs);
> +	if (retval)
> +		goto errout;
> +	print_resource_track(rfs, &rtrack, fs->io);
> +
>  	init_resource_track(&rtrack, "move_itables", fs->io);
>  	retval = move_itables(rfs);
>  	if (retval)
> @@ -1963,7 +1975,8 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
>  
>  	if ((rfs->old_fs->group_desc_count <=
>  	     rfs->new_fs->group_desc_count) &&
> -	    !rfs->bmap)
> +	    !rfs->bmap &&
> +	    !(rfs->flags & RESIZE_SPECIAL_INODES))
>  		return 0;
>  
>  	set_com_err_hook(quiet_com_err_proc);
> @@ -2018,7 +2031,11 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
>  			goto errout;
>  
>  		new_inode = ino;
> -		if (ino <= start_to_move)
> +		if (ino >= EXT2_FIRST_INO(rfs->old_fs->super) &&
> +		    ino <  EXT2_FIRST_INO(rfs->new_fs->super)) {
> +			ext2fs_inode_alloc_stats2(rfs->new_fs, ino, -1,
> +						  pb.is_dir);
> +		} else if (ino <= start_to_move)
>  			goto remap_blocks; /* Don't need to move inode. */
>  
>  		/*
> @@ -2552,6 +2569,37 @@ static errcode_t reserve_sparse_super2_last_group(ext2_resize_t rfs,
>  }
>  
>  /*
> + * Clear new special inodes
> + */
> +static errcode_t zero_new_special_inodes(ext2_resize_t rfs)
> +{
> +	ext2_filsys		fs = rfs->new_fs;
> +	int			inode_size;
> +	struct ext2_inode	*inode;
> +	errcode_t		retval;
> +	ext2_ino_t		ino;
> +
> +	if (!(rfs->flags & RESIZE_SPECIAL_INODES))
> +		return 0;
> +
> +	inode_size = EXT2_INODE_SIZE(fs->super);
> +	retval = ext2fs_get_memzero(inode_size, &inode);
> +	if (retval)
> +		return retval;
> +
> +	for (ino = EXT2_FIRST_INO(rfs->old_fs->super);
> +	     ino < EXT2_FIRST_INO(fs->super); ino++) {
> +		/* All special inodes are marked as inuse */
> +		ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
> +		retval = ext2fs_write_inode_full(fs, ino, inode, inode_size);
> +		if (retval)
> +			break;
> +	}
> +	ext2fs_free_mem(&inode);
> +	return retval;
> +}
> +
> +/*
>   * Fix the resize inode
>   */
>  static errcode_t fix_resize_inode(ext2_filsys fs)
> diff --git a/resize/resize2fs.h b/resize/resize2fs.h
> index c5377e2b06c3..84f83b09f237 100644
> --- a/resize/resize2fs.h
> +++ b/resize/resize2fs.h
> @@ -85,6 +85,8 @@ typedef struct ext2_sim_progress *ext2_sim_progmeter;
>  #define RESIZE_ENABLE_64BIT		0x0400
>  #define RESIZE_DISABLE_64BIT		0x0800
>  
> +#define RESIZE_SPECIAL_INODES		0x1000
> +
>  /*
>   * This structure is used for keeping track of how much resources have
>   * been used for a particular resize2fs pass.
> @@ -130,6 +132,7 @@ struct ext2_resize_struct {
>  	void		*prog_data;
>  
>  	blk64_t		new_size;
> +	ext2_ino_t	first_ino;
>  };
>  
>  /*
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Konstantin Khlebnikov March 13, 2015, 10:52 a.m. UTC | #2
On 12.03.2015 22:26, Darrick J. Wong wrote:
> On Thu, Mar 12, 2015 at 07:20:13PM +0300, Konstantin Khlebnikov wrote:
>> Resize2fs relocates last inodes when it shinks filesystem.
>> This patch reuses this code for relocating first inodes,
>> it adds option '-I' for changing first normal inode.
>>
>> Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
>> ---
>>   resize/main.c         |   38 ++++++++++++++++++++++++++++++++----
>>   resize/resize2fs.8.in |    8 ++++++++
>>   resize/resize2fs.c    |   52 +++++++++++++++++++++++++++++++++++++++++++++++--
>>   resize/resize2fs.h    |    3 +++
>>   4 files changed, 95 insertions(+), 6 deletions(-)
>>
>> diff --git a/resize/main.c b/resize/main.c
>> index 16f48d438cb0..eae7146f41ab 100644
>> --- a/resize/main.c
>> +++ b/resize/main.c

-cut

>> @@ -507,6 +513,28 @@ int main (int argc, char ** argv)
>>   				"feature.\n"));
>>   			exit(1);
>>   		}
>> +	} else if (flags & RESIZE_SPECIAL_INODES) {
>> +		if (rfs->first_ino > fs->super->s_inodes_count) {
>
> An FS with rfs->first_ino == fs->super->s_inodes_count isn't going to be
> very useful... presumably you'd want at least one regular inode, right?

In this case there will be exactly one regular inode:
s_inodes_count is index of last inode on the filesystem.

>
>> +			fprintf(stderr, _("First inode too big\n"));
>
> "Cannot reserve more than ($s_inodes_count - 1) inodes"?

So, you're suggest to rephrase option as "reserve special inodes"
instead of "set first normal inode"?

>
>> +			exit(1);
>> +		}
>> +		if (rfs->first_ino < EXT2_FIRST_INO(fs->super)) {
>> +			fprintf(stderr, _("The filesystem has %d special inodes."
>> +					  "Reducing isn't supported.\n\n"),
>> +					EXT2_FIRST_INO(fs->super));
>> +			exit(1);
>> +		}
>> +		if (rfs->first_ino == EXT2_FIRST_INO(fs->super)) {
>> +			fprintf(stderr, _("The filesystem already has %d "
>> +					  "special inodes. Nothing to do!\n\n"),
>> +					EXT2_FIRST_INO(fs->super));
>> +			exit(0);
>> +		}
>> +		if (mount_flags & EXT2_MF_MOUNTED) {
>> +			fprintf(stderr, _("Cannot change count of special "
>> +				"inodes while the filesystem is mounted.\n"));
>> +			exit(1);
>> +		}
>>   	} else if (new_size == ext2fs_blocks_count(fs->super)) {
>>   		fprintf(stderr, _("The filesystem is already %llu (%dk) "
>>   			"blocks long.  Nothing to do!\n\n"), new_size,
>> @@ -532,6 +560,8 @@ int main (int argc, char ** argv)
>>   			printf(_("Converting the filesystem to 64-bit.\n"));
>>   		else if (flags & RESIZE_DISABLE_64BIT)
>>   			printf(_("Converting the filesystem to 32-bit.\n"));
>> +		else if (flags & RESIZE_SPECIAL_INODES)
>> +			printf(_("Reserving special inodes.\n"));
>>   		else
>>   			printf(_("Resizing the filesystem on "
>>   				 "%s to %llu (%dk) blocks.\n"),
>> diff --git a/resize/resize2fs.8.in b/resize/resize2fs.8.in
>> index 0129bfcafa3b..f22563fe07e1 100644
>> --- a/resize/resize2fs.8.in
>> +++ b/resize/resize2fs.8.in
>> @@ -18,6 +18,10 @@ resize2fs \- ext2/ext3/ext4 file system resizer
>>   .B \-S
>>   .I RAID-stride
>>   ]
>> +[
>> +.B \-I
>> +.I first-inode
>> +]
>>   .I device
>>   [
>>   .I size
>> @@ -101,6 +105,10 @@ to resize the filesystem concurrent with changing the 64bit status.
>>   Turns on the 64bit feature, resizes the group descriptors as necessary, and
>>   moves other metadata out of the way.
>>   .TP
>> +.B \-I \fI <first-inode>
>> +This changes first normal inode and relocates inuse inodes into vacant slots.
>> +Inodes below that are reserved for internal use. Reducing isn't supported.
>
> "Increases the number of reserved inodes, moving any in-use inodes into vacant
> slots."?
>
> --D
>
>> +.TP
>>   .B \-d \fIdebug-flags
>>   Turns on various resize2fs debugging features, if they have been compiled
>>   into the binary.
>> diff --git a/resize/resize2fs.c b/resize/resize2fs.c
>> index dead364bf4bf..2fb653b76dd8 100644
>> --- a/resize/resize2fs.c
>> +++ b/resize/resize2fs.c
>> @@ -48,6 +48,7 @@ static errcode_t block_mover(ext2_resize_t rfs);
>>   static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
>>   static errcode_t inode_ref_fix(ext2_resize_t rfs);
>>   static errcode_t move_itables(ext2_resize_t rfs);
>> +static errcode_t zero_new_special_inodes(ext2_resize_t rfs);
>>   static errcode_t fix_resize_inode(ext2_filsys fs);
>>   static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
>>   static errcode_t fix_sb_journal_backup(ext2_filsys fs);
>> @@ -112,6 +113,11 @@ errcode_t resize_fs(ext2_filsys fs, ext2_resize_t rfs)
>>   	if (retval)
>>   		goto errout;
>>
>> +	if (flags & RESIZE_SPECIAL_INODES) {
>> +		ext2fs_update_dynamic_rev(rfs->new_fs);
>> +		EXT2_SB(rfs->new_fs->super)->s_first_ino = rfs->first_ino;
>> +	}
>> +
>>   	init_resource_track(&rtrack, "resize_group_descriptors", fs->io);
>>   	retval = resize_group_descriptors(rfs);
>>   	if (retval)
>> @@ -177,6 +183,12 @@ errcode_t resize_fs(ext2_filsys fs, ext2_resize_t rfs)
>>   		goto errout;
>>   	print_resource_track(rfs, &rtrack, fs->io);
>>
>> +	init_resource_track(&rtrack, "zero_new_special_inodes", fs->io);
>> +	retval = zero_new_special_inodes(rfs);
>> +	if (retval)
>> +		goto errout;
>> +	print_resource_track(rfs, &rtrack, fs->io);
>> +
>>   	init_resource_track(&rtrack, "move_itables", fs->io);
>>   	retval = move_itables(rfs);
>>   	if (retval)
>> @@ -1963,7 +1975,8 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
>>
>>   	if ((rfs->old_fs->group_desc_count <=
>>   	     rfs->new_fs->group_desc_count) &&
>> -	    !rfs->bmap)
>> +	    !rfs->bmap &&
>> +	    !(rfs->flags & RESIZE_SPECIAL_INODES))
>>   		return 0;
>>
>>   	set_com_err_hook(quiet_com_err_proc);
>> @@ -2018,7 +2031,11 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
>>   			goto errout;
>>
>>   		new_inode = ino;
>> -		if (ino <= start_to_move)
>> +		if (ino >= EXT2_FIRST_INO(rfs->old_fs->super) &&
>> +		    ino <  EXT2_FIRST_INO(rfs->new_fs->super)) {
>> +			ext2fs_inode_alloc_stats2(rfs->new_fs, ino, -1,
>> +						  pb.is_dir);
>> +		} else if (ino <= start_to_move)
>>   			goto remap_blocks; /* Don't need to move inode. */
>>
>>   		/*
>> @@ -2552,6 +2569,37 @@ static errcode_t reserve_sparse_super2_last_group(ext2_resize_t rfs,
>>   }
>>
>>   /*
>> + * Clear new special inodes
>> + */
>> +static errcode_t zero_new_special_inodes(ext2_resize_t rfs)
>> +{
>> +	ext2_filsys		fs = rfs->new_fs;
>> +	int			inode_size;
>> +	struct ext2_inode	*inode;
>> +	errcode_t		retval;
>> +	ext2_ino_t		ino;
>> +
>> +	if (!(rfs->flags & RESIZE_SPECIAL_INODES))
>> +		return 0;
>> +
>> +	inode_size = EXT2_INODE_SIZE(fs->super);
>> +	retval = ext2fs_get_memzero(inode_size, &inode);
>> +	if (retval)
>> +		return retval;
>> +
>> +	for (ino = EXT2_FIRST_INO(rfs->old_fs->super);
>> +	     ino < EXT2_FIRST_INO(fs->super); ino++) {
>> +		/* All special inodes are marked as inuse */
>> +		ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
>> +		retval = ext2fs_write_inode_full(fs, ino, inode, inode_size);
>> +		if (retval)
>> +			break;
>> +	}
>> +	ext2fs_free_mem(&inode);
>> +	return retval;
>> +}
>> +
>> +/*
>>    * Fix the resize inode
>>    */
>>   static errcode_t fix_resize_inode(ext2_filsys fs)
>> diff --git a/resize/resize2fs.h b/resize/resize2fs.h
>> index c5377e2b06c3..84f83b09f237 100644
>> --- a/resize/resize2fs.h
>> +++ b/resize/resize2fs.h
>> @@ -85,6 +85,8 @@ typedef struct ext2_sim_progress *ext2_sim_progmeter;
>>   #define RESIZE_ENABLE_64BIT		0x0400
>>   #define RESIZE_DISABLE_64BIT		0x0800
>>
>> +#define RESIZE_SPECIAL_INODES		0x1000
>> +
>>   /*
>>    * This structure is used for keeping track of how much resources have
>>    * been used for a particular resize2fs pass.
>> @@ -130,6 +132,7 @@ struct ext2_resize_struct {
>>   	void		*prog_data;
>>
>>   	blk64_t		new_size;
>> +	ext2_ino_t	first_ino;
>>   };
>>
>>   /*
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Darrick Wong March 13, 2015, 8:36 p.m. UTC | #3
On Fri, Mar 13, 2015 at 01:52:33PM +0300, Konstantin Khlebnikov wrote:
> On 12.03.2015 22:26, Darrick J. Wong wrote:
> >On Thu, Mar 12, 2015 at 07:20:13PM +0300, Konstantin Khlebnikov wrote:
> >>Resize2fs relocates last inodes when it shinks filesystem.
> >>This patch reuses this code for relocating first inodes,
> >>it adds option '-I' for changing first normal inode.
> >>
> >>Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
> >>---
> >>  resize/main.c         |   38 ++++++++++++++++++++++++++++++++----
> >>  resize/resize2fs.8.in |    8 ++++++++
> >>  resize/resize2fs.c    |   52 +++++++++++++++++++++++++++++++++++++++++++++++--
> >>  resize/resize2fs.h    |    3 +++
> >>  4 files changed, 95 insertions(+), 6 deletions(-)
> >>
> >>diff --git a/resize/main.c b/resize/main.c
> >>index 16f48d438cb0..eae7146f41ab 100644
> >>--- a/resize/main.c
> >>+++ b/resize/main.c
> 
> -cut
> 
> >>@@ -507,6 +513,28 @@ int main (int argc, char ** argv)
> >>  				"feature.\n"));
> >>  			exit(1);
> >>  		}
> >>+	} else if (flags & RESIZE_SPECIAL_INODES) {
> >>+		if (rfs->first_ino > fs->super->s_inodes_count) {
> >
> >An FS with rfs->first_ino == fs->super->s_inodes_count isn't going to be
> >very useful... presumably you'd want at least one regular inode, right?
> 
> In this case there will be exactly one regular inode:
> s_inodes_count is index of last inode on the filesystem.

Yes.  Consider, however, that /lost+found is a regular inode, which means that
you'd have to remove it before you can store a single file on the FS, and fsck
will be unhappy if there's no /lost+found.

Actually come to think of it, this is resize2fs; the increase in first_ino must
be less than the free inode count or you'll later run out of inodes while
moving things around.

> 
> >
> >>+			fprintf(stderr, _("First inode too big\n"));
> >
> >"Cannot reserve more than ($s_inodes_count - 1) inodes"?
> 
> So, you're suggest to rephrase option as "reserve special inodes"
> instead of "set first normal inode"?

I was referring to the words 'inode too big', which could be confused for a
message about the size of the inode itself being too large, instead of the
first non-reserved inode *number* being too large.

Come to think of it, our naming isn't especially consistent -- s_first_ino =>
'first non-reserved inode' => 'special inodes'.  Ho hum.  Ted, do you care
about nomenclature?

--D

> 
> >
> >>+			exit(1);
> >>+		}
> >>+		if (rfs->first_ino < EXT2_FIRST_INO(fs->super)) {
> >>+			fprintf(stderr, _("The filesystem has %d special inodes."
> >>+					  "Reducing isn't supported.\n\n"),
> >>+					EXT2_FIRST_INO(fs->super));
> >>+			exit(1);
> >>+		}
> >>+		if (rfs->first_ino == EXT2_FIRST_INO(fs->super)) {
> >>+			fprintf(stderr, _("The filesystem already has %d "
> >>+					  "special inodes. Nothing to do!\n\n"),
> >>+					EXT2_FIRST_INO(fs->super));
> >>+			exit(0);
> >>+		}
> >>+		if (mount_flags & EXT2_MF_MOUNTED) {
> >>+			fprintf(stderr, _("Cannot change count of special "
> >>+				"inodes while the filesystem is mounted.\n"));
> >>+			exit(1);
> >>+		}
> >>  	} else if (new_size == ext2fs_blocks_count(fs->super)) {
> >>  		fprintf(stderr, _("The filesystem is already %llu (%dk) "
> >>  			"blocks long.  Nothing to do!\n\n"), new_size,
> >>@@ -532,6 +560,8 @@ int main (int argc, char ** argv)
> >>  			printf(_("Converting the filesystem to 64-bit.\n"));
> >>  		else if (flags & RESIZE_DISABLE_64BIT)
> >>  			printf(_("Converting the filesystem to 32-bit.\n"));
> >>+		else if (flags & RESIZE_SPECIAL_INODES)
> >>+			printf(_("Reserving special inodes.\n"));
> >>  		else
> >>  			printf(_("Resizing the filesystem on "
> >>  				 "%s to %llu (%dk) blocks.\n"),
> >>diff --git a/resize/resize2fs.8.in b/resize/resize2fs.8.in
> >>index 0129bfcafa3b..f22563fe07e1 100644
> >>--- a/resize/resize2fs.8.in
> >>+++ b/resize/resize2fs.8.in
> >>@@ -18,6 +18,10 @@ resize2fs \- ext2/ext3/ext4 file system resizer
> >>  .B \-S
> >>  .I RAID-stride
> >>  ]
> >>+[
> >>+.B \-I
> >>+.I first-inode
> >>+]
> >>  .I device
> >>  [
> >>  .I size
> >>@@ -101,6 +105,10 @@ to resize the filesystem concurrent with changing the 64bit status.
> >>  Turns on the 64bit feature, resizes the group descriptors as necessary, and
> >>  moves other metadata out of the way.
> >>  .TP
> >>+.B \-I \fI <first-inode>
> >>+This changes first normal inode and relocates inuse inodes into vacant slots.
> >>+Inodes below that are reserved for internal use. Reducing isn't supported.
> >
> >"Increases the number of reserved inodes, moving any in-use inodes into vacant
> >slots."?
> >
> >--D
> >
> >>+.TP
> >>  .B \-d \fIdebug-flags
> >>  Turns on various resize2fs debugging features, if they have been compiled
> >>  into the binary.
> >>diff --git a/resize/resize2fs.c b/resize/resize2fs.c
> >>index dead364bf4bf..2fb653b76dd8 100644
> >>--- a/resize/resize2fs.c
> >>+++ b/resize/resize2fs.c
> >>@@ -48,6 +48,7 @@ static errcode_t block_mover(ext2_resize_t rfs);
> >>  static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
> >>  static errcode_t inode_ref_fix(ext2_resize_t rfs);
> >>  static errcode_t move_itables(ext2_resize_t rfs);
> >>+static errcode_t zero_new_special_inodes(ext2_resize_t rfs);
> >>  static errcode_t fix_resize_inode(ext2_filsys fs);
> >>  static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
> >>  static errcode_t fix_sb_journal_backup(ext2_filsys fs);
> >>@@ -112,6 +113,11 @@ errcode_t resize_fs(ext2_filsys fs, ext2_resize_t rfs)
> >>  	if (retval)
> >>  		goto errout;
> >>
> >>+	if (flags & RESIZE_SPECIAL_INODES) {
> >>+		ext2fs_update_dynamic_rev(rfs->new_fs);
> >>+		EXT2_SB(rfs->new_fs->super)->s_first_ino = rfs->first_ino;
> >>+	}
> >>+
> >>  	init_resource_track(&rtrack, "resize_group_descriptors", fs->io);
> >>  	retval = resize_group_descriptors(rfs);
> >>  	if (retval)
> >>@@ -177,6 +183,12 @@ errcode_t resize_fs(ext2_filsys fs, ext2_resize_t rfs)
> >>  		goto errout;
> >>  	print_resource_track(rfs, &rtrack, fs->io);
> >>
> >>+	init_resource_track(&rtrack, "zero_new_special_inodes", fs->io);
> >>+	retval = zero_new_special_inodes(rfs);
> >>+	if (retval)
> >>+		goto errout;
> >>+	print_resource_track(rfs, &rtrack, fs->io);
> >>+
> >>  	init_resource_track(&rtrack, "move_itables", fs->io);
> >>  	retval = move_itables(rfs);
> >>  	if (retval)
> >>@@ -1963,7 +1975,8 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
> >>
> >>  	if ((rfs->old_fs->group_desc_count <=
> >>  	     rfs->new_fs->group_desc_count) &&
> >>-	    !rfs->bmap)
> >>+	    !rfs->bmap &&
> >>+	    !(rfs->flags & RESIZE_SPECIAL_INODES))
> >>  		return 0;
> >>
> >>  	set_com_err_hook(quiet_com_err_proc);
> >>@@ -2018,7 +2031,11 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
> >>  			goto errout;
> >>
> >>  		new_inode = ino;
> >>-		if (ino <= start_to_move)
> >>+		if (ino >= EXT2_FIRST_INO(rfs->old_fs->super) &&
> >>+		    ino <  EXT2_FIRST_INO(rfs->new_fs->super)) {
> >>+			ext2fs_inode_alloc_stats2(rfs->new_fs, ino, -1,
> >>+						  pb.is_dir);
> >>+		} else if (ino <= start_to_move)
> >>  			goto remap_blocks; /* Don't need to move inode. */
> >>
> >>  		/*
> >>@@ -2552,6 +2569,37 @@ static errcode_t reserve_sparse_super2_last_group(ext2_resize_t rfs,
> >>  }
> >>
> >>  /*
> >>+ * Clear new special inodes
> >>+ */
> >>+static errcode_t zero_new_special_inodes(ext2_resize_t rfs)
> >>+{
> >>+	ext2_filsys		fs = rfs->new_fs;
> >>+	int			inode_size;
> >>+	struct ext2_inode	*inode;
> >>+	errcode_t		retval;
> >>+	ext2_ino_t		ino;
> >>+
> >>+	if (!(rfs->flags & RESIZE_SPECIAL_INODES))
> >>+		return 0;
> >>+
> >>+	inode_size = EXT2_INODE_SIZE(fs->super);
> >>+	retval = ext2fs_get_memzero(inode_size, &inode);
> >>+	if (retval)
> >>+		return retval;
> >>+
> >>+	for (ino = EXT2_FIRST_INO(rfs->old_fs->super);
> >>+	     ino < EXT2_FIRST_INO(fs->super); ino++) {
> >>+		/* All special inodes are marked as inuse */
> >>+		ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
> >>+		retval = ext2fs_write_inode_full(fs, ino, inode, inode_size);
> >>+		if (retval)
> >>+			break;
> >>+	}
> >>+	ext2fs_free_mem(&inode);
> >>+	return retval;
> >>+}
> >>+
> >>+/*
> >>   * Fix the resize inode
> >>   */
> >>  static errcode_t fix_resize_inode(ext2_filsys fs)
> >>diff --git a/resize/resize2fs.h b/resize/resize2fs.h
> >>index c5377e2b06c3..84f83b09f237 100644
> >>--- a/resize/resize2fs.h
> >>+++ b/resize/resize2fs.h
> >>@@ -85,6 +85,8 @@ typedef struct ext2_sim_progress *ext2_sim_progmeter;
> >>  #define RESIZE_ENABLE_64BIT		0x0400
> >>  #define RESIZE_DISABLE_64BIT		0x0800
> >>
> >>+#define RESIZE_SPECIAL_INODES		0x1000
> >>+
> >>  /*
> >>   * This structure is used for keeping track of how much resources have
> >>   * been used for a particular resize2fs pass.
> >>@@ -130,6 +132,7 @@ struct ext2_resize_struct {
> >>  	void		*prog_data;
> >>
> >>  	blk64_t		new_size;
> >>+	ext2_ino_t	first_ino;
> >>  };
> >>
> >>  /*
> >>
> >>--
> >>To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> >>the body of a message to majordomo@vger.kernel.org
> >>More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
> -- 
> Konstantin
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/resize/main.c b/resize/main.c
index 16f48d438cb0..eae7146f41ab 100644
--- a/resize/main.c
+++ b/resize/main.c
@@ -41,8 +41,9 @@  static char *device_name, *io_options;
 
 static void usage (char *prog)
 {
-	fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] "
-			   "[-p] device [-b|-s|new_size]\n\n"), prog);
+	fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P]"
+			   "[-p] [-I first_inode] device [-b|-s|new_size]\n\n"),
+			prog);
 
 	exit (1);
 }
@@ -213,7 +214,7 @@  int main (int argc, char ** argv)
 		exit(1);
 	}
 
-	while ((c = getopt(argc, argv, "d:fFhMPpS:bs")) != EOF) {
+	while ((c = getopt(argc, argv, "d:fFhMPpS:bsI:")) != EOF) {
 		switch (c) {
 		case 'h':
 			usage(program_name);
@@ -245,6 +246,10 @@  int main (int argc, char ** argv)
 		case 's':
 			flags |= RESIZE_DISABLE_64BIT;
 			break;
+		case 'I':
+			flags |= RESIZE_SPECIAL_INODES;
+			rfs->first_ino = atoi(optarg);
+			break;
 		default:
 			usage(program_name);
 		}
@@ -430,7 +435,8 @@  int main (int argc, char ** argv)
 			new_size &= ~((sys_page_size / blocksize)-1);
 	}
 	/* If changing 64bit, don't change the filesystem size. */
-	if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) {
+	if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT |
+		     RESIZE_SPECIAL_INODES)) {
 		new_size = ext2fs_blocks_count(fs->super);
 	}
 	if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
@@ -507,6 +513,28 @@  int main (int argc, char ** argv)
 				"feature.\n"));
 			exit(1);
 		}
+	} else if (flags & RESIZE_SPECIAL_INODES) {
+		if (rfs->first_ino > fs->super->s_inodes_count) {
+			fprintf(stderr, _("First inode too big\n"));
+			exit(1);
+		}
+		if (rfs->first_ino < EXT2_FIRST_INO(fs->super)) {
+			fprintf(stderr, _("The filesystem has %d special inodes."
+					  "Reducing isn't supported.\n\n"),
+					EXT2_FIRST_INO(fs->super));
+			exit(1);
+		}
+		if (rfs->first_ino == EXT2_FIRST_INO(fs->super)) {
+			fprintf(stderr, _("The filesystem already has %d "
+					  "special inodes. Nothing to do!\n\n"),
+					EXT2_FIRST_INO(fs->super));
+			exit(0);
+		}
+		if (mount_flags & EXT2_MF_MOUNTED) {
+			fprintf(stderr, _("Cannot change count of special "
+				"inodes while the filesystem is mounted.\n"));
+			exit(1);
+		}
 	} else if (new_size == ext2fs_blocks_count(fs->super)) {
 		fprintf(stderr, _("The filesystem is already %llu (%dk) "
 			"blocks long.  Nothing to do!\n\n"), new_size,
@@ -532,6 +560,8 @@  int main (int argc, char ** argv)
 			printf(_("Converting the filesystem to 64-bit.\n"));
 		else if (flags & RESIZE_DISABLE_64BIT)
 			printf(_("Converting the filesystem to 32-bit.\n"));
+		else if (flags & RESIZE_SPECIAL_INODES)
+			printf(_("Reserving special inodes.\n"));
 		else
 			printf(_("Resizing the filesystem on "
 				 "%s to %llu (%dk) blocks.\n"),
diff --git a/resize/resize2fs.8.in b/resize/resize2fs.8.in
index 0129bfcafa3b..f22563fe07e1 100644
--- a/resize/resize2fs.8.in
+++ b/resize/resize2fs.8.in
@@ -18,6 +18,10 @@  resize2fs \- ext2/ext3/ext4 file system resizer
 .B \-S
 .I RAID-stride
 ]
+[
+.B \-I
+.I first-inode
+]
 .I device
 [
 .I size
@@ -101,6 +105,10 @@  to resize the filesystem concurrent with changing the 64bit status.
 Turns on the 64bit feature, resizes the group descriptors as necessary, and
 moves other metadata out of the way.
 .TP
+.B \-I \fI <first-inode>
+This changes first normal inode and relocates inuse inodes into vacant slots.
+Inodes below that are reserved for internal use. Reducing isn't supported.
+.TP
 .B \-d \fIdebug-flags
 Turns on various resize2fs debugging features, if they have been compiled
 into the binary.
diff --git a/resize/resize2fs.c b/resize/resize2fs.c
index dead364bf4bf..2fb653b76dd8 100644
--- a/resize/resize2fs.c
+++ b/resize/resize2fs.c
@@ -48,6 +48,7 @@  static errcode_t block_mover(ext2_resize_t rfs);
 static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
 static errcode_t inode_ref_fix(ext2_resize_t rfs);
 static errcode_t move_itables(ext2_resize_t rfs);
+static errcode_t zero_new_special_inodes(ext2_resize_t rfs);
 static errcode_t fix_resize_inode(ext2_filsys fs);
 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
 static errcode_t fix_sb_journal_backup(ext2_filsys fs);
@@ -112,6 +113,11 @@  errcode_t resize_fs(ext2_filsys fs, ext2_resize_t rfs)
 	if (retval)
 		goto errout;
 
+	if (flags & RESIZE_SPECIAL_INODES) {
+		ext2fs_update_dynamic_rev(rfs->new_fs);
+		EXT2_SB(rfs->new_fs->super)->s_first_ino = rfs->first_ino;
+	}
+
 	init_resource_track(&rtrack, "resize_group_descriptors", fs->io);
 	retval = resize_group_descriptors(rfs);
 	if (retval)
@@ -177,6 +183,12 @@  errcode_t resize_fs(ext2_filsys fs, ext2_resize_t rfs)
 		goto errout;
 	print_resource_track(rfs, &rtrack, fs->io);
 
+	init_resource_track(&rtrack, "zero_new_special_inodes", fs->io);
+	retval = zero_new_special_inodes(rfs);
+	if (retval)
+		goto errout;
+	print_resource_track(rfs, &rtrack, fs->io);
+
 	init_resource_track(&rtrack, "move_itables", fs->io);
 	retval = move_itables(rfs);
 	if (retval)
@@ -1963,7 +1975,8 @@  static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
 
 	if ((rfs->old_fs->group_desc_count <=
 	     rfs->new_fs->group_desc_count) &&
-	    !rfs->bmap)
+	    !rfs->bmap &&
+	    !(rfs->flags & RESIZE_SPECIAL_INODES))
 		return 0;
 
 	set_com_err_hook(quiet_com_err_proc);
@@ -2018,7 +2031,11 @@  static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
 			goto errout;
 
 		new_inode = ino;
-		if (ino <= start_to_move)
+		if (ino >= EXT2_FIRST_INO(rfs->old_fs->super) &&
+		    ino <  EXT2_FIRST_INO(rfs->new_fs->super)) {
+			ext2fs_inode_alloc_stats2(rfs->new_fs, ino, -1,
+						  pb.is_dir);
+		} else if (ino <= start_to_move)
 			goto remap_blocks; /* Don't need to move inode. */
 
 		/*
@@ -2552,6 +2569,37 @@  static errcode_t reserve_sparse_super2_last_group(ext2_resize_t rfs,
 }
 
 /*
+ * Clear new special inodes
+ */
+static errcode_t zero_new_special_inodes(ext2_resize_t rfs)
+{
+	ext2_filsys		fs = rfs->new_fs;
+	int			inode_size;
+	struct ext2_inode	*inode;
+	errcode_t		retval;
+	ext2_ino_t		ino;
+
+	if (!(rfs->flags & RESIZE_SPECIAL_INODES))
+		return 0;
+
+	inode_size = EXT2_INODE_SIZE(fs->super);
+	retval = ext2fs_get_memzero(inode_size, &inode);
+	if (retval)
+		return retval;
+
+	for (ino = EXT2_FIRST_INO(rfs->old_fs->super);
+	     ino < EXT2_FIRST_INO(fs->super); ino++) {
+		/* All special inodes are marked as inuse */
+		ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
+		retval = ext2fs_write_inode_full(fs, ino, inode, inode_size);
+		if (retval)
+			break;
+	}
+	ext2fs_free_mem(&inode);
+	return retval;
+}
+
+/*
  * Fix the resize inode
  */
 static errcode_t fix_resize_inode(ext2_filsys fs)
diff --git a/resize/resize2fs.h b/resize/resize2fs.h
index c5377e2b06c3..84f83b09f237 100644
--- a/resize/resize2fs.h
+++ b/resize/resize2fs.h
@@ -85,6 +85,8 @@  typedef struct ext2_sim_progress *ext2_sim_progmeter;
 #define RESIZE_ENABLE_64BIT		0x0400
 #define RESIZE_DISABLE_64BIT		0x0800
 
+#define RESIZE_SPECIAL_INODES		0x1000
+
 /*
  * This structure is used for keeping track of how much resources have
  * been used for a particular resize2fs pass.
@@ -130,6 +132,7 @@  struct ext2_resize_struct {
 	void		*prog_data;
 
 	blk64_t		new_size;
+	ext2_ino_t	first_ino;
 };
 
 /*