resize2fs.c revision 101c84f2e049bffcdb6c5ba1784842cdd50dbf05
124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * resize2fs.c --- ext2 main routine
324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o *
424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * Copyright (C) 1997 Theodore Ts'o
524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o *
624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * %Begin-Header%
724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * All rights reserved.
824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * %End-Header%
924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
1024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
1105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o/*
1205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o * Resizing a filesystem consists of the following phases:
1305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o *
14a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *	1.  Adjust superblock and write out new parts of the inode
1505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o * 		table
16a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 	2.  Determine blocks which need to be relocated, and copy the
17a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 		contents of blocks from their old locations to the new ones.
18a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 	3.  Scan the inode table, doing the following:
19a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 		a.  If blocks have been moved, update the block
20a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			pointers in the inodes and indirect blocks to
21a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			point at the new block locations.
22a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 		b.  If parts of the inode table need to be evacuated,
23a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			copy inodes from their old locations to their
24a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			new ones.
25a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 		c.  If (b) needs to be done, note which blocks contain
26a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			directory information, since we will need to
27a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 			update the directory information.
28a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 	4.  Update the directory blocks with the new inode locations.
29a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * 	5.  Move the inode tables, if necessary.
3005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o */
31a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
3224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o#include "resize2fs.h"
3324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
34a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef linux			/* Kludge for debugging */
35a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define RESIZE2FS_DEBUG
36a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
37a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
38a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size);
39a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t blocks_to_move(ext2_resize_t rfs);
40a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t block_mover(ext2_resize_t rfs);
41a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_scan_and_fix(ext2_resize_t rfs);
42a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_ref_fix(ext2_resize_t rfs);
43a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t move_itables(ext2_resize_t rfs);
44a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
45a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
46a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
47a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Some helper CPP macros
48a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
49a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define FS_BLOCK_BM(fs, i) ((fs)->group_desc[(i)].bg_block_bitmap)
50a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define FS_INODE_BM(fs, i) ((fs)->group_desc[(i)].bg_inode_bitmap)
51a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define FS_INODE_TB(fs, i) ((fs)->group_desc[(i)].bg_inode_table)
52a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
53a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define IS_BLOCK_BM(fs, i, blk) ((blk) == FS_BLOCK_BM((fs),(i)))
54a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define IS_INODE_BM(fs, i, blk) ((blk) == FS_INODE_BM((fs),(i)))
55a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
56a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define IS_INODE_TB(fs, i, blk) (((blk) >= FS_INODE_TB((fs), (i))) && \
57a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				 ((blk) < (FS_INODE_TB((fs), (i)) + \
58a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   (fs)->inode_blocks_per_group)))
59a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
60a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
61a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
62a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
63a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * This is the top-level routine which does the dirty deed....
64a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
65a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags,
663b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		    errcode_t (*progress)(ext2_resize_t rfs, int pass,
67a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     unsigned long cur,
68a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     unsigned long max))
69a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
70a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t	rfs;
71a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
72a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
73a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_read_bitmaps(fs);
74a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
75a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
76a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
77a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
78a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Create the data structure
79a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
80a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct),
81a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				(void **) &rfs);
82a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
83a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
84a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	memset(rfs, 0, sizeof(struct ext2_resize_struct));
85a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
86a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->old_fs = fs;
87a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->flags = flags;
88a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->itable_buf	 = 0;
89a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->progress = progress;
90a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_dup_handle(fs, &rfs->new_fs);
91a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
92a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
93a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
94a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = adjust_superblock(rfs, new_size);
95a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
96a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
97a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
98a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = blocks_to_move(rfs);
99a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
100a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
101a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
102a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
103a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->flags & RESIZE_DEBUG_BMOVE)
104a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		printf("Number of free blocks: %d/%d, Needed: %d\n",
105a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->old_fs->super->s_free_blocks_count,
106a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->new_fs->super->s_free_blocks_count,
107a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       rfs->needed_blocks);
108a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
109a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
110a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = block_mover(rfs);
111a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
112a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
113a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
114a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = inode_scan_and_fix(rfs);
115a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
116a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
117a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
118a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = inode_ref_fix(rfs);
119a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
120a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
121a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
122a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_calculate_summary_stats(rfs->new_fs);
123a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
124a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
125a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
126a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = move_itables(rfs);
127a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
128a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
129a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
130a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_close(rfs->new_fs);
131a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
132a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
133a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
134a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->flags = flags;
135a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
136a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free(rfs->old_fs);
137a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->itable_buf)
138a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_mem((void **) &rfs->itable_buf);
139a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free_mem((void **) &rfs);
140a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
141a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return 0;
142a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
143a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
144a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->new_fs)
145a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free(rfs->new_fs);
146a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->itable_buf)
147a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_mem((void **) &rfs->itable_buf);
148a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free_mem((void **) &rfs);
149a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
150a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
151a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
152a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
153a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
154a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 1.
155a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
156a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we adjust the in-memory superblock information, and
157a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * initialize any new parts of the inode table.  The new parts of the
158a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode table are created in virgin disk space, so we can abort here
159a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * without any side effects.
160a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
161a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
162a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
16324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
16424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * This routine adjusts the superblock and other data structures...
16524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
16624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'ostatic errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
16724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o{
16824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	ext2_filsys fs;
16924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	int		overhead = 0;
170c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	int		rem, adj = 0;
17124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	errcode_t	retval;
17224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	ino_t		real_end;
17324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	blk_t		blk, group_block;
1741e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	unsigned long	i, j;
1751e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	int		old_numblocks, numblocks, adjblocks;
17663b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o	unsigned long	max_group;
17724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
17824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs = rfs->new_fs;
17924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->super->s_blocks_count = new_size;
1801e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	ext2fs_mark_super_dirty(fs);
1811e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	ext2fs_mark_bb_dirty(fs);
1821e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	ext2fs_mark_ib_dirty(fs);
18324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
18424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'oretry:
18524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->group_desc_count = (fs->super->s_blocks_count -
18624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o				fs->super->s_first_data_block +
18724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o				EXT2_BLOCKS_PER_GROUP(fs->super) - 1)
18824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		/ EXT2_BLOCKS_PER_GROUP(fs->super);
18924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (fs->group_desc_count == 0)
19024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return EXT2_ET_TOOSMALL;
19124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->desc_blocks = (fs->group_desc_count +
19224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			   EXT2_DESC_PER_BLOCK(fs->super) - 1)
19324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		/ EXT2_DESC_PER_BLOCK(fs->super);
19424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
19524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
19624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Overhead is the number of bookkeeping blocks per group.  It
19724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * includes the superblock backup, the group descriptor
19824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * backups, the inode bitmap, the block bitmap, and the inode
19924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * table.
20024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 *
20124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * XXX Not all block groups need the descriptor blocks, but
20224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * being clever is tricky...
20324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
20424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
20524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
20624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
20724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * See if the last group is big enough to support the
20824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * necessary data structures.  If not, we need to get rid of
20924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * it.
21024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
21124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
21224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_blocks_per_group;
21324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if ((fs->group_desc_count == 1) && rem && (rem < overhead))
21424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return EXT2_ET_TOOSMALL;
21524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (rem && (rem < overhead+50)) {
21624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_blocks_count -= rem;
21724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		goto retry;
21824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
21924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
22024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Adjust the number of inodes
22124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
22224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	fs->super->s_inodes_count = fs->super->s_inodes_per_group *
22324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->group_desc_count;
22424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
22524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
22624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Adjust the number of free blocks
22724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
22824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	blk = rfs->old_fs->super->s_blocks_count;
22924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (blk > fs->super->s_blocks_count)
23024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_free_blocks_count -=
23124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			(blk - fs->super->s_blocks_count);
23224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	else
23324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		fs->super->s_free_blocks_count +=
23424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			(fs->super->s_blocks_count - blk);
23524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
23624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
237c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 * Adjust the number of reserved blocks
238c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 */
239c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	blk = rfs->old_fs->super->s_r_blocks_count * 100 /
240c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		rfs->old_fs->super->s_blocks_count;
241c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs->super->s_r_blocks_count = ((fs->super->s_blocks_count * blk)
242c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				       / 100);
243c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
244c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	/*
24524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Adjust the bitmaps for size
24624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
24724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
24824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o					    fs->super->s_inodes_count,
24924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o					    fs->inode_map);
250c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval) goto errout;
25124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
25224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
25324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		     * fs->group_desc_count)) - 1 +
25424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			     fs->super->s_first_data_block;
25524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
25624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o					    real_end, fs->block_map);
25724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
258c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval) goto errout;
25924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
26024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
26124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * Reallocate the group descriptors as necessary.
26224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
26324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (rfs->old_fs->desc_blocks != fs->desc_blocks) {
264ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = ext2fs_resize_mem(fs->desc_blocks * fs->blocksize,
265ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o					   (void **) &fs->group_desc);
266ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		if (retval)
267a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
26824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
2691e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
2701e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
271a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Check to make sure there are enough inodes
272a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
273a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if ((rfs->old_fs->super->s_inodes_count -
274a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     rfs->old_fs->super->s_free_inodes_count) >
275a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	    rfs->new_fs->super->s_inodes_count) {
276a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ENOSPC;
277a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
278a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
279a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
280a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
281a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * If we are shrinking the number block groups, we're done and
282a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * can exit now.
2831e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
284c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
285c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
286c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
287c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
288a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
289a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Fix the count of the last (old) block group
290a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
2911e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	old_numblocks = (rfs->old_fs->super->s_blocks_count -
2921e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			 rfs->old_fs->super->s_first_data_block) %
2931e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 rfs->old_fs->super->s_blocks_per_group;
2941e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	if (!old_numblocks)
2951e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		old_numblocks = rfs->old_fs->super->s_blocks_per_group;
2961e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	if (rfs->old_fs->group_desc_count == fs->group_desc_count) {
2971e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		numblocks = (rfs->new_fs->super->s_blocks_count -
2981e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			     rfs->new_fs->super->s_first_data_block) %
2991e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				     rfs->new_fs->super->s_blocks_per_group;
3001e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (!numblocks)
3011e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = rfs->new_fs->super->s_blocks_per_group;
3021e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	} else
3031e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		numblocks = rfs->new_fs->super->s_blocks_per_group;
3041e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	i = rfs->old_fs->group_desc_count - 1;
3051e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
3061e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3071e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
308a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * If the number of block groups is staying the same, we're
309a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * done and can exit now.  (If the number block groups is
310a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * shrinking, we had exited earlier.)
3111e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
312c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
313c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
314c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
315c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
316a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
317a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Initialize the new block group descriptors
318a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
319ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o	retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
320ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o				(void **) &rfs->itable_buf);
321ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o	if (retval)
322c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
323ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o
32405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
3251e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	group_block = fs->super->s_first_data_block +
3261e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
327c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
32863b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o	adj = rfs->old_fs->group_desc_count;
32963b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o	max_group = fs->group_desc_count - adj;
3303b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
3313b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
3323b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				       0, max_group);
3333b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
3343b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
3353b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
3361e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	for (i = rfs->old_fs->group_desc_count;
3371e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	     i < fs->group_desc_count; i++) {
3381e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		memset(&fs->group_desc[i], 0,
3391e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		       sizeof(struct ext2_group_desc));
3401e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		adjblocks = 0;
3411e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3421e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (i == fs->group_desc_count-1) {
3431e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = (fs->super->s_blocks_count -
3441e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				     fs->super->s_first_data_block) %
3451e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o					     fs->super->s_blocks_per_group;
3461e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			if (!numblocks)
3471e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				numblocks = fs->super->s_blocks_per_group;
3481e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		} else
3491e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			numblocks = fs->super->s_blocks_per_group;
3501e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3511e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (ext2fs_bg_has_super(fs, i)) {
3521e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			for (j=0; j < fs->desc_blocks+1; j++)
3531e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_mark_block_bitmap(fs->block_map,
3541e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o							 group_block + j);
3551e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			adjblocks = 1 + fs->desc_blocks;
35624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
3571e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		adjblocks += 2 + fs->inode_blocks_per_group;
3581e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
3591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		numblocks -= adjblocks;
3601e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->super->s_free_blocks_count -= adjblocks;
3611e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->super->s_free_inodes_count +=
3621e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			fs->super->s_inodes_per_group;
3631e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_free_blocks_count = numblocks;
3641e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_free_inodes_count =
3651e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			fs->super->s_inodes_per_group;
3661e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		fs->group_desc[i].bg_used_dirs_count = 0;
36724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
3681e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		retval = ext2fs_allocate_group_table(fs, i, 0);
369c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (retval) goto errout;
37024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
37105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		/*
37205e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 * Write out the new inode table
37305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 */
37405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		retval = io_channel_write_blk(fs->io,
37505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      fs->group_desc[i].bg_inode_table,
37605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      fs->inode_blocks_per_group,
37705e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      rfs->itable_buf);
378c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (retval) goto errout;
379c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
380a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
3813b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (rfs->progress) {
3823b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
3833b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					       i - adj + 1, max_group);
3843b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			if (retval)
3853b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				goto errout;
3863b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		}
3871e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		group_block += fs->super->s_blocks_per_group;
38824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
389c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	io_channel_flush(fs->io);
390c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = 0;
391c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
392c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'oerrout:
393c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	return retval;
394c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o}
395c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
396a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
397a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
398a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 2.
399a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
400a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we adjust determine which blocks need to be moved, in
401a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * blocks_to_move().  We then copy the blocks to their ultimate new
402a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * destinations using block_mover().  Since we are copying blocks to
403a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * their new locations, again during this pass we can abort without
404a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * any problems.
405a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
406a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
407a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
408c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o/*
409c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o * This helper function creates a block bitmap with all of the
410c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o * filesystem meta-data blocks.
411c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o */
412c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t mark_table_blocks(ext2_filsys fs,
413c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				   ext2fs_block_bitmap *ret_bmap)
414c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o{
415c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	blk_t			block, b;
416c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	int			i,j;
417c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2fs_block_bitmap	bmap;
418c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	errcode_t		retval;
419c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
420c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, "meta-data blocks", &bmap);
421c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
422c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
423c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
424c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	block = fs->super->s_first_data_block;
425c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	for (i = 0; i < fs->group_desc_count; i++) {
426c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (ext2fs_bg_has_super(fs, i)) {
427c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			/*
428c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			 * Mark this group's copy of the superblock
429c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			 */
430c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(bmap, block);
431c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
432c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			/*
433c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			 * Mark this group's copy of the descriptors
434c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			 */
435c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			for (j = 0; j < fs->desc_blocks; j++)
436c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(bmap, block + j + 1);
437c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
438c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
439c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
440c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark the blocks used for the inode table
441c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
442c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		for (j = 0, b = fs->group_desc[i].bg_inode_table;
443c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j < fs->inode_blocks_per_group;
444c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j++, b++)
445c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(bmap, b);
446c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
447c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
448c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark block used for the block bitmap
449c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
450c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_mark_block_bitmap(bmap,
451c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					 fs->group_desc[i].bg_block_bitmap);
452c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
453c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Mark block used for the inode bitmap
454c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
455c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_mark_block_bitmap(bmap,
456c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					 fs->group_desc[i].bg_inode_bitmap);
457c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		block += fs->super->s_blocks_per_group;
458c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
459c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	*ret_bmap = bmap;
4601e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	return 0;
46124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o}
46224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
46324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
46424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * This routine marks and unmarks reserved blocks in the new block
46524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * bitmap.  It also determines which blocks need to be moved and
46624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o * places this information into the move_blocks bitmap.
46724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o */
468c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t blocks_to_move(ext2_resize_t rfs)
46924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o{
470c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	int	i, j, max;
47124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	blk_t	blk, group_blk;
47224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	unsigned long old_blocks, new_blocks;
47324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	errcode_t	retval;
474c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2_filsys 	fs, old_fs;
475c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	ext2fs_block_bitmap	meta_bmap;
47624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
477c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs = rfs->new_fs;
478c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	old_fs = rfs->old_fs;
479c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
480c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		fs = rfs->old_fs;
481c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
482c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, "reserved blocks",
4831e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o					      &rfs->reserve_blocks);
48424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (retval)
48524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		return retval;
4861e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
487c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(fs, "blocks to be moved",
488c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o					      &rfs->move_blocks);
489c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
490c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
491c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
492bce49798f7f4380dff5693bc8308019b3cf8de25Theodore Ts'o	retval = mark_table_blocks(old_fs, &meta_bmap);
493c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (retval)
494c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return retval;
495c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
496c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	fs = rfs->new_fs;
497c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
4981e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	/*
4991e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * If we're shrinking the filesystem, we need to move all of
5001e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * the blocks that don't fit any more
5011e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 */
5021e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	for (blk = fs->super->s_blocks_count;
503c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	     blk < old_fs->super->s_blocks_count; blk++) {
504c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
505c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    !ext2fs_test_block_bitmap(meta_bmap, blk)) {
506c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
5071e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			rfs->needed_blocks++;
508c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
5091e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
5101e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	}
51124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
512c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	old_blocks = old_fs->desc_blocks;
5131e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	new_blocks = fs->desc_blocks;
5141e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
515c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (old_blocks == new_blocks) {
516c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
517c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
518c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	}
51924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
520052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	max = fs->group_desc_count;
521c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (max > old_fs->group_desc_count)
522c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		max = old_fs->group_desc_count;
523c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	group_blk = old_fs->super->s_first_data_block;
52424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
52524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * If we're reducing the number of descriptor blocks, this
52624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * makes life easy.  :-)   We just have to mark some extra
52724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * blocks as free.
52824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
52924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	if (old_blocks > new_blocks) {
530052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		for (i = 0; i < max; i++) {
5311e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			if (!ext2fs_bg_has_super(fs, i)) {
5321e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				group_blk += fs->super->s_blocks_per_group;
53324b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o				continue;
53424b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o			}
535c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			for (blk = group_blk+1+new_blocks;
536c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			     blk < group_blk+1+old_blocks; blk++) {
5371e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_unmark_block_bitmap(fs->block_map,
53824b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o							   blk);
539052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				rfs->needed_blocks--;
540052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			}
5411e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			group_blk += fs->super->s_blocks_per_group;
54224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
543c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		retval = 0;
544c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		goto errout;
54524b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	}
54624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	/*
54724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 * If we're increasing the number of descriptor blocks, life
5481e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	 * gets interesting....
54924b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o	 */
550052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	for (i = 0; i < max; i++) {
5511e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (!ext2fs_bg_has_super(fs, i))
5521e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			goto next_group;
5531e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
5541e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		for (blk = group_blk;
5551e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		     blk < group_blk + 1 + new_blocks; blk++) {
5561e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
5571e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
5581e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
5591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			/*
5601e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			 * Check to see if we overlap with the inode
561c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			 * or block bitmap, or the inode tables.  If
562c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			 * not, and the block is in use, then mark it
563c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			 * as a block to be moved.
5641e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			 */
565c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (IS_BLOCK_BM(fs, i, blk)) {
566c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				FS_BLOCK_BM(fs, i) = 0;
567052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				rfs->needed_blocks++;
568c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			} else if (IS_INODE_BM(fs, i, blk)) {
569c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				FS_INODE_BM(fs, i) = 0;
570c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				rfs->needed_blocks++;
571c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			} else if (IS_INODE_TB(fs, i, blk)) {
572c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				FS_INODE_TB(fs, i) = 0;
573c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				rfs->needed_blocks++;
574c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			} else if (ext2fs_test_block_bitmap(old_fs->block_map,
575c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							    blk) &&
576c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				   !ext2fs_test_block_bitmap(meta_bmap, blk)) {
577c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
578c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
579052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				rfs->needed_blocks++;
580052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			}
58124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o		}
5821e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_table &&
5831e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		    fs->group_desc[i].bg_inode_bitmap &&
5841e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		    fs->group_desc[i].bg_block_bitmap)
5851e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			goto next_group;
58624b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
5871e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
588c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Reserve the existing meta blocks that we know
589c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * aren't to be moved.
5901e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
5911e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_block_bitmap)
5921e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks,
5931e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 fs->group_desc[i].bg_block_bitmap);
5941e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_bitmap)
5951e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks,
5961e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				 fs->group_desc[i].bg_inode_bitmap);
5971e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (fs->group_desc[i].bg_inode_table)
5981e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			for (blk = fs->group_desc[i].bg_inode_table, j=0;
5991e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			     j < fs->inode_blocks_per_group ; j++, blk++)
6001e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->reserve_blocks,
6011e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o							 blk);
60224b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
603c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		/*
604c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * Allocate the missing data structures
605c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 */
6061e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		retval = ext2fs_allocate_group_table(fs, i,
6071e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o						     rfs->reserve_blocks);
6081e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		if (retval)
609c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			goto errout;
61024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
6111e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
612c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * For those structures that have changed, we need to
613c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * do bookkeepping.
6141e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
615c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_BLOCK_BM(old_fs, i) !=
616c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    (blk = FS_BLOCK_BM(fs, i))) {
617c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
618c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
619c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
620c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
621c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
622c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
623c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_INODE_BM(old_fs, i) !=
624c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    (blk = FS_INODE_BM(fs, i))) {
625c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
626c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
627c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
628c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
629c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
630c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
63124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
632052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		/*
633052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * The inode table, if we need to relocate it, is
634052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * handled specially.  We have to reserve the blocks
635052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * for both the old and the new inode table, since we
636052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * can't have the inode table be destroyed during the
637052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * block relocation phase.
638052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 */
639c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
640052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			goto next_group; /* inode table not moved */
641052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
642c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		rfs->needed_blocks += fs->inode_blocks_per_group;
643052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
644052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		/*
645052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * Mark the new inode table as in use in the new block
646c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * allocation bitmap, and move any blocks that might
647c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		 * be necessary.
648052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 */
6491e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		for (blk = fs->group_desc[i].bg_inode_table, j=0;
650c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++) {
6511e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o			ext2fs_mark_block_bitmap(fs->block_map, blk);
652c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
653c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			    !ext2fs_test_block_bitmap(meta_bmap, blk))
654c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o				ext2fs_mark_block_bitmap(rfs->move_blocks,
655c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o							 blk);
656c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
657c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
6581e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		/*
659052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * Make sure the old inode table is reserved in the
660052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		 * block reservation bitmap.
6611e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		 */
662052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
663052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		     j < fs->inode_blocks_per_group ; j++, blk++)
664052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
6651e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o
6661e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	next_group:
6671e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o		group_blk += rfs->new_fs->super->s_blocks_per_group;
6681e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o	}
669c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	retval = 0;
670c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
671c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'oerrout:
672c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (meta_bmap)
673c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		ext2fs_free_block_bitmap(meta_bmap);
674c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
675c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	return retval;
6761e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o}
67724b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
678a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
679a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * This helper function tries to allocate a new block.  We try to
680a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * avoid hitting the original group descriptor blocks at least at
681a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * first, since we want to make it possible to recover from a badly
682a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * aborted resize operation as much as possible.
683a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
684a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In the future, I may further modify this routine to balance out
685a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * where we get the new blocks across the various block groups.
686a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Ideally we would allocate blocks that corresponded with the block
687a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * group of the containing inode, and keep contiguous blocks
688a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * together.  However, this very difficult to do efficiently, since we
689a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * don't have the necessary information up front.
690a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
691a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
692a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define AVOID_OLD	1
693a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#define DESPERATION	2
694a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
695a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic void init_block_alloc(ext2_resize_t rfs)
696a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
697a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->alloc_state = AVOID_OLD;
698a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->new_blk = rfs->new_fs->super->s_first_data_block;
6992bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o#if 0
7002bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	/* HACK for testing */
7012bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	if (rfs->new_fs->super->s_blocks_count >
7022bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	    rfs->old_fs->super->s_blocks_count)
7032bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o		rfs->new_blk = rfs->old_fs->super->s_blocks_count;
7042bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o#endif
705a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
706a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
707a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic blk_t get_new_block(ext2_resize_t rfs)
708a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
709a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys	fs = rfs->new_fs;
710a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
711a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
712a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->new_blk >= fs->super->s_blocks_count) {
713a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->alloc_state == DESPERATION)
714a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				return 0;
715a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
716a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
717a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->flags & RESIZE_DEBUG_BMOVE)
718a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				printf("Going into desperation "
719a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				       "mode for block allocations\n");
720a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
721a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->alloc_state = DESPERATION;
722a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_blk = fs->super->s_first_data_block;
723a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
724a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
725a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ext2fs_test_block_bitmap(fs->block_map, rfs->new_blk) ||
726a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    ext2fs_test_block_bitmap(rfs->reserve_blocks,
727a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					     rfs->new_blk) ||
728a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    ((rfs->alloc_state == AVOID_OLD) &&
729bce49798f7f4380dff5693bc8308019b3cf8de25Theodore Ts'o		     (rfs->new_blk < rfs->old_fs->super->s_blocks_count) &&
730a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		     ext2fs_test_block_bitmap(rfs->old_fs->block_map,
731a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					      rfs->new_blk))) {
732a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_blk++;
733a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
734a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
735a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return rfs->new_blk;
736a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
737a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
738a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
739a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t block_mover(ext2_resize_t rfs)
740a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
741a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	blk_t			blk, old_blk, new_blk;
742a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys		fs = rfs->new_fs;
743a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_filsys		old_fs = rfs->old_fs;
744a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
745a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			size, c;
746a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			to_move, moved;
747a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
748a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_blk = fs->super->s_first_data_block;
749a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!rfs->itable_buf) {
750a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_get_mem(fs->blocksize *
751a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					fs->inode_blocks_per_group,
752a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					(void **) &rfs->itable_buf);
753a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval)
754a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			return retval;
755a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
756a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_create_extent_table(&rfs->bmap, 0);
757a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval)
758a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return retval;
759a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
760a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
761a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * The first step is to figure out where all of the blocks
762a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * will go.
763a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
764a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	to_move = moved = 0;
765a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	init_block_alloc(rfs);
766a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	for (blk = old_fs->super->s_first_data_block;
767a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     blk < old_fs->super->s_blocks_count; blk++) {
768a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ext2fs_test_block_bitmap(old_fs->block_map, blk))
769a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
770a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk))
771a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue;
772a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
773a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		new_blk = get_new_block(rfs);
774a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!new_blk) {
775a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ENOSPC;
776a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
777a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
778a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_block_bitmap(fs->block_map, new_blk);
779a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_add_extent_entry(rfs->bmap, blk, new_blk);
780a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		to_move++;
781a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
782a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
783a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (to_move == 0) {
784a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = 0;
785a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		goto errout;
786a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
787a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
788a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
789a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Step two is to actually move the blocks
790a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
791a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval =  ext2fs_iterate_extent(rfs->bmap, 0, 0, 0);
792a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
793a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
7943b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
7953b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS,
7963b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 0, to_move);
7973b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
7983b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
7993b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
800a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
801a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size);
802a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
803a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!size)
804a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			break;
805a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
806a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_BMOVE)
807a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			printf("Moving %d blocks %u->%u\n", size,
808a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			       old_blk, new_blk);
809a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
810a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		do {
811a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			c = size;
812a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (c > fs->inode_blocks_per_group)
813a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				c = fs->inode_blocks_per_group;
814a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = io_channel_read_blk(fs->io, old_blk, c,
815a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						     rfs->itable_buf);
816a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
817a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = io_channel_write_blk(fs->io, new_blk, c,
818a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						      rfs->itable_buf);
819a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
820a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			size -= c;
821a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			new_blk += c;
822a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			old_blk += c;
823a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			moved += c;
824a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (rfs->progress) {
825a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				io_channel_flush(fs->io);
8263b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				retval = (rfs->progress)(rfs,
8273b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o						E2_RSZ_BLOCK_RELOC_PASS,
828a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						moved, to_move);
8293b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				if (retval)
8303b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					goto errout;
831a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
832a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		} while (size > 0);
833a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
834a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
835a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
836a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
837a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
838a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
839a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
840a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
841a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
842a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
843a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 3
844a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
845a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
846a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
847a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
848a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
849a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostruct process_block_struct {
850a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t 		rfs;
851a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ino_t			ino;
852a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct ext2_inode *	inode;
853a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		error;
854a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			is_dir;
855a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			changed;
856a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o};
857a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
858a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic int process_block(ext2_filsys fs, blk_t	*block_nr,
859101c84f2e049bffcdb6c5ba1784842cdd50dbf05Theodore Ts'o			 blkcnt_t blockcnt, blk_t ref_block,
860a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			 int ref_offset, void *priv_data)
861a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
862a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct process_block_struct *pb;
863a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
864a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	blk_t		block, new_block;
865a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int		ret = 0;
866a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
867a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb = (struct process_block_struct *) priv_data;
868a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	block = *block_nr;
869a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (pb->rfs->bmap) {
870a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		new_block = ext2fs_extent_translate(pb->rfs->bmap, block);
871a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (new_block) {
872a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			*block_nr = new_block;
873a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ret |= BLOCK_CHANGED;
874a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb->changed = 1;
875a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
876a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
877101c84f2e049bffcdb6c5ba1784842cdd50dbf05Theodore Ts'o				printf("ino=%ld, blockcnt=%ld, %u->%u\n",
878a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				       pb->ino, blockcnt, block, new_block);
879a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
880a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			block = new_block;
881a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
882a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
883a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (pb->is_dir) {
884a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
885101c84f2e049bffcdb6c5ba1784842cdd50dbf05Theodore Ts'o					      block, (int) blockcnt);
886a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) {
887a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb->error = retval;
888a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ret |= BLOCK_ABORT;
889a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
890a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
891a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return ret;
892a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
893a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
894a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/*
895a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Progress callback
896a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
897a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t progress_callback(ext2_filsys fs, ext2_inode_scan scan,
898a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   dgrp_t group, void * priv_data)
899a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
900a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t rfs = (ext2_resize_t) priv_data;
9013b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	errcode_t		retval;
902a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
903a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
904f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	 * This check is to protect against old ext2 libraries.  It
905f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	 * shouldn't be needed against new libraries.
906a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
907f4b2a6db3f13f4210697bcd273086006c719929bTheodore Ts'o	if ((group+1) == 0)
908a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
909a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
910a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->progress) {
911a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(fs->io);
9123b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
9133b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 group+1, fs->group_desc_count);
9143b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
9153b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			return retval;
916a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
917a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
918a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return 0;
919a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
920a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
921a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_scan_and_fix(ext2_resize_t rfs)
922a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
923a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct process_block_struct	pb;
924a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ino_t			ino, new_inode;
925a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct ext2_inode 	inode;
926a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_inode_scan 	scan = NULL;
927a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
928a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int			group;
929a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	char			*block_buf = 0;
930a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ino_t			start_to_move;
9312bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	blk_t			orig_size;
932a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
933a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if ((rfs->old_fs->group_desc_count <=
934a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	     rfs->new_fs->group_desc_count) &&
935a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	    !rfs->bmap)
936a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
937a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
9382bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	/*
9392bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * Save the original size of the old filesystem, and
9402bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * temporarily set the size to be the new size if the new size
9412bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * is larger.  We need to do this to avoid catching an error
9422bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 * by the block iterator routines
9432bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	 */
9442bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	orig_size = rfs->old_fs->super->s_blocks_count;
9452bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	if (orig_size < rfs->new_fs->super->s_blocks_count)
9462bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o		rfs->old_fs->super->s_blocks_count =
9472bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o			rfs->new_fs->super->s_blocks_count;
9482bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o
949a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
950a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
951a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
952a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_init_dblist(rfs->old_fs, 0);
953a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
954a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_get_mem(rfs->old_fs->blocksize * 3,
955a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				(void **) &block_buf);
956a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (retval) goto errout;
957a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
958a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	start_to_move = (rfs->new_fs->group_desc_count *
959a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			 rfs->new_fs->super->s_inodes_per_group);
960a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
9613b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
9623b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
9633b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 0, rfs->old_fs->group_desc_count);
9643b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
9653b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
9663b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
967a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
968a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.rfs = rfs;
969a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.inode = &inode;
970a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	pb.error = 0;
971a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
972a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
973a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * First, copy all of the inodes that need to be moved
974a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * elsewhere in the inode table
975a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
976a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	while (1) {
977a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_get_next_inode(scan, &ino, &inode);
978a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
979a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!ino)
980a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			break;
981a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
982a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (inode.i_links_count == 0)
983a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue; /* inode not in use */
984a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
985a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
986a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		pb.changed = 0;
987a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
988a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ext2fs_inode_has_valid_blocks(&inode) &&
989a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		    (rfs->bmap || pb.is_dir)) {
990a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			pb.ino = ino;
991a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_block_iterate2(rfs->old_fs,
992a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						       ino, 0, block_buf,
993a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						       process_block, &pb);
994a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval)
995a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
996a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (pb.error) {
997a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				retval = pb.error;
998a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
999a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1000a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1001a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1002a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (ino <= start_to_move)
1003a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			continue; /* Don't need to move it. */
1004a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1005a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		/*
1006a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * Find a new inode
1007a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 */
1008a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		while (1) {
1009a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map,
1010a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o						      new_inode))
1011a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				break;
1012a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			new_inode++;
1013a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (new_inode > rfs->new_fs->super->s_inodes_count) {
1014a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				retval = ENOSPC;
1015a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1016a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			}
1017a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1018a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new_inode);
1019a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (pb.changed) {
1020a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			/* Get the new version of the inode */
1021a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_read_inode(rfs->old_fs, ino, &inode);
1022a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval) goto errout;
1023a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1024a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		retval = ext2fs_write_inode(rfs->old_fs, new_inode, &inode);
1025a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (retval) goto errout;
1026a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1027a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
1028a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (LINUX_S_ISDIR(inode.i_mode))
1029a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			rfs->new_fs->group_desc[group].bg_used_dirs_count++;
1030a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1031a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1032a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_INODEMAP)
1033a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			printf("Inode moved %ld->%ld\n", ino, new_inode);
1034a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1035a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (!rfs->imap) {
1036a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			retval = ext2fs_create_extent_table(&rfs->imap, 0);
1037a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			if (retval)
1038a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1039a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1040a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
1041a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1042a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	io_channel_flush(rfs->old_fs->io);
1043a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1044a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
10452bc4d4f7e52ae1af9fb1a3dcff7c8752145d5a5cTheodore Ts'o	rfs->old_fs->super->s_blocks_count = orig_size;
1046a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (rfs->bmap) {
1047a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_extent_table(rfs->bmap);
1048a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		rfs->bmap = 0;
1049a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1050a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (scan)
1051a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_close_inode_scan(scan);
1052a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (block_buf)
1053a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_free_mem((void **) &block_buf);
1054a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1055a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1056a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1057a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1058a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1059a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 4.
1060a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1061a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1062a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1063a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1064a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostruct istruct {
1065a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2_resize_t rfs;
10663b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	errcode_t	err;
1067a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	unsigned long	max;
1068a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	int		num;
1069a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o};
1070a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1071a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic int check_and_change_inodes(ino_t dir, int entry,
1072a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   struct ext2_dir_entry *dirent, int offset,
1073a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				   int	blocksize, char *buf, void *priv_data)
1074a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1075a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct istruct *is = (struct istruct *) priv_data;
10763b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	ino_t		new_inode;
1077a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1078a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (is->rfs->progress && offset == 0) {
1079a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		io_channel_flush(is->rfs->old_fs->io);
10803b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		is->err = (is->rfs->progress)(is->rfs,
10813b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					      E2_RSZ_INODE_REF_UPD_PASS,
10823b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					      ++is->num, is->max);
10833b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (is->err)
10843b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			return DIRENT_ABORT;
1085a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	}
1086a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1087a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!dirent->inode)
1088a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1089a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1090a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
1091a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1092a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!new_inode)
1093a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1094a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#ifdef RESIZE2FS_DEBUG
1095a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
1096a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		printf("Inode translate (dir=%ld, name=%.*s, %u->%ld)\n",
1097a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       dir, dirent->name_len, dirent->name,
1098a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		       dirent->inode, new_inode);
1099a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o#endif
1100a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1101a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	dirent->inode = new_inode;
1102a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1103a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return DIRENT_CHANGED;
1104a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1105a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1106a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'ostatic errcode_t inode_ref_fix(ext2_resize_t rfs)
1107a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o{
1108a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t		retval;
1109a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	struct istruct 		is;
1110a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1111a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	if (!rfs->imap)
1112a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		return 0;
1113a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1114a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	/*
1115a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * Now, we iterate over all of the directories to update the
1116a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 * inode references
1117a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	 */
1118a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	is.num = 0;
1119a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	is.max = ext2fs_dblist_count(rfs->old_fs->dblist);
1120a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	is.rfs = rfs;
11213b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	is.err = 0;
1122a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
11233b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
11243b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
11253b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					 0, is.max);
11263b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
11273b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
11283b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1129a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1130a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
1131a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   DIRENT_FLAG_INCLUDE_EMPTY, 0,
1132a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o					   check_and_change_inodes, &is);
11333b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (retval)
11343b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		goto errout;
11353b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (is.err) {
11363b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = is.err;
11373b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		goto errout;
11383b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
1139a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
11403b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'oerrout:
1141a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_free_extent_table(rfs->imap);
1142a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->imap = 0;
1143a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	return retval;
1144a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o}
1145a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1146a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1147a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o/* --------------------------------------------------------------------
1148a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1149a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * Resize processing, phase 5.
1150a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o *
1151a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * In this phase we actually move the inode table around, and then
1152a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * update the summary statistics.  This is scary, since aborting here
1153a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * will potentially scramble the filesystem.  (We are moving the
1154a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode tables around in place, and so the potential for lost data,
1155a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * or at the very least scrambling the mapping between filenames and
1156a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * inode numbers is very high in case of a power failure here.)
1157a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o * --------------------------------------------------------------------
1158a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o */
1159a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
116024b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o
116124b2c7a7a14cec8480a75af7d535cf267e6abe1fTheodore Ts'o/*
1162052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * A very scary routine --- this one moves the inode table around!!!
1163052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o *
1164052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * After this you have to use the rfs->new_fs file handle to read and
1165052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * write inodes.
1166052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o */
1167c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'ostatic errcode_t move_itables(ext2_resize_t rfs)
1168052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o{
116905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	int		i, n, num, max, size, diff;
1170052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	ext2_filsys	fs = rfs->new_fs;
117105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	char		*cp;
1172ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o	blk_t		old_blk, new_blk;
1173a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	errcode_t	retval;
1174c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	int		to_move, moved;
1175052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1176052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	max = fs->group_desc_count;
1177052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	if (max > rfs->old_fs->group_desc_count)
1178052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		max = rfs->old_fs->group_desc_count;
1179052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
118005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	size = fs->blocksize * fs->inode_blocks_per_group;
118105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	if (!rfs->itable_buf) {
1182ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = ext2fs_get_mem(size, (void **) &rfs->itable_buf);
1183ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		if (retval)
1184ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			return retval;
118505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	}
1186c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
1187c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	/*
1188c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 * Figure out how many inode tables we need to move
1189c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	 */
1190c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	to_move = moved = 0;
1191c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	for (i=0; i < max; i++)
1192c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		if (rfs->old_fs->group_desc[i].bg_inode_table !=
1193c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		    fs->group_desc[i].bg_inode_table)
1194c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			to_move++;
1195c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
1196c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o	if (to_move == 0)
1197c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		return 0;
1198c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o
11993b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	if (rfs->progress) {
12003b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
12013b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				       0, to_move);
12023b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o		if (retval)
12033b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			goto errout;
12043b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o	}
120563b44fbe303ea00118cbe24cbbcde351a9bc0aacTheodore Ts'o
1206a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
1207a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o
1208052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	for (i=0; i < max; i++) {
1209ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		old_blk = rfs->old_fs->group_desc[i].bg_inode_table;
1210ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		new_blk = fs->group_desc[i].bg_inode_table;
1211ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		diff = new_blk - old_blk;
1212052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
121380c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
121405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
121505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			printf("Itable move group %d block "
1216c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o			       "%u->%u (diff %d)\n",
1217ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			       i, old_blk, new_blk, diff);
121880c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
1219052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
122005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (!diff)
1221052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			continue;
1222052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1223ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = io_channel_read_blk(fs->io, old_blk,
122405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     fs->inode_blocks_per_group,
122505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     rfs->itable_buf);
1226052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (retval)
1227a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
122805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		/*
122905e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 * The end of the inode table segment often contains
1230a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * all zeros, and we're often only moving the inode
1231a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * table down a block or two.  If so, we can optimize
1232a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * things by not rewriting blocks that we know to be zero
1233a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		 * already.
123405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		 */
123505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		for (cp = rfs->itable_buf+size, n=0; n < size; n++, cp--)
123605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			if (*cp)
123705e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o				break;
123805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
123980c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
124005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
124105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			printf("%d blocks of zeros...\n", n);
124280c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
124305e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		num = fs->inode_blocks_per_group;
124405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (n > diff)
124505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			num -= n;
124605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o
1247ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o		retval = io_channel_write_blk(fs->io, new_blk,
124805e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					      num, rfs->itable_buf);
1249052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (retval) {
1250ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			io_channel_write_blk(fs->io, old_blk,
125105e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o					     num, rfs->itable_buf);
1252a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			goto errout;
1253052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
125405e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		if (n > diff) {
125505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			retval = io_channel_write_blk(fs->io,
1256ca8abba7e0970fd1702db53e3f89ceb68c70768cTheodore Ts'o			      old_blk + fs->inode_blocks_per_group,
1257a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			      diff, (rfs->itable_buf +
1258a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     (fs->inode_blocks_per_group - diff) *
1259a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				     fs->blocksize));
126005e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o			if (retval)
1261a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o				goto errout;
1262c762c8e63216a301c9de7d24c6136d8370378a08Theodore Ts'o		}
1263a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
1264a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		ext2fs_mark_super_dirty(rfs->old_fs);
1265a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		if (rfs->progress) {
1266a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o			ext2fs_flush(rfs->old_fs);
12673b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
12683b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o					       ++moved, to_move);
12693b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o			if (retval)
12703b627e8d6735fd81906117d580ee70292b2cfaafTheodore Ts'o				goto errout;
1271a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o		}
1272052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1273a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'o	ext2fs_flush(fs);
127480c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#ifdef RESIZE2FS_DEBUG
127505e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o	if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
127605e112a11b6508c2b12d5d4ee0c322171db9b538Theodore Ts'o		printf("Inode table move finished.\n");
127780c0fc3492278168448017e79730905aa5b9b62bTheodore Ts'o#endif
1278052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return 0;
1279052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1280a8519a2dbec429846d89fee581a2ecb829904cd2Theodore Ts'oerrout:
1281052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return retval;
1282052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o}
1283052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1284052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o/*
1285052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o * Finally, recalculate the summary information
1286052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o */
1287052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'ostatic errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1288052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o{
1289052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	blk_t	blk;
1290052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	ino_t	ino;
1291052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	int	group = 0;
1292052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	int	count = 0;
1293052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	int	total_free = 0;
1294052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	int	group_free = 0;
1295052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1296052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	/*
1297052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 * First calculate the block statistics
1298052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 */
1299052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	for (blk = fs->super->s_first_data_block;
1300052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	     blk < fs->super->s_blocks_count; blk++) {
1301052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
1302052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free++;
1303052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			total_free++;
1304052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1305052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		count++;
1306052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if ((count == fs->super->s_blocks_per_group) ||
1307052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		    (blk == fs->super->s_blocks_count-1)) {
1308052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			fs->group_desc[group++].bg_free_blocks_count =
1309052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				group_free;
1310052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			count = 0;
1311052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free = 0;
1312052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1313052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1314052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	fs->super->s_free_blocks_count = total_free;
1315052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o
1316052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	/*
1317052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 * Next, calculate the inode statistics
1318052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	 */
1319052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	group_free = 0;
1320052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	total_free = 0;
1321052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	count = 0;
1322052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	group = 0;
1323052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	for (ino = 1; ino <= fs->super->s_inodes_count; ino++) {
1324052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
1325052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free++;
1326052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			total_free++;
1327052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1328052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		count++;
1329052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		if ((count == fs->super->s_inodes_per_group) ||
1330052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		    (ino == fs->super->s_inodes_count)) {
1331052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			fs->group_desc[group++].bg_free_inodes_count =
1332052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o				group_free;
1333052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			count = 0;
1334052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o			group_free = 0;
1335052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o		}
1336052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	}
1337052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	fs->super->s_free_inodes_count = total_free;
1338052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	ext2fs_mark_super_dirty(fs);
1339052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o	return 0;
1340052db4b76e552682c1ad94ff4943faa98c958343Theodore Ts'o}
1341