Whamcloud - gitweb
Fix bug in resize2fs which caused it to fail on filesystems with a
[tools/e2fsprogs.git] / resize / resize2fs.c
1 /*
2  * resize2fs.c --- ext2 main routine
3  *
4  * Copyright (C) 1997, 1998 by Theodore Ts'o and
5  *      PowerQuest, Inc.
6  *
7  * Copyright (C) 1999, 2000 by Theosore Ts'o
8  * 
9  * %Begin-Header%
10  * This file may be redistributed under the terms of the GNU Public
11  * License.
12  * %End-Header%
13  */
14
15 /*
16  * Resizing a filesystem consists of the following phases:
17  *
18  *      1.  Adjust superblock and write out new parts of the inode
19  *              table
20  *      2.  Determine blocks which need to be relocated, and copy the
21  *              contents of blocks from their old locations to the new ones.
22  *      3.  Scan the inode table, doing the following:
23  *              a.  If blocks have been moved, update the block
24  *                      pointers in the inodes and indirect blocks to
25  *                      point at the new block locations.
26  *              b.  If parts of the inode table need to be evacuated,
27  *                      copy inodes from their old locations to their
28  *                      new ones.
29  *              c.  If (b) needs to be done, note which blocks contain
30  *                      directory information, since we will need to
31  *                      update the directory information.
32  *      4.  Update the directory blocks with the new inode locations.
33  *      5.  Move the inode tables, if necessary.
34  */
35
36 #include "resize2fs.h"
37
38 #ifdef __linux__                        /* Kludge for debugging */
39 #define RESIZE2FS_DEBUG
40 #endif
41
42 static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size);
43 static errcode_t blocks_to_move(ext2_resize_t rfs);
44 static errcode_t block_mover(ext2_resize_t rfs);
45 static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
46 static errcode_t inode_ref_fix(ext2_resize_t rfs);
47 static errcode_t move_itables(ext2_resize_t rfs);
48 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
49
50 /*
51  * Some helper CPP macros
52  */
53 #define FS_BLOCK_BM(fs, i) ((fs)->group_desc[(i)].bg_block_bitmap)
54 #define FS_INODE_BM(fs, i) ((fs)->group_desc[(i)].bg_inode_bitmap)
55 #define FS_INODE_TB(fs, i) ((fs)->group_desc[(i)].bg_inode_table)
56
57 #define IS_BLOCK_BM(fs, i, blk) ((blk) == FS_BLOCK_BM((fs),(i)))
58 #define IS_INODE_BM(fs, i, blk) ((blk) == FS_INODE_BM((fs),(i)))
59
60 #define IS_INODE_TB(fs, i, blk) (((blk) >= FS_INODE_TB((fs), (i))) && \
61                                  ((blk) < (FS_INODE_TB((fs), (i)) + \
62                                            (fs)->inode_blocks_per_group)))
63
64
65
66 /*
67  * This is the top-level routine which does the dirty deed....
68  */
69 errcode_t resize_fs(ext2_filsys fs, blk_t *new_size, int flags,
70                     errcode_t (*progress)(ext2_resize_t rfs, int pass,
71                                      unsigned long cur,
72                                      unsigned long max_val))
73 {
74         ext2_resize_t   rfs;
75         errcode_t       retval;
76
77         retval = ext2fs_read_bitmaps(fs);
78         if (retval)
79                 return retval;
80         
81         /*
82          * Create the data structure
83          */
84         retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct),
85                                 (void **) &rfs);
86         if (retval)
87                 return retval;
88         memset(rfs, 0, sizeof(struct ext2_resize_struct));
89
90         rfs->old_fs = fs;
91         rfs->flags = flags;
92         rfs->itable_buf  = 0;
93         rfs->progress = progress;
94         retval = ext2fs_dup_handle(fs, &rfs->new_fs);
95         if (retval)
96                 goto errout;
97
98         retval = adjust_superblock(rfs, *new_size);
99         if (retval)
100                 goto errout;
101
102         *new_size = rfs->new_fs->super->s_blocks_count;
103
104         retval = blocks_to_move(rfs);
105         if (retval)
106                 goto errout;
107
108 #ifdef RESIZE2FS_DEBUG
109         if (rfs->flags & RESIZE_DEBUG_BMOVE)
110                 printf(_("Number of free blocks: %d/%d, Needed: %d\n"),
111                        rfs->old_fs->super->s_free_blocks_count,
112                        rfs->new_fs->super->s_free_blocks_count,
113                        rfs->needed_blocks);
114 #endif
115         
116         retval = block_mover(rfs);
117         if (retval)
118                 goto errout;
119
120         retval = inode_scan_and_fix(rfs);
121         if (retval)
122                 goto errout;
123
124         retval = inode_ref_fix(rfs);
125         if (retval)
126                 goto errout;
127
128         retval = ext2fs_calculate_summary_stats(rfs->new_fs);
129         if (retval)
130                 goto errout;
131         
132         retval = move_itables(rfs);
133         if (retval)
134                 goto errout;
135
136         retval = ext2fs_close(rfs->new_fs);
137         if (retval)
138                 goto errout;
139
140         rfs->flags = flags;
141         
142         ext2fs_free(rfs->old_fs);
143         if (rfs->itable_buf)
144                 ext2fs_free_mem((void **) &rfs->itable_buf);
145         ext2fs_free_mem((void **) &rfs);
146         
147         return 0;
148
149 errout:
150         if (rfs->new_fs)
151                 ext2fs_free(rfs->new_fs);
152         if (rfs->itable_buf)
153                 ext2fs_free_mem((void **) &rfs->itable_buf);
154         ext2fs_free_mem((void **) &rfs);
155         return retval;
156 }
157
158 /* --------------------------------------------------------------------
159  *
160  * Resize processing, phase 1.
161  *
162  * In this phase we adjust the in-memory superblock information, and
163  * initialize any new parts of the inode table.  The new parts of the
164  * inode table are created in virgin disk space, so we can abort here
165  * without any side effects.
166  * --------------------------------------------------------------------
167  */
168
169 /*
170  * This routine adjusts the superblock and other data structures...
171  */
172 static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
173 {
174         ext2_filsys fs;
175         int             overhead = 0;
176         int             rem, adj = 0;
177         errcode_t       retval;
178         ext2_ino_t      real_end;
179         blk_t           blk, group_block;
180         unsigned long   i, j;
181         int             old_numblocks, numblocks, adjblocks;
182         int             has_super, meta_bg, meta_bg_size, old_desc_blocks;
183         unsigned long   max_group;
184         
185         fs = rfs->new_fs;
186         fs->super->s_blocks_count = new_size;
187         ext2fs_mark_super_dirty(fs);
188         ext2fs_mark_bb_dirty(fs);
189         ext2fs_mark_ib_dirty(fs);
190
191 retry:
192         fs->group_desc_count = (fs->super->s_blocks_count -
193                                 fs->super->s_first_data_block +
194                                 EXT2_BLOCKS_PER_GROUP(fs->super) - 1)
195                 / EXT2_BLOCKS_PER_GROUP(fs->super);
196         if (fs->group_desc_count == 0)
197                 return EXT2_ET_TOOSMALL;
198         fs->desc_blocks = (fs->group_desc_count +
199                            EXT2_DESC_PER_BLOCK(fs->super) - 1)
200                 / EXT2_DESC_PER_BLOCK(fs->super);
201
202         /*
203          * Overhead is the number of bookkeeping blocks per group.  It
204          * includes the superblock backup, the group descriptor
205          * backups, the inode bitmap, the block bitmap, and the inode
206          * table.
207          *
208          * XXX Not all block groups need the descriptor blocks, but
209          * being clever is tricky...
210          */
211         overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
212         
213         /*
214          * See if the last group is big enough to support the
215          * necessary data structures.  If not, we need to get rid of
216          * it.
217          */
218         rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
219                 fs->super->s_blocks_per_group;
220         if ((fs->group_desc_count == 1) && rem && (rem < overhead))
221                 return EXT2_ET_TOOSMALL;
222         if (rem && (rem < overhead+50)) {
223                 fs->super->s_blocks_count -= rem;
224                 goto retry;
225         }
226         /*
227          * Adjust the number of inodes
228          */
229         fs->super->s_inodes_count = fs->super->s_inodes_per_group *
230                 fs->group_desc_count;
231
232         /*
233          * Adjust the number of free blocks
234          */
235         blk = rfs->old_fs->super->s_blocks_count;
236         if (blk > fs->super->s_blocks_count)
237                 fs->super->s_free_blocks_count -=
238                         (blk - fs->super->s_blocks_count);
239         else
240                 fs->super->s_free_blocks_count +=
241                         (fs->super->s_blocks_count - blk);
242
243         /*
244          * Adjust the number of reserved blocks
245          */
246         blk = rfs->old_fs->super->s_r_blocks_count * 100 /
247                 rfs->old_fs->super->s_blocks_count;
248         fs->super->s_r_blocks_count = ((fs->super->s_blocks_count * blk)
249                                        / 100);
250
251         /*
252          * Adjust the bitmaps for size
253          */
254         retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
255                                             fs->super->s_inodes_count,
256                                             fs->inode_map);
257         if (retval) goto errout;
258         
259         real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
260                      * fs->group_desc_count)) - 1 +
261                              fs->super->s_first_data_block;
262         retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
263                                             real_end, fs->block_map);
264
265         if (retval) goto errout;
266
267         /*
268          * Reallocate the group descriptors as necessary.
269          */
270         if (rfs->old_fs->desc_blocks != fs->desc_blocks) {
271                 retval = ext2fs_resize_mem(rfs->old_fs->desc_blocks *
272                                            fs->blocksize,
273                                            fs->desc_blocks * fs->blocksize,
274                                            (void **) &fs->group_desc);
275                 if (retval)
276                         goto errout;
277         }
278
279         /*
280          * Check to make sure there are enough inodes
281          */
282         if ((rfs->old_fs->super->s_inodes_count -
283              rfs->old_fs->super->s_free_inodes_count) >
284             rfs->new_fs->super->s_inodes_count) {
285                 retval = ENOSPC;
286                 goto errout;
287         }
288
289         /*
290          * If we are shrinking the number block groups, we're done and
291          * can exit now.
292          */
293         if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
294                 retval = 0;
295                 goto errout;
296         }
297         /*
298          * Fix the count of the last (old) block group
299          */
300         old_numblocks = (rfs->old_fs->super->s_blocks_count -
301                          rfs->old_fs->super->s_first_data_block) %
302                                  rfs->old_fs->super->s_blocks_per_group;
303         if (!old_numblocks)
304                 old_numblocks = rfs->old_fs->super->s_blocks_per_group;
305         if (rfs->old_fs->group_desc_count == fs->group_desc_count) {
306                 numblocks = (rfs->new_fs->super->s_blocks_count -
307                              rfs->new_fs->super->s_first_data_block) %
308                                      rfs->new_fs->super->s_blocks_per_group;
309                 if (!numblocks)
310                         numblocks = rfs->new_fs->super->s_blocks_per_group;
311         } else
312                 numblocks = rfs->new_fs->super->s_blocks_per_group;
313         i = rfs->old_fs->group_desc_count - 1;
314         fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
315                 
316         /*
317          * If the number of block groups is staying the same, we're
318          * done and can exit now.  (If the number block groups is
319          * shrinking, we had exited earlier.)
320          */
321         if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
322                 retval = 0;
323                 goto errout;
324         }
325         /*
326          * Initialize the new block group descriptors
327          */
328         retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
329                                 (void **) &rfs->itable_buf);
330         if (retval)
331                 goto errout;
332
333         memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
334         group_block = fs->super->s_first_data_block +
335                 rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
336
337         adj = rfs->old_fs->group_desc_count;
338         max_group = fs->group_desc_count - adj;
339         if (rfs->progress) {
340                 retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
341                                        0, max_group);
342                 if (retval)
343                         goto errout;
344         }
345         if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
346                 old_desc_blocks = fs->super->s_first_meta_bg;
347         else
348                 old_desc_blocks = fs->desc_blocks;
349         for (i = rfs->old_fs->group_desc_count;
350              i < fs->group_desc_count; i++) {
351                 memset(&fs->group_desc[i], 0,
352                        sizeof(struct ext2_group_desc));
353                 adjblocks = 0;
354
355                 if (i == fs->group_desc_count-1) {
356                         numblocks = (fs->super->s_blocks_count -
357                                      fs->super->s_first_data_block) %
358                                              fs->super->s_blocks_per_group;
359                         if (!numblocks)
360                                 numblocks = fs->super->s_blocks_per_group;
361                 } else
362                         numblocks = fs->super->s_blocks_per_group;
363
364                 has_super = ext2fs_bg_has_super(fs, i);
365                 if (has_super) {
366                         ext2fs_mark_block_bitmap(fs->block_map, group_block);
367                         adjblocks++;
368                 }
369                 meta_bg_size = (fs->blocksize /
370                                 sizeof (struct ext2_group_desc));
371                 meta_bg = i / meta_bg_size;
372                 if (!(fs->super->s_feature_incompat &
373                       EXT2_FEATURE_INCOMPAT_META_BG) ||
374                     (meta_bg < fs->super->s_first_meta_bg)) {
375                         if (has_super) {
376                                 for (j=0; j < old_desc_blocks; j++)
377                                         ext2fs_mark_block_bitmap(fs->block_map,
378                                                          group_block + 1 + j);
379                                 adjblocks += old_desc_blocks;
380                         }
381                 } else {
382                         if (has_super)
383                                 has_super = 1;
384                         if (((i % meta_bg_size) == 0) ||
385                             ((i % meta_bg_size) == 1) ||
386                             ((i % meta_bg_size) == (meta_bg_size-1)))
387                                 ext2fs_mark_block_bitmap(fs->block_map,
388                                                  group_block + has_super);
389                 }
390                 
391                 adjblocks += 2 + fs->inode_blocks_per_group;
392                 
393                 numblocks -= adjblocks;
394                 fs->super->s_free_blocks_count -= adjblocks;
395                 fs->super->s_free_inodes_count +=
396                         fs->super->s_inodes_per_group;
397                 fs->group_desc[i].bg_free_blocks_count = numblocks;
398                 fs->group_desc[i].bg_free_inodes_count =
399                         fs->super->s_inodes_per_group;
400                 fs->group_desc[i].bg_used_dirs_count = 0;
401
402                 retval = ext2fs_allocate_group_table(fs, i, 0);
403                 if (retval) goto errout;
404
405                 /*
406                  * Write out the new inode table
407                  */
408                 retval = io_channel_write_blk(fs->io,
409                                               fs->group_desc[i].bg_inode_table,
410                                               fs->inode_blocks_per_group,
411                                               rfs->itable_buf);
412                 if (retval) goto errout;
413
414                 io_channel_flush(fs->io);
415                 if (rfs->progress) {
416                         retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
417                                                i - adj + 1, max_group);
418                         if (retval)
419                                 goto errout;
420                 }
421                 group_block += fs->super->s_blocks_per_group;
422         }
423         io_channel_flush(fs->io);
424         retval = 0;
425
426 errout:
427         return retval;
428 }
429
430 /* --------------------------------------------------------------------
431  *
432  * Resize processing, phase 2.
433  *
434  * In this phase we adjust determine which blocks need to be moved, in
435  * blocks_to_move().  We then copy the blocks to their ultimate new
436  * destinations using block_mover().  Since we are copying blocks to
437  * their new locations, again during this pass we can abort without
438  * any problems.
439  * --------------------------------------------------------------------
440  */
441
442 /*
443  * This helper function creates a block bitmap with all of the
444  * filesystem meta-data blocks.
445  */
446 static errcode_t mark_table_blocks(ext2_filsys fs,
447                                    ext2fs_block_bitmap *ret_bmap)
448 {
449         blk_t                   block, b;
450         int                     i,j, has_super, meta_bg, meta_bg_size;
451         int                     old_desc_blocks;
452         ext2fs_block_bitmap     bmap;
453         errcode_t               retval;
454
455         retval = ext2fs_allocate_block_bitmap(fs, _("meta-data blocks"), 
456                                               &bmap);
457         if (retval)
458                 return retval;
459         
460         meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
461         block = fs->super->s_first_data_block;
462         if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
463                 old_desc_blocks = fs->super->s_first_meta_bg;
464         else
465                 old_desc_blocks = fs->desc_blocks;
466         for (i = 0; i < fs->group_desc_count; i++) {
467                 has_super = ext2fs_bg_has_super(fs, i);
468                 if (has_super)
469                         /*
470                          * Mark this group's copy of the superblock
471                          */
472                         ext2fs_mark_block_bitmap(bmap, block);
473                 
474                 meta_bg = i / meta_bg_size;
475                 
476                 if (!(fs->super->s_feature_incompat &
477                       EXT2_FEATURE_INCOMPAT_META_BG) ||
478                     (meta_bg < fs->super->s_first_meta_bg)) {
479                         if (has_super) {
480                                 /*
481                                  * Mark this group's copy of the descriptors
482                                  */
483                                 for (j = 0; j < old_desc_blocks; j++)
484                                         ext2fs_mark_block_bitmap(bmap,
485                                                          block + j + 1);
486                         }
487                 } else {
488                         if (has_super)
489                                 has_super = 1;
490                         if (((i % meta_bg_size) == 0) ||
491                             ((i % meta_bg_size) == 1) ||
492                             ((i % meta_bg_size) == (meta_bg_size-1)))
493                                 ext2fs_mark_block_bitmap(bmap,
494                                                          block + has_super);
495                 }
496         
497                 /*
498                  * Mark the blocks used for the inode table
499                  */
500                 for (j = 0, b = fs->group_desc[i].bg_inode_table;
501                      j < fs->inode_blocks_per_group;
502                      j++, b++)
503                         ext2fs_mark_block_bitmap(bmap, b);
504                             
505                 /*
506                  * Mark block used for the block bitmap 
507                  */
508                 ext2fs_mark_block_bitmap(bmap,
509                                          fs->group_desc[i].bg_block_bitmap);
510                 /*
511                  * Mark block used for the inode bitmap 
512                  */
513                 ext2fs_mark_block_bitmap(bmap,
514                                          fs->group_desc[i].bg_inode_bitmap);
515                 block += fs->super->s_blocks_per_group;
516         }
517         *ret_bmap = bmap;
518         return 0;
519 }
520
521 /*
522  * This function checks to see if a particular block (either a
523  * superblock or a block group descriptor) overlaps with an inode or
524  * block bitmap block, or with the inode table.
525  */
526 static void mark_fs_metablock(ext2_resize_t rfs,
527                               ext2fs_block_bitmap meta_bmap,
528                               int group, blk_t blk)
529 {
530         ext2_filsys     fs = rfs->new_fs;
531         
532         ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
533         ext2fs_mark_block_bitmap(fs->block_map, blk);
534
535         /*
536          * Check to see if we overlap with the inode or block bitmap,
537          * or the inode tables.  If not, and the block is in use, then
538          * mark it as a block to be moved.
539          */
540         if (IS_BLOCK_BM(fs, group, blk)) {
541                 FS_BLOCK_BM(fs, group) = 0;
542                 rfs->needed_blocks++;
543         } else if (IS_INODE_BM(fs, group, blk)) {
544                 FS_INODE_BM(fs, group) = 0;
545                 rfs->needed_blocks++;
546         } else if (IS_INODE_TB(fs, group, blk)) {
547                 FS_INODE_TB(fs, group) = 0;
548                 rfs->needed_blocks++;
549         } else if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk) &&
550                    !ext2fs_test_block_bitmap(meta_bmap, blk)) {
551                 ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
552                 rfs->needed_blocks++;
553         }
554 }
555
556
557 /*
558  * This routine marks and unmarks reserved blocks in the new block
559  * bitmap.  It also determines which blocks need to be moved and
560  * places this information into the move_blocks bitmap.
561  */
562 static errcode_t blocks_to_move(ext2_resize_t rfs)
563 {
564         int     i, j, max_groups, has_super, meta_bg, meta_bg_size;
565         blk_t   blk, group_blk;
566         unsigned long old_blocks, new_blocks;
567         errcode_t       retval;
568         ext2_filsys     fs, old_fs;
569         ext2fs_block_bitmap     meta_bmap;
570
571         fs = rfs->new_fs;
572         old_fs = rfs->old_fs;
573         if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
574                 fs = rfs->old_fs;
575         
576         retval = ext2fs_allocate_block_bitmap(fs, _("reserved blocks"),
577                                               &rfs->reserve_blocks);
578         if (retval)
579                 return retval;
580
581         retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
582                                               &rfs->move_blocks);
583         if (retval)
584                 return retval;
585
586         retval = mark_table_blocks(old_fs, &meta_bmap);
587         if (retval)
588                 return retval;
589
590         fs = rfs->new_fs;
591         
592         /*
593          * If we're shrinking the filesystem, we need to move all of
594          * the blocks that don't fit any more
595          */
596         for (blk = fs->super->s_blocks_count;
597              blk < old_fs->super->s_blocks_count; blk++) {
598                 if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
599                     !ext2fs_test_block_bitmap(meta_bmap, blk)) {
600                         ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
601                         rfs->needed_blocks++;
602                 }
603                 ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
604         }
605         
606         if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) {
607                 old_blocks = old_fs->super->s_first_meta_bg;
608                 new_blocks = fs->super->s_first_meta_bg;
609         } else {
610                 old_blocks = old_fs->desc_blocks;
611                 new_blocks = fs->desc_blocks;
612         }
613         
614         if (old_blocks == new_blocks) {
615                 retval = 0;
616                 goto errout;
617         }
618
619         max_groups = fs->group_desc_count;
620         if (max_groups > old_fs->group_desc_count)
621                 max_groups = old_fs->group_desc_count;
622         group_blk = old_fs->super->s_first_data_block;
623         /*
624          * If we're reducing the number of descriptor blocks, this
625          * makes life easy.  :-)   We just have to mark some extra
626          * blocks as free.
627          */
628         if (old_blocks > new_blocks) {
629                 for (i = 0; i < max_groups; i++) {
630                         if (!ext2fs_bg_has_super(fs, i)) {
631                                 group_blk += fs->super->s_blocks_per_group;
632                                 continue;
633                         }
634                         for (blk = group_blk+1+new_blocks;
635                              blk < group_blk+1+old_blocks; blk++) {
636                                 ext2fs_unmark_block_bitmap(fs->block_map,
637                                                            blk);
638                                 rfs->needed_blocks--;
639                         }
640                         group_blk += fs->super->s_blocks_per_group;
641                 }
642                 retval = 0;
643                 goto errout;
644         }
645         /*
646          * If we're increasing the number of descriptor blocks, life
647          * gets interesting....  
648          */
649         meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
650         for (i = 0; i < max_groups; i++) {
651                 has_super = ext2fs_bg_has_super(fs, i);
652                 if (has_super)
653                         mark_fs_metablock(rfs, meta_bmap, i, group_blk);
654
655                 meta_bg = i / meta_bg_size;
656                 if (!(fs->super->s_feature_incompat &
657                       EXT2_FEATURE_INCOMPAT_META_BG) ||
658                     (meta_bg < fs->super->s_first_meta_bg)) {
659                         if (has_super) {
660                                 for (blk = group_blk+1;
661                                      blk < group_blk + 1 + new_blocks; blk++)
662                                         mark_fs_metablock(rfs, meta_bmap, 
663                                                           i, blk);
664                         }
665                 } else {
666                         if (has_super)
667                                 has_super = 1;
668                         if (((i % meta_bg_size) == 0) ||
669                             ((i % meta_bg_size) == 1) ||
670                             ((i % meta_bg_size) == (meta_bg_size-1)))
671                                 mark_fs_metablock(rfs, meta_bmap, i,
672                                                   group_blk + has_super);
673                 }
674
675                 if (fs->group_desc[i].bg_inode_table &&
676                     fs->group_desc[i].bg_inode_bitmap &&
677                     fs->group_desc[i].bg_block_bitmap)
678                         goto next_group;
679
680                 /*
681                  * Reserve the existing meta blocks that we know
682                  * aren't to be moved.
683                  */
684                 if (fs->group_desc[i].bg_block_bitmap)
685                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
686                                  fs->group_desc[i].bg_block_bitmap);
687                 if (fs->group_desc[i].bg_inode_bitmap)
688                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
689                                  fs->group_desc[i].bg_inode_bitmap);
690                 if (fs->group_desc[i].bg_inode_table)
691                         for (blk = fs->group_desc[i].bg_inode_table, j=0;
692                              j < fs->inode_blocks_per_group ; j++, blk++)
693                                 ext2fs_mark_block_bitmap(rfs->reserve_blocks,
694                                                          blk);
695
696                 /*
697                  * Allocate the missing data structures
698                  */
699                 retval = ext2fs_allocate_group_table(fs, i,
700                                                      rfs->reserve_blocks);
701                 if (retval)
702                         goto errout;
703
704                 /*
705                  * For those structures that have changed, we need to
706                  * do bookkeepping.
707                  */
708                 if (FS_BLOCK_BM(old_fs, i) !=
709                     (blk = FS_BLOCK_BM(fs, i))) {
710                         ext2fs_mark_block_bitmap(fs->block_map, blk);
711                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
712                             !ext2fs_test_block_bitmap(meta_bmap, blk))
713                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
714                                                          blk);
715                 }
716                 if (FS_INODE_BM(old_fs, i) !=
717                     (blk = FS_INODE_BM(fs, i))) {
718                         ext2fs_mark_block_bitmap(fs->block_map, blk);
719                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
720                             !ext2fs_test_block_bitmap(meta_bmap, blk))
721                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
722                                                          blk);
723                 }
724
725                 /*
726                  * The inode table, if we need to relocate it, is
727                  * handled specially.  We have to reserve the blocks
728                  * for both the old and the new inode table, since we
729                  * can't have the inode table be destroyed during the
730                  * block relocation phase.
731                  */
732                 if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
733                         goto next_group; /* inode table not moved */
734
735                 rfs->needed_blocks += fs->inode_blocks_per_group;
736
737                 /*
738                  * Mark the new inode table as in use in the new block
739                  * allocation bitmap, and move any blocks that might 
740                  * be necessary.
741                  */
742                 for (blk = fs->group_desc[i].bg_inode_table, j=0;
743                      j < fs->inode_blocks_per_group ; j++, blk++) {
744                         ext2fs_mark_block_bitmap(fs->block_map, blk);
745                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
746                             !ext2fs_test_block_bitmap(meta_bmap, blk))
747                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
748                                                          blk);
749                 }
750                 
751                 /*
752                  * Make sure the old inode table is reserved in the
753                  * block reservation bitmap.
754                  */
755                 for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
756                      j < fs->inode_blocks_per_group ; j++, blk++)
757                         ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
758                 
759         next_group:
760                 group_blk += rfs->new_fs->super->s_blocks_per_group;
761         }
762         retval = 0;
763
764 errout:
765         if (meta_bmap)
766                 ext2fs_free_block_bitmap(meta_bmap);
767         
768         return retval;
769 }
770
771 /*
772  * This helper function tries to allocate a new block.  We try to
773  * avoid hitting the original group descriptor blocks at least at
774  * first, since we want to make it possible to recover from a badly
775  * aborted resize operation as much as possible.
776  *
777  * In the future, I may further modify this routine to balance out
778  * where we get the new blocks across the various block groups.
779  * Ideally we would allocate blocks that corresponded with the block
780  * group of the containing inode, and keep contiguous blocks
781  * together.  However, this very difficult to do efficiently, since we
782  * don't have the necessary information up front.
783  */
784
785 #define AVOID_OLD       1
786 #define DESPERATION     2
787
788 static void init_block_alloc(ext2_resize_t rfs)
789 {
790         rfs->alloc_state = AVOID_OLD;
791         rfs->new_blk = rfs->new_fs->super->s_first_data_block;
792 #if 0
793         /* HACK for testing */
794         if (rfs->new_fs->super->s_blocks_count >
795             rfs->old_fs->super->s_blocks_count)
796                 rfs->new_blk = rfs->old_fs->super->s_blocks_count;
797 #endif
798 }
799
800 static blk_t get_new_block(ext2_resize_t rfs)
801 {
802         ext2_filsys     fs = rfs->new_fs;
803         
804         while (1) {
805                 if (rfs->new_blk >= fs->super->s_blocks_count) {
806                         if (rfs->alloc_state == DESPERATION)
807                                 return 0;
808
809 #ifdef RESIZE2FS_DEBUG
810                         if (rfs->flags & RESIZE_DEBUG_BMOVE)
811                                 printf(_("Going into desperation "
812                                        "mode for block allocations\n"));
813 #endif                  
814                         rfs->alloc_state = DESPERATION;
815                         rfs->new_blk = fs->super->s_first_data_block;
816                         continue;
817                 }
818                 if (ext2fs_test_block_bitmap(fs->block_map, rfs->new_blk) ||
819                     ext2fs_test_block_bitmap(rfs->reserve_blocks,
820                                              rfs->new_blk) ||
821                     ((rfs->alloc_state == AVOID_OLD) &&
822                      (rfs->new_blk < rfs->old_fs->super->s_blocks_count) &&
823                      ext2fs_test_block_bitmap(rfs->old_fs->block_map,
824                                               rfs->new_blk))) {
825                         rfs->new_blk++;
826                         continue;
827                 }
828                 return rfs->new_blk;
829         }
830 }
831
832 static errcode_t block_mover(ext2_resize_t rfs)
833 {
834         blk_t                   blk, old_blk, new_blk;
835         ext2_filsys             fs = rfs->new_fs;
836         ext2_filsys             old_fs = rfs->old_fs;
837         errcode_t               retval;
838         int                     size, c;
839         int                     to_move, moved;
840         ext2_badblocks_list     badblock_list = 0;
841         int                     bb_modified = 0;
842         
843         retval = ext2fs_read_bb_inode(old_fs, &badblock_list);
844         if (retval)
845                 return retval;
846
847         new_blk = fs->super->s_first_data_block;
848         if (!rfs->itable_buf) {
849                 retval = ext2fs_get_mem(fs->blocksize *
850                                         fs->inode_blocks_per_group,
851                                         (void **) &rfs->itable_buf);
852                 if (retval)
853                         return retval;
854         }
855         retval = ext2fs_create_extent_table(&rfs->bmap, 0);
856         if (retval)
857                 return retval;
858
859         /*
860          * The first step is to figure out where all of the blocks
861          * will go.
862          */
863         to_move = moved = 0;
864         init_block_alloc(rfs);
865         for (blk = old_fs->super->s_first_data_block;
866              blk < old_fs->super->s_blocks_count; blk++) {
867                 if (!ext2fs_test_block_bitmap(old_fs->block_map, blk))
868                         continue;
869                 if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk))
870                         continue;
871                 if (ext2fs_badblocks_list_test(badblock_list, blk)) {
872                         ext2fs_badblocks_list_del(badblock_list, blk);
873                         bb_modified++;
874                         continue;
875                 }
876
877                 new_blk = get_new_block(rfs);
878                 if (!new_blk) {
879                         retval = ENOSPC;
880                         goto errout;
881                 }
882                 ext2fs_mark_block_bitmap(fs->block_map, new_blk);
883                 ext2fs_add_extent_entry(rfs->bmap, blk, new_blk);
884                 to_move++;
885         }
886         
887         if (to_move == 0) {
888                 if (rfs->bmap) {
889                         ext2fs_free_extent_table(rfs->bmap);
890                         rfs->bmap = 0;
891                 }
892                 retval = 0;
893                 goto errout;
894         }
895
896         /*
897          * Step two is to actually move the blocks
898          */
899         retval =  ext2fs_iterate_extent(rfs->bmap, 0, 0, 0);
900         if (retval) goto errout;
901
902         if (rfs->progress) {
903                 retval = (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS,
904                                          0, to_move);
905                 if (retval)
906                         goto errout;
907         }
908         while (1) {
909                 retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size);
910                 if (retval) goto errout;
911                 if (!size)
912                         break;
913 #ifdef RESIZE2FS_DEBUG
914                 if (rfs->flags & RESIZE_DEBUG_BMOVE)
915                         printf(_("Moving %d blocks %u->%u\n"), size,
916                                old_blk, new_blk);
917 #endif
918                 do {
919                         c = size;
920                         if (c > fs->inode_blocks_per_group)
921                                 c = fs->inode_blocks_per_group;
922                         retval = io_channel_read_blk(fs->io, old_blk, c,
923                                                      rfs->itable_buf);
924                         if (retval) goto errout;
925                         retval = io_channel_write_blk(fs->io, new_blk, c,
926                                                       rfs->itable_buf);
927                         if (retval) goto errout;
928                         size -= c;
929                         new_blk += c;
930                         old_blk += c;
931                         moved += c;
932                         if (rfs->progress) {
933                                 io_channel_flush(fs->io);
934                                 retval = (rfs->progress)(rfs,
935                                                 E2_RSZ_BLOCK_RELOC_PASS,
936                                                 moved, to_move);
937                                 if (retval)
938                                         goto errout;
939                         }
940                 } while (size > 0);
941                 io_channel_flush(fs->io);
942         }
943
944 errout:
945         if (badblock_list) {
946                 if (!retval && bb_modified)
947                         retval = ext2fs_update_bb_inode(old_fs,
948                                                         badblock_list);
949                 ext2fs_badblocks_list_free(badblock_list);
950         }
951         return retval;
952 }
953
954
955 /* --------------------------------------------------------------------
956  *
957  * Resize processing, phase 3
958  *
959  * --------------------------------------------------------------------
960  */
961
962
963 struct process_block_struct {
964         ext2_resize_t           rfs;
965         ext2_ino_t              ino;
966         struct ext2_inode *     inode;
967         errcode_t               error;
968         int                     is_dir;
969         int                     changed;
970 };
971
972 static int process_block(ext2_filsys fs, blk_t  *block_nr,
973                          e2_blkcnt_t blockcnt, blk_t ref_block,
974                          int ref_offset, void *priv_data)
975 {
976         struct process_block_struct *pb;
977         errcode_t       retval;
978         blk_t           block, new_block;
979         int             ret = 0;
980
981         pb = (struct process_block_struct *) priv_data;
982         block = *block_nr;
983         if (pb->rfs->bmap) {
984                 new_block = ext2fs_extent_translate(pb->rfs->bmap, block);
985                 if (new_block) {
986                         *block_nr = new_block;
987                         ret |= BLOCK_CHANGED;
988                         pb->changed = 1;
989 #ifdef RESIZE2FS_DEBUG
990                         if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
991                                 printf(_("ino=%u, blockcnt=%lld, %u->%u\n"), 
992                                        pb->ino, blockcnt, block, new_block);
993 #endif
994                         block = new_block;
995                 }
996         }
997         if (pb->is_dir) {
998                 retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
999                                               block, (int) blockcnt);
1000                 if (retval) {
1001                         pb->error = retval;
1002                         ret |= BLOCK_ABORT;
1003                 }
1004         }
1005         return ret;
1006 }
1007
1008 /*
1009  * Progress callback
1010  */
1011 static errcode_t progress_callback(ext2_filsys fs, ext2_inode_scan scan,
1012                                    dgrp_t group, void * priv_data)
1013 {
1014         ext2_resize_t rfs = (ext2_resize_t) priv_data;
1015         errcode_t               retval;
1016
1017         /*
1018          * This check is to protect against old ext2 libraries.  It
1019          * shouldn't be needed against new libraries.
1020          */
1021         if ((group+1) == 0)
1022                 return 0;
1023
1024         if (rfs->progress) {
1025                 io_channel_flush(fs->io);
1026                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
1027                                          group+1, fs->group_desc_count);
1028                 if (retval)
1029                         return retval;
1030         }
1031         
1032         return 0;
1033 }
1034
1035 static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
1036 {
1037         struct process_block_struct     pb;
1038         ext2_ino_t              ino, new_inode;
1039         struct ext2_inode       inode;
1040         ext2_inode_scan         scan = NULL;
1041         errcode_t               retval;
1042         int                     group;
1043         char                    *block_buf = 0;
1044         ext2_ino_t              start_to_move;
1045         blk_t                   orig_size, new_block;
1046         
1047         if ((rfs->old_fs->group_desc_count <=
1048              rfs->new_fs->group_desc_count) &&
1049             !rfs->bmap)
1050                 return 0;
1051
1052         /*
1053          * Save the original size of the old filesystem, and
1054          * temporarily set the size to be the new size if the new size
1055          * is larger.  We need to do this to avoid catching an error
1056          * by the block iterator routines
1057          */
1058         orig_size = rfs->old_fs->super->s_blocks_count;
1059         if (orig_size < rfs->new_fs->super->s_blocks_count)
1060                 rfs->old_fs->super->s_blocks_count =
1061                         rfs->new_fs->super->s_blocks_count;
1062
1063         retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
1064         if (retval) goto errout;
1065
1066         retval = ext2fs_init_dblist(rfs->old_fs, 0);
1067         if (retval) goto errout;
1068         retval = ext2fs_get_mem(rfs->old_fs->blocksize * 3,
1069                                 (void **) &block_buf);
1070         if (retval) goto errout;
1071
1072         start_to_move = (rfs->new_fs->group_desc_count *
1073                          rfs->new_fs->super->s_inodes_per_group);
1074         
1075         if (rfs->progress) {
1076                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
1077                                          0, rfs->old_fs->group_desc_count);
1078                 if (retval)
1079                         goto errout;
1080         }
1081         ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
1082         pb.rfs = rfs;
1083         pb.inode = &inode;
1084         pb.error = 0;
1085         new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
1086         /*
1087          * First, copy all of the inodes that need to be moved
1088          * elsewhere in the inode table
1089          */
1090         while (1) {
1091                 retval = ext2fs_get_next_inode(scan, &ino, &inode);
1092                 if (retval) goto errout;
1093                 if (!ino)
1094                         break;
1095
1096                 if (inode.i_links_count == 0)
1097                         continue; /* inode not in use */
1098
1099                 pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
1100                 pb.changed = 0;
1101
1102                 if (inode.i_file_acl && rfs->bmap) {
1103                         new_block = ext2fs_extent_translate(rfs->bmap, 
1104                                                             inode.i_file_acl);
1105                         if (new_block) {
1106                                 inode.i_file_acl = new_block;
1107                                 retval = ext2fs_write_inode(rfs->old_fs, 
1108                                                             ino, &inode);
1109                                 if (retval) goto errout;
1110                         }
1111                 }
1112                 
1113                 if (ext2fs_inode_has_valid_blocks(&inode) &&
1114                     (rfs->bmap || pb.is_dir)) {
1115                         pb.ino = ino;
1116                         retval = ext2fs_block_iterate2(rfs->old_fs,
1117                                                        ino, 0, block_buf,
1118                                                        process_block, &pb);
1119                         if (retval)
1120                                 goto errout;
1121                         if (pb.error) {
1122                                 retval = pb.error;
1123                                 goto errout;
1124                         }
1125                 }
1126
1127                 if (ino <= start_to_move)
1128                         continue; /* Don't need to move it. */
1129
1130                 /*
1131                  * Find a new inode
1132                  */
1133                 while (1) { 
1134                         if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map, 
1135                                                       new_inode))
1136                                 break;
1137                         new_inode++;
1138                         if (new_inode > rfs->new_fs->super->s_inodes_count) {
1139                                 retval = ENOSPC;
1140                                 goto errout;
1141                         }
1142                 }
1143                 ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new_inode);
1144                 if (pb.changed) {
1145                         /* Get the new version of the inode */
1146                         retval = ext2fs_read_inode(rfs->old_fs, ino, &inode);
1147                         if (retval) goto errout;
1148                 }
1149                 inode.i_ctime = time(0);
1150                 retval = ext2fs_write_inode(rfs->old_fs, new_inode, &inode);
1151                 if (retval) goto errout;
1152
1153                 group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
1154                 if (LINUX_S_ISDIR(inode.i_mode))
1155                         rfs->new_fs->group_desc[group].bg_used_dirs_count++;
1156                 
1157 #ifdef RESIZE2FS_DEBUG
1158                 if (rfs->flags & RESIZE_DEBUG_INODEMAP)
1159                         printf(_("Inode moved %u->%u\n"), ino, new_inode);
1160 #endif
1161                 if (!rfs->imap) {
1162                         retval = ext2fs_create_extent_table(&rfs->imap, 0);
1163                         if (retval)
1164                                 goto errout;
1165                 }
1166                 ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
1167         }
1168         io_channel_flush(rfs->old_fs->io);
1169
1170 errout:
1171         rfs->old_fs->super->s_blocks_count = orig_size;
1172         if (rfs->bmap) {
1173                 ext2fs_free_extent_table(rfs->bmap);
1174                 rfs->bmap = 0;
1175         }
1176         if (scan)
1177                 ext2fs_close_inode_scan(scan);
1178         if (block_buf)
1179                 ext2fs_free_mem((void **) &block_buf);
1180         return retval;
1181 }
1182
1183 /* --------------------------------------------------------------------
1184  *
1185  * Resize processing, phase 4.
1186  *
1187  * --------------------------------------------------------------------
1188  */
1189
1190 struct istruct {
1191         ext2_resize_t rfs;
1192         errcode_t       err;
1193         unsigned long   max_dirs;
1194         int             num;
1195 };
1196
1197 static int check_and_change_inodes(ext2_ino_t dir, int entry,
1198                                    struct ext2_dir_entry *dirent, int offset,
1199                                    int  blocksize, char *buf, void *priv_data)
1200 {
1201         struct istruct *is = (struct istruct *) priv_data;
1202         struct ext2_inode       inode;
1203         ext2_ino_t              new_inode;
1204         errcode_t               retval;
1205
1206         if (is->rfs->progress && offset == 0) {
1207                 io_channel_flush(is->rfs->old_fs->io);
1208                 is->err = (is->rfs->progress)(is->rfs,
1209                                               E2_RSZ_INODE_REF_UPD_PASS,
1210                                               ++is->num, is->max_dirs);
1211                 if (is->err)
1212                         return DIRENT_ABORT;
1213         }
1214
1215         if (!dirent->inode)
1216                 return 0;
1217
1218         new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
1219
1220         if (!new_inode)
1221                 return 0;
1222 #ifdef RESIZE2FS_DEBUG
1223         if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
1224                 printf(_("Inode translate (dir=%u, name=%.*s, %u->%u)\n"),
1225                        dir, dirent->name_len, dirent->name,
1226                        dirent->inode, new_inode);
1227 #endif
1228
1229         dirent->inode = new_inode;
1230
1231         /* Update the directory mtime and ctime */
1232         retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
1233         if (retval == 0) {
1234                 inode.i_mtime = inode.i_ctime = time(0);
1235                 ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
1236         }
1237
1238         return DIRENT_CHANGED;
1239 }
1240
1241 static errcode_t inode_ref_fix(ext2_resize_t rfs)
1242 {
1243         errcode_t               retval;
1244         struct istruct          is;
1245         
1246         if (!rfs->imap)
1247                 return 0;
1248        
1249         /*
1250          * Now, we iterate over all of the directories to update the
1251          * inode references
1252          */
1253         is.num = 0;
1254         is.max_dirs = ext2fs_dblist_count(rfs->old_fs->dblist);
1255         is.rfs = rfs;
1256         is.err = 0;
1257
1258         if (rfs->progress) {
1259                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
1260                                          0, is.max_dirs);
1261                 if (retval)
1262                         goto errout;
1263         }
1264         
1265         retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
1266                                            DIRENT_FLAG_INCLUDE_EMPTY, 0,
1267                                            check_and_change_inodes, &is);
1268         if (retval)
1269                 goto errout;
1270         if (is.err) {
1271                 retval = is.err;
1272                 goto errout;
1273         }
1274
1275 errout:
1276         ext2fs_free_extent_table(rfs->imap);
1277         rfs->imap = 0;
1278         return retval;
1279 }
1280
1281
1282 /* --------------------------------------------------------------------
1283  *
1284  * Resize processing, phase 5.
1285  *
1286  * In this phase we actually move the inode table around, and then
1287  * update the summary statistics.  This is scary, since aborting here
1288  * will potentially scramble the filesystem.  (We are moving the
1289  * inode tables around in place, and so the potential for lost data,
1290  * or at the very least scrambling the mapping between filenames and
1291  * inode numbers is very high in case of a power failure here.)
1292  * --------------------------------------------------------------------
1293  */
1294
1295
1296 /*
1297  * A very scary routine --- this one moves the inode table around!!!
1298  *
1299  * After this you have to use the rfs->new_fs file handle to read and
1300  * write inodes.
1301  */
1302 static errcode_t move_itables(ext2_resize_t rfs)
1303 {
1304         int             i, n, num, max_groups, size, diff;
1305         ext2_filsys     fs = rfs->new_fs;
1306         char            *cp;
1307         blk_t           old_blk, new_blk;
1308         errcode_t       retval;
1309         int             to_move, moved;
1310
1311         max_groups = fs->group_desc_count;
1312         if (max_groups > rfs->old_fs->group_desc_count)
1313                 max_groups = rfs->old_fs->group_desc_count;
1314
1315         size = fs->blocksize * fs->inode_blocks_per_group;
1316         if (!rfs->itable_buf) {
1317                 retval = ext2fs_get_mem(size, (void **) &rfs->itable_buf);
1318                 if (retval)
1319                         return retval;
1320         }
1321
1322         /*
1323          * Figure out how many inode tables we need to move
1324          */
1325         to_move = moved = 0;
1326         for (i=0; i < max_groups; i++)
1327                 if (rfs->old_fs->group_desc[i].bg_inode_table !=
1328                     fs->group_desc[i].bg_inode_table)
1329                         to_move++;
1330
1331         if (to_move == 0)
1332                 return 0;
1333
1334         if (rfs->progress) {
1335                 retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1336                                        0, to_move);
1337                 if (retval)
1338                         goto errout;
1339         }
1340
1341         rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
1342
1343         for (i=0; i < max_groups; i++) {
1344                 old_blk = rfs->old_fs->group_desc[i].bg_inode_table;
1345                 new_blk = fs->group_desc[i].bg_inode_table;
1346                 diff = new_blk - old_blk;
1347                 
1348 #ifdef RESIZE2FS_DEBUG
1349                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
1350                         printf(_("Itable move group %d block "
1351                                "%u->%u (diff %d)\n"), 
1352                                i, old_blk, new_blk, diff);
1353 #endif
1354                 
1355                 if (!diff)
1356                         continue;
1357
1358                 retval = io_channel_read_blk(fs->io, old_blk,
1359                                              fs->inode_blocks_per_group,
1360                                              rfs->itable_buf);
1361                 if (retval) 
1362                         goto errout;
1363                 /*
1364                  * The end of the inode table segment often contains
1365                  * all zeros, and we're often only moving the inode
1366                  * table down a block or two.  If so, we can optimize
1367                  * things by not rewriting blocks that we know to be zero
1368                  * already.
1369                  */
1370                 for (cp = rfs->itable_buf+size, n=0; n < size; n++, cp--)
1371                         if (*cp)
1372                                 break;
1373                 n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
1374 #ifdef RESIZE2FS_DEBUG
1375                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
1376                         printf(_("%d blocks of zeros...\n"), n);
1377 #endif
1378                 num = fs->inode_blocks_per_group;
1379                 if (n > diff)
1380                         num -= n;
1381
1382                 retval = io_channel_write_blk(fs->io, new_blk,
1383                                               num, rfs->itable_buf);
1384                 if (retval) {
1385                         io_channel_write_blk(fs->io, old_blk,
1386                                              num, rfs->itable_buf);
1387                         goto errout;
1388                 }
1389                 if (n > diff) {
1390                         retval = io_channel_write_blk(fs->io,
1391                               old_blk + fs->inode_blocks_per_group,
1392                               diff, (rfs->itable_buf +
1393                                      (fs->inode_blocks_per_group - diff) *
1394                                      fs->blocksize));
1395                         if (retval)
1396                                 goto errout;
1397                 }
1398                 rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
1399                 ext2fs_mark_super_dirty(rfs->old_fs);
1400                 if (rfs->progress) {
1401                         ext2fs_flush(rfs->old_fs);
1402                         retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1403                                                ++moved, to_move);
1404                         if (retval)
1405                                 goto errout;
1406                 }
1407         }
1408         ext2fs_flush(fs);
1409 #ifdef RESIZE2FS_DEBUG
1410         if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
1411                 printf(_("Inode table move finished.\n"));
1412 #endif
1413         return 0;
1414         
1415 errout:
1416         return retval;
1417 }
1418
1419 /*
1420  * Finally, recalculate the summary information
1421  */
1422 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1423 {
1424         blk_t           blk;
1425         ext2_ino_t      ino;
1426         int             group = 0;
1427         int             count = 0;
1428         int             total_free = 0;
1429         int             group_free = 0;
1430
1431         /*
1432          * First calculate the block statistics
1433          */
1434         for (blk = fs->super->s_first_data_block;
1435              blk < fs->super->s_blocks_count; blk++) {
1436                 if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
1437                         group_free++;
1438                         total_free++;
1439                 }
1440                 count++;
1441                 if ((count == fs->super->s_blocks_per_group) ||
1442                     (blk == fs->super->s_blocks_count-1)) {
1443                         fs->group_desc[group++].bg_free_blocks_count =
1444                                 group_free;
1445                         count = 0;
1446                         group_free = 0;
1447                 }
1448         }
1449         fs->super->s_free_blocks_count = total_free;
1450         
1451         /*
1452          * Next, calculate the inode statistics
1453          */
1454         group_free = 0;
1455         total_free = 0;
1456         count = 0;
1457         group = 0;
1458         for (ino = 1; ino <= fs->super->s_inodes_count; ino++) {
1459                 if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
1460                         group_free++;
1461                         total_free++;
1462                 }
1463                 count++;
1464                 if ((count == fs->super->s_inodes_per_group) ||
1465                     (ino == fs->super->s_inodes_count)) {
1466                         fs->group_desc[group++].bg_free_inodes_count =
1467                                 group_free;
1468                         count = 0;
1469                         group_free = 0;
1470                 }
1471         }
1472         fs->super->s_free_inodes_count = total_free;
1473         ext2fs_mark_super_dirty(fs);
1474         return 0;
1475 }