e2fsprogs: report minimal resize size when given size is too small
PATCH 1/1 e2fsprogs: report minimal resize size when given size is too small
Hello,
Munged the subject on the last resend and didn't add the Signed-off-by, so here's the 3rd try. This patch will spit out the minimum number of blocks the fs can be resized if the resize size it is given is too small. This is usefull for those creating live boot images who create large images to install what they need onto, and then resize down to the smalles size that they can. Thanks much,
resize/main.c +0 -5
@@ -342,11 +342,6 @@ int main (int argc, char ** argv)if (new_size_str) { new_size =parse_num_blocks (new_size_str, fs->super->s_log_block_size); -if (!new_size) { -com_err (program_name,0 ,_ ("bad filesystem size - %s" ), - new_size_str); -exit (1 ); - } }else { new_size = max_size;/* Round down to an even multiple of a pagesize */
resize/resize2fs.c +148 -1
175 lines not on this page · raw message
Quoted 10 lines · Josef Bacik
Hello,
Munged the subject on the last resend and didn't add the Signed-off-by, so here's the 3rd try. This patch will spit out the minimum number of blocks the fs can be resized if the resize size it is given is too small. This is usefull for those creating live boot images who create large images to install what they need onto, and then resize down to the smalles size that they can. Thanks much,
Signed-off-by Josef Back <[email protected]>
Hmm.... so I tried creating a filesystem using a 1k blocksize, to make sure that your code does the right thing when the number of block group descriptors goes down. And it doesn't work correctly.
So first, I create a logical volume for doing testing, with a 1024 blocksize, and populate it with e2fsprogs sources. The we run e2fsck so that reszie2fs will be able to run with it:
# lvcreate --size 1G --name testresize /dev/closure Logical volume "testresize" created # mke2fs -b 1024 -jq /dev/closure/testresize Warning: 256-byte inodes not usable on older systems # mount /dev/closure/testresize /mnt # tar -C /mnt -xzf /usr/projects/e2fsprogs/e2fsprogs-1.40.8.tar.gz # umount /mnt # e2fsck -fp /dev/closure/testresize e2fsck 1.40.8 (13-Mar-2008) /dev/closure/testresize: 1177/65536 files (0.9% non-contiguous), 72811/1048576 blocks
OK, let's create s snapshot, and then try resizing it using your patched resize2fs:
# lvcreate --snapshot --size 1G --name resizesnap /dev/closure/testresize Logical volume "resizesnap" created # ./resize/resize2fs /dev/closure/resizesnap 0 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 0 (1k) blocks. 0 blocks is too small, minimum size is 55254 blocks ./resize/resize2fs: Not enough space to build proposed filesystem while trying to resize /dev/closure/resizesnap # ./resize/resize2fs /dev/closure/resizesnap 55254 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55254 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55254 blocks long.
OK, so we resized it down to 55,254. Are we done?
# ./resize/resize2fs /dev/closure/resizesnap 0 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 0 (1k) blocks. 0 blocks is too small, minimum size is 55242 blocks # ./resize/resize2fs /dev/closure/resizesnap 55242 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55242 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55242 blocks long. # lvremove -f /dev/closure/resizesnap Logical volume "resizesnap" successfully removed
No wait! It turns out we can resize it down further, to 55,242 blocks.
Now let's try to resize it down to 55,242 blocks directly using an unpatched resize2fs:
# lvcreate --snapshot --size 1G --name resizesnap /dev/closure/testresize Logical volume "resizesnap" created # /sbin/resize2fs /dev/closure/resizesnap 55242 resize2fs 1.40.8 (13-Mar-2008) Resizing the filesystem on /dev/closure/resizesnap to 55242 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55242 blocks long. # lvremove -f /dev/closure/resizesnap Logical volume "resizesnap" successfully removed
Gee, look! It works.
Can we do it with your patched resize2fs?
# lvcreate --snapshot --size 1G --name resizesnap /dev/closure/testresize Logical volume "resizesnap" created # ./resize/resize2fs /dev/closure/resizesnap 55242 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55242 (1k) blocks. 55242 blocks is too small, minimum size is 55254 blocks ./resize/resize2fs: Not enough space to build proposed filesystem while trying to resize /dev/closure/resizesnap
Nope. It won't let you resize down to 55,254 blocks in one go, although you can do it in two steps. This is a regression, since with the unpatched resize2fs, it works with one step. The problem is that your code assumes that ext2fs_calculate_minimum_resize_size() reliably returns the minimum size, and if the user specifies a size smaller than returned size, it should bomb out with an error. Unfortunately, it *isn't* the minimum possible size.
# ./resize/resize2fs /dev/closure/resizesnap 55254 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55254 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55254 blocks long. # ./resize/resize2fs /dev/closure/resizesnap 55242 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55242 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55242 blocks long. # lvremove -f /dev/closure/resizesnap Logical volume "resizesnap" successfully removed
What bothers me with your patch, though is that even though it apparently isn't doing the right thing when the filesystem changes the number of group descriptor blocks after doing the resize:
# dumpe2fs /dev/closure/testresize | grep "Group descriptors" | head -5 dumpe2fs 1.40.8 (13-Mar-2008) Primary superblock at 1, Group descriptors at 2-5 Backup superblock at 8193, Group descriptors at 8194-8197 Backup superblock at 24577, Group descriptors at 24578-24581 Backup superblock at 40961, Group descriptors at 40962-40965 Backup superblock at 57345, Group descriptors at 57346-57349
# dumpe2fs /dev/closure/resizesnap | grep "Group descriptors" | head -5 dumpe2fs 1.40.8 (13-Mar-2008) Primary superblock at 1, Group descriptors at 2-2 Backup superblock at 8193, Group descriptors at 8194-8194 Backup superblock at 24577, Group descriptors at 24578-24578 Backup superblock at 40961, Group descriptors at 40962-40962
.... yet when I tried doing the test with 4k blocksizes, where I started with a filesystem which is 17 gigabytes (with a 4k blocksize, every 16gigs there are 128 block groups, which will occupy a single 4k block's worth of block group descriptors), and then shrunk it down, expecting it to break --- and it didn't. The fact it should have broken, since the number of group descriptors did go down, and it the code didn't take that into account --- and yet it didn't, disturbed me. Not knowing why it works when an inspection seems to indicate that it should fails always scares me.
So I can't apply this the way it is. What I *can* do is set it up so that it will only call the calculate minimum size if the specified size is 0 blocks. I'll mention in the known bugs that it can sometimes be wrong with its estimates with 1k and 2k block filesystems.
- Ted
PATCH 1/1 resize2fs: Add options to print (and resizing to) the minimum filesystem size
From: Josef Bacik <[email protected]>
Add the -P option to print the minimum filesystem size and exit.
Add the -M option to force resizing the filesystem to the minimum filesystem size.
--- resize/main.c | 29 +++++++--- resize/resize2fs.8.in | 47 +++++++++-------- resize/resize2fs.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++- resize/resize2fs.h | 1 + 4 files changed, 185 insertions(+), 32 deletions(-)
resize/main.c +20 -9
@@ -36,8 +36,8 @@ char *program_name, *device_name, *io_options;static void usage (char *prog) { -fprintf (stderr,_ ("Usage: %s [-d debug_flags] [-f] [-F] [-p] " -"device [new_size]\n\n" ), prog); +fprintf (stderr,_ ("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] " +"[-p] device [new_size]\n\n" ), prog);exit (1 ); }
@@ -152,6 +152,8 @@ int main (int argc, char ** argv)int flush =0 ;int force =0 ;int io_flags =0 ; +int force_min_size =0 ; +int print_min_size =0 ;int fd, ret;blk_t new_size =0 ;blk_t max_size =0 ;
@@ -183,7 +185,7 @@ int main (int argc, char ** argv)if (argc && *argv) program_name = *argv; -while ((c =getopt (argc, argv,"d:fFhpS:" )) !=EOF ) { +while ((c =getopt (argc, argv,"d:fFhMPpS:" )) !=EOF ) {switch (c) {case 'h' :usage (program_name);
@@ -194,6 +196,12 @@ int main (int argc, char ** argv)case 'F' : flush =1 ;break ; +case 'M' : + force_min_size =1 ; +break ; +case 'P' : + print_min_size =1 ; +break ;case 'd' : flags |=atoi (optarg);break ;
@@ -308,6 +316,12 @@ int main (int argc, char ** argv)exit (1 ); } +if (print_min_size) { +printf ("Estimated minimum size of the filesystem: %lu\n" , +calculate_minimum_resize_size (fs)); +exit (0 ); + } +/* Determine the system page size if possible */ #ifdef HAVE_SYSCONF #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
@@ -332,14 +346,11 @@ int main (int argc, char ** argv) _("while trying to determine filesystem size"));exit (1 ); } -if (new_size_str) { +if (force_min_size) + new_size =calculate_minimum_resize_size (fs); +else if (new_size_str) { new_size =parse_num_blocks (new_size_str, fs->super->s_log_block_size); -if (!new_size) { -com_err (program_name,0 ,_ ("bad filesystem size - %s" ), - new_size_str); -exit (1 ); - } }else { new_size = max_size;/* Round down to an even multiple of a pagesize */
resize/resize2fs.8.in +25 -22
71 lines not on this page · raw message
resize/resize2fs.c +139 -1
149 lines not on this page · raw message
resize/resize2fs.h +1 -0
@@ -129,6 +129,7 @@ extern errcode_t resize_fs(ext2_filsys fs, blk_t *new_size, int flags,extern errcode_t adjust_fs_info (ext2_filsys fs,ext2_filsys old_fs,blk_t new_size); +extern blk_t calculate_minimum_resize_size (ext2_filsys fs);/* extent.c */
Signature · 1 line
1.5.4.1.144.gdfee-dirty
Quoted 135 lines · Theodore Tso
Quoted 10 lines · Josef Bacik
Hello,
Munged the subject on the last resend and didn't add the Signed-off-by, so here's the 3rd try. This patch will spit out the minimum number of blocks the fs can be resized if the resize size it is given is too small. This is usefull for those creating live boot images who create large images to install what they need onto, and then resize down to the smalles size that they can. Thanks much,
Signed-off-by Josef Back <[email protected]>Hmm.... so I tried creating a filesystem using a 1k blocksize, to make sure that your code does the right thing when the number of block group descriptors goes down. And it doesn't work correctly.
So first, I create a logical volume for doing testing, with a 1024 blocksize, and populate it with e2fsprogs sources. The we run e2fsck so that reszie2fs will be able to run with it:
# lvcreate --size 1G --name testresize /dev/closure Logical volume "testresize" created # mke2fs -b 1024 -jq /dev/closure/testresize Warning: 256-byte inodes not usable on older systems # mount /dev/closure/testresize /mnt # tar -C /mnt -xzf /usr/projects/e2fsprogs/e2fsprogs-1.40.8.tar.gz # umount /mnt # e2fsck -fp /dev/closure/testresize e2fsck 1.40.8 (13-Mar-2008) /dev/closure/testresize: 1177/65536 files (0.9% non-contiguous), 72811/1048576 blocksOK, let's create s snapshot, and then try resizing it using your patched resize2fs:
# lvcreate --snapshot --size 1G --name resizesnap /dev/closure/testresize Logical volume "resizesnap" created # ./resize/resize2fs /dev/closure/resizesnap 0 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 0 (1k) blocks. 0 blocks is too small, minimum size is 55254 blocks ./resize/resize2fs: Not enough space to build proposed filesystem while trying to resize /dev/closure/resizesnap # ./resize/resize2fs /dev/closure/resizesnap 55254 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55254 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55254 blocks long.OK, so we resized it down to 55,254. Are we done?
# ./resize/resize2fs /dev/closure/resizesnap 0 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 0 (1k) blocks. 0 blocks is too small, minimum size is 55242 blocks # ./resize/resize2fs /dev/closure/resizesnap 55242 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55242 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55242 blocks long. # lvremove -f /dev/closure/resizesnap Logical volume "resizesnap" successfully removedNo wait! It turns out we can resize it down further, to 55,242 blocks.
Now let's try to resize it down to 55,242 blocks directly using an unpatched resize2fs:
# lvcreate --snapshot --size 1G --name resizesnap /dev/closure/testresize Logical volume "resizesnap" created # /sbin/resize2fs /dev/closure/resizesnap 55242 resize2fs 1.40.8 (13-Mar-2008) Resizing the filesystem on /dev/closure/resizesnap to 55242 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55242 blocks long. # lvremove -f /dev/closure/resizesnap Logical volume "resizesnap" successfully removedGee, look! It works.
Can we do it with your patched resize2fs?
# lvcreate --snapshot --size 1G --name resizesnap /dev/closure/testresize Logical volume "resizesnap" created # ./resize/resize2fs /dev/closure/resizesnap 55242 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55242 (1k) blocks. 55242 blocks is too small, minimum size is 55254 blocks ./resize/resize2fs: Not enough space to build proposed filesystem while trying to resize /dev/closure/resizesnapNope. It won't let you resize down to 55,254 blocks in one go, although you can do it in two steps. This is a regression, since with the unpatched resize2fs, it works with one step. The problem is that your code assumes that
ext2fs_calculate_minimum_resize_size()reliably returns the minimum size, and if the user specifies a size smaller than returned size, it should bomb out with an error. Unfortunately, it *isn't* the minimum possible size.# ./resize/resize2fs /dev/closure/resizesnap 55254 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55254 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55254 blocks long. # ./resize/resize2fs /dev/closure/resizesnap 55242 resize2fs 1.40.7 (28-Feb-2008) Resizing the filesystem on /dev/closure/resizesnap to 55242 (1k) blocks. The filesystem on /dev/closure/resizesnap is now 55242 blocks long. # lvremove -f /dev/closure/resizesnap Logical volume "resizesnap" successfully removedWhat bothers me with your patch, though is that even though it apparently isn't doing the right thing when the filesystem changes the number of group descriptor blocks after doing the resize:
# dumpe2fs /dev/closure/testresize | grep "Group descriptors" | head -5 dumpe2fs 1.40.8 (13-Mar-2008) Primary superblock at 1, Group descriptors at 2-5 Backup superblock at 8193, Group descriptors at 8194-8197 Backup superblock at 24577, Group descriptors at 24578-24581 Backup superblock at 40961, Group descriptors at 40962-40965 Backup superblock at 57345, Group descriptors at 57346-57349# dumpe2fs /dev/closure/resizesnap | grep "Group descriptors" | head -5 dumpe2fs 1.40.8 (13-Mar-2008) Primary superblock at 1, Group descriptors at 2-2 Backup superblock at 8193, Group descriptors at 8194-8194 Backup superblock at 24577, Group descriptors at 24578-24578 Backup superblock at 40961, Group descriptors at 40962-40962.... yet when I tried doing the test with 4k blocksizes, where I started with a filesystem which is 17 gigabytes (with a 4k blocksize, every 16gigs there are 128 block groups, which will occupy a single 4k block's worth of block group descriptors), and then shrunk it down, expecting it to break --- and it didn't. The fact it should have broken, since the number of group descriptors did go down, and it the code didn't take that into account --- and yet it didn't, disturbed me. Not knowing why it works when an inspection seems to indicate that it should fails always scares me.
Quoted 6 lines
So I can't apply this the way it is. What I *can* do is set it up so that it will only call the calculate minimum size if the specified size is 0 blocks. I'll mention in the known bugs that it can sometimes be wrong with its estimates with 1k and 2k block filesystems.
So this is all very strange. I fixed my patch to let resize2fs do what it always does whether or not my calculation thinks it will work so I could test it. With 1k and 2k blocks you are right, when reducing the number of group descriptors i can always go lower. However with 4k blocks (which is what I always tested with) it works completely fine. For example, a completely cleanly mkfs.ext3'd 15gb lv I get this
[root@unused resize]# ./resize2fs -P /dev/testvg/testext3 resize2fs 1.40.8 (13-Mar-2008)
Estimated minimum size of the filesystem: 35758
I try to resize to something smaller
[root@unused resize]# ./resize2fs /dev/testvg/testext3 35757 resize2fs 1.40.8 (13-Mar-2008)
Resizing the filesystem on /dev/testvg/testext3 to 35757 (4k) blocks. ./resize2fs: No space left on device while trying to resize /dev/testvg/testext3
No dice, it won't work, but using my calcluation it works fine
[root@unused resize]# ./resize2fs /dev/testvg/testext3 35758 resize2fs 1.40.8 (13-Mar-2008)
Resizing the filesystem on /dev/testvg/testext3 to 35758 (4k) blocks. The filesystem on /dev/testvg/testext3 is now 35758 blocks long.
I'll try to figure out whats wrong in the 1k/2k block case, but for 4k it seems to work fine. Thanks,
Josef