resize2fs.c revision 7d7bdd578b307cad1dc248310eb279c6fb73b682
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"
3724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
38546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'o#ifdef __linux__			/* Kludge for debugging */
39a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define RESIZE2FS_DEBUG
40a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
41a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
42a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size);
43a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t blocks_to_move(ext2_resize_t rfs);
44a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t block_mover(ext2_resize_t rfs);
45a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_scan_and_fix(ext2_resize_t rfs);
46a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_ref_fix(ext2_resize_t rfs);
47a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t move_itables(ext2_resize_t rfs);
48a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
49a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
50a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
51a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Some helper CPP macros
52a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
53a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define FS_BLOCK_BM(fs, i) ((fs)->group_desc[(i)].bg_block_bitmap)
54a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define FS_INODE_BM(fs, i) ((fs)->group_desc[(i)].bg_inode_bitmap)
55a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define FS_INODE_TB(fs, i) ((fs)->group_desc[(i)].bg_inode_table)
56a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
57a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define IS_BLOCK_BM(fs, i, blk) ((blk) == FS_BLOCK_BM((fs),(i)))
58a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define IS_INODE_BM(fs, i, blk) ((blk) == FS_INODE_BM((fs),(i)))
59a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
60a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define IS_INODE_TB(fs, i, blk) (((blk) >= FS_INODE_TB((fs), (i))) && \
61a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				 ((blk) < (FS_INODE_TB((fs), (i)) + \
62a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   (fs)->inode_blocks_per_group)))
63a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
64a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
65a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
66a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
67a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * This is the top-level routine which does the dirty deed....
68a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
69116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'oerrcode_t resize_fs(ext2_filsys fs, blk_t *new_size, int flags,
703b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		    errcode_t (*progress)(ext2_resize_t rfs, int pass,
71a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     unsigned long cur,
721333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o				     unsigned long max_val))
73a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
74a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t	rfs;
75a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
76a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
77a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_read_bitmaps(fs);
78a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
79a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
80a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
81a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
82a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Create the data structure
83a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
84a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct),
85a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				(void **) &rfs);
86a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
87a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
88a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	memset(rfs, 0, sizeof(struct ext2_resize_struct));
89a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
90a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->old_fs = fs;
91a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->flags = flags;
92a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->itable_buf	 = 0;
93a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->progress = progress;
94a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_dup_handle(fs, &rfs->new_fs);
95a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
96a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
97a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
98116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'o	retval = adjust_superblock(rfs, *new_size);
99a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
100a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
101a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
102116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'o	*new_size = rfs->new_fs->super->s_blocks_count;
103116db1b513f6901415d1f5f8c01fc297d7cc64a4Theodore Ts'o
104a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = blocks_to_move(rfs);
105a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
106a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
107a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
108a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
109a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->flags & RESIZE_DEBUG_BMOVE)
110a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o		printf(_("Number of free blocks: %d/%d, Needed: %d\n"),
111a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->old_fs->super->s_free_blocks_count,
112a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->new_fs->super->s_free_blocks_count,
113a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->needed_blocks);
114a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
115a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
116a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = block_mover(rfs);
117a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
118a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
119a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
120a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = inode_scan_and_fix(rfs);
121a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
122a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
123a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
124a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = inode_ref_fix(rfs);
125a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
126a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
127a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
128a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_calculate_summary_stats(rfs->new_fs);
129a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
130a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
131a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
132a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = move_itables(rfs);
133a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
134a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
135a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
136a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_close(rfs->new_fs);
137a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
138a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
139a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
140a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->flags = flags;
141a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
142a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free(rfs->old_fs);
143a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->itable_buf)
144a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_mem((void **) &rfs->itable_buf);
145a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free_mem((void **) &rfs);
146a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
147a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return 0;
148a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
149a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
150a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->new_fs)
151a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free(rfs->new_fs);
152a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->itable_buf)
153a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_mem((void **) &rfs->itable_buf);
154a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free_mem((void **) &rfs);
155a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
156a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
157a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
158a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
159a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
160a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 1.
161a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
162a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we adjust the in-memory superblock information, and
163a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * initialize any new parts of the inode table.  The new parts of the
164a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode table are created in virgin disk space, so we can abort here
165a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * without any side effects.
166a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
167a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
168a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
16924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
17024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * This routine adjusts the superblock and other data structures...
17124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
17224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'ostatic errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
17324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o{
17424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	ext2_filsys fs;
17524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	int		overhead = 0;
176c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	int		rem, adj = 0;
17724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	errcode_t	retval;
178dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t	real_end;
17924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	blk_t		blk, group_block;
1801e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	unsigned long	i, j;
1811e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	int		old_numblocks, numblocks, adjblocks;
18276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	int		has_super, meta_bg, meta_bg_size, old_desc_blocks;
18363b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o	unsigned long	max_group;
18424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
18524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs = rfs->new_fs;
18624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->super->s_blocks_count = new_size;
1871e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	ext2fs_mark_super_dirty(fs);
1881e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	ext2fs_mark_bb_dirty(fs);
1891e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	ext2fs_mark_ib_dirty(fs);
19024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
19124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'oretry:
19224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->group_desc_count = (fs->super->s_blocks_count -
19324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o				fs->super->s_first_data_block +
19424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o				EXT2_BLOCKS_PER_GROUP(fs->super) - 1)
19524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		/ EXT2_BLOCKS_PER_GROUP(fs->super);
19624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (fs->group_desc_count == 0)
19724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return EXT2_ET_TOOSMALL;
19824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->desc_blocks = (fs->group_desc_count +
19924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			   EXT2_DESC_PER_BLOCK(fs->super) - 1)
20024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		/ EXT2_DESC_PER_BLOCK(fs->super);
20124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
20224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
20324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Overhead is the number of bookkeeping blocks per group.  It
20424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * includes the superblock backup, the group descriptor
20524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * backups, the inode bitmap, the block bitmap, and the inode
20624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * table.
20724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 *
20824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * XXX Not all block groups need the descriptor blocks, but
20924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * being clever is tricky...
21024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
21124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
21224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore 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	 */
23524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	blk = rfs->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	 */
246c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	blk = rfs->old_fs->super->s_r_blocks_count * 100 /
247c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		rfs->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	 */
27024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (rfs->old_fs->desc_blocks != fs->desc_blocks) {
27176f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o		retval = ext2fs_resize_mem(rfs->old_fs->desc_blocks *
27276f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o					   fs->blocksize,
27376f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o					   fs->desc_blocks * fs->blocksize,
274ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o					   (void **) &fs->group_desc);
275ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		if (retval)
276a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
27724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
2781e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
2791e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
280a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Check to make sure there are enough inodes
281a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
282a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if ((rfs->old_fs->super->s_inodes_count -
283a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     rfs->old_fs->super->s_free_inodes_count) >
284a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	    rfs->new_fs->super->s_inodes_count) {
285a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ENOSPC;
286a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
287a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
288a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
289a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
290a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * If we are shrinking the number block groups, we're done and
291a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * can exit now.
2921e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
293c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
294c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
295c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
296c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
297a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
298a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Fix the count of the last (old) block group
299a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
3001e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	old_numblocks = (rfs->old_fs->super->s_blocks_count -
3011e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			 rfs->old_fs->super->s_first_data_block) %
3021e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 rfs->old_fs->super->s_blocks_per_group;
3031e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	if (!old_numblocks)
3041e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		old_numblocks = rfs->old_fs->super->s_blocks_per_group;
3051e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	if (rfs->old_fs->group_desc_count == fs->group_desc_count) {
3061e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		numblocks = (rfs->new_fs->super->s_blocks_count -
3071e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			     rfs->new_fs->super->s_first_data_block) %
3081e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				     rfs->new_fs->super->s_blocks_per_group;
3091e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (!numblocks)
3101e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = rfs->new_fs->super->s_blocks_per_group;
3111e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	} else
3121e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		numblocks = rfs->new_fs->super->s_blocks_per_group;
3131e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	i = rfs->old_fs->group_desc_count - 1;
3141e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
3151e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3161e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
317a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * If the number of block groups is staying the same, we're
318a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * done and can exit now.  (If the number block groups is
319a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * shrinking, we had exited earlier.)
3201e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
321c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
322c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
323c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
324c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
325a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
326a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Initialize the new block group descriptors
327a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
328ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o	retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
329ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o				(void **) &rfs->itable_buf);
330ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o	if (retval)
331c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
332ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o
33305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
3341e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	group_block = fs->super->s_first_data_block +
3351e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
336c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
33763b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o	adj = rfs->old_fs->group_desc_count;
33863b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o	max_group = fs->group_desc_count - adj;
3393b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
3403b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
3413b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				       0, max_group);
3423b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
3433b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
3443b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
34576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
34676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_desc_blocks = fs->super->s_first_meta_bg;
34776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	else
34876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_desc_blocks = fs->desc_blocks;
3491e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	for (i = rfs->old_fs->group_desc_count;
3501e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	     i < fs->group_desc_count; i++) {
3511e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		memset(&fs->group_desc[i], 0,
3521e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		       sizeof(struct ext2_group_desc));
3531e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		adjblocks = 0;
3541e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3551e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (i == fs->group_desc_count-1) {
3561e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = (fs->super->s_blocks_count -
3571e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				     fs->super->s_first_data_block) %
3581e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o					     fs->super->s_blocks_per_group;
3591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			if (!numblocks)
3601e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				numblocks = fs->super->s_blocks_per_group;
3611e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		} else
3621e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = fs->super->s_blocks_per_group;
3631e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
36476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		has_super = ext2fs_bg_has_super(fs, i);
36576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (has_super) {
36676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, group_block);
36776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			adjblocks++;
36876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		}
36976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		meta_bg_size = (fs->blocksize /
37076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				sizeof (struct ext2_group_desc));
37176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		meta_bg = i / meta_bg_size;
37276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (!(fs->super->s_feature_incompat &
37376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		      EXT2_FEATURE_INCOMPAT_META_BG) ||
37476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		    (meta_bg < fs->super->s_first_meta_bg)) {
37576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super) {
37676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				for (j=0; j < old_desc_blocks; j++)
37776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o					ext2fs_mark_block_bitmap(fs->block_map,
37876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o							 group_block + 1 + j);
37976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				adjblocks += old_desc_blocks;
38076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			}
38176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		} else {
38276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super)
38376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				has_super = 1;
38476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (((i % meta_bg_size) == 0) ||
38576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == 1) ||
38676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == (meta_bg_size-1)))
3871e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_mark_block_bitmap(fs->block_map,
38876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o						 group_block + has_super);
38924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
39076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
3911e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		adjblocks += 2 + fs->inode_blocks_per_group;
3921e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3931e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		numblocks -= adjblocks;
3941e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->super->s_free_blocks_count -= adjblocks;
3951e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->super->s_free_inodes_count +=
3961e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			fs->super->s_inodes_per_group;
3971e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_free_blocks_count = numblocks;
3981e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_free_inodes_count =
3991e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			fs->super->s_inodes_per_group;
4001e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_used_dirs_count = 0;
40124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
4021e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		retval = ext2fs_allocate_group_table(fs, i, 0);
403c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (retval) goto errout;
40424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
40505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		/*
40605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 * Write out the new inode table
40705e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 */
40805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		retval = io_channel_write_blk(fs->io,
40905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      fs->group_desc[i].bg_inode_table,
41005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      fs->inode_blocks_per_group,
41105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      rfs->itable_buf);
412c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (retval) goto errout;
413c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
414a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
4153b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (rfs->progress) {
4163b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
4173b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					       i - adj + 1, max_group);
4183b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			if (retval)
4193b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				goto errout;
4203b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		}
4211e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		group_block += fs->super->s_blocks_per_group;
42224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
423c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	io_channel_flush(fs->io);
424c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = 0;
425c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
426c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'oerrout:
427c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	return retval;
428c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o}
429c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
430a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
431a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
432a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 2.
433a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
434a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we adjust determine which blocks need to be moved, in
435a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * blocks_to_move().  We then copy the blocks to their ultimate new
436a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * destinations using block_mover().  Since we are copying blocks to
437a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * their new locations, again during this pass we can abort without
438a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * any problems.
439a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
440a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
441a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
442c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o/*
443c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o * This helper function creates a block bitmap with all of the
444c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o * filesystem meta-data blocks.
445c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o */
446c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t mark_table_blocks(ext2_filsys fs,
447c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				   ext2fs_block_bitmap *ret_bmap)
448c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o{
449c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	blk_t			block, b;
45076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	int			i,j, has_super, meta_bg, meta_bg_size;
45176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	int			old_desc_blocks;
452c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2fs_block_bitmap	bmap;
453c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	errcode_t		retval;
454c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
455a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, _("meta-data blocks"),
456a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o					      &bmap);
457c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
458c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
459c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
46076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
461c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	block = fs->super->s_first_data_block;
46276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
46376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_desc_blocks = fs->super->s_first_meta_bg;
46476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	else
46576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_desc_blocks = fs->desc_blocks;
466c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	for (i = 0; i < fs->group_desc_count; i++) {
46776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		has_super = ext2fs_bg_has_super(fs, i);
46876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (has_super)
469c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			/*
470c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			 * Mark this group's copy of the superblock
471c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			 */
472c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(bmap, block);
473c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
47476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		meta_bg = i / meta_bg_size;
475c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
47676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (!(fs->super->s_feature_incompat &
47776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		      EXT2_FEATURE_INCOMPAT_META_BG) ||
47876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		    (meta_bg < fs->super->s_first_meta_bg)) {
47976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super) {
48076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				/*
48176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				 * Mark this group's copy of the descriptors
48276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				 */
48376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				for (j = 0; j < old_desc_blocks; j++)
48476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o					ext2fs_mark_block_bitmap(bmap,
48576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o							 block + j + 1);
48676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			}
48776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		} else {
48876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super)
48976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				has_super = 1;
49076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (((i % meta_bg_size) == 0) ||
49176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == 1) ||
49276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == (meta_bg_size-1)))
49376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				ext2fs_mark_block_bitmap(bmap,
49476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o							 block + has_super);
49576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		}
49676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
497c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
498c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark the blocks used for the inode table
499c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
500c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		for (j = 0, b = fs->group_desc[i].bg_inode_table;
501c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j < fs->inode_blocks_per_group;
502c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j++, b++)
503c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(bmap, b);
504c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
505c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
506c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark block used for the block bitmap
507c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
508c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_mark_block_bitmap(bmap,
509c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					 fs->group_desc[i].bg_block_bitmap);
510c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
511c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark block used for the inode bitmap
512c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
513c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_mark_block_bitmap(bmap,
514c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					 fs->group_desc[i].bg_inode_bitmap);
515c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		block += fs->super->s_blocks_per_group;
516c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
517c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	*ret_bmap = bmap;
5181e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	return 0;
51924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o}
52024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
52124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
52276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o * This function checks to see if a particular block (either a
52376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o * superblock or a block group descriptor) overlaps with an inode or
52476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o * block bitmap block, or with the inode table.
52576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o */
52676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'ostatic void mark_fs_metablock(ext2_resize_t rfs,
52776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			      ext2fs_block_bitmap meta_bmap,
52876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			      int group, blk_t blk)
52976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o{
53076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	ext2_filsys 	fs = rfs->new_fs;
53176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
53276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
53376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	ext2fs_mark_block_bitmap(fs->block_map, blk);
53476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
53576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	/*
53676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 * Check to see if we overlap with the inode or block bitmap,
53776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 * or the inode tables.  If not, and the block is in use, then
53876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 * mark it as a block to be moved.
53976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	 */
54076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (IS_BLOCK_BM(fs, group, blk)) {
54176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		FS_BLOCK_BM(fs, group) = 0;
54276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
54376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else if (IS_INODE_BM(fs, group, blk)) {
54476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		FS_INODE_BM(fs, group) = 0;
54576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
54676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else if (IS_INODE_TB(fs, group, blk)) {
54776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		FS_INODE_TB(fs, group) = 0;
54876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
54976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk) &&
55076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		   !ext2fs_test_block_bitmap(meta_bmap, blk)) {
55176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
55276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		rfs->needed_blocks++;
55376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	}
55476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o}
55576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
55676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
55776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o/*
55824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * This routine marks and unmarks reserved blocks in the new block
55924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * bitmap.  It also determines which blocks need to be moved and
56024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * places this information into the move_blocks bitmap.
56124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
562c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t blocks_to_move(ext2_resize_t rfs)
56324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o{
56476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	int	i, j, max_groups, has_super, meta_bg, meta_bg_size;
56524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	blk_t	blk, group_blk;
56624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	unsigned long old_blocks, new_blocks;
56724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	errcode_t	retval;
568c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2_filsys 	fs, old_fs;
569c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2fs_block_bitmap	meta_bmap;
57024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
571c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs = rfs->new_fs;
572c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	old_fs = rfs->old_fs;
573c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
574c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		fs = rfs->old_fs;
575c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
576a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, _("reserved blocks"),
5771e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o					      &rfs->reserve_blocks);
57824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (retval)
57924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return retval;
5801e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
581a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
582c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					      &rfs->move_blocks);
583c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
584c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
585c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
586bce49798f7f4380dff5693bc8308019b3cf8de25Theodore Ts'o	retval = mark_table_blocks(old_fs, &meta_bmap);
587c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
588c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
589c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
590c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs = rfs->new_fs;
591c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
5921e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
5931e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * If we're shrinking the filesystem, we need to move all of
5941e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * the blocks that don't fit any more
5951e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
5961e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	for (blk = fs->super->s_blocks_count;
597c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	     blk < old_fs->super->s_blocks_count; blk++) {
598c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
599c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    !ext2fs_test_block_bitmap(meta_bmap, blk)) {
600c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
6011e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			rfs->needed_blocks++;
602c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
6031e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
6041e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	}
60524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
60676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) {
60776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_blocks = old_fs->super->s_first_meta_bg;
60876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		new_blocks = fs->super->s_first_meta_bg;
60976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	} else {
61076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		old_blocks = old_fs->desc_blocks;
61176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		new_blocks = fs->desc_blocks;
61276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	}
61376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
614c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (old_blocks == new_blocks) {
615c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
616c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
617c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
61824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
6191333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	max_groups = fs->group_desc_count;
6201333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	if (max_groups > old_fs->group_desc_count)
6211333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o		max_groups = old_fs->group_desc_count;
622c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	group_blk = old_fs->super->s_first_data_block;
62324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
62424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * If we're reducing the number of descriptor blocks, this
62524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * makes life easy.  :-)   We just have to mark some extra
62624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * blocks as free.
62724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
62824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (old_blocks > new_blocks) {
6291333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o		for (i = 0; i < max_groups; i++) {
6301e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			if (!ext2fs_bg_has_super(fs, i)) {
6311e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				group_blk += fs->super->s_blocks_per_group;
63224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o				continue;
63324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			}
634c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			for (blk = group_blk+1+new_blocks;
635c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			     blk < group_blk+1+old_blocks; blk++) {
6361e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_unmark_block_bitmap(fs->block_map,
63724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o							   blk);
638052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				rfs->needed_blocks--;
639052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			}
6401e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			group_blk += fs->super->s_blocks_per_group;
64124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
642c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
643c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
64424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
64524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
64624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * If we're increasing the number of descriptor blocks, life
6471e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * gets interesting....
64824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
64976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
6501333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	for (i = 0; i < max_groups; i++) {
65176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		has_super = ext2fs_bg_has_super(fs, i);
65276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (has_super)
65376dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			mark_fs_metablock(rfs, meta_bmap, i, group_blk);
65476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
65576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		meta_bg = i / meta_bg_size;
65676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		if (!(fs->super->s_feature_incompat &
65776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		      EXT2_FEATURE_INCOMPAT_META_BG) ||
65876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		    (meta_bg < fs->super->s_first_meta_bg)) {
659424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o			if (has_super) {
660424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o				for (blk = group_blk+1;
661424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o				     blk < group_blk + 1 + new_blocks; blk++)
662424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o					mark_fs_metablock(rfs, meta_bmap,
663424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o							  i, blk);
664424cb7b62aa417db2eaec79cfaec7433b31f8726Theodore Ts'o			}
66576dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o		} else {
66676dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (has_super)
66776dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				has_super = 1;
66876dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			if (((i % meta_bg_size) == 0) ||
66976dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == 1) ||
67076dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o			    ((i % meta_bg_size) == (meta_bg_size-1)))
67176dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o				mark_fs_metablock(rfs, meta_bmap, i,
67276dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o						  group_blk + has_super);
67324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
67476dd5e5c2842fb1a7b858aad3e68b5e9c16890c9Theodore Ts'o
6751e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_table &&
6761e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		    fs->group_desc[i].bg_inode_bitmap &&
6771e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		    fs->group_desc[i].bg_block_bitmap)
6781e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			goto next_group;
67924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
6801e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
681c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Reserve the existing meta blocks that we know
682c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * aren't to be moved.
6831e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
6841e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_block_bitmap)
6851e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks,
6861e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 fs->group_desc[i].bg_block_bitmap);
6871e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_bitmap)
6881e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks,
6891e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 fs->group_desc[i].bg_inode_bitmap);
6901e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_table)
6911e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			for (blk = fs->group_desc[i].bg_inode_table, j=0;
6921e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			     j < fs->inode_blocks_per_group ; j++, blk++)
6931e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->reserve_blocks,
6941e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o							 blk);
69524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
696c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
697c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Allocate the missing data structures
698c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
6991e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		retval = ext2fs_allocate_group_table(fs, i,
7001e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o						     rfs->reserve_blocks);
7011e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (retval)
702c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			goto errout;
70324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
7041e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
705c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * For those structures that have changed, we need to
706c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * do bookkeepping.
7071e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
708c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_BLOCK_BM(old_fs, i) !=
709c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    (blk = FS_BLOCK_BM(fs, i))) {
710c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
711c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
712c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
713c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
714c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
715c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
716c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_INODE_BM(old_fs, i) !=
717c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    (blk = FS_INODE_BM(fs, i))) {
718c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
719c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
720c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
721c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
722c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
723c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
72424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
725052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		/*
726052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * The inode table, if we need to relocate it, is
727052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * handled specially.  We have to reserve the blocks
728052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * for both the old and the new inode table, since we
729052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * can't have the inode table be destroyed during the
730052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * block relocation phase.
731052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 */
732c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
733052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			goto next_group; /* inode table not moved */
734052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
735c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		rfs->needed_blocks += fs->inode_blocks_per_group;
736052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
737052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		/*
738052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * Mark the new inode table as in use in the new block
739c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * allocation bitmap, and move any blocks that might
740c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * be necessary.
741052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 */
7421e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		for (blk = fs->group_desc[i].bg_inode_table, j=0;
743c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++) {
7441e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
745c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
746c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
747c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
748c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
749c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
750c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
7511e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
752052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * Make sure the old inode table is reserved in the
753052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * block reservation bitmap.
7541e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
755052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
756052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++)
757052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
7581e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
7591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	next_group:
7601e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		group_blk += rfs->new_fs->super->s_blocks_per_group;
7611e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	}
762c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = 0;
763c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
764c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'oerrout:
765c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (meta_bmap)
766c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_free_block_bitmap(meta_bmap);
767c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
768c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	return retval;
7691e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o}
77024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
771a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
772a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * This helper function tries to allocate a new block.  We try to
773a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * avoid hitting the original group descriptor blocks at least at
774a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * first, since we want to make it possible to recover from a badly
775a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * aborted resize operation as much as possible.
776a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
777a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In the future, I may further modify this routine to balance out
778a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * where we get the new blocks across the various block groups.
779a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Ideally we would allocate blocks that corresponded with the block
780a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * group of the containing inode, and keep contiguous blocks
781a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * together.  However, this very difficult to do efficiently, since we
782a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * don't have the necessary information up front.
783a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
784a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
785a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define AVOID_OLD	1
786a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define DESPERATION	2
787a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
788a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic void init_block_alloc(ext2_resize_t rfs)
789a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
790a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->alloc_state = AVOID_OLD;
791a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->new_blk = rfs->new_fs->super->s_first_data_block;
7922bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o#if 0
7932bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	/* HACK for testing */
7942bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	if (rfs->new_fs->super->s_blocks_count >
7952bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	    rfs->old_fs->super->s_blocks_count)
7962bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o		rfs->new_blk = rfs->old_fs->super->s_blocks_count;
7972bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o#endif
798a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
799a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
800a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic blk_t get_new_block(ext2_resize_t rfs)
801a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
802a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys	fs = rfs->new_fs;
803a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
804a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
805a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->new_blk >= fs->super->s_blocks_count) {
806a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->alloc_state == DESPERATION)
807a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				return 0;
808a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
809a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
810a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->flags & RESIZE_DEBUG_BMOVE)
811a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o				printf(_("Going into desperation "
812a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o				       "mode for block allocations\n"));
813a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
814a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->alloc_state = DESPERATION;
815a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_blk = fs->super->s_first_data_block;
816a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
817a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
818a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ext2fs_test_block_bitmap(fs->block_map, rfs->new_blk) ||
819a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    ext2fs_test_block_bitmap(rfs->reserve_blocks,
820a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					     rfs->new_blk) ||
821a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    ((rfs->alloc_state == AVOID_OLD) &&
822bce49798f7f4380dff5693bc8308019b3cf8de25Theodore Ts'o		     (rfs->new_blk < rfs->old_fs->super->s_blocks_count) &&
823a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		     ext2fs_test_block_bitmap(rfs->old_fs->block_map,
824a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					      rfs->new_blk))) {
825a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_blk++;
826a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
827a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
828a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return rfs->new_blk;
829a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
830a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
831a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
832a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t block_mover(ext2_resize_t rfs)
833a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
834a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	blk_t			blk, old_blk, new_blk;
835a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys		fs = rfs->new_fs;
836a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys		old_fs = rfs->old_fs;
837a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
838a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			size, c;
839a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			to_move, moved;
8407d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	ext2_badblocks_list	badblock_list = 0;
8417d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	int			bb_modified = 0;
8427d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o
8437d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	retval = ext2fs_read_bb_inode(old_fs, &badblock_list);
8447d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	if (retval)
8457d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		return retval;
846a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
847a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_blk = fs->super->s_first_data_block;
848a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!rfs->itable_buf) {
849a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_get_mem(fs->blocksize *
850a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					fs->inode_blocks_per_group,
851a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					(void **) &rfs->itable_buf);
852a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval)
853a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			return retval;
854a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
855a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_create_extent_table(&rfs->bmap, 0);
856a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
857a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
858a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
859a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
860a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * The first step is to figure out where all of the blocks
861a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * will go.
862a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
863a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	to_move = moved = 0;
864a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	init_block_alloc(rfs);
865a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	for (blk = old_fs->super->s_first_data_block;
866a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     blk < old_fs->super->s_blocks_count; blk++) {
867a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ext2fs_test_block_bitmap(old_fs->block_map, blk))
868a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
869a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk))
870a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
8717d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		if (ext2fs_badblocks_list_test(badblock_list, blk)) {
8727d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			ext2fs_badblocks_list_del(badblock_list, blk);
8737d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			bb_modified++;
8747d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			continue;
8757d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		}
876a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
877a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		new_blk = get_new_block(rfs);
878a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!new_blk) {
879a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ENOSPC;
880a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
881a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
882a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_block_bitmap(fs->block_map, new_blk);
883a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_add_extent_entry(rfs->bmap, blk, new_blk);
884a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		to_move++;
885a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
886a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
887a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (to_move == 0) {
888cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o		if (rfs->bmap) {
889cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o			ext2fs_free_extent_table(rfs->bmap);
890cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o			rfs->bmap = 0;
891cefbf4870c0593e3c7a01b8d5494463b247d90f0Theodore Ts'o		}
892a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = 0;
893a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
894a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
895a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
896a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
897a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Step two is to actually move the blocks
898a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
899a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval =  ext2fs_iterate_extent(rfs->bmap, 0, 0, 0);
900a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
901a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
9023b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
9033b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS,
9043b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 0, to_move);
9053b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
9063b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
9073b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
908a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
909a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size);
910a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
911a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!size)
912a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			break;
913a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
914a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_BMOVE)
915a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o			printf(_("Moving %d blocks %u->%u\n"), size,
916a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			       old_blk, new_blk);
917a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
918a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		do {
919a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			c = size;
920a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (c > fs->inode_blocks_per_group)
921a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				c = fs->inode_blocks_per_group;
922a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = io_channel_read_blk(fs->io, old_blk, c,
923a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						     rfs->itable_buf);
924a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
925a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = io_channel_write_blk(fs->io, new_blk, c,
926a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						      rfs->itable_buf);
927a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
928a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			size -= c;
929a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			new_blk += c;
930a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			old_blk += c;
931a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			moved += c;
932a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->progress) {
933a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				io_channel_flush(fs->io);
9343b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				retval = (rfs->progress)(rfs,
9353b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o						E2_RSZ_BLOCK_RELOC_PASS,
936a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						moved, to_move);
9373b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				if (retval)
9383b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					goto errout;
939a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
940a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		} while (size > 0);
941a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
942a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
943a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
944a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
9457d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	if (badblock_list) {
9467d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		if (!retval && bb_modified)
9477d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o			retval = ext2fs_update_bb_inode(old_fs,
9487d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o							badblock_list);
9497d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o		ext2fs_badblocks_list_free(badblock_list);
9507d7bdd578b307cad1dc248310eb279c6fb73b682Theodore Ts'o	}
951a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
952a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
953a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
954a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
955a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
956a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
957a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 3
958a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
959a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
960a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
961a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
962a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
963a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostruct process_block_struct {
964a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t 		rfs;
965dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t		ino;
966a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct ext2_inode *	inode;
967a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		error;
968a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			is_dir;
969a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			changed;
970a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o};
971a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
972a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic int process_block(ext2_filsys fs, blk_t	*block_nr,
973084307590c5e28b6a8305933220ff5b2bd1bcda2Theodore Ts'o			 e2_blkcnt_t blockcnt, blk_t ref_block,
974a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			 int ref_offset, void *priv_data)
975a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
976a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct process_block_struct *pb;
977a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
978a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	blk_t		block, new_block;
979a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int		ret = 0;
980a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
981a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb = (struct process_block_struct *) priv_data;
982a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	block = *block_nr;
983a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (pb->rfs->bmap) {
984a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		new_block = ext2fs_extent_translate(pb->rfs->bmap, block);
985a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (new_block) {
986a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			*block_nr = new_block;
987a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ret |= BLOCK_CHANGED;
988a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb->changed = 1;
989a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
990a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
991546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'o				printf(_("ino=%u, blockcnt=%lld, %u->%u\n"),
992a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				       pb->ino, blockcnt, block, new_block);
993a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
994a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			block = new_block;
995a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
996a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
997a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (pb->is_dir) {
998a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
999101c84f2e049bffcdb6c5ba1784842cdd50dbf05Theodore Ts'o					      block, (int) blockcnt);
1000a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) {
1001a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb->error = retval;
1002a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ret |= BLOCK_ABORT;
1003a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1004a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1005a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return ret;
1006a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1007a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1008a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
1009a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Progress callback
1010a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1011a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t progress_callback(ext2_filsys fs, ext2_inode_scan scan,
1012a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   dgrp_t group, void * priv_data)
1013a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1014a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t rfs = (ext2_resize_t) priv_data;
10153b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	errcode_t		retval;
1016a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1017a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1018f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	 * This check is to protect against old ext2 libraries.  It
1019f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	 * shouldn't be needed against new libraries.
1020a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1021f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	if ((group+1) == 0)
1022a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1023a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1024a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->progress) {
1025a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
10263b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
10273b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 group+1, fs->group_desc_count);
10283b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
10293b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			return retval;
1030a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1031a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1032a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return 0;
1033a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1034a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1035a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_scan_and_fix(ext2_resize_t rfs)
1036a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1037a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct process_block_struct	pb;
1038dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t		ino, new_inode;
1039a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct ext2_inode 	inode;
1040a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_inode_scan 	scan = NULL;
1041a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
1042a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			group;
1043a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	char			*block_buf = 0;
1044dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t		start_to_move;
10450ccd488a764c14b27983b92435deca5e1adf9061Theodore Ts'o	blk_t			orig_size, new_block;
1046a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1047a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if ((rfs->old_fs->group_desc_count <=
1048a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     rfs->new_fs->group_desc_count) &&
1049a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	    !rfs->bmap)
1050a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1051a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
10522bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	/*
10532bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * Save the original size of the old filesystem, and
10542bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * temporarily set the size to be the new size if the new size
10552bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * is larger.  We need to do this to avoid catching an error
10562bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * by the block iterator routines
10572bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 */
10582bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	orig_size = rfs->old_fs->super->s_blocks_count;
10592bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	if (orig_size < rfs->new_fs->super->s_blocks_count)
10602bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o		rfs->old_fs->super->s_blocks_count =
10612bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o			rfs->new_fs->super->s_blocks_count;
10622bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o
1063a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
1064a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
1065a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1066a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_init_dblist(rfs->old_fs, 0);
1067a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
1068a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_get_mem(rfs->old_fs->blocksize * 3,
1069a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				(void **) &block_buf);
1070a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
1071a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1072a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	start_to_move = (rfs->new_fs->group_desc_count *
1073a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			 rfs->new_fs->super->s_inodes_per_group);
1074a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
10753b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
10763b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
10773b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 0, rfs->old_fs->group_desc_count);
10783b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
10793b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
10803b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1081a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
1082a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.rfs = rfs;
1083a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.inode = &inode;
1084a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.error = 0;
1085a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
1086a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1087a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * First, copy all of the inodes that need to be moved
1088a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * elsewhere in the inode table
1089a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1090a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
1091a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_get_next_inode(scan, &ino, &inode);
1092a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
1093a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ino)
1094a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			break;
1095a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1096a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (inode.i_links_count == 0)
1097a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue; /* inode not in use */
1098a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1099a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
1100a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		pb.changed = 0;
1101a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
11020ccd488a764c14b27983b92435deca5e1adf9061Theodore Ts'o		if (inode.i_file_acl && rfs->bmap) {
11030ccd488a764c14b27983b92435deca5e1adf9061Theodore Ts'o			new_block = ext2fs_extent_translate(rfs->bmap,
1104ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o							    inode.i_file_acl);
1105ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o			if (new_block) {
1106ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o				inode.i_file_acl = new_block;
1107ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o				retval = ext2fs_write_inode(rfs->old_fs,
1108ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o							    ino, &inode);
1109ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o				if (retval) goto errout;
1110ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o			}
1111ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o		}
1112ed909bbe20d3fbeeee65c48dc0df2dbffdf2a0a9Theodore Ts'o
1113a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ext2fs_inode_has_valid_blocks(&inode) &&
1114a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    (rfs->bmap || pb.is_dir)) {
1115a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb.ino = ino;
1116a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_block_iterate2(rfs->old_fs,
1117a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						       ino, 0, block_buf,
1118a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						       process_block, &pb);
1119a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval)
1120a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1121a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (pb.error) {
1122a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				retval = pb.error;
1123a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1124a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1125a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1126a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1127a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ino <= start_to_move)
1128a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue; /* Don't need to move it. */
1129a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1130a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		/*
1131a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * Find a new inode
1132a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 */
1133a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		while (1) {
1134a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map,
1135a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						      new_inode))
1136a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				break;
1137a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			new_inode++;
1138a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (new_inode > rfs->new_fs->super->s_inodes_count) {
1139a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				retval = ENOSPC;
1140a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1141a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1142a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1143a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new_inode);
1144a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (pb.changed) {
1145a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			/* Get the new version of the inode */
1146a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_read_inode(rfs->old_fs, ino, &inode);
1147a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
1148a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1149085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o		inode.i_ctime = time(0);
1150a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_write_inode(rfs->old_fs, new_inode, &inode);
1151a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
1152a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1153a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
1154a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (LINUX_S_ISDIR(inode.i_mode))
1155a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_fs->group_desc[group].bg_used_dirs_count++;
1156a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1157a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1158a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_INODEMAP)
1159546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'o			printf(_("Inode moved %u->%u\n"), ino, new_inode);
1160a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1161a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!rfs->imap) {
1162a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_create_extent_table(&rfs->imap, 0);
1163a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval)
1164a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1165a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1166a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
1167a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1168a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	io_channel_flush(rfs->old_fs->io);
1169a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1170a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
11712bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	rfs->old_fs->super->s_blocks_count = orig_size;
1172a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->bmap) {
1173a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_extent_table(rfs->bmap);
1174a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		rfs->bmap = 0;
1175a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1176a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (scan)
1177a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_close_inode_scan(scan);
1178a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (block_buf)
1179a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_mem((void **) &block_buf);
1180a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1181a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1182a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1183a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1184a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1185a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 4.
1186a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1187a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1188a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1189a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1190a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostruct istruct {
1191a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t rfs;
11923b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	errcode_t	err;
11931333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	unsigned long	max_dirs;
1194a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int		num;
1195a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o};
1196a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1197dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'ostatic int check_and_change_inodes(ext2_ino_t dir, int entry,
1198a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   struct ext2_dir_entry *dirent, int offset,
1199a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   int	blocksize, char *buf, void *priv_data)
1200a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1201a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct istruct *is = (struct istruct *) priv_data;
1202085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	struct ext2_inode 	inode;
1203085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	ext2_ino_t		new_inode;
1204085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	errcode_t		retval;
1205a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1206a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (is->rfs->progress && offset == 0) {
1207a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(is->rfs->old_fs->io);
12083b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		is->err = (is->rfs->progress)(is->rfs,
12093b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					      E2_RSZ_INODE_REF_UPD_PASS,
12101333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o					      ++is->num, is->max_dirs);
12113b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (is->err)
12123b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			return DIRENT_ABORT;
1213a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1214a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1215a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!dirent->inode)
1216a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1217a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1218a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
1219a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1220a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!new_inode)
1221a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1222a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1223a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
1224546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'o		printf(_("Inode translate (dir=%u, name=%.*s, %u->%u)\n"),
1225a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       dir, dirent->name_len, dirent->name,
1226a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       dirent->inode, new_inode);
1227a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1228a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1229a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	dirent->inode = new_inode;
1230a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1231085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	/* Update the directory mtime and ctime */
1232085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
1233085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	if (retval == 0) {
1234085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o		inode.i_mtime = inode.i_ctime = time(0);
1235085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o		ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
1236085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o	}
1237085d2a8397d4eb37ad604f568edb8b2662c22d46Theodore Ts'o
1238a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return DIRENT_CHANGED;
1239a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1240a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1241a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_ref_fix(ext2_resize_t rfs)
1242a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1243a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
1244a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct istruct 		is;
1245a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1246a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!rfs->imap)
1247a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1248a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1249a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1250a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Now, we iterate over all of the directories to update the
1251a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * inode references
1252a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1253a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	is.num = 0;
12541333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	is.max_dirs = ext2fs_dblist_count(rfs->old_fs->dblist);
1255a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	is.rfs = rfs;
12563b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	is.err = 0;
1257a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
12583b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
12593b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
12601333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o					 0, is.max_dirs);
12613b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
12623b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
12633b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1264a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1265a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
1266a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   DIRENT_FLAG_INCLUDE_EMPTY, 0,
1267a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   check_and_change_inodes, &is);
12683b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (retval)
12693b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		goto errout;
12703b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (is.err) {
12713b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = is.err;
12723b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		goto errout;
12733b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1274a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
12753b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'oerrout:
1276a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free_extent_table(rfs->imap);
1277a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->imap = 0;
1278a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1279a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1280a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1281a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1282a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1283a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1284a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 5.
1285a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1286a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we actually move the inode table around, and then
1287a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * update the summary statistics.  This is scary, since aborting here
1288a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * will potentially scramble the filesystem.  (We are moving the
1289a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode tables around in place, and so the potential for lost data,
1290a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * or at the very least scrambling the mapping between filenames and
1291a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode numbers is very high in case of a power failure here.)
1292a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1293a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1294a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
129524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
129624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
1297052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * A very scary routine --- this one moves the inode table around!!!
1298052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o *
1299052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * After this you have to use the rfs->new_fs file handle to read and
1300052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * write inodes.
1301052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o */
1302c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t move_itables(ext2_resize_t rfs)
1303052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o{
13041333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	int		i, n, num, max_groups, size, diff;
1305052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	ext2_filsys	fs = rfs->new_fs;
130605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	char		*cp;
1307ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o	blk_t		old_blk, new_blk;
1308a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
1309c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	int		to_move, moved;
1310052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
13111333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	max_groups = fs->group_desc_count;
13121333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	if (max_groups > rfs->old_fs->group_desc_count)
13131333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o		max_groups = rfs->old_fs->group_desc_count;
1314052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
131505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	size = fs->blocksize * fs->inode_blocks_per_group;
131605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	if (!rfs->itable_buf) {
1317ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = ext2fs_get_mem(size, (void **) &rfs->itable_buf);
1318ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		if (retval)
1319ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			return retval;
132005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	}
1321c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
1322c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	/*
1323c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 * Figure out how many inode tables we need to move
1324c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 */
1325c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	to_move = moved = 0;
13261333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	for (i=0; i < max_groups; i++)
1327c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (rfs->old_fs->group_desc[i].bg_inode_table !=
1328c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    fs->group_desc[i].bg_inode_table)
1329c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			to_move++;
1330c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
1331c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (to_move == 0)
1332c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return 0;
1333c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
13343b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
13353b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
13363b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				       0, to_move);
13373b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
13383b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
13393b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
134063b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o
1341a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
1342a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
13431333fe93446a09ceb866a7f2a1ca0c196964b952Theodore Ts'o	for (i=0; i < max_groups; i++) {
1344ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		old_blk = rfs->old_fs->group_desc[i].bg_inode_table;
1345ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		new_blk = fs->group_desc[i].bg_inode_table;
1346ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		diff = new_blk - old_blk;
1347052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
134880c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
134905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1350a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o			printf(_("Itable move group %d block "
1351a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o			       "%u->%u (diff %d)\n"),
1352ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			       i, old_blk, new_blk, diff);
135380c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
1354052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
135505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (!diff)
1356052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			continue;
1357052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1358ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = io_channel_read_blk(fs->io, old_blk,
135905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     fs->inode_blocks_per_group,
136005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     rfs->itable_buf);
1361052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (retval)
1362a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
136305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		/*
136405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 * The end of the inode table segment often contains
1365a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * all zeros, and we're often only moving the inode
1366a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * table down a block or two.  If so, we can optimize
1367a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * things by not rewriting blocks that we know to be zero
1368a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * already.
136905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 */
137005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		for (cp = rfs->itable_buf+size, n=0; n < size; n++, cp--)
137105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			if (*cp)
137205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o				break;
137305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
137480c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
137505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1376a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o			printf(_("%d blocks of zeros...\n"), n);
137780c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
137805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		num = fs->inode_blocks_per_group;
137905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (n > diff)
138005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			num -= n;
138105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o
1382ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = io_channel_write_blk(fs->io, new_blk,
138305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      num, rfs->itable_buf);
1384052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (retval) {
1385ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			io_channel_write_blk(fs->io, old_blk,
138605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     num, rfs->itable_buf);
1387a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
1388052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
138905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (n > diff) {
139005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			retval = io_channel_write_blk(fs->io,
1391ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			      old_blk + fs->inode_blocks_per_group,
1392a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			      diff, (rfs->itable_buf +
1393a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     (fs->inode_blocks_per_group - diff) *
1394a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     fs->blocksize));
139505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			if (retval)
1396a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1397c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
1398a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
1399a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_super_dirty(rfs->old_fs);
1400a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->progress) {
1401a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ext2fs_flush(rfs->old_fs);
14023b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
14033b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					       ++moved, to_move);
14043b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			if (retval)
14053b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				goto errout;
1406a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1407052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1408a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_flush(fs);
140980c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
141005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1411a13575f4d29a908add19ea27baa102bc6944ee30Theodore Ts'o		printf(_("Inode table move finished.\n"));
141280c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
1413052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return 0;
1414052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1415a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
1416052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return retval;
1417052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o}
1418052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1419052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o/*
1420052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * Finally, recalculate the summary information
1421052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o */
1422052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'ostatic errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1423052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o{
1424dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	blk_t		blk;
1425dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	ext2_ino_t	ino;
1426dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	int		group = 0;
1427dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	int		count = 0;
1428dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	int		total_free = 0;
1429dfcdc32f8d6623a35a9e66f503c535e4081b7266Theodore Ts'o	int		group_free = 0;
1430052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1431052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	/*
1432052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 * First calculate the block statistics
1433052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 */
1434052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	for (blk = fs->super->s_first_data_block;
1435052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	     blk < fs->super->s_blocks_count; blk++) {
1436052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
1437052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free++;
1438052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			total_free++;
1439052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1440052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		count++;
1441052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if ((count == fs->super->s_blocks_per_group) ||
1442052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		    (blk == fs->super->s_blocks_count-1)) {
1443052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			fs->group_desc[group++].bg_free_blocks_count =
1444052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				group_free;
1445052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			count = 0;
1446052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free = 0;
1447052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1448052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1449052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	fs->super->s_free_blocks_count = total_free;
1450052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1451052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	/*
1452052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 * Next, calculate the inode statistics
1453052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 */
1454052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	group_free = 0;
1455052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	total_free = 0;
1456052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	count = 0;
1457052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	group = 0;
1458052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	for (ino = 1; ino <= fs->super->s_inodes_count; ino++) {
1459052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
1460052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free++;
1461052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			total_free++;
1462052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1463052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		count++;
1464052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if ((count == fs->super->s_inodes_per_group) ||
1465052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		    (ino == fs->super->s_inodes_count)) {
1466052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			fs->group_desc[group++].bg_free_inodes_count =
1467052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				group_free;
1468052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			count = 0;
1469052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free = 0;
1470052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1471052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1472052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	fs->super->s_free_inodes_count = total_free;
1473052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	ext2fs_mark_super_dirty(fs);
1474052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return 0;
1475052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o}
1476