resize2fs.c revision 236efede1922fa173b3c2f20d9e0886856664ab4
124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * resize2fs.c --- ext2 main routine
324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o *
40cee8a5c423c2a1054c7366e74870592ec8db95eTheodore Ts'o * Copyright (C) 1997, 1998 by Theodore Ts'o and
50cee8a5c423c2a1054c7366e74870592ec8db95eTheodore Ts'o * 	PowerQuest, Inc.
60cee8a5c423c2a1054c7366e74870592ec8db95eTheodore Ts'o *
70cee8a5c423c2a1054c7366e74870592ec8db95eTheodore Ts'o * Copyright (C) 1999, 2000 by Theosore Ts'o
824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o *
924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * %Begin-Header%
100cee8a5c423c2a1054c7366e74870592ec8db95eTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
110cee8a5c423c2a1054c7366e74870592ec8db95eTheodore Ts'o * License.
1224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * %End-Header%
1324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
1424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
1505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o/*
1605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o * Resizing a filesystem consists of the following phases:
1705e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o *
18a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *	1.  Adjust superblock and write out new parts of the inode
1905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o * 		table
20a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 	2.  Determine blocks which need to be relocated, and copy the
21a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 		contents of blocks from their old locations to the new ones.
22a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 	3.  Scan the inode table, doing the following:
23a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 		a.  If blocks have been moved, update the block
24a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			pointers in the inodes and indirect blocks to
25a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			point at the new block locations.
26a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 		b.  If parts of the inode table need to be evacuated,
27a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			copy inodes from their old locations to their
28a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			new ones.
29a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 		c.  If (b) needs to be done, note which blocks contain
30a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			directory information, since we will need to
31a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			update the directory information.
32a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 	4.  Update the directory blocks with the new inode locations.
33a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 	5.  Move the inode tables, if necessary.
3405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o */
35a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
3624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o#include "resize2fs.h"
37b969b1b8a5c13992cadb026114731958644540d8Matthias Andree#include <time.h>
3824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
39546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'o#ifdef __linux__			/* Kludge for debugging */
40a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define RESIZE2FS_DEBUG
41a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
42a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
43a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size);
44a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t blocks_to_move(ext2_resize_t rfs);
45a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t block_mover(ext2_resize_t rfs);
46a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_scan_and_fix(ext2_resize_t rfs);
47a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_ref_fix(ext2_resize_t rfs);
48a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t move_itables(ext2_resize_t rfs);
499213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'ostatic errcode_t fix_resize_inode(ext2_filsys fs);
50a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
51a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
52a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
53a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Some helper CPP macros
54a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
55a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define FS_BLOCK_BM(fs, i) ((fs)->group_desc[(i)].bg_block_bitmap)
56a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define FS_INODE_BM(fs, i) ((fs)->group_desc[(i)].bg_inode_bitmap)
57a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define FS_INODE_TB(fs, i) ((fs)->group_desc[(i)].bg_inode_table)
58a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
59a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define IS_BLOCK_BM(fs, i, blk) ((blk) == FS_BLOCK_BM((fs),(i)))
60a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define IS_INODE_BM(fs, i, blk) ((blk) == FS_INODE_BM((fs),(i)))
61a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
62a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define IS_INODE_TB(fs, i, blk) (((blk) >= FS_INODE_TB((fs), (i))) && \
63a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				 ((blk) < (FS_INODE_TB((fs), (i)) + \
64a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   (fs)->inode_blocks_per_group)))
65a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
66199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik#define META_OVERHEAD(fs) (2 + (fs)->inode_blocks_per_group)
67199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik#define SUPER_OVERHEAD(fs) (1 + (fs)->desc_blocks +\
68199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			    (fs)->super->s_reserved_gdt_blocks)
69a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
70a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
71a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * This is the top-level routine which does the dirty deed....
72a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
73116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'oerrcode_t resize_fs(ext2_filsys fs, blk_t *new_size, int flags,
743b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		    errcode_t (*progress)(ext2_resize_t rfs, int pass,
75a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     unsigned long cur,
761333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o				     unsigned long max_val))
77a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
78a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t	rfs;
79a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
80a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
81a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_read_bitmaps(fs);
82a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
83a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
84a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
85a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
86a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Create the data structure
87a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
88c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct), &rfs);
89a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
90a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
91a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	memset(rfs, 0, sizeof(struct ext2_resize_struct));
92a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
93a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->old_fs = fs;
94a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->flags = flags;
95a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->itable_buf	 = 0;
96a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->progress = progress;
97a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_dup_handle(fs, &rfs->new_fs);
98a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
99a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
100a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
101116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'o	retval = adjust_superblock(rfs, *new_size);
102a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
103a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
104a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
105116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'o	*new_size = rfs->new_fs->super->s_blocks_count;
106116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'o
107a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = blocks_to_move(rfs);
108a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
109a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
110a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
111a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
112a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->flags & RESIZE_DEBUG_BMOVE)
1138deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato		printf("Number of free blocks: %u/%u, Needed: %d\n",
114a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->old_fs->super->s_free_blocks_count,
115a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->new_fs->super->s_free_blocks_count,
116a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->needed_blocks);
117a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
118a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
119a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = block_mover(rfs);
120a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
121a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
122a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
123a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = inode_scan_and_fix(rfs);
124a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
125a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
126a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
127a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = inode_ref_fix(rfs);
128a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
129a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
130a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
131a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = move_itables(rfs);
132a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
133a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
134a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
13564ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	retval = ext2fs_calculate_summary_stats(rfs->new_fs);
13664ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	if (retval)
13764ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		goto errout;
13864ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
1399213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = fix_resize_inode(rfs->new_fs);
1409213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval)
1419213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		goto errout;
1429213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
143058ad1c70c9a097d282270c6f76d3c3493e15fe2Theodore Ts'o	rfs->new_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
144a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_close(rfs->new_fs);
145a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
146a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
147a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
148a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->flags = flags;
149a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
150a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free(rfs->old_fs);
151a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->itable_buf)
152c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&rfs->itable_buf);
153c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&rfs);
154a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
155a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return 0;
156a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
157a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
158a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->new_fs)
159a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free(rfs->new_fs);
160a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->itable_buf)
161c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&rfs->itable_buf);
162c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&rfs);
163a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
164a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
165a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
166a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
167a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
168a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 1.
169a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
170a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we adjust the in-memory superblock information, and
171a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * initialize any new parts of the inode table.  The new parts of the
172a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode table are created in virgin disk space, so we can abort here
173a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * without any side effects.
174a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
175a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
176a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
17724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
178bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o * This routine is shared by the online and offline resize routines.
179bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o * All of the information which is adjusted in memory is done here.
18024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
181bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'oerrcode_t adjust_fs_info(ext2_filsys fs, ext2_filsys old_fs, blk_t new_size)
18224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o{
18324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	errcode_t	retval;
184bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	int		overhead = 0;
185bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	int		rem;
18624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	blk_t		blk, group_block;
187bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2_ino_t	real_end;
188bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	int		adj, old_numblocks, numblocks, adjblocks;
189bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	unsigned long	i, j, old_desc_blocks, max_group;
190544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	meta_bg, meta_bg_size;
191544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	int		has_super;
192de8f3a76218255e443ba57dec5d74850180fa75dAndreas Dilger	unsigned long long new_inodes;	/* u64 to check for overflow */
193bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
19424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->super->s_blocks_count = new_size;
19524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
19624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'oretry:
19769022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o	fs->group_desc_count = ext2fs_div_ceil(fs->super->s_blocks_count -
19869022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o				       fs->super->s_first_data_block,
19969022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o				       EXT2_BLOCKS_PER_GROUP(fs->super));
20024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (fs->group_desc_count == 0)
20124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return EXT2_ET_TOOSMALL;
20269022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o	fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
20369022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o					  EXT2_DESC_PER_BLOCK(fs->super));
20424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
20524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
20624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Overhead is the number of bookkeeping blocks per group.  It
20724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * includes the superblock backup, the group descriptor
20824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * backups, the inode bitmap, the block bitmap, and the inode
20924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * table.
21024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
2119213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	overhead = (int) (2 + fs->inode_blocks_per_group);
2129213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
2139213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
2149213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		overhead += 1 + fs->desc_blocks +
2159213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			fs->super->s_reserved_gdt_blocks;
2169213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
21724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
21824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * See if the last group is big enough to support the
21924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * necessary data structures.  If not, we need to get rid of
22024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * it.
22124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
22224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
22324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_blocks_per_group;
22424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if ((fs->group_desc_count == 1) && rem && (rem < overhead))
22524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return EXT2_ET_TOOSMALL;
22624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (rem && (rem < overhead+50)) {
22724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_blocks_count -= rem;
22824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		goto retry;
22924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
23024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
23124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Adjust the number of inodes
23224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
233de8f3a76218255e443ba57dec5d74850180fa75dAndreas Dilger	new_inodes =(unsigned long long) fs->super->s_inodes_per_group * fs->group_desc_count;
234f335864338a6fbce8134a445ffdd0cdeb3f3f1bcEric Sandeen	if (new_inodes > ~0U) {
235f335864338a6fbce8134a445ffdd0cdeb3f3f1bcEric Sandeen		fprintf(stderr, _("inodes (%llu) must be less than %u"),
236f335864338a6fbce8134a445ffdd0cdeb3f3f1bcEric Sandeen				   new_inodes, ~0U);
237f335864338a6fbce8134a445ffdd0cdeb3f3f1bcEric Sandeen		return EXT2_ET_TOO_MANY_INODES;
238f335864338a6fbce8134a445ffdd0cdeb3f3f1bcEric Sandeen	}
23924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->super->s_inodes_count = fs->super->s_inodes_per_group *
24024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->group_desc_count;
24124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
24224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
24324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Adjust the number of free blocks
24424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
245bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	blk = old_fs->super->s_blocks_count;
24624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (blk > fs->super->s_blocks_count)
24724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_free_blocks_count -=
24824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			(blk - fs->super->s_blocks_count);
24924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	else
25024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_free_blocks_count +=
25124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			(fs->super->s_blocks_count - blk);
25224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
25324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
254c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 * Adjust the number of reserved blocks
255c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 */
256d1b4b85c3a201705c5d3d2916c7a9ca00a04e44cEric Sandeen	blk = (__u64)old_fs->super->s_r_blocks_count * 100 /
257bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		old_fs->super->s_blocks_count;
258a8862d9e90d0d94761ba28dbbf9674308fd7d7c0Theodore Ts'o	fs->super->s_r_blocks_count = e2p_percent(blk,
259a8862d9e90d0d94761ba28dbbf9674308fd7d7c0Theodore Ts'o						  fs->super->s_blocks_count);
260c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
261c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	/*
26224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Adjust the bitmaps for size
26324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
26424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
26524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o					    fs->super->s_inodes_count,
26624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o					    fs->inode_map);
267c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval) goto errout;
26824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
26924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
27024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		     * fs->group_desc_count)) - 1 +
27124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			     fs->super->s_first_data_block;
27224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
27324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o					    real_end, fs->block_map);
27424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
275c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval) goto errout;
27624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
27724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
27824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Reallocate the group descriptors as necessary.
27924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
280bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (old_fs->desc_blocks != fs->desc_blocks) {
281bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = ext2fs_resize_mem(old_fs->desc_blocks *
28276f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o					   fs->blocksize,
28376f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o					   fs->desc_blocks * fs->blocksize,
284c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					   &fs->group_desc);
285ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		if (retval)
286a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
287bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		if (fs->desc_blocks > old_fs->desc_blocks)
2882787276ec59e1d52087d307bc30446d088ec65bcTheodore Ts'o			memset((char *) fs->group_desc +
289bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			       (old_fs->desc_blocks * fs->blocksize), 0,
290bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			       (fs->desc_blocks - old_fs->desc_blocks) *
2912787276ec59e1d52087d307bc30446d088ec65bcTheodore Ts'o			       fs->blocksize);
29224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
2931e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
2941e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
2959213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 * If the resize_inode feature is set, and we are changing the
2969213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 * number of descriptor blocks, then adjust
2979213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 * s_reserved_gdt_blocks if possible to avoid needing to move
2989213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 * the inode table either now or in the future.
2999213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 */
3009213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if ((fs->super->s_feature_compat &
3019213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	     EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
302bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	    (old_fs->desc_blocks != fs->desc_blocks)) {
3039213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		int new;
3049213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
3059213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		new = ((int) fs->super->s_reserved_gdt_blocks) +
306bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			(old_fs->desc_blocks - fs->desc_blocks);
3079213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		if (new < 0)
3089213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			new = 0;
309de8f3a76218255e443ba57dec5d74850180fa75dAndreas Dilger		if (new > (int) fs->blocksize/4)
3109213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			new = fs->blocksize/4;
3119213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		fs->super->s_reserved_gdt_blocks = new;
3129213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		if (new == 0)
3139213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			fs->super->s_feature_compat &=
3149213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o				~EXT2_FEATURE_COMPAT_RESIZE_INODE;
3159213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	}
3169213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
3179213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	/*
318a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * If we are shrinking the number block groups, we're done and
319a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * can exit now.
3201e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
321bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (old_fs->group_desc_count > fs->group_desc_count) {
322c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
323c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
324c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
325bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
326a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
327a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Fix the count of the last (old) block group
328a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
329bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	old_numblocks = (old_fs->super->s_blocks_count -
330bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			 old_fs->super->s_first_data_block) %
331bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o				 old_fs->super->s_blocks_per_group;
3321e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	if (!old_numblocks)
333bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		old_numblocks = old_fs->super->s_blocks_per_group;
334bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (old_fs->group_desc_count == fs->group_desc_count) {
335bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		numblocks = (fs->super->s_blocks_count -
336bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			     fs->super->s_first_data_block) %
337bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			fs->super->s_blocks_per_group;
3381e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (!numblocks)
339bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			numblocks = fs->super->s_blocks_per_group;
3401e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	} else
341bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		numblocks = fs->super->s_blocks_per_group;
342bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	i = old_fs->group_desc_count - 1;
3431e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
344236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos	ext2fs_group_desc_csum_set(fs, i);
345236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos
3461e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
347a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * If the number of block groups is staying the same, we're
348a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * done and can exit now.  (If the number block groups is
349a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * shrinking, we had exited earlier.)
3501e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
351bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (old_fs->group_desc_count >= fs->group_desc_count) {
352c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
353c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
354c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
355bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
356a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
357a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Initialize the new block group descriptors
358a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
3591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	group_block = fs->super->s_first_data_block +
360bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		old_fs->group_desc_count * fs->super->s_blocks_per_group;
361c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
362bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	adj = old_fs->group_desc_count;
36363b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o	max_group = fs->group_desc_count - adj;
36476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
36576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_desc_blocks = fs->super->s_first_meta_bg;
36676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	else
3679213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		old_desc_blocks = fs->desc_blocks +
3689213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			fs->super->s_reserved_gdt_blocks;
369bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	for (i = old_fs->group_desc_count;
3701e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	     i < fs->group_desc_count; i++) {
3711e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		memset(&fs->group_desc[i], 0,
3721e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		       sizeof(struct ext2_group_desc));
3731e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		adjblocks = 0;
3741e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3751e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (i == fs->group_desc_count-1) {
3761e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = (fs->super->s_blocks_count -
3771e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				     fs->super->s_first_data_block) %
3781e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o					     fs->super->s_blocks_per_group;
3791e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			if (!numblocks)
3801e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				numblocks = fs->super->s_blocks_per_group;
3811e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		} else
3821e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = fs->super->s_blocks_per_group;
3831e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
38476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		has_super = ext2fs_bg_has_super(fs, i);
38576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (has_super) {
38676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, group_block);
38776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			adjblocks++;
38876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		}
389f2de1d38d0819b17895977fabc52d81d0ea6ec00Valerie Clement		meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
39076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		meta_bg = i / meta_bg_size;
39176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (!(fs->super->s_feature_incompat &
39276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		      EXT2_FEATURE_INCOMPAT_META_BG) ||
39376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		    (meta_bg < fs->super->s_first_meta_bg)) {
39476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super) {
39576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				for (j=0; j < old_desc_blocks; j++)
39676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o					ext2fs_mark_block_bitmap(fs->block_map,
39776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o							 group_block + 1 + j);
39876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				adjblocks += old_desc_blocks;
39976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			}
40076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		} else {
40176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super)
40276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				has_super = 1;
40376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (((i % meta_bg_size) == 0) ||
40476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == 1) ||
40576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == (meta_bg_size-1)))
4061e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_mark_block_bitmap(fs->block_map,
40776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o						 group_block + has_super);
40824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
40976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
4101e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		adjblocks += 2 + fs->inode_blocks_per_group;
4111e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
4121e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		numblocks -= adjblocks;
4131e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->super->s_free_blocks_count -= adjblocks;
4141e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->super->s_free_inodes_count +=
4151e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			fs->super->s_inodes_per_group;
4161e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_free_blocks_count = numblocks;
4171e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_free_inodes_count =
4181e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			fs->super->s_inodes_per_group;
4191e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_used_dirs_count = 0;
420236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos		ext2fs_group_desc_csum_set(fs, i);
42124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
4221e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		retval = ext2fs_allocate_group_table(fs, i, 0);
423c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (retval) goto errout;
42424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
425bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		group_block += fs->super->s_blocks_per_group;
426bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
427bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	retval = 0;
428bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
429bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'oerrout:
430bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	return (retval);
431bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o}
432bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
433bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o/*
434bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o * This routine adjusts the superblock and other data structures, both
435bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o * in disk as well as in memory...
436bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o */
437bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'ostatic errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
438bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o{
439bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2_filsys fs;
440bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	int		adj = 0;
441bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	errcode_t	retval;
442bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	blk_t		group_block;
443bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	unsigned long	i;
444bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	unsigned long	max_group;
445bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
446bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	fs = rfs->new_fs;
447bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2fs_mark_super_dirty(fs);
448bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2fs_mark_bb_dirty(fs);
449bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2fs_mark_ib_dirty(fs);
450bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
451bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	retval = adjust_fs_info(fs, rfs->old_fs, new_size);
452bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (retval)
453bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
454bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
455bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	/*
456bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * Check to make sure there are enough inodes
457bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 */
458bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if ((rfs->old_fs->super->s_inodes_count -
459bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	     rfs->old_fs->super->s_free_inodes_count) >
460bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	    rfs->new_fs->super->s_inodes_count) {
461bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = ENOSPC;
462bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
463bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
464bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
465bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	/*
466bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * If we are shrinking the number block groups, we're done and
467bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * can exit now.
468bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 */
469bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
470bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = 0;
471bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
472bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
473bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
474bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	/*
475bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * If the number of block groups is staying the same, we're
476bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * done and can exit now.  (If the number block groups is
477bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * shrinking, we had exited earlier.)
478bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 */
479bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
480bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = 0;
481bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
482bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
483bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
484bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	/*
485bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * Initialize the new block group descriptors
486bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 */
487e5aace908e9d1161a594944d9360f9f0cdd18099Theodore Ts'o	retval = ext2fs_get_array(fs->blocksize, fs->inode_blocks_per_group,
488bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o				&rfs->itable_buf);
489bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (retval)
490bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
491bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
492bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
493bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	group_block = fs->super->s_first_data_block +
494bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
495bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
496bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	adj = rfs->old_fs->group_desc_count;
497bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	max_group = fs->group_desc_count - adj;
498bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (rfs->progress) {
499bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
500bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o				       0, max_group);
501bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		if (retval)
502bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			goto errout;
503bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
504bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	for (i = rfs->old_fs->group_desc_count;
505bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	     i < fs->group_desc_count; i++) {
50605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		/*
50705e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 * Write out the new inode table
50805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 */
50905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		retval = io_channel_write_blk(fs->io,
51005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      fs->group_desc[i].bg_inode_table,
51105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      fs->inode_blocks_per_group,
51205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      rfs->itable_buf);
513c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (retval) goto errout;
514c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
515a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
5163b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (rfs->progress) {
5173b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
5183b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					       i - adj + 1, max_group);
5193b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			if (retval)
5203b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				goto errout;
5213b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		}
5221e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		group_block += fs->super->s_blocks_per_group;
52324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
524c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	io_channel_flush(fs->io);
525c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = 0;
526c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
527c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'oerrout:
528c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	return retval;
529c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o}
530c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
531a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
532a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
533a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 2.
534a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
535a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we adjust determine which blocks need to be moved, in
536a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * blocks_to_move().  We then copy the blocks to their ultimate new
537a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * destinations using block_mover().  Since we are copying blocks to
538a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * their new locations, again during this pass we can abort without
539a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * any problems.
540a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
541a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
542a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
543c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o/*
544c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o * This helper function creates a block bitmap with all of the
545c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o * filesystem meta-data blocks.
546c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o */
547c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t mark_table_blocks(ext2_filsys fs,
54864ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o				   ext2fs_block_bitmap bmap)
549c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o{
55062c6d1403ea00dd72890862c761a41baa10a7ad4Eric Sandeen	blk_t			b;
551544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int		j;
552544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	dgrp_t			i;
55368963d5a262ad49cbdad8f946e59ebc34677fe33Theodore Ts'o	unsigned long		meta_bg_size;
554544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int		old_desc_blocks;
555c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
556f2de1d38d0819b17895977fabc52d81d0ea6ec00Valerie Clement	meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
55776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
55876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_desc_blocks = fs->super->s_first_meta_bg;
55976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	else
5609213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		old_desc_blocks = fs->desc_blocks +
5619213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			fs->super->s_reserved_gdt_blocks;
562c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	for (i = 0; i < fs->group_desc_count; i++) {
56364ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		ext2fs_reserve_super_and_bgd(fs, i, bmap);
56476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
565c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
566c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark the blocks used for the inode table
567c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
568c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		for (j = 0, b = fs->group_desc[i].bg_inode_table;
569544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		     j < (unsigned int) fs->inode_blocks_per_group;
570c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j++, b++)
571c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(bmap, b);
572c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
573c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
574c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark block used for the block bitmap
575c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
576c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_mark_block_bitmap(bmap,
577c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					 fs->group_desc[i].bg_block_bitmap);
57864ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
579c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
580c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark block used for the inode bitmap
581c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
582c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_mark_block_bitmap(bmap,
583c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					 fs->group_desc[i].bg_inode_bitmap);
584c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
5851e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	return 0;
58624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o}
58724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
58824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
58976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o * This function checks to see if a particular block (either a
59076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o * superblock or a block group descriptor) overlaps with an inode or
59176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o * block bitmap block, or with the inode table.
59276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o */
59376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'ostatic void mark_fs_metablock(ext2_resize_t rfs,
59476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			      ext2fs_block_bitmap meta_bmap,
59576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			      int group, blk_t blk)
59676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o{
59776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	ext2_filsys 	fs = rfs->new_fs;
59876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
59976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
60076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, blk);
60176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
60276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	/*
60376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 * Check to see if we overlap with the inode or block bitmap,
60476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 * or the inode tables.  If not, and the block is in use, then
60576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 * mark it as a block to be moved.
60676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 */
60776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (IS_BLOCK_BM(fs, group, blk)) {
60876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		FS_BLOCK_BM(fs, group) = 0;
60976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
61076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else if (IS_INODE_BM(fs, group, blk)) {
61176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		FS_INODE_BM(fs, group) = 0;
61276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
61376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else if (IS_INODE_TB(fs, group, blk)) {
61476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		FS_INODE_TB(fs, group) = 0;
61576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
61676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk) &&
61776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		   !ext2fs_test_block_bitmap(meta_bmap, blk)) {
61876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
61976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
62076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	}
62176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o}
62276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
62376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
62476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o/*
62524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * This routine marks and unmarks reserved blocks in the new block
62624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * bitmap.  It also determines which blocks need to be moved and
62724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * places this information into the move_blocks bitmap.
62824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
629c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t blocks_to_move(ext2_resize_t rfs)
63024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o{
631544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	int		j, has_super;
632544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	dgrp_t		i, max_groups;
633544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	blk_t		blk, group_blk;
634544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned long	old_blocks, new_blocks;
635544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	meta_bg, meta_bg_size;
63624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	errcode_t	retval;
637c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2_filsys 	fs, old_fs;
638c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2fs_block_bitmap	meta_bmap;
63924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
640c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs = rfs->new_fs;
641c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	old_fs = rfs->old_fs;
642c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
643c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		fs = rfs->old_fs;
644c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
645a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, _("reserved blocks"),
6461e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o					      &rfs->reserve_blocks);
64724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (retval)
64824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return retval;
6491e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
650a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
651c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					      &rfs->move_blocks);
652c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
653c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
654c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
65564ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, _("meta-data blocks"),
65664ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o					      &meta_bmap);
65764ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	if (retval)
65864ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		return retval;
65964ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
66064ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	retval = mark_table_blocks(old_fs, meta_bmap);
661c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
662c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
663c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
664c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs = rfs->new_fs;
665c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
6661e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
6671e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * If we're shrinking the filesystem, we need to move all of
6681e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * the blocks that don't fit any more
6691e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
6701e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	for (blk = fs->super->s_blocks_count;
671c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	     blk < old_fs->super->s_blocks_count; blk++) {
672c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
673c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    !ext2fs_test_block_bitmap(meta_bmap, blk)) {
674c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
6751e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			rfs->needed_blocks++;
676c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
6771e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
6781e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	}
67924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
68076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) {
68176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_blocks = old_fs->super->s_first_meta_bg;
68276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		new_blocks = fs->super->s_first_meta_bg;
68376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else {
6849213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		old_blocks = old_fs->desc_blocks + old_fs->super->s_reserved_gdt_blocks;
6859213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		new_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
68676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	}
68776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
688c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (old_blocks == new_blocks) {
689c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
690c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
691c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
69224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
6931333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	max_groups = fs->group_desc_count;
6941333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	if (max_groups > old_fs->group_desc_count)
6951333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o		max_groups = old_fs->group_desc_count;
696c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	group_blk = old_fs->super->s_first_data_block;
69724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
69824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * If we're reducing the number of descriptor blocks, this
69924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * makes life easy.  :-)   We just have to mark some extra
70024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * blocks as free.
70124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
70224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (old_blocks > new_blocks) {
7031333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o		for (i = 0; i < max_groups; i++) {
7041e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			if (!ext2fs_bg_has_super(fs, i)) {
7051e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				group_blk += fs->super->s_blocks_per_group;
70624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o				continue;
70724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			}
708c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			for (blk = group_blk+1+new_blocks;
709c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			     blk < group_blk+1+old_blocks; blk++) {
7101e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_unmark_block_bitmap(fs->block_map,
71124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o							   blk);
712052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				rfs->needed_blocks--;
713052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			}
7141e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			group_blk += fs->super->s_blocks_per_group;
71524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
716c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
717c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
71824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
71924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
72024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * If we're increasing the number of descriptor blocks, life
7211e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * gets interesting....
72224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
723f2de1d38d0819b17895977fabc52d81d0ea6ec00Valerie Clement	meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
7241333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	for (i = 0; i < max_groups; i++) {
72576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		has_super = ext2fs_bg_has_super(fs, i);
72676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (has_super)
72776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			mark_fs_metablock(rfs, meta_bmap, i, group_blk);
72876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
72976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		meta_bg = i / meta_bg_size;
73076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (!(fs->super->s_feature_incompat &
73176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		      EXT2_FEATURE_INCOMPAT_META_BG) ||
73276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		    (meta_bg < fs->super->s_first_meta_bg)) {
733424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o			if (has_super) {
734424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o				for (blk = group_blk+1;
735424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o				     blk < group_blk + 1 + new_blocks; blk++)
736424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o					mark_fs_metablock(rfs, meta_bmap,
737424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o							  i, blk);
738424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o			}
73976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		} else {
74076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super)
74176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				has_super = 1;
74276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (((i % meta_bg_size) == 0) ||
74376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == 1) ||
74476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == (meta_bg_size-1)))
74576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				mark_fs_metablock(rfs, meta_bmap, i,
74676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o						  group_blk + has_super);
74724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
74876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
7491e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_table &&
7501e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		    fs->group_desc[i].bg_inode_bitmap &&
7511e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		    fs->group_desc[i].bg_block_bitmap)
7521e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			goto next_group;
75324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
7541e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
755c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Reserve the existing meta blocks that we know
756c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * aren't to be moved.
7571e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
7581e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_block_bitmap)
7591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks,
7601e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 fs->group_desc[i].bg_block_bitmap);
7611e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_bitmap)
7621e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks,
7631e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 fs->group_desc[i].bg_inode_bitmap);
7641e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_table)
7651e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			for (blk = fs->group_desc[i].bg_inode_table, j=0;
7661e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			     j < fs->inode_blocks_per_group ; j++, blk++)
7671e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->reserve_blocks,
7681e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o							 blk);
76924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
770c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
771c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Allocate the missing data structures
772c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
7731e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		retval = ext2fs_allocate_group_table(fs, i,
7741e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o						     rfs->reserve_blocks);
7751e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (retval)
776c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			goto errout;
77724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
7781e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
779c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * For those structures that have changed, we need to
780c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * do bookkeepping.
7811e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
782c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_BLOCK_BM(old_fs, i) !=
783c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    (blk = FS_BLOCK_BM(fs, i))) {
784c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
785c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
786c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
787c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
788c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
789c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
790c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_INODE_BM(old_fs, i) !=
791c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    (blk = FS_INODE_BM(fs, i))) {
792c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
793c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
794c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
795c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
796c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
797c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
79824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
799052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		/*
800052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * The inode table, if we need to relocate it, is
801052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * handled specially.  We have to reserve the blocks
802052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * for both the old and the new inode table, since we
803052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * can't have the inode table be destroyed during the
804052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * block relocation phase.
805052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 */
806c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
807052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			goto next_group; /* inode table not moved */
808052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
809c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		rfs->needed_blocks += fs->inode_blocks_per_group;
810052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
811052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		/*
812052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * Mark the new inode table as in use in the new block
813c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * allocation bitmap, and move any blocks that might
814c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * be necessary.
815052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 */
8161e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		for (blk = fs->group_desc[i].bg_inode_table, j=0;
817c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++) {
8181e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
819c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
820c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
821c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
822c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
823c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
824c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
8251e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
826052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * Make sure the old inode table is reserved in the
827052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * block reservation bitmap.
8281e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
829052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
830052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++)
831052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
8321e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
8331e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	next_group:
8341e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		group_blk += rfs->new_fs->super->s_blocks_per_group;
8351e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	}
836c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = 0;
837c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
838c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'oerrout:
839c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (meta_bmap)
840c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_free_block_bitmap(meta_bmap);
841c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
842c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	return retval;
8431e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o}
84424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
845a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
846a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * This helper function tries to allocate a new block.  We try to
847a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * avoid hitting the original group descriptor blocks at least at
848a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * first, since we want to make it possible to recover from a badly
849a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * aborted resize operation as much as possible.
850a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
851a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In the future, I may further modify this routine to balance out
852a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * where we get the new blocks across the various block groups.
853a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Ideally we would allocate blocks that corresponded with the block
854a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * group of the containing inode, and keep contiguous blocks
855a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * together.  However, this very difficult to do efficiently, since we
856a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * don't have the necessary information up front.
857a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
858a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
859a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define AVOID_OLD	1
860a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define DESPERATION	2
861a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
862a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic void init_block_alloc(ext2_resize_t rfs)
863a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
864a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->alloc_state = AVOID_OLD;
865a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->new_blk = rfs->new_fs->super->s_first_data_block;
8662bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o#if 0
8672bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	/* HACK for testing */
8682bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	if (rfs->new_fs->super->s_blocks_count >
8692bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	    rfs->old_fs->super->s_blocks_count)
8702bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o		rfs->new_blk = rfs->old_fs->super->s_blocks_count;
8712bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o#endif
872a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
873a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
874a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic blk_t get_new_block(ext2_resize_t rfs)
875a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
876a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys	fs = rfs->new_fs;
877a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
878a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
879a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->new_blk >= fs->super->s_blocks_count) {
880a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->alloc_state == DESPERATION)
881a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				return 0;
882a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
883a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
884a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->flags & RESIZE_DEBUG_BMOVE)
885f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o				printf("Going into desperation mode "
886f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o				       "for block allocations\n");
887a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
888a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->alloc_state = DESPERATION;
889a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_blk = fs->super->s_first_data_block;
890a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
891a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
892a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ext2fs_test_block_bitmap(fs->block_map, rfs->new_blk) ||
893a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    ext2fs_test_block_bitmap(rfs->reserve_blocks,
894a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					     rfs->new_blk) ||
895a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    ((rfs->alloc_state == AVOID_OLD) &&
896bce49798f7f4380dff5693bc8308019b3cf8de25Theodore Ts'o		     (rfs->new_blk < rfs->old_fs->super->s_blocks_count) &&
897a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		     ext2fs_test_block_bitmap(rfs->old_fs->block_map,
898a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					      rfs->new_blk))) {
899a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_blk++;
900a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
901a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
902a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return rfs->new_blk;
903a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
904a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
905a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
906a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t block_mover(ext2_resize_t rfs)
907a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
908a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	blk_t			blk, old_blk, new_blk;
909a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys		fs = rfs->new_fs;
910a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys		old_fs = rfs->old_fs;
911a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
912a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			size, c;
913a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			to_move, moved;
9147d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	ext2_badblocks_list	badblock_list = 0;
9157d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	int			bb_modified = 0;
9167d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o
9177d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	retval = ext2fs_read_bb_inode(old_fs, &badblock_list);
9187d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	if (retval)
9197d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		return retval;
920a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
921a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_blk = fs->super->s_first_data_block;
922a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!rfs->itable_buf) {
923e5aace908e9d1161a594944d9360f9f0cdd18099Theodore Ts'o		retval = ext2fs_get_array(fs->blocksize,
924a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					fs->inode_blocks_per_group,
925c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					&rfs->itable_buf);
926a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval)
927a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			return retval;
928a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
929a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_create_extent_table(&rfs->bmap, 0);
930a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
931a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
932a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
933a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
934a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * The first step is to figure out where all of the blocks
935a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * will go.
936a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
937a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	to_move = moved = 0;
938a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	init_block_alloc(rfs);
939a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	for (blk = old_fs->super->s_first_data_block;
940a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     blk < old_fs->super->s_blocks_count; blk++) {
941a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ext2fs_test_block_bitmap(old_fs->block_map, blk))
942a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
943a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk))
944a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
9457d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		if (ext2fs_badblocks_list_test(badblock_list, blk)) {
9467d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			ext2fs_badblocks_list_del(badblock_list, blk);
9477d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			bb_modified++;
9487d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			continue;
9497d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		}
950a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
951a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		new_blk = get_new_block(rfs);
952a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!new_blk) {
953a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ENOSPC;
954a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
955a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
956a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_block_bitmap(fs->block_map, new_blk);
957a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_add_extent_entry(rfs->bmap, blk, new_blk);
958a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		to_move++;
959a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
960a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
961a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (to_move == 0) {
962cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o		if (rfs->bmap) {
963cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o			ext2fs_free_extent_table(rfs->bmap);
964cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o			rfs->bmap = 0;
965cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o		}
966a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = 0;
967a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
968a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
969a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
970a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
971a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Step two is to actually move the blocks
972a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
973a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval =  ext2fs_iterate_extent(rfs->bmap, 0, 0, 0);
974a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
975a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
9763b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
9773b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS,
9783b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 0, to_move);
9793b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
9803b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
9813b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
982a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
983a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size);
984a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
985a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!size)
986a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			break;
987a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
988a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_BMOVE)
989f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			printf("Moving %d blocks %u->%u\n",
990f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			       size, old_blk, new_blk);
991a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
992a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		do {
993a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			c = size;
994a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (c > fs->inode_blocks_per_group)
995a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				c = fs->inode_blocks_per_group;
996a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = io_channel_read_blk(fs->io, old_blk, c,
997a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						     rfs->itable_buf);
998a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
999a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = io_channel_write_blk(fs->io, new_blk, c,
1000a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						      rfs->itable_buf);
1001a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
1002a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			size -= c;
1003a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			new_blk += c;
1004a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			old_blk += c;
1005a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			moved += c;
1006a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->progress) {
1007a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				io_channel_flush(fs->io);
10083b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				retval = (rfs->progress)(rfs,
10093b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o						E2_RSZ_BLOCK_RELOC_PASS,
1010a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						moved, to_move);
10113b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				if (retval)
10123b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					goto errout;
1013a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1014a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		} while (size > 0);
1015a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
1016a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1017a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1018a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
10197d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	if (badblock_list) {
10207d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		if (!retval && bb_modified)
10217d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			retval = ext2fs_update_bb_inode(old_fs,
10227d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o							badblock_list);
10237d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		ext2fs_badblocks_list_free(badblock_list);
10247d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	}
1025a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1026a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1027a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1028a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1029a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1030a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1031a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 3
1032a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1033a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1034a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1035a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1036a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1037a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostruct process_block_struct {
1038a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t 		rfs;
1039dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t		ino;
1040a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct ext2_inode *	inode;
1041a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		error;
1042a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			is_dir;
1043a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			changed;
1044a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o};
1045a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1046a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic int process_block(ext2_filsys fs, blk_t	*block_nr,
1047544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			 e2_blkcnt_t blockcnt,
1048544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			 blk_t ref_block EXT2FS_ATTR((unused)),
1049544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			 int ref_offset EXT2FS_ATTR((unused)), void *priv_data)
1050a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1051a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct process_block_struct *pb;
1052a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
1053a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	blk_t		block, new_block;
1054a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int		ret = 0;
1055a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1056a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb = (struct process_block_struct *) priv_data;
1057a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	block = *block_nr;
1058a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (pb->rfs->bmap) {
1059a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		new_block = ext2fs_extent_translate(pb->rfs->bmap, block);
1060a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (new_block) {
1061a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			*block_nr = new_block;
1062a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ret |= BLOCK_CHANGED;
1063a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb->changed = 1;
1064a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1065a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
1066f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o				printf("ino=%u, blockcnt=%lld, %u->%u\n",
1067a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				       pb->ino, blockcnt, block, new_block);
1068a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1069a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			block = new_block;
1070a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1071a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1072a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (pb->is_dir) {
1073a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
1074101c84f2e049bffcdb6c5ba1784842cdd50dbf05Theodore Ts'o					      block, (int) blockcnt);
1075a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) {
1076a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb->error = retval;
1077a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ret |= BLOCK_ABORT;
1078a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1079a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1080a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return ret;
1081a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1082a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1083a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
1084a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Progress callback
1085a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1086544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic errcode_t progress_callback(ext2_filsys fs,
1087544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   ext2_inode_scan scan EXT2FS_ATTR((unused)),
1088a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   dgrp_t group, void * priv_data)
1089a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1090a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t rfs = (ext2_resize_t) priv_data;
10913b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	errcode_t		retval;
1092a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1093a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1094f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	 * This check is to protect against old ext2 libraries.  It
1095f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	 * shouldn't be needed against new libraries.
1096a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1097f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	if ((group+1) == 0)
1098a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1099a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1100a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->progress) {
1101a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
11023b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
11033b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 group+1, fs->group_desc_count);
11043b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
11053b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			return retval;
1106a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1107a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1108a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return 0;
1109a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1110a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1111a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_scan_and_fix(ext2_resize_t rfs)
1112a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1113a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct process_block_struct	pb;
1114dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t		ino, new_inode;
1115edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o	struct ext2_inode 	*inode = NULL;
1116a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_inode_scan 	scan = NULL;
1117a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
1118a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			group;
1119a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	char			*block_buf = 0;
1120dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t		start_to_move;
11210ccd488a764c14b27983b92435deca5e1adf9061Theodore Ts'o	blk_t			orig_size, new_block;
11224ef28824ca29e86053398c3e4cecca6d88b2b397Eric Sandeen	int			inode_size;
1123a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1124a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if ((rfs->old_fs->group_desc_count <=
1125a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     rfs->new_fs->group_desc_count) &&
1126a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	    !rfs->bmap)
1127a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1128a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
11292bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	/*
11302bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * Save the original size of the old filesystem, and
11312bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * temporarily set the size to be the new size if the new size
11322bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * is larger.  We need to do this to avoid catching an error
11332bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * by the block iterator routines
11342bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 */
11352bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	orig_size = rfs->old_fs->super->s_blocks_count;
11362bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	if (orig_size < rfs->new_fs->super->s_blocks_count)
11372bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o		rfs->old_fs->super->s_blocks_count =
11382bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o			rfs->new_fs->super->s_blocks_count;
11392bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o
1140a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
1141a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
1142a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1143a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_init_dblist(rfs->old_fs, 0);
1144a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
1145e5aace908e9d1161a594944d9360f9f0cdd18099Theodore Ts'o	retval = ext2fs_get_array(rfs->old_fs->blocksize, 3, &block_buf);
1146a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
1147a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1148a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	start_to_move = (rfs->new_fs->group_desc_count *
1149a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			 rfs->new_fs->super->s_inodes_per_group);
1150a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
11513b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
11523b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
11533b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 0, rfs->old_fs->group_desc_count);
11543b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
11553b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
11563b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1157a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
1158a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.rfs = rfs;
1159edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o	pb.inode = inode;
1160a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.error = 0;
1161a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
11624ef28824ca29e86053398c3e4cecca6d88b2b397Eric Sandeen	inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
1163edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o	inode = malloc(inode_size);
1164edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o	if (!inode) {
11654ef28824ca29e86053398c3e4cecca6d88b2b397Eric Sandeen		retval = ENOMEM;
11664ef28824ca29e86053398c3e4cecca6d88b2b397Eric Sandeen		goto errout;
11674ef28824ca29e86053398c3e4cecca6d88b2b397Eric Sandeen	}
1168a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1169a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * First, copy all of the inodes that need to be moved
1170a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * elsewhere in the inode table
1171a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1172a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
1173edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o		retval = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
1174a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
1175a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ino)
1176a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			break;
1177a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1178edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o		if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
1179a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue; /* inode not in use */
1180a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1181edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o		pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
1182a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		pb.changed = 0;
1183a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1184edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o		if (inode->i_file_acl && rfs->bmap) {
11850ccd488a764c14b27983b92435deca5e1adf9061Theodore Ts'o			new_block = ext2fs_extent_translate(rfs->bmap,
1186edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o							    inode->i_file_acl);
1187ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o			if (new_block) {
1188edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o				inode->i_file_acl = new_block;
1189edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o				retval = ext2fs_write_inode_full(rfs->old_fs,
1190edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o							    ino, inode, inode_size);
1191ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o				if (retval) goto errout;
1192ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o			}
1193ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o		}
1194ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o
1195edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o		if (ext2fs_inode_has_valid_blocks(inode) &&
1196a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    (rfs->bmap || pb.is_dir)) {
1197a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb.ino = ino;
1198a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_block_iterate2(rfs->old_fs,
1199a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						       ino, 0, block_buf,
1200a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						       process_block, &pb);
1201a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval)
1202a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1203a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (pb.error) {
1204a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				retval = pb.error;
1205a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1206a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1207a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1208a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1209a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ino <= start_to_move)
1210a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue; /* Don't need to move it. */
1211a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1212a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		/*
1213a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * Find a new inode
1214a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 */
1215a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		while (1) {
1216a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map,
1217a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						      new_inode))
1218a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				break;
1219a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			new_inode++;
1220a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (new_inode > rfs->new_fs->super->s_inodes_count) {
1221a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				retval = ENOSPC;
1222a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1223a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1224a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1225a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new_inode);
1226a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (pb.changed) {
1227a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			/* Get the new version of the inode */
12284ef28824ca29e86053398c3e4cecca6d88b2b397Eric Sandeen			retval = ext2fs_read_inode_full(rfs->old_fs, ino,
1229edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o						inode, inode_size);
1230a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
1231a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1232edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o		inode->i_ctime = time(0);
12334ef28824ca29e86053398c3e4cecca6d88b2b397Eric Sandeen		retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
1234edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o						inode, inode_size);
1235a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
1236a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1237a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
1238236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos		if (LINUX_S_ISDIR(inode->i_mode)) {
1239a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_fs->group_desc[group].bg_used_dirs_count++;
1240236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos			ext2fs_group_desc_csum_set(rfs->new_fs, group);
1241236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos		}
1242236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos
1243a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1244a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_INODEMAP)
1245f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			printf("Inode moved %u->%u\n", ino, new_inode);
1246a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1247a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!rfs->imap) {
1248a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_create_extent_table(&rfs->imap, 0);
1249a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval)
1250a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1251a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1252a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
1253a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1254a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	io_channel_flush(rfs->old_fs->io);
1255a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1256a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
12572bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	rfs->old_fs->super->s_blocks_count = orig_size;
1258a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->bmap) {
1259a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_extent_table(rfs->bmap);
1260a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		rfs->bmap = 0;
1261a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1262a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (scan)
1263a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_close_inode_scan(scan);
1264a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (block_buf)
1265c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&block_buf);
1266edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o	if (inode)
1267edfd9b0a9fe7b90f56da981ca26d5233cc3749d6Theodore Ts'o		free(inode);
1268a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1269a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1270a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1271a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1272a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1273a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 4.
1274a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1275a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1276a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1277a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1278a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostruct istruct {
1279a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t rfs;
12803b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	errcode_t	err;
12811333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	unsigned long	max_dirs;
1282a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int		num;
1283a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o};
1284a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1285544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic int check_and_change_inodes(ext2_ino_t dir,
1286544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   int entry EXT2FS_ATTR((unused)),
1287a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   struct ext2_dir_entry *dirent, int offset,
1288544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   int	blocksize EXT2FS_ATTR((unused)),
1289544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   char *buf EXT2FS_ATTR((unused)),
1290544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   void *priv_data)
1291a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1292a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct istruct *is = (struct istruct *) priv_data;
1293085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	struct ext2_inode 	inode;
1294085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	ext2_ino_t		new_inode;
1295085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	errcode_t		retval;
1296a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1297a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (is->rfs->progress && offset == 0) {
1298a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(is->rfs->old_fs->io);
12993b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		is->err = (is->rfs->progress)(is->rfs,
13003b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					      E2_RSZ_INODE_REF_UPD_PASS,
13011333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o					      ++is->num, is->max_dirs);
13023b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (is->err)
13033b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			return DIRENT_ABORT;
1304a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1305a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1306a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!dirent->inode)
1307a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1308a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1309a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
1310a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1311a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!new_inode)
1312a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1313a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1314a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
1315f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o		printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
131606191693d4d253a8496677dd02e3b8529a7fce2cTheodore Ts'o		       dir, dirent->name_len&0xFF, dirent->name,
1317a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       dirent->inode, new_inode);
1318a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1319a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1320a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	dirent->inode = new_inode;
1321a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1322085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	/* Update the directory mtime and ctime */
1323085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
1324085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	if (retval == 0) {
1325085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o		inode.i_mtime = inode.i_ctime = time(0);
1326d2b2a488f996871e6e40789a7890afc2f59730dbBrian Behlendorf		is->err = ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
1327d2b2a488f996871e6e40789a7890afc2f59730dbBrian Behlendorf		if (is->err)
1328d2b2a488f996871e6e40789a7890afc2f59730dbBrian Behlendorf			return DIRENT_ABORT;
1329085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	}
1330085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o
1331a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return DIRENT_CHANGED;
1332a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1333a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1334a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_ref_fix(ext2_resize_t rfs)
1335a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1336a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
1337a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct istruct 		is;
1338a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1339a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!rfs->imap)
1340a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1341a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1342a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1343a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Now, we iterate over all of the directories to update the
1344a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * inode references
1345a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1346a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	is.num = 0;
13471333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	is.max_dirs = ext2fs_dblist_count(rfs->old_fs->dblist);
1348a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	is.rfs = rfs;
13493b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	is.err = 0;
1350a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
13513b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
13523b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
13531333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o					 0, is.max_dirs);
13543b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
13553b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
13563b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1357a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1358a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
1359a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   DIRENT_FLAG_INCLUDE_EMPTY, 0,
1360a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   check_and_change_inodes, &is);
13613b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (retval)
13623b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		goto errout;
13633b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (is.err) {
13643b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = is.err;
13653b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		goto errout;
13663b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1367a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
13683b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'oerrout:
1369a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free_extent_table(rfs->imap);
1370a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->imap = 0;
1371a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1372a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1373a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1374a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1375a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1376a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1377a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 5.
1378a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1379a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we actually move the inode table around, and then
1380a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * update the summary statistics.  This is scary, since aborting here
1381a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * will potentially scramble the filesystem.  (We are moving the
1382a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode tables around in place, and so the potential for lost data,
1383a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * or at the very least scrambling the mapping between filenames and
1384a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode numbers is very high in case of a power failure here.)
1385a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1386a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1387a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
138824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
138924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
1390052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * A very scary routine --- this one moves the inode table around!!!
1391052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o *
1392052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * After this you have to use the rfs->new_fs file handle to read and
1393052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * write inodes.
1394052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o */
1395c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t move_itables(ext2_resize_t rfs)
1396052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o{
1397544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	int		n, num, size, diff;
1398544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	dgrp_t		i, max_groups;
1399052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	ext2_filsys	fs = rfs->new_fs;
140005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	char		*cp;
140164ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	blk_t		old_blk, new_blk, blk;
1402a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
140364ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	int		j, to_move, moved;
1404052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
14051333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	max_groups = fs->group_desc_count;
14061333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	if (max_groups > rfs->old_fs->group_desc_count)
14071333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o		max_groups = rfs->old_fs->group_desc_count;
1408052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
140905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	size = fs->blocksize * fs->inode_blocks_per_group;
141005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	if (!rfs->itable_buf) {
1411c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		retval = ext2fs_get_mem(size, &rfs->itable_buf);
1412ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		if (retval)
1413ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			return retval;
141405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	}
1415c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
1416c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	/*
1417c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 * Figure out how many inode tables we need to move
1418c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 */
1419c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	to_move = moved = 0;
14201333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	for (i=0; i < max_groups; i++)
1421c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (rfs->old_fs->group_desc[i].bg_inode_table !=
1422c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    fs->group_desc[i].bg_inode_table)
1423c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			to_move++;
1424c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
1425c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (to_move == 0)
1426c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return 0;
1427c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
14283b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
14293b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
14303b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				       0, to_move);
14313b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
14323b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
14333b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
143463b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o
1435a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
1436a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
14371333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	for (i=0; i < max_groups; i++) {
1438ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		old_blk = rfs->old_fs->group_desc[i].bg_inode_table;
1439ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		new_blk = fs->group_desc[i].bg_inode_table;
1440ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		diff = new_blk - old_blk;
1441052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
144280c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
144305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1444f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			printf("Itable move group %d block %u->%u (diff %d)\n",
1445ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			       i, old_blk, new_blk, diff);
144680c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
1447052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
144805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (!diff)
1449052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			continue;
1450052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1451ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = io_channel_read_blk(fs->io, old_blk,
145205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     fs->inode_blocks_per_group,
145305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     rfs->itable_buf);
1454052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (retval)
1455a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
145605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		/*
145705e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 * The end of the inode table segment often contains
1458a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * all zeros, and we're often only moving the inode
1459a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * table down a block or two.  If so, we can optimize
1460a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * things by not rewriting blocks that we know to be zero
1461a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * already.
146205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 */
14632787276ec59e1d52087d307bc30446d088ec65bcTheodore Ts'o		for (cp = rfs->itable_buf+size-1, n=0; n < size; n++, cp--)
146405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			if (*cp)
146505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o				break;
146605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
146780c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
146805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1469f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			printf("%d blocks of zeros...\n", n);
147080c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
147105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		num = fs->inode_blocks_per_group;
147205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (n > diff)
147305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			num -= n;
147405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o
1475ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = io_channel_write_blk(fs->io, new_blk,
147605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      num, rfs->itable_buf);
1477052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (retval) {
1478ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			io_channel_write_blk(fs->io, old_blk,
147905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     num, rfs->itable_buf);
1480a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
1481052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
148205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (n > diff) {
148305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			retval = io_channel_write_blk(fs->io,
1484ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			      old_blk + fs->inode_blocks_per_group,
1485a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			      diff, (rfs->itable_buf +
1486a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     (fs->inode_blocks_per_group - diff) *
1487a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     fs->blocksize));
148805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			if (retval)
1489a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1490c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
149164ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
149264ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
149364ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++)
149464ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o			ext2fs_unmark_block_bitmap(fs->block_map, blk);
149564ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
1496a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
1497236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos		ext2fs_group_desc_csum_set(rfs->old_fs, i);
1498a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_super_dirty(rfs->old_fs);
149964ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		ext2fs_flush(rfs->old_fs);
150064ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
1501a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->progress) {
15023b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
15033b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					       ++moved, to_move);
15043b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			if (retval)
15053b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				goto errout;
1506a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1507052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
150864ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	mark_table_blocks(fs, fs->block_map);
1509a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_flush(fs);
151080c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
151105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1512f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o		printf("Inode table move finished.\n");
151380c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
1514052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return 0;
1515052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1516a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
1517052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return retval;
1518052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o}
1519052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1520052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o/*
15219213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o * Fix the resize inode
15229213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o */
15239213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'ostatic errcode_t fix_resize_inode(ext2_filsys fs)
15249213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o{
15259213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	struct ext2_inode	inode;
15269213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	errcode_t		retval;
15279213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	char *			block_buf;
15289213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15299213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (!(fs->super->s_feature_compat &
15309213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	      EXT2_FEATURE_COMPAT_RESIZE_INODE))
15319213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		return 0;
15329213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15339213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = ext2fs_get_mem(fs->blocksize, &block_buf);
15349213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval) goto errout;
15359213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15369213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
15379213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval) goto errout;
15389213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15399213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	inode.i_blocks = fs->blocksize/512;
15409213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15419213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
15429213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval) goto errout;
15439213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15449213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (!inode.i_block[EXT2_DIND_BLOCK]) {
15459213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		/*
15469213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		 * Avoid zeroing out block #0; that's rude.  This
15479213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		 * should never happen anyway since the filesystem
15489213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		 * should be fsck'ed and we assume it is consistent.
15499213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		 */
15509213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		fprintf(stderr,
1551f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			_("Should never happen: resize inode corrupt!\n"));
15529213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		exit(1);
15539213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	}
15549213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15559213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	memset(block_buf, 0, fs->blocksize);
15569213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15579213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = io_channel_write_blk(fs->io, inode.i_block[EXT2_DIND_BLOCK],
15589213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o				      1, block_buf);
15599213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval) goto errout;
15609213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15619213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = ext2fs_create_resize_inode(fs);
15629213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval)
15639213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		goto errout;
15649213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15659213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'oerrout:
15669213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (block_buf)
15679213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		ext2fs_free_mem(&block_buf);
15689213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	return retval;
15699213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o}
15709213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15719213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o/*
1572052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * Finally, recalculate the summary information
1573052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o */
1574052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'ostatic errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1575052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o{
1576dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	blk_t		blk;
1577dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t	ino;
1578544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	group = 0;
1579544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	count = 0;
1580dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	int		total_free = 0;
1581dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	int		group_free = 0;
1582052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1583052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	/*
1584052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 * First calculate the block statistics
1585052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 */
1586052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	for (blk = fs->super->s_first_data_block;
1587052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	     blk < fs->super->s_blocks_count; blk++) {
1588052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
1589052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free++;
1590052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			total_free++;
1591052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1592052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		count++;
1593052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if ((count == fs->super->s_blocks_per_group) ||
1594052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		    (blk == fs->super->s_blocks_count-1)) {
1595236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos			fs->group_desc[group].bg_free_blocks_count =
1596052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				group_free;
1597236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos			ext2fs_group_desc_csum_set(fs, group);
1598236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos			group++;
1599052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			count = 0;
1600052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free = 0;
1601052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1602052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1603052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	fs->super->s_free_blocks_count = total_free;
1604052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1605052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	/*
1606052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 * Next, calculate the inode statistics
1607052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 */
1608052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	group_free = 0;
1609052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	total_free = 0;
1610052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	count = 0;
1611052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	group = 0;
16125830d6be9c33e23bb20c339036083e6e4fa6795eEric Sandeen
16135830d6be9c33e23bb20c339036083e6e4fa6795eEric Sandeen	/* Protect loop from wrap-around if s_inodes_count maxed */
16145830d6be9c33e23bb20c339036083e6e4fa6795eEric Sandeen	for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
1615052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
1616052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free++;
1617052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			total_free++;
1618052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1619052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		count++;
1620052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if ((count == fs->super->s_inodes_per_group) ||
1621052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		    (ino == fs->super->s_inodes_count)) {
1622236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos			fs->group_desc[group].bg_free_inodes_count =
1623052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				group_free;
1624236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos			ext2fs_group_desc_csum_set(fs, group);
1625236efede1922fa173b3c2f20d9e0886856664ab4Jose R. Santos			group++;
1626052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			count = 0;
1627052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free = 0;
1628052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1629052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1630052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	fs->super->s_free_inodes_count = total_free;
1631052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	ext2fs_mark_super_dirty(fs);
1632052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return 0;
1633052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o}
1634199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1635199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik/*
1636199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik * calcluate the minimum number of blocks the given fs can be resized to
1637199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik */
1638199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacikblk_t calculate_minimum_resize_size(ext2_filsys fs)
1639199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik{
1640199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	blk_t inode_count, blks_needed, groups, blk, data_blocks;
1641199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	blk_t grp, data_needed, last_start;
1642199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	int overhead = 0, old_group = -1, num_of_superblocks = 0;
1643199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1644199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	/*
1645199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * first figure out how many group descriptors we need to
1646199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * handle the number of inodes we have
1647199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 */
1648199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	inode_count = fs->super->s_inodes_count -
1649199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		fs->super->s_free_inodes_count;
1650199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	blks_needed = ext2fs_div_ceil(inode_count,
1651199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik				      fs->super->s_inodes_per_group) *
1652199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		EXT2_BLOCKS_PER_GROUP(fs->super);
1653199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	groups = ext2fs_div_ceil(blks_needed,
1654199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik				 EXT2_BLOCKS_PER_GROUP(fs->super));
1655199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1656199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	/*
1657199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * we need to figure out how many backup superblocks we have so we can
1658199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * account for that in the metadata
1659199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 */
1660199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	for (grp = 0; grp < fs->group_desc_count; grp++) {
1661199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		if (ext2fs_bg_has_super(fs, grp))
1662199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			num_of_superblocks++;
1663199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	}
1664199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1665199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	/* calculate how many blocks are needed for data */
1666199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	data_needed = fs->super->s_blocks_count -
1667199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		fs->super->s_free_blocks_count;
1668199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	data_needed -= SUPER_OVERHEAD(fs) * num_of_superblocks;
1669199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	data_needed -= META_OVERHEAD(fs) * fs->group_desc_count;
1670199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1671199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	/*
1672199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * figure out how many data blocks we have given the number of groups
1673199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * we need for our inodes
1674199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 */
1675199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	data_blocks = groups * EXT2_BLOCKS_PER_GROUP(fs->super);
1676199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	last_start = 0;
1677199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	for (grp = 0; grp < groups; grp++) {
1678199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		overhead = META_OVERHEAD(fs);
1679199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1680199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		if (ext2fs_bg_has_super(fs, grp))
1681199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			overhead += SUPER_OVERHEAD(fs);
1682199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1683199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		/*
1684199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		 * we want to keep track of how much data we can store in
1685199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		 * the groups leading up to the last group so we can determine
1686199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		 * how big the last group needs to be
1687199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		 */
1688199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		if (grp != (groups - 1))
1689199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			last_start += EXT2_BLOCKS_PER_GROUP(fs->super) -
1690199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik				overhead;
1691199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1692199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		data_blocks -= overhead;
1693199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	}
1694199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1695199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	/*
1696199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * if we need more group descriptors in order to accomodate our data
1697199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * then we need to add them here
1698199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 */
1699199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	while (data_needed > data_blocks) {
1700199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		blk_t remainder = data_needed - data_blocks;
1701199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		blk_t extra_grps;
1702199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1703199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		/* figure out how many more groups we need for the data */
1704199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		extra_grps = ext2fs_div_ceil(remainder,
1705199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik					     EXT2_BLOCKS_PER_GROUP(fs->super));
1706199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1707199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		data_blocks += extra_grps * EXT2_BLOCKS_PER_GROUP(fs->super);
1708199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1709199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		/* ok we have to account for the last group */
1710199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		overhead = META_OVERHEAD(fs);
1711199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		if (ext2fs_bg_has_super(fs, groups-1))
1712199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			overhead += SUPER_OVERHEAD(fs);
1713199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		last_start += EXT2_BLOCKS_PER_GROUP(fs->super) - overhead;
1714199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1715199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		for (grp = groups; grp < groups+extra_grps; grp++) {
1716199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			overhead = META_OVERHEAD(fs);
1717199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			if (ext2fs_bg_has_super(fs, grp))
1718199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik				overhead += SUPER_OVERHEAD(fs);
1719199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1720199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			/*
1721199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			 * again, we need to see how much data we cram into
1722199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			 * all of the groups leading up to the last group
1723199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			 */
1724199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			if (grp != (groups + extra_grps - 1))
1725199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik				last_start += EXT2_BLOCKS_PER_GROUP(fs->super)
1726199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik					- overhead;
1727199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1728199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			data_blocks -= overhead;
1729199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		}
1730199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1731199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		groups += extra_grps;
1732199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	}
1733199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1734199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	/* now for the fun voodoo */
1735199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	overhead = META_OVERHEAD(fs);
1736199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1737199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	/*
1738199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * if this is the case then the last group is going to have data in it
1739199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * so we need to adjust the size of the last group accordingly
1740199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 */
1741199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	if (last_start < data_needed) {
1742199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		blk_t remainder = data_needed - last_start;
1743199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1744199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		/*
1745199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		 * 50 is a magic number that mkfs/resize uses to see if its
1746199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		 * even worth making/resizing the fs.  basically you need to
1747199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		 * have at least 50 blocks in addition to the blocks needed
1748199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		 * for the metadata in the last group
1749199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		 */
1750199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		if (remainder > 50)
1751199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			overhead += remainder;
1752199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		else
1753199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik			overhead += 50;
1754199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	} else
1755199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		overhead += 50;
1756199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1757199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	if (ext2fs_bg_has_super(fs, groups-1))
1758199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik		overhead += SUPER_OVERHEAD(fs);
1759199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1760199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	/*
1761199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * since our last group doesn't have to be BLOCKS_PER_GROUP large, we
1762199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * only do groups-1, and then add the number of blocks needed to
1763199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 * handle the group descriptor metadata+data that we need
1764199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	 */
1765199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	blks_needed = (groups-1) * EXT2_BLOCKS_PER_GROUP(fs->super);
1766199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	blks_needed += overhead;
1767199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik
1768199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik	return blks_needed;
1769199ddaaa445e14fca8113b0db85e2576267071c9Josef Bacik}
1770