resize2fs.c revision 5830d6be9c33e23bb20c339036083e6e4fa6795e
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
66a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
67a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
68a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
69a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * This is the top-level routine which does the dirty deed....
70a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
71116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'oerrcode_t resize_fs(ext2_filsys fs, blk_t *new_size, int flags,
723b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		    errcode_t (*progress)(ext2_resize_t rfs, int pass,
73a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     unsigned long cur,
741333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o				     unsigned long max_val))
75a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
76a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t	rfs;
77a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
78a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
79a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_read_bitmaps(fs);
80a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
81a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
82a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
83a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
84a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Create the data structure
85a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
86c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct), &rfs);
87a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
88a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
89a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	memset(rfs, 0, sizeof(struct ext2_resize_struct));
90a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
91a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->old_fs = fs;
92a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->flags = flags;
93a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->itable_buf	 = 0;
94a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->progress = progress;
95a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_dup_handle(fs, &rfs->new_fs);
96a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
97a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
98a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
99116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'o	retval = adjust_superblock(rfs, *new_size);
100a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
101a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
102a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
103116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'o	*new_size = rfs->new_fs->super->s_blocks_count;
104116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'o
105a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = blocks_to_move(rfs);
106a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
107a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
108a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
109a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
110a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->flags & RESIZE_DEBUG_BMOVE)
1118deb80a5d1078cbe43eaffcdeebf0a1a549d6a54Takashi Sato		printf("Number of free blocks: %u/%u, Needed: %d\n",
112a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->old_fs->super->s_free_blocks_count,
113a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->new_fs->super->s_free_blocks_count,
114a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->needed_blocks);
115a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
116a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
117a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = block_mover(rfs);
118a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
119a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
120a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
121a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = inode_scan_and_fix(rfs);
122a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
123a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
124a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
125a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = inode_ref_fix(rfs);
126a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
127a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
128a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
129a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = move_itables(rfs);
130a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
131a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
132a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
13364ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	retval = ext2fs_calculate_summary_stats(rfs->new_fs);
13464ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	if (retval)
13564ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		goto errout;
13664ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
1379213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = fix_resize_inode(rfs->new_fs);
1389213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval)
1399213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		goto errout;
1409213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
141a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_close(rfs->new_fs);
142a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
143a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
144a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
145a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->flags = flags;
146a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
147a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free(rfs->old_fs);
148a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->itable_buf)
149c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&rfs->itable_buf);
150c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&rfs);
151a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
152a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return 0;
153a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
154a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
155a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->new_fs)
156a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free(rfs->new_fs);
157a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->itable_buf)
158c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&rfs->itable_buf);
159c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&rfs);
160a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
161a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
162a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
163a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
164a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
165a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 1.
166a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
167a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we adjust the in-memory superblock information, and
168a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * initialize any new parts of the inode table.  The new parts of the
169a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode table are created in virgin disk space, so we can abort here
170a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * without any side effects.
171a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
172a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
173a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
17424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
175bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o * This routine is shared by the online and offline resize routines.
176bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o * All of the information which is adjusted in memory is done here.
17724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
178bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'oerrcode_t adjust_fs_info(ext2_filsys fs, ext2_filsys old_fs, blk_t new_size)
17924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o{
18024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	errcode_t	retval;
181bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	int		overhead = 0;
182bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	int		rem;
18324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	blk_t		blk, group_block;
184bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2_ino_t	real_end;
185bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	int		adj, old_numblocks, numblocks, adjblocks;
186bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	unsigned long	i, j, old_desc_blocks, max_group;
187544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	meta_bg, meta_bg_size;
188544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	int		has_super;
189bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
19024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->super->s_blocks_count = new_size;
19124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
19224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'oretry:
19369022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o	fs->group_desc_count = ext2fs_div_ceil(fs->super->s_blocks_count -
19469022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o				       fs->super->s_first_data_block,
19569022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o				       EXT2_BLOCKS_PER_GROUP(fs->super));
19624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (fs->group_desc_count == 0)
19724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return EXT2_ET_TOOSMALL;
19869022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o	fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
19969022e029f3273b3b860bf701219cd3fe615f76bTheodore Ts'o					  EXT2_DESC_PER_BLOCK(fs->super));
20024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
20124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
20224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Overhead is the number of bookkeeping blocks per group.  It
20324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * includes the superblock backup, the group descriptor
20424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * backups, the inode bitmap, the block bitmap, and the inode
20524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * table.
20624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
2079213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	overhead = (int) (2 + fs->inode_blocks_per_group);
2089213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
2099213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
2109213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		overhead += 1 + fs->desc_blocks +
2119213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			fs->super->s_reserved_gdt_blocks;
2129213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
21324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
21424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * See if the last group is big enough to support the
21524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * necessary data structures.  If not, we need to get rid of
21624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * it.
21724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
21824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
21924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_blocks_per_group;
22024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if ((fs->group_desc_count == 1) && rem && (rem < overhead))
22124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return EXT2_ET_TOOSMALL;
22224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (rem && (rem < overhead+50)) {
22324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_blocks_count -= rem;
22424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		goto retry;
22524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
22624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
22724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Adjust the number of inodes
22824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
22924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->super->s_inodes_count = fs->super->s_inodes_per_group *
23024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->group_desc_count;
23124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
23224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
23324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Adjust the number of free blocks
23424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
235bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	blk = old_fs->super->s_blocks_count;
23624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (blk > fs->super->s_blocks_count)
23724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_free_blocks_count -=
23824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			(blk - fs->super->s_blocks_count);
23924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	else
24024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_free_blocks_count +=
24124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			(fs->super->s_blocks_count - blk);
24224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
24324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
244c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 * Adjust the number of reserved blocks
245c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 */
246bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	blk = old_fs->super->s_r_blocks_count * 100 /
247bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		old_fs->super->s_blocks_count;
248c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs->super->s_r_blocks_count = ((fs->super->s_blocks_count * blk)
249c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				       / 100);
250c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
251c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	/*
25224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Adjust the bitmaps for size
25324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
25424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
25524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o					    fs->super->s_inodes_count,
25624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o					    fs->inode_map);
257c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval) goto errout;
25824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
25924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
26024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		     * fs->group_desc_count)) - 1 +
26124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			     fs->super->s_first_data_block;
26224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
26324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o					    real_end, fs->block_map);
26424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
265c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval) goto errout;
26624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
26724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
26824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Reallocate the group descriptors as necessary.
26924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
270bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (old_fs->desc_blocks != fs->desc_blocks) {
271bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = ext2fs_resize_mem(old_fs->desc_blocks *
27276f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o					   fs->blocksize,
27376f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o					   fs->desc_blocks * fs->blocksize,
274c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					   &fs->group_desc);
275ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		if (retval)
276a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
277bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		if (fs->desc_blocks > old_fs->desc_blocks)
2782787276ec59e1d52087d307bc30446d088ec65bcTheodore Ts'o			memset((char *) fs->group_desc +
279bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			       (old_fs->desc_blocks * fs->blocksize), 0,
280bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			       (fs->desc_blocks - old_fs->desc_blocks) *
2812787276ec59e1d52087d307bc30446d088ec65bcTheodore Ts'o			       fs->blocksize);
28224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
2831e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
2841e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
2859213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 * If the resize_inode feature is set, and we are changing the
2869213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 * number of descriptor blocks, then adjust
2879213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 * s_reserved_gdt_blocks if possible to avoid needing to move
2889213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 * the inode table either now or in the future.
2899213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	 */
2909213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if ((fs->super->s_feature_compat &
2919213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	     EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
292bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	    (old_fs->desc_blocks != fs->desc_blocks)) {
2939213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		int new;
2949213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
2959213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		new = ((int) fs->super->s_reserved_gdt_blocks) +
296bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			(old_fs->desc_blocks - fs->desc_blocks);
2979213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		if (new < 0)
2989213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			new = 0;
2999213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		if (new > fs->blocksize/4)
3009213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			new = fs->blocksize/4;
3019213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		fs->super->s_reserved_gdt_blocks = new;
3029213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		if (new == 0)
3039213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			fs->super->s_feature_compat &=
3049213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o				~EXT2_FEATURE_COMPAT_RESIZE_INODE;
3059213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	}
3069213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
3079213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	/*
308a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * If we are shrinking the number block groups, we're done and
309a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * can exit now.
3101e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
311bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (old_fs->group_desc_count > fs->group_desc_count) {
312c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
313c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
314c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
315bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
316a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
317a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Fix the count of the last (old) block group
318a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
319bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	old_numblocks = (old_fs->super->s_blocks_count -
320bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			 old_fs->super->s_first_data_block) %
321bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o				 old_fs->super->s_blocks_per_group;
3221e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	if (!old_numblocks)
323bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		old_numblocks = old_fs->super->s_blocks_per_group;
324bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (old_fs->group_desc_count == fs->group_desc_count) {
325bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		numblocks = (fs->super->s_blocks_count -
326bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			     fs->super->s_first_data_block) %
327bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			fs->super->s_blocks_per_group;
3281e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (!numblocks)
329bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			numblocks = fs->super->s_blocks_per_group;
3301e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	} else
331bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		numblocks = fs->super->s_blocks_per_group;
332bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	i = old_fs->group_desc_count - 1;
3331e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
3341e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3351e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
336a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * If the number of block groups is staying the same, we're
337a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * done and can exit now.  (If the number block groups is
338a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * shrinking, we had exited earlier.)
3391e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
340bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (old_fs->group_desc_count >= fs->group_desc_count) {
341c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
342c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
343c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
344bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
345a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
346a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Initialize the new block group descriptors
347a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
3481e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	group_block = fs->super->s_first_data_block +
349bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		old_fs->group_desc_count * fs->super->s_blocks_per_group;
350c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
351bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	adj = old_fs->group_desc_count;
35263b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o	max_group = fs->group_desc_count - adj;
35376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
35476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_desc_blocks = fs->super->s_first_meta_bg;
35576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	else
3569213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		old_desc_blocks = fs->desc_blocks +
3579213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			fs->super->s_reserved_gdt_blocks;
358bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	for (i = old_fs->group_desc_count;
3591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	     i < fs->group_desc_count; i++) {
3601e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		memset(&fs->group_desc[i], 0,
3611e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		       sizeof(struct ext2_group_desc));
3621e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		adjblocks = 0;
3631e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3641e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (i == fs->group_desc_count-1) {
3651e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = (fs->super->s_blocks_count -
3661e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				     fs->super->s_first_data_block) %
3671e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o					     fs->super->s_blocks_per_group;
3681e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			if (!numblocks)
3691e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				numblocks = fs->super->s_blocks_per_group;
3701e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		} else
3711e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = fs->super->s_blocks_per_group;
3721e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
37376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		has_super = ext2fs_bg_has_super(fs, i);
37476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (has_super) {
37576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, group_block);
37676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			adjblocks++;
37776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		}
37876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		meta_bg_size = (fs->blocksize /
37976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				sizeof (struct ext2_group_desc));
38076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		meta_bg = i / meta_bg_size;
38176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (!(fs->super->s_feature_incompat &
38276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		      EXT2_FEATURE_INCOMPAT_META_BG) ||
38376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		    (meta_bg < fs->super->s_first_meta_bg)) {
38476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super) {
38576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				for (j=0; j < old_desc_blocks; j++)
38676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o					ext2fs_mark_block_bitmap(fs->block_map,
38776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o							 group_block + 1 + j);
38876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				adjblocks += old_desc_blocks;
38976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			}
39076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		} else {
39176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super)
39276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				has_super = 1;
39376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (((i % meta_bg_size) == 0) ||
39476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == 1) ||
39576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == (meta_bg_size-1)))
3961e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_mark_block_bitmap(fs->block_map,
39776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o						 group_block + has_super);
39824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
39976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
4001e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		adjblocks += 2 + fs->inode_blocks_per_group;
4011e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
4021e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		numblocks -= adjblocks;
4031e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->super->s_free_blocks_count -= adjblocks;
4041e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->super->s_free_inodes_count +=
4051e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			fs->super->s_inodes_per_group;
4061e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_free_blocks_count = numblocks;
4071e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_free_inodes_count =
4081e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			fs->super->s_inodes_per_group;
4091e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_used_dirs_count = 0;
41024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
4111e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		retval = ext2fs_allocate_group_table(fs, i, 0);
412c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (retval) goto errout;
41324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
414bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		group_block += fs->super->s_blocks_per_group;
415bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
416bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	retval = 0;
417bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
418bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'oerrout:
419bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	return (retval);
420bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o}
421bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
422bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o/*
423bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o * This routine adjusts the superblock and other data structures, both
424bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o * in disk as well as in memory...
425bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o */
426bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'ostatic errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
427bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o{
428bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2_filsys fs;
429bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	int		adj = 0;
430bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	errcode_t	retval;
431bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	blk_t		group_block;
432bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	unsigned long	i;
433bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	unsigned long	max_group;
434bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
435bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	fs = rfs->new_fs;
436bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2fs_mark_super_dirty(fs);
437bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2fs_mark_bb_dirty(fs);
438bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	ext2fs_mark_ib_dirty(fs);
439bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
440bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	retval = adjust_fs_info(fs, rfs->old_fs, new_size);
441bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (retval)
442bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
443bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
444bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	/*
445bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * Check to make sure there are enough inodes
446bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 */
447bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if ((rfs->old_fs->super->s_inodes_count -
448bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	     rfs->old_fs->super->s_free_inodes_count) >
449bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	    rfs->new_fs->super->s_inodes_count) {
450bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = ENOSPC;
451bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
452bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
453bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
454bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	/*
455bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * If we are shrinking the number block groups, we're done and
456bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * can exit now.
457bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 */
458bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
459bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = 0;
460bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
461bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
462bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
463bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	/*
464bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * If the number of block groups is staying the same, we're
465bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * done and can exit now.  (If the number block groups is
466bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * shrinking, we had exited earlier.)
467bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 */
468bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
469bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = 0;
470bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
471bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
472bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
473bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	/*
474bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 * Initialize the new block group descriptors
475bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	 */
476bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
477bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o				&rfs->itable_buf);
478bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (retval)
479bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		goto errout;
480bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
481bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
482bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	group_block = fs->super->s_first_data_block +
483bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
484bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o
485bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	adj = rfs->old_fs->group_desc_count;
486bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	max_group = fs->group_desc_count - adj;
487bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	if (rfs->progress) {
488bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
489bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o				       0, max_group);
490bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o		if (retval)
491bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o			goto errout;
492bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	}
493bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	for (i = rfs->old_fs->group_desc_count;
494bf69235ad0073c80386b70caba0e1b58e5f85697Theodore Ts'o	     i < fs->group_desc_count; i++) {
49505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		/*
49605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 * Write out the new inode table
49705e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 */
49805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		retval = io_channel_write_blk(fs->io,
49905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      fs->group_desc[i].bg_inode_table,
50005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      fs->inode_blocks_per_group,
50105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      rfs->itable_buf);
502c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (retval) goto errout;
503c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
504a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
5053b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (rfs->progress) {
5063b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
5073b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					       i - adj + 1, max_group);
5083b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			if (retval)
5093b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				goto errout;
5103b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		}
5111e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		group_block += fs->super->s_blocks_per_group;
51224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
513c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	io_channel_flush(fs->io);
514c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = 0;
515c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
516c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'oerrout:
517c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	return retval;
518c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o}
519c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
520a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
521a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
522a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 2.
523a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
524a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we adjust determine which blocks need to be moved, in
525a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * blocks_to_move().  We then copy the blocks to their ultimate new
526a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * destinations using block_mover().  Since we are copying blocks to
527a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * their new locations, again during this pass we can abort without
528a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * any problems.
529a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
530a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
531a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
532c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o/*
533c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o * This helper function creates a block bitmap with all of the
534c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o * filesystem meta-data blocks.
535c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o */
536c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t mark_table_blocks(ext2_filsys fs,
53764ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o				   ext2fs_block_bitmap bmap)
538c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o{
539c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	blk_t			block, b;
540544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int		j;
541544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	dgrp_t			i;
54268963d5a262ad49cbdad8f946e59ebc34677fe33Theodore Ts'o	unsigned long		meta_bg_size;
543544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int		old_desc_blocks;
544c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
54576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
546c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	block = fs->super->s_first_data_block;
54776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
54876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_desc_blocks = fs->super->s_first_meta_bg;
54976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	else
5509213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		old_desc_blocks = fs->desc_blocks +
5519213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o			fs->super->s_reserved_gdt_blocks;
552c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	for (i = 0; i < fs->group_desc_count; i++) {
55364ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		ext2fs_reserve_super_and_bgd(fs, i, bmap);
55476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
555c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
556c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark the blocks used for the inode table
557c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
558c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		for (j = 0, b = fs->group_desc[i].bg_inode_table;
559544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		     j < (unsigned int) fs->inode_blocks_per_group;
560c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j++, b++)
561c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(bmap, b);
562c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
563c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
564c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark block used for the block bitmap
565c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
566c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_mark_block_bitmap(bmap,
567c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					 fs->group_desc[i].bg_block_bitmap);
56864ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
569c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
570c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark block used for the inode bitmap
571c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
572c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_mark_block_bitmap(bmap,
573c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					 fs->group_desc[i].bg_inode_bitmap);
574c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		block += fs->super->s_blocks_per_group;
575c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
5761e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	return 0;
57724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o}
57824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
57924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
58076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o * This function checks to see if a particular block (either a
58176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o * superblock or a block group descriptor) overlaps with an inode or
58276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o * block bitmap block, or with the inode table.
58376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o */
58476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'ostatic void mark_fs_metablock(ext2_resize_t rfs,
58576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			      ext2fs_block_bitmap meta_bmap,
58676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			      int group, blk_t blk)
58776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o{
58876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	ext2_filsys 	fs = rfs->new_fs;
58976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
59076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
59176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, blk);
59276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
59376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	/*
59476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 * Check to see if we overlap with the inode or block bitmap,
59576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 * or the inode tables.  If not, and the block is in use, then
59676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 * mark it as a block to be moved.
59776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 */
59876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (IS_BLOCK_BM(fs, group, blk)) {
59976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		FS_BLOCK_BM(fs, group) = 0;
60076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
60176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else if (IS_INODE_BM(fs, group, blk)) {
60276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		FS_INODE_BM(fs, group) = 0;
60376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
60476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else if (IS_INODE_TB(fs, group, blk)) {
60576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		FS_INODE_TB(fs, group) = 0;
60676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
60776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk) &&
60876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		   !ext2fs_test_block_bitmap(meta_bmap, blk)) {
60976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
61076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
61176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	}
61276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o}
61376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
61476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
61576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o/*
61624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * This routine marks and unmarks reserved blocks in the new block
61724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * bitmap.  It also determines which blocks need to be moved and
61824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * places this information into the move_blocks bitmap.
61924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
620c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t blocks_to_move(ext2_resize_t rfs)
62124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o{
622544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	int		j, has_super;
623544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	dgrp_t		i, max_groups;
624544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	blk_t		blk, group_blk;
625544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned long	old_blocks, new_blocks;
626544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	meta_bg, meta_bg_size;
62724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	errcode_t	retval;
628c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2_filsys 	fs, old_fs;
629c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2fs_block_bitmap	meta_bmap;
63024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
631c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs = rfs->new_fs;
632c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	old_fs = rfs->old_fs;
633c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
634c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		fs = rfs->old_fs;
635c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
636a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, _("reserved blocks"),
6371e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o					      &rfs->reserve_blocks);
63824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (retval)
63924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return retval;
6401e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
641a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
642c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					      &rfs->move_blocks);
643c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
644c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
645c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
64664ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, _("meta-data blocks"),
64764ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o					      &meta_bmap);
64864ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	if (retval)
64964ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		return retval;
65064ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
65164ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	retval = mark_table_blocks(old_fs, meta_bmap);
652c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
653c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
654c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
655c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs = rfs->new_fs;
656c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
6571e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
6581e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * If we're shrinking the filesystem, we need to move all of
6591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * the blocks that don't fit any more
6601e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
6611e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	for (blk = fs->super->s_blocks_count;
662c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	     blk < old_fs->super->s_blocks_count; blk++) {
663c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
664c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    !ext2fs_test_block_bitmap(meta_bmap, blk)) {
665c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
6661e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			rfs->needed_blocks++;
667c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
6681e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
6691e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	}
67024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
67176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) {
67276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_blocks = old_fs->super->s_first_meta_bg;
67376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		new_blocks = fs->super->s_first_meta_bg;
67476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else {
6759213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		old_blocks = old_fs->desc_blocks + old_fs->super->s_reserved_gdt_blocks;
6769213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		new_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
67776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	}
67876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
679c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (old_blocks == new_blocks) {
680c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
681c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
682c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
68324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
6841333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	max_groups = fs->group_desc_count;
6851333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	if (max_groups > old_fs->group_desc_count)
6861333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o		max_groups = old_fs->group_desc_count;
687c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	group_blk = old_fs->super->s_first_data_block;
68824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
68924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * If we're reducing the number of descriptor blocks, this
69024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * makes life easy.  :-)   We just have to mark some extra
69124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * blocks as free.
69224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
69324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (old_blocks > new_blocks) {
6941333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o		for (i = 0; i < max_groups; i++) {
6951e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			if (!ext2fs_bg_has_super(fs, i)) {
6961e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				group_blk += fs->super->s_blocks_per_group;
69724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o				continue;
69824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			}
699c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			for (blk = group_blk+1+new_blocks;
700c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			     blk < group_blk+1+old_blocks; blk++) {
7011e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_unmark_block_bitmap(fs->block_map,
70224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o							   blk);
703052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				rfs->needed_blocks--;
704052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			}
7051e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			group_blk += fs->super->s_blocks_per_group;
70624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
707c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
708c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
70924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
71024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
71124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * If we're increasing the number of descriptor blocks, life
7121e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * gets interesting....
71324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
71476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
7151333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	for (i = 0; i < max_groups; i++) {
71676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		has_super = ext2fs_bg_has_super(fs, i);
71776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (has_super)
71876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			mark_fs_metablock(rfs, meta_bmap, i, group_blk);
71976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
72076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		meta_bg = i / meta_bg_size;
72176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (!(fs->super->s_feature_incompat &
72276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		      EXT2_FEATURE_INCOMPAT_META_BG) ||
72376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		    (meta_bg < fs->super->s_first_meta_bg)) {
724424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o			if (has_super) {
725424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o				for (blk = group_blk+1;
726424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o				     blk < group_blk + 1 + new_blocks; blk++)
727424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o					mark_fs_metablock(rfs, meta_bmap,
728424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o							  i, blk);
729424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o			}
73076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		} else {
73176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super)
73276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				has_super = 1;
73376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (((i % meta_bg_size) == 0) ||
73476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == 1) ||
73576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == (meta_bg_size-1)))
73676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				mark_fs_metablock(rfs, meta_bmap, i,
73776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o						  group_blk + has_super);
73824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
73976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
7401e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_table &&
7411e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		    fs->group_desc[i].bg_inode_bitmap &&
7421e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		    fs->group_desc[i].bg_block_bitmap)
7431e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			goto next_group;
74424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
7451e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
746c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Reserve the existing meta blocks that we know
747c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * aren't to be moved.
7481e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
7491e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_block_bitmap)
7501e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks,
7511e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 fs->group_desc[i].bg_block_bitmap);
7521e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_bitmap)
7531e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks,
7541e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 fs->group_desc[i].bg_inode_bitmap);
7551e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_table)
7561e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			for (blk = fs->group_desc[i].bg_inode_table, j=0;
7571e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			     j < fs->inode_blocks_per_group ; j++, blk++)
7581e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->reserve_blocks,
7591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o							 blk);
76024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
761c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
762c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Allocate the missing data structures
763c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
7641e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		retval = ext2fs_allocate_group_table(fs, i,
7651e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o						     rfs->reserve_blocks);
7661e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (retval)
767c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			goto errout;
76824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
7691e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
770c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * For those structures that have changed, we need to
771c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * do bookkeepping.
7721e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
773c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_BLOCK_BM(old_fs, i) !=
774c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    (blk = FS_BLOCK_BM(fs, i))) {
775c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
776c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
777c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
778c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
779c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
780c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
781c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_INODE_BM(old_fs, i) !=
782c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    (blk = FS_INODE_BM(fs, i))) {
783c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
784c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
785c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
786c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
787c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
788c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
78924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
790052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		/*
791052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * The inode table, if we need to relocate it, is
792052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * handled specially.  We have to reserve the blocks
793052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * for both the old and the new inode table, since we
794052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * can't have the inode table be destroyed during the
795052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * block relocation phase.
796052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 */
797c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
798052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			goto next_group; /* inode table not moved */
799052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
800c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		rfs->needed_blocks += fs->inode_blocks_per_group;
801052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
802052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		/*
803052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * Mark the new inode table as in use in the new block
804c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * allocation bitmap, and move any blocks that might
805c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * be necessary.
806052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 */
8071e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		for (blk = fs->group_desc[i].bg_inode_table, j=0;
808c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++) {
8091e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
810c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
811c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
812c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
813c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
814c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
815c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
8161e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
817052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * Make sure the old inode table is reserved in the
818052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * block reservation bitmap.
8191e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
820052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
821052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++)
822052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
8231e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
8241e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	next_group:
8251e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		group_blk += rfs->new_fs->super->s_blocks_per_group;
8261e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	}
827c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = 0;
828c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
829c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'oerrout:
830c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (meta_bmap)
831c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_free_block_bitmap(meta_bmap);
832c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
833c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	return retval;
8341e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o}
83524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
836a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
837a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * This helper function tries to allocate a new block.  We try to
838a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * avoid hitting the original group descriptor blocks at least at
839a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * first, since we want to make it possible to recover from a badly
840a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * aborted resize operation as much as possible.
841a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
842a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In the future, I may further modify this routine to balance out
843a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * where we get the new blocks across the various block groups.
844a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Ideally we would allocate blocks that corresponded with the block
845a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * group of the containing inode, and keep contiguous blocks
846a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * together.  However, this very difficult to do efficiently, since we
847a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * don't have the necessary information up front.
848a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
849a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
850a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define AVOID_OLD	1
851a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define DESPERATION	2
852a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
853a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic void init_block_alloc(ext2_resize_t rfs)
854a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
855a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->alloc_state = AVOID_OLD;
856a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->new_blk = rfs->new_fs->super->s_first_data_block;
8572bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o#if 0
8582bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	/* HACK for testing */
8592bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	if (rfs->new_fs->super->s_blocks_count >
8602bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	    rfs->old_fs->super->s_blocks_count)
8612bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o		rfs->new_blk = rfs->old_fs->super->s_blocks_count;
8622bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o#endif
863a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
864a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
865a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic blk_t get_new_block(ext2_resize_t rfs)
866a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
867a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys	fs = rfs->new_fs;
868a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
869a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
870a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->new_blk >= fs->super->s_blocks_count) {
871a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->alloc_state == DESPERATION)
872a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				return 0;
873a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
874a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
875a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->flags & RESIZE_DEBUG_BMOVE)
876f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o				printf("Going into desperation mode "
877f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o				       "for block allocations\n");
878a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
879a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->alloc_state = DESPERATION;
880a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_blk = fs->super->s_first_data_block;
881a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
882a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
883a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ext2fs_test_block_bitmap(fs->block_map, rfs->new_blk) ||
884a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    ext2fs_test_block_bitmap(rfs->reserve_blocks,
885a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					     rfs->new_blk) ||
886a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    ((rfs->alloc_state == AVOID_OLD) &&
887bce49798f7f4380dff5693bc8308019b3cf8de25Theodore Ts'o		     (rfs->new_blk < rfs->old_fs->super->s_blocks_count) &&
888a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		     ext2fs_test_block_bitmap(rfs->old_fs->block_map,
889a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					      rfs->new_blk))) {
890a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_blk++;
891a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
892a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
893a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return rfs->new_blk;
894a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
895a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
896a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
897a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t block_mover(ext2_resize_t rfs)
898a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
899a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	blk_t			blk, old_blk, new_blk;
900a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys		fs = rfs->new_fs;
901a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys		old_fs = rfs->old_fs;
902a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
903a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			size, c;
904a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			to_move, moved;
9057d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	ext2_badblocks_list	badblock_list = 0;
9067d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	int			bb_modified = 0;
9077d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o
9087d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	retval = ext2fs_read_bb_inode(old_fs, &badblock_list);
9097d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	if (retval)
9107d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		return retval;
911a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
912a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_blk = fs->super->s_first_data_block;
913a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!rfs->itable_buf) {
914a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_get_mem(fs->blocksize *
915a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					fs->inode_blocks_per_group,
916c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					&rfs->itable_buf);
917a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval)
918a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			return retval;
919a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
920a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_create_extent_table(&rfs->bmap, 0);
921a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
922a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
923a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
924a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
925a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * The first step is to figure out where all of the blocks
926a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * will go.
927a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
928a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	to_move = moved = 0;
929a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	init_block_alloc(rfs);
930a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	for (blk = old_fs->super->s_first_data_block;
931a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     blk < old_fs->super->s_blocks_count; blk++) {
932a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ext2fs_test_block_bitmap(old_fs->block_map, blk))
933a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
934a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk))
935a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
9367d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		if (ext2fs_badblocks_list_test(badblock_list, blk)) {
9377d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			ext2fs_badblocks_list_del(badblock_list, blk);
9387d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			bb_modified++;
9397d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			continue;
9407d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		}
941a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
942a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		new_blk = get_new_block(rfs);
943a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!new_blk) {
944a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ENOSPC;
945a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
946a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
947a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_block_bitmap(fs->block_map, new_blk);
948a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_add_extent_entry(rfs->bmap, blk, new_blk);
949a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		to_move++;
950a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
951a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
952a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (to_move == 0) {
953cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o		if (rfs->bmap) {
954cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o			ext2fs_free_extent_table(rfs->bmap);
955cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o			rfs->bmap = 0;
956cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o		}
957a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = 0;
958a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
959a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
960a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
961a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
962a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Step two is to actually move the blocks
963a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
964a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval =  ext2fs_iterate_extent(rfs->bmap, 0, 0, 0);
965a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
966a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
9673b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
9683b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS,
9693b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 0, to_move);
9703b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
9713b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
9723b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
973a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
974a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size);
975a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
976a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!size)
977a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			break;
978a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
979a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_BMOVE)
980f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			printf("Moving %d blocks %u->%u\n",
981f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			       size, old_blk, new_blk);
982a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
983a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		do {
984a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			c = size;
985a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (c > fs->inode_blocks_per_group)
986a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				c = fs->inode_blocks_per_group;
987a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = io_channel_read_blk(fs->io, old_blk, c,
988a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						     rfs->itable_buf);
989a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
990a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = io_channel_write_blk(fs->io, new_blk, c,
991a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						      rfs->itable_buf);
992a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
993a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			size -= c;
994a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			new_blk += c;
995a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			old_blk += c;
996a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			moved += c;
997a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->progress) {
998a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				io_channel_flush(fs->io);
9993b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				retval = (rfs->progress)(rfs,
10003b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o						E2_RSZ_BLOCK_RELOC_PASS,
1001a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						moved, to_move);
10023b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				if (retval)
10033b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					goto errout;
1004a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1005a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		} while (size > 0);
1006a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
1007a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1008a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1009a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
10107d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	if (badblock_list) {
10117d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		if (!retval && bb_modified)
10127d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			retval = ext2fs_update_bb_inode(old_fs,
10137d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o							badblock_list);
10147d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		ext2fs_badblocks_list_free(badblock_list);
10157d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	}
1016a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1017a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1018a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1019a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1020a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1021a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1022a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 3
1023a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1024a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1025a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1026a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1027a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1028a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostruct process_block_struct {
1029a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t 		rfs;
1030dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t		ino;
1031a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct ext2_inode *	inode;
1032a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		error;
1033a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			is_dir;
1034a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			changed;
1035a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o};
1036a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1037a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic int process_block(ext2_filsys fs, blk_t	*block_nr,
1038544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			 e2_blkcnt_t blockcnt,
1039544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			 blk_t ref_block EXT2FS_ATTR((unused)),
1040544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			 int ref_offset EXT2FS_ATTR((unused)), void *priv_data)
1041a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1042a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct process_block_struct *pb;
1043a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
1044a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	blk_t		block, new_block;
1045a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int		ret = 0;
1046a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1047a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb = (struct process_block_struct *) priv_data;
1048a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	block = *block_nr;
1049a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (pb->rfs->bmap) {
1050a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		new_block = ext2fs_extent_translate(pb->rfs->bmap, block);
1051a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (new_block) {
1052a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			*block_nr = new_block;
1053a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ret |= BLOCK_CHANGED;
1054a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb->changed = 1;
1055a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1056a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
1057f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o				printf("ino=%u, blockcnt=%lld, %u->%u\n",
1058a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				       pb->ino, blockcnt, block, new_block);
1059a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1060a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			block = new_block;
1061a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1062a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1063a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (pb->is_dir) {
1064a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
1065101c84f2e049bffcdb6c5ba1784842cdd50dbf05Theodore Ts'o					      block, (int) blockcnt);
1066a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) {
1067a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb->error = retval;
1068a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ret |= BLOCK_ABORT;
1069a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1070a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1071a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return ret;
1072a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1073a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1074a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
1075a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Progress callback
1076a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1077544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic errcode_t progress_callback(ext2_filsys fs,
1078544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   ext2_inode_scan scan EXT2FS_ATTR((unused)),
1079a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   dgrp_t group, void * priv_data)
1080a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1081a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t rfs = (ext2_resize_t) priv_data;
10823b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	errcode_t		retval;
1083a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1084a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1085f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	 * This check is to protect against old ext2 libraries.  It
1086f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	 * shouldn't be needed against new libraries.
1087a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1088f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	if ((group+1) == 0)
1089a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1090a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1091a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->progress) {
1092a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
10933b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
10943b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 group+1, fs->group_desc_count);
10953b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
10963b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			return retval;
1097a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1098a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1099a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return 0;
1100a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1101a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1102a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_scan_and_fix(ext2_resize_t rfs)
1103a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1104a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct process_block_struct	pb;
1105dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t		ino, new_inode;
1106a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct ext2_inode 	inode;
1107a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_inode_scan 	scan = NULL;
1108a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
1109a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			group;
1110a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	char			*block_buf = 0;
1111dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t		start_to_move;
11120ccd488a764c14b27983b92435deca5e1adf9061Theodore Ts'o	blk_t			orig_size, new_block;
1113a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1114a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if ((rfs->old_fs->group_desc_count <=
1115a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     rfs->new_fs->group_desc_count) &&
1116a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	    !rfs->bmap)
1117a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1118a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
11192bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	/*
11202bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * Save the original size of the old filesystem, and
11212bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * temporarily set the size to be the new size if the new size
11222bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * is larger.  We need to do this to avoid catching an error
11232bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * by the block iterator routines
11242bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 */
11252bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	orig_size = rfs->old_fs->super->s_blocks_count;
11262bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	if (orig_size < rfs->new_fs->super->s_blocks_count)
11272bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o		rfs->old_fs->super->s_blocks_count =
11282bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o			rfs->new_fs->super->s_blocks_count;
11292bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o
1130a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
1131a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
1132a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1133a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_init_dblist(rfs->old_fs, 0);
1134a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
1135c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(rfs->old_fs->blocksize * 3, &block_buf);
1136a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
1137a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1138a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	start_to_move = (rfs->new_fs->group_desc_count *
1139a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			 rfs->new_fs->super->s_inodes_per_group);
1140a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
11413b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
11423b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
11433b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 0, rfs->old_fs->group_desc_count);
11443b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
11453b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
11463b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1147a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
1148a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.rfs = rfs;
1149a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.inode = &inode;
1150a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.error = 0;
1151a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
1152a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1153a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * First, copy all of the inodes that need to be moved
1154a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * elsewhere in the inode table
1155a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1156a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
1157a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_get_next_inode(scan, &ino, &inode);
1158a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
1159a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ino)
1160a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			break;
1161a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
11629213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		if (inode.i_links_count == 0 && ino != EXT2_RESIZE_INO)
1163a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue; /* inode not in use */
1164a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1165a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
1166a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		pb.changed = 0;
1167a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
11680ccd488a764c14b27983b92435deca5e1adf9061Theodore Ts'o		if (inode.i_file_acl && rfs->bmap) {
11690ccd488a764c14b27983b92435deca5e1adf9061Theodore Ts'o			new_block = ext2fs_extent_translate(rfs->bmap,
1170ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o							    inode.i_file_acl);
1171ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o			if (new_block) {
1172ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o				inode.i_file_acl = new_block;
1173ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o				retval = ext2fs_write_inode(rfs->old_fs,
1174ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o							    ino, &inode);
1175ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o				if (retval) goto errout;
1176ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o			}
1177ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o		}
1178ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o
1179a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ext2fs_inode_has_valid_blocks(&inode) &&
1180a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    (rfs->bmap || pb.is_dir)) {
1181a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb.ino = ino;
1182a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_block_iterate2(rfs->old_fs,
1183a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						       ino, 0, block_buf,
1184a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						       process_block, &pb);
1185a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval)
1186a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1187a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (pb.error) {
1188a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				retval = pb.error;
1189a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1190a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1191a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1192a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1193a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ino <= start_to_move)
1194a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue; /* Don't need to move it. */
1195a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1196a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		/*
1197a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * Find a new inode
1198a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 */
1199a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		while (1) {
1200a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map,
1201a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						      new_inode))
1202a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				break;
1203a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			new_inode++;
1204a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (new_inode > rfs->new_fs->super->s_inodes_count) {
1205a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				retval = ENOSPC;
1206a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1207a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1208a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1209a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new_inode);
1210a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (pb.changed) {
1211a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			/* Get the new version of the inode */
1212a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_read_inode(rfs->old_fs, ino, &inode);
1213a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
1214a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1215085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o		inode.i_ctime = time(0);
1216a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_write_inode(rfs->old_fs, new_inode, &inode);
1217a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
1218a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1219a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
1220a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (LINUX_S_ISDIR(inode.i_mode))
1221a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_fs->group_desc[group].bg_used_dirs_count++;
1222a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1223a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1224a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_INODEMAP)
1225f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			printf("Inode moved %u->%u\n", ino, new_inode);
1226a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1227a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!rfs->imap) {
1228a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_create_extent_table(&rfs->imap, 0);
1229a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval)
1230a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1231a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1232a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
1233a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1234a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	io_channel_flush(rfs->old_fs->io);
1235a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1236a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
12372bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	rfs->old_fs->super->s_blocks_count = orig_size;
1238a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->bmap) {
1239a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_extent_table(rfs->bmap);
1240a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		rfs->bmap = 0;
1241a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1242a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (scan)
1243a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_close_inode_scan(scan);
1244a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (block_buf)
1245c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&block_buf);
1246a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1247a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1248a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1249a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1250a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1251a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 4.
1252a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1253a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1254a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1255a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1256a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostruct istruct {
1257a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t rfs;
12583b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	errcode_t	err;
12591333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	unsigned long	max_dirs;
1260a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int		num;
1261a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o};
1262a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1263544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic int check_and_change_inodes(ext2_ino_t dir,
1264544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   int entry EXT2FS_ATTR((unused)),
1265a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   struct ext2_dir_entry *dirent, int offset,
1266544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   int	blocksize EXT2FS_ATTR((unused)),
1267544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   char *buf EXT2FS_ATTR((unused)),
1268544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o				   void *priv_data)
1269a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1270a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct istruct *is = (struct istruct *) priv_data;
1271085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	struct ext2_inode 	inode;
1272085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	ext2_ino_t		new_inode;
1273085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	errcode_t		retval;
1274a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1275a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (is->rfs->progress && offset == 0) {
1276a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(is->rfs->old_fs->io);
12773b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		is->err = (is->rfs->progress)(is->rfs,
12783b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					      E2_RSZ_INODE_REF_UPD_PASS,
12791333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o					      ++is->num, is->max_dirs);
12803b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (is->err)
12813b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			return DIRENT_ABORT;
1282a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1283a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1284a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!dirent->inode)
1285a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1286a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1287a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
1288a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1289a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!new_inode)
1290a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1291a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1292a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
1293f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o		printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
129406191693d4d253a8496677dd02e3b8529a7fce2cTheodore Ts'o		       dir, dirent->name_len&0xFF, dirent->name,
1295a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       dirent->inode, new_inode);
1296a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1297a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1298a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	dirent->inode = new_inode;
1299a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1300085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	/* Update the directory mtime and ctime */
1301085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
1302085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	if (retval == 0) {
1303085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o		inode.i_mtime = inode.i_ctime = time(0);
1304085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o		ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
1305085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	}
1306085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o
1307a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return DIRENT_CHANGED;
1308a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1309a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1310a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_ref_fix(ext2_resize_t rfs)
1311a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1312a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
1313a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct istruct 		is;
1314a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1315a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!rfs->imap)
1316a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1317a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1318a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1319a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Now, we iterate over all of the directories to update the
1320a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * inode references
1321a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1322a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	is.num = 0;
13231333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	is.max_dirs = ext2fs_dblist_count(rfs->old_fs->dblist);
1324a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	is.rfs = rfs;
13253b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	is.err = 0;
1326a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
13273b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
13283b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
13291333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o					 0, is.max_dirs);
13303b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
13313b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
13323b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1333a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1334a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
1335a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   DIRENT_FLAG_INCLUDE_EMPTY, 0,
1336a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   check_and_change_inodes, &is);
13373b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (retval)
13383b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		goto errout;
13393b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (is.err) {
13403b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = is.err;
13413b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		goto errout;
13423b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1343a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
13443b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'oerrout:
1345a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free_extent_table(rfs->imap);
1346a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->imap = 0;
1347a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1348a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1349a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1350a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1351a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1352a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1353a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 5.
1354a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1355a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we actually move the inode table around, and then
1356a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * update the summary statistics.  This is scary, since aborting here
1357a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * will potentially scramble the filesystem.  (We are moving the
1358a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode tables around in place, and so the potential for lost data,
1359a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * or at the very least scrambling the mapping between filenames and
1360a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode numbers is very high in case of a power failure here.)
1361a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1362a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1363a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
136424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
136524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
1366052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * A very scary routine --- this one moves the inode table around!!!
1367052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o *
1368052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * After this you have to use the rfs->new_fs file handle to read and
1369052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * write inodes.
1370052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o */
1371c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t move_itables(ext2_resize_t rfs)
1372052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o{
1373544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	int		n, num, size, diff;
1374544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	dgrp_t		i, max_groups;
1375052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	ext2_filsys	fs = rfs->new_fs;
137605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	char		*cp;
137764ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	blk_t		old_blk, new_blk, blk;
1378a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
137964ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	int		j, to_move, moved;
1380052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
13811333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	max_groups = fs->group_desc_count;
13821333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	if (max_groups > rfs->old_fs->group_desc_count)
13831333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o		max_groups = rfs->old_fs->group_desc_count;
1384052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
138505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	size = fs->blocksize * fs->inode_blocks_per_group;
138605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	if (!rfs->itable_buf) {
1387c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		retval = ext2fs_get_mem(size, &rfs->itable_buf);
1388ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		if (retval)
1389ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			return retval;
139005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	}
1391c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
1392c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	/*
1393c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 * Figure out how many inode tables we need to move
1394c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 */
1395c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	to_move = moved = 0;
13961333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	for (i=0; i < max_groups; i++)
1397c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (rfs->old_fs->group_desc[i].bg_inode_table !=
1398c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    fs->group_desc[i].bg_inode_table)
1399c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			to_move++;
1400c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
1401c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (to_move == 0)
1402c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return 0;
1403c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
14043b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
14053b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
14063b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				       0, to_move);
14073b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
14083b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
14093b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
141063b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o
1411a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
1412a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
14131333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	for (i=0; i < max_groups; i++) {
1414ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		old_blk = rfs->old_fs->group_desc[i].bg_inode_table;
1415ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		new_blk = fs->group_desc[i].bg_inode_table;
1416ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		diff = new_blk - old_blk;
1417052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
141880c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
141905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1420f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			printf("Itable move group %d block %u->%u (diff %d)\n",
1421ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			       i, old_blk, new_blk, diff);
142280c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
1423052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
142405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (!diff)
1425052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			continue;
1426052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1427ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = io_channel_read_blk(fs->io, old_blk,
142805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     fs->inode_blocks_per_group,
142905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     rfs->itable_buf);
1430052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (retval)
1431a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
143205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		/*
143305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 * The end of the inode table segment often contains
1434a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * all zeros, and we're often only moving the inode
1435a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * table down a block or two.  If so, we can optimize
1436a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * things by not rewriting blocks that we know to be zero
1437a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * already.
143805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 */
14392787276ec59e1d52087d307bc30446d088ec65bcTheodore Ts'o		for (cp = rfs->itable_buf+size-1, n=0; n < size; n++, cp--)
144005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			if (*cp)
144105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o				break;
144205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
144380c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
144405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1445f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			printf("%d blocks of zeros...\n", n);
144680c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
144705e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		num = fs->inode_blocks_per_group;
144805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (n > diff)
144905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			num -= n;
145005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o
1451ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = io_channel_write_blk(fs->io, new_blk,
145205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      num, rfs->itable_buf);
1453052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (retval) {
1454ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			io_channel_write_blk(fs->io, old_blk,
145505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     num, rfs->itable_buf);
1456a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
1457052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
145805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (n > diff) {
145905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			retval = io_channel_write_blk(fs->io,
1460ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			      old_blk + fs->inode_blocks_per_group,
1461a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			      diff, (rfs->itable_buf +
1462a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     (fs->inode_blocks_per_group - diff) *
1463a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     fs->blocksize));
146405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			if (retval)
1465a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1466c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
146764ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
146864ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
146964ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++)
147064ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o			ext2fs_unmark_block_bitmap(fs->block_map, blk);
147164ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
1472a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
1473a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_super_dirty(rfs->old_fs);
147464ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o		ext2fs_flush(rfs->old_fs);
147564ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o
1476a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->progress) {
14773b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
14783b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					       ++moved, to_move);
14793b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			if (retval)
14803b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				goto errout;
1481a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1482052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
148364ad98acbe694e74925ad4e4fc88fd10fd3b3a44Theodore Ts'o	mark_table_blocks(fs, fs->block_map);
1484a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_flush(fs);
148580c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
148605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1487f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o		printf("Inode table move finished.\n");
148880c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
1489052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return 0;
1490052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1491a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
1492052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return retval;
1493052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o}
1494052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1495052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o/*
14969213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o * Fix the resize inode
14979213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o */
14989213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'ostatic errcode_t fix_resize_inode(ext2_filsys fs)
14999213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o{
15009213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	struct ext2_inode	inode;
15019213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	errcode_t		retval;
15029213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	char *			block_buf;
15039213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15049213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (!(fs->super->s_feature_compat &
15059213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	      EXT2_FEATURE_COMPAT_RESIZE_INODE))
15069213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		return 0;
15079213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15089213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = ext2fs_get_mem(fs->blocksize, &block_buf);
15099213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval) goto errout;
15109213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15119213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
15129213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval) goto errout;
15139213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15149213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	inode.i_blocks = fs->blocksize/512;
15159213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15169213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
15179213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval) goto errout;
15189213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15199213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (!inode.i_block[EXT2_DIND_BLOCK]) {
15209213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		/*
15219213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		 * Avoid zeroing out block #0; that's rude.  This
15229213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		 * should never happen anyway since the filesystem
15239213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		 * should be fsck'ed and we assume it is consistent.
15249213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		 */
15259213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		fprintf(stderr,
1526f35fd3d5eeb3e35660ea87adbc170978c3cdf9e3Theodore Ts'o			_("Should never happen: resize inode corrupt!\n"));
15279213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		exit(1);
15289213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	}
15299213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15309213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	memset(block_buf, 0, fs->blocksize);
15319213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15329213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = io_channel_write_blk(fs->io, inode.i_block[EXT2_DIND_BLOCK],
15339213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o				      1, block_buf);
15349213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval) goto errout;
15359213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15369213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	retval = ext2fs_create_resize_inode(fs);
15379213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (retval)
15389213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		goto errout;
15399213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15409213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'oerrout:
15419213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	if (block_buf)
15429213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o		ext2fs_free_mem(&block_buf);
15439213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o	return retval;
15449213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o}
15459213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o
15469213a93b22accd2a27064b12f6bc5f1221ca6a70Theodore Ts'o/*
1547052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * Finally, recalculate the summary information
1548052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o */
1549052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'ostatic errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1550052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o{
1551dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	blk_t		blk;
1552dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t	ino;
1553544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	group = 0;
1554544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	unsigned int	count = 0;
1555dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	int		total_free = 0;
1556dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	int		group_free = 0;
1557052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1558052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	/*
1559052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 * First calculate the block statistics
1560052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 */
1561052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	for (blk = fs->super->s_first_data_block;
1562052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	     blk < fs->super->s_blocks_count; blk++) {
1563052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
1564052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free++;
1565052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			total_free++;
1566052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1567052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		count++;
1568052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if ((count == fs->super->s_blocks_per_group) ||
1569052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		    (blk == fs->super->s_blocks_count-1)) {
1570052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			fs->group_desc[group++].bg_free_blocks_count =
1571052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				group_free;
1572052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			count = 0;
1573052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free = 0;
1574052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1575052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1576052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	fs->super->s_free_blocks_count = total_free;
1577052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1578052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	/*
1579052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 * Next, calculate the inode statistics
1580052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 */
1581052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	group_free = 0;
1582052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	total_free = 0;
1583052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	count = 0;
1584052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	group = 0;
15855830d6be9c33e23bb20c339036083e6e4fa6795eEric Sandeen
15865830d6be9c33e23bb20c339036083e6e4fa6795eEric Sandeen	/* Protect loop from wrap-around if s_inodes_count maxed */
15875830d6be9c33e23bb20c339036083e6e4fa6795eEric Sandeen	for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
1588052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
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_inodes_per_group) ||
1594052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		    (ino == fs->super->s_inodes_count)) {
1595052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			fs->group_desc[group++].bg_free_inodes_count =
1596052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				group_free;
1597052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			count = 0;
1598052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free = 0;
1599052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1600052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1601052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	fs->super->s_free_inodes_count = total_free;
1602052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	ext2fs_mark_super_dirty(fs);
1603052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return 0;
1604052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o}
1605