Whamcloud - gitweb
Add support for the meta_bg feature flag to the resize2fs program.
[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                         for (blk = group_blk+1;
660                              blk < group_blk + 1 + new_blocks; blk++)
661                                 mark_fs_metablock(rfs, meta_bmap, i, blk);
662                 } else {
663                         if (has_super)
664                                 has_super = 1;
665                         if (((i % meta_bg_size) == 0) ||
666                             ((i % meta_bg_size) == 1) ||
667                             ((i % meta_bg_size) == (meta_bg_size-1)))
668                                 mark_fs_metablock(rfs, meta_bmap, i,
669                                                   group_blk + has_super);
670                 }
671
672                 if (fs->group_desc[i].bg_inode_table &&
673                     fs->group_desc[i].bg_inode_bitmap &&
674                     fs->group_desc[i].bg_block_bitmap)
675                         goto next_group;
676
677                 /*
678                  * Reserve the existing meta blocks that we know
679                  * aren't to be moved.
680                  */
681                 if (fs->group_desc[i].bg_block_bitmap)
682                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
683                                  fs->group_desc[i].bg_block_bitmap);
684                 if (fs->group_desc[i].bg_inode_bitmap)
685                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
686                                  fs->group_desc[i].bg_inode_bitmap);
687                 if (fs->group_desc[i].bg_inode_table)
688                         for (blk = fs->group_desc[i].bg_inode_table, j=0;
689                              j < fs->inode_blocks_per_group ; j++, blk++)
690                                 ext2fs_mark_block_bitmap(rfs->reserve_blocks,
691                                                          blk);
692
693                 /*
694                  * Allocate the missing data structures
695                  */
696                 retval = ext2fs_allocate_group_table(fs, i,
697                                                      rfs->reserve_blocks);
698                 if (retval)
699                         goto errout;
700
701                 /*
702                  * For those structures that have changed, we need to
703                  * do bookkeepping.
704                  */
705                 if (FS_BLOCK_BM(old_fs, i) !=
706                     (blk = FS_BLOCK_BM(fs, i))) {
707                         ext2fs_mark_block_bitmap(fs->block_map, blk);
708                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
709                             !ext2fs_test_block_bitmap(meta_bmap, blk))
710                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
711                                                          blk);
712                 }
713                 if (FS_INODE_BM(old_fs, i) !=
714                     (blk = FS_INODE_BM(fs, i))) {
715                         ext2fs_mark_block_bitmap(fs->block_map, blk);
716                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
717                             !ext2fs_test_block_bitmap(meta_bmap, blk))
718                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
719                                                          blk);
720                 }
721
722                 /*
723                  * The inode table, if we need to relocate it, is
724                  * handled specially.  We have to reserve the blocks
725                  * for both the old and the new inode table, since we
726                  * can't have the inode table be destroyed during the
727                  * block relocation phase.
728                  */
729                 if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
730                         goto next_group; /* inode table not moved */
731
732                 rfs->needed_blocks += fs->inode_blocks_per_group;
733
734                 /*
735                  * Mark the new inode table as in use in the new block
736                  * allocation bitmap, and move any blocks that might 
737                  * be necessary.
738                  */
739                 for (blk = fs->group_desc[i].bg_inode_table, j=0;
740                      j < fs->inode_blocks_per_group ; j++, blk++) {
741                         ext2fs_mark_block_bitmap(fs->block_map, blk);
742                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
743                             !ext2fs_test_block_bitmap(meta_bmap, blk))
744                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
745                                                          blk);
746                 }
747                 
748                 /*
749                  * Make sure the old inode table is reserved in the
750                  * block reservation bitmap.
751                  */
752                 for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
753                      j < fs->inode_blocks_per_group ; j++, blk++)
754                         ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
755                 
756         next_group:
757                 group_blk += rfs->new_fs->super->s_blocks_per_group;
758         }
759         retval = 0;
760
761 errout:
762         if (meta_bmap)
763                 ext2fs_free_block_bitmap(meta_bmap);
764         
765         return retval;
766 }
767
768 /*
769  * This helper function tries to allocate a new block.  We try to
770  * avoid hitting the original group descriptor blocks at least at
771  * first, since we want to make it possible to recover from a badly
772  * aborted resize operation as much as possible.
773  *
774  * In the future, I may further modify this routine to balance out
775  * where we get the new blocks across the various block groups.
776  * Ideally we would allocate blocks that corresponded with the block
777  * group of the containing inode, and keep contiguous blocks
778  * together.  However, this very difficult to do efficiently, since we
779  * don't have the necessary information up front.
780  */
781
782 #define AVOID_OLD       1
783 #define DESPERATION     2
784
785 static void init_block_alloc(ext2_resize_t rfs)
786 {
787         rfs->alloc_state = AVOID_OLD;
788         rfs->new_blk = rfs->new_fs->super->s_first_data_block;
789 #if 0
790         /* HACK for testing */
791         if (rfs->new_fs->super->s_blocks_count >
792             rfs->old_fs->super->s_blocks_count)
793                 rfs->new_blk = rfs->old_fs->super->s_blocks_count;
794 #endif
795 }
796
797 static blk_t get_new_block(ext2_resize_t rfs)
798 {
799         ext2_filsys     fs = rfs->new_fs;
800         
801         while (1) {
802                 if (rfs->new_blk >= fs->super->s_blocks_count) {
803                         if (rfs->alloc_state == DESPERATION)
804                                 return 0;
805
806 #ifdef RESIZE2FS_DEBUG
807                         if (rfs->flags & RESIZE_DEBUG_BMOVE)
808                                 printf(_("Going into desperation "
809                                        "mode for block allocations\n"));
810 #endif                  
811                         rfs->alloc_state = DESPERATION;
812                         rfs->new_blk = fs->super->s_first_data_block;
813                         continue;
814                 }
815                 if (ext2fs_test_block_bitmap(fs->block_map, rfs->new_blk) ||
816                     ext2fs_test_block_bitmap(rfs->reserve_blocks,
817                                              rfs->new_blk) ||
818                     ((rfs->alloc_state == AVOID_OLD) &&
819                      (rfs->new_blk < rfs->old_fs->super->s_blocks_count) &&
820                      ext2fs_test_block_bitmap(rfs->old_fs->block_map,
821                                               rfs->new_blk))) {
822                         rfs->new_blk++;
823                         continue;
824                 }
825                 return rfs->new_blk;
826         }
827 }
828
829 static errcode_t block_mover(ext2_resize_t rfs)
830 {
831         blk_t                   blk, old_blk, new_blk;
832         ext2_filsys             fs = rfs->new_fs;
833         ext2_filsys             old_fs = rfs->old_fs;
834         errcode_t               retval;
835         int                     size, c;
836         int                     to_move, moved;
837
838         new_blk = fs->super->s_first_data_block;
839         if (!rfs->itable_buf) {
840                 retval = ext2fs_get_mem(fs->blocksize *
841                                         fs->inode_blocks_per_group,
842                                         (void **) &rfs->itable_buf);
843                 if (retval)
844                         return retval;
845         }
846         retval = ext2fs_create_extent_table(&rfs->bmap, 0);
847         if (retval)
848                 return retval;
849
850         /*
851          * The first step is to figure out where all of the blocks
852          * will go.
853          */
854         to_move = moved = 0;
855         init_block_alloc(rfs);
856         for (blk = old_fs->super->s_first_data_block;
857              blk < old_fs->super->s_blocks_count; blk++) {
858                 if (!ext2fs_test_block_bitmap(old_fs->block_map, blk))
859                         continue;
860                 if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk))
861                         continue;
862
863                 new_blk = get_new_block(rfs);
864                 if (!new_blk) {
865                         retval = ENOSPC;
866                         goto errout;
867                 }
868                 ext2fs_mark_block_bitmap(fs->block_map, new_blk);
869                 ext2fs_add_extent_entry(rfs->bmap, blk, new_blk);
870                 to_move++;
871         }
872         
873         if (to_move == 0) {
874                 if (rfs->bmap) {
875                         ext2fs_free_extent_table(rfs->bmap);
876                         rfs->bmap = 0;
877                 }
878                 retval = 0;
879                 goto errout;
880         }
881
882         /*
883          * Step two is to actually move the blocks
884          */
885         retval =  ext2fs_iterate_extent(rfs->bmap, 0, 0, 0);
886         if (retval) goto errout;
887
888         if (rfs->progress) {
889                 retval = (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS,
890                                          0, to_move);
891                 if (retval)
892                         goto errout;
893         }
894         while (1) {
895                 retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size);
896                 if (retval) goto errout;
897                 if (!size)
898                         break;
899 #ifdef RESIZE2FS_DEBUG
900                 if (rfs->flags & RESIZE_DEBUG_BMOVE)
901                         printf(_("Moving %d blocks %u->%u\n"), size,
902                                old_blk, new_blk);
903 #endif
904                 do {
905                         c = size;
906                         if (c > fs->inode_blocks_per_group)
907                                 c = fs->inode_blocks_per_group;
908                         retval = io_channel_read_blk(fs->io, old_blk, c,
909                                                      rfs->itable_buf);
910                         if (retval) goto errout;
911                         retval = io_channel_write_blk(fs->io, new_blk, c,
912                                                       rfs->itable_buf);
913                         if (retval) goto errout;
914                         size -= c;
915                         new_blk += c;
916                         old_blk += c;
917                         moved += c;
918                         if (rfs->progress) {
919                                 io_channel_flush(fs->io);
920                                 retval = (rfs->progress)(rfs,
921                                                 E2_RSZ_BLOCK_RELOC_PASS,
922                                                 moved, to_move);
923                                 if (retval)
924                                         goto errout;
925                         }
926                 } while (size > 0);
927                 io_channel_flush(fs->io);
928         }
929
930 errout:
931         return retval;
932 }
933
934
935 /* --------------------------------------------------------------------
936  *
937  * Resize processing, phase 3
938  *
939  * --------------------------------------------------------------------
940  */
941
942
943 struct process_block_struct {
944         ext2_resize_t           rfs;
945         ext2_ino_t              ino;
946         struct ext2_inode *     inode;
947         errcode_t               error;
948         int                     is_dir;
949         int                     changed;
950 };
951
952 static int process_block(ext2_filsys fs, blk_t  *block_nr,
953                          e2_blkcnt_t blockcnt, blk_t ref_block,
954                          int ref_offset, void *priv_data)
955 {
956         struct process_block_struct *pb;
957         errcode_t       retval;
958         blk_t           block, new_block;
959         int             ret = 0;
960
961         pb = (struct process_block_struct *) priv_data;
962         block = *block_nr;
963         if (pb->rfs->bmap) {
964                 new_block = ext2fs_extent_translate(pb->rfs->bmap, block);
965                 if (new_block) {
966                         *block_nr = new_block;
967                         ret |= BLOCK_CHANGED;
968                         pb->changed = 1;
969 #ifdef RESIZE2FS_DEBUG
970                         if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
971                                 printf(_("ino=%u, blockcnt=%lld, %u->%u\n"), 
972                                        pb->ino, blockcnt, block, new_block);
973 #endif
974                         block = new_block;
975                 }
976         }
977         if (pb->is_dir) {
978                 retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
979                                               block, (int) blockcnt);
980                 if (retval) {
981                         pb->error = retval;
982                         ret |= BLOCK_ABORT;
983                 }
984         }
985         return ret;
986 }
987
988 /*
989  * Progress callback
990  */
991 static errcode_t progress_callback(ext2_filsys fs, ext2_inode_scan scan,
992                                    dgrp_t group, void * priv_data)
993 {
994         ext2_resize_t rfs = (ext2_resize_t) priv_data;
995         errcode_t               retval;
996
997         /*
998          * This check is to protect against old ext2 libraries.  It
999          * shouldn't be needed against new libraries.
1000          */
1001         if ((group+1) == 0)
1002                 return 0;
1003
1004         if (rfs->progress) {
1005                 io_channel_flush(fs->io);
1006                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
1007                                          group+1, fs->group_desc_count);
1008                 if (retval)
1009                         return retval;
1010         }
1011         
1012         return 0;
1013 }
1014
1015 static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
1016 {
1017         struct process_block_struct     pb;
1018         ext2_ino_t              ino, new_inode;
1019         struct ext2_inode       inode;
1020         ext2_inode_scan         scan = NULL;
1021         errcode_t               retval;
1022         int                     group;
1023         char                    *block_buf = 0;
1024         ext2_ino_t              start_to_move;
1025         blk_t                   orig_size, new_block;
1026         
1027         if ((rfs->old_fs->group_desc_count <=
1028              rfs->new_fs->group_desc_count) &&
1029             !rfs->bmap)
1030                 return 0;
1031
1032         /*
1033          * Save the original size of the old filesystem, and
1034          * temporarily set the size to be the new size if the new size
1035          * is larger.  We need to do this to avoid catching an error
1036          * by the block iterator routines
1037          */
1038         orig_size = rfs->old_fs->super->s_blocks_count;
1039         if (orig_size < rfs->new_fs->super->s_blocks_count)
1040                 rfs->old_fs->super->s_blocks_count =
1041                         rfs->new_fs->super->s_blocks_count;
1042
1043         retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
1044         if (retval) goto errout;
1045
1046         retval = ext2fs_init_dblist(rfs->old_fs, 0);
1047         if (retval) goto errout;
1048         retval = ext2fs_get_mem(rfs->old_fs->blocksize * 3,
1049                                 (void **) &block_buf);
1050         if (retval) goto errout;
1051
1052         start_to_move = (rfs->new_fs->group_desc_count *
1053                          rfs->new_fs->super->s_inodes_per_group);
1054         
1055         if (rfs->progress) {
1056                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
1057                                          0, rfs->old_fs->group_desc_count);
1058                 if (retval)
1059                         goto errout;
1060         }
1061         ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
1062         pb.rfs = rfs;
1063         pb.inode = &inode;
1064         pb.error = 0;
1065         new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
1066         /*
1067          * First, copy all of the inodes that need to be moved
1068          * elsewhere in the inode table
1069          */
1070         while (1) {
1071                 retval = ext2fs_get_next_inode(scan, &ino, &inode);
1072                 if (retval) goto errout;
1073                 if (!ino)
1074                         break;
1075
1076                 if (inode.i_links_count == 0)
1077                         continue; /* inode not in use */
1078
1079                 pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
1080                 pb.changed = 0;
1081
1082                 if (inode.i_file_acl && rfs->bmap) {
1083                         new_block = ext2fs_extent_translate(rfs->bmap, 
1084                                                             inode.i_file_acl);
1085                         if (new_block) {
1086                                 inode.i_file_acl = new_block;
1087                                 retval = ext2fs_write_inode(rfs->old_fs, 
1088                                                             ino, &inode);
1089                                 if (retval) goto errout;
1090                         }
1091                 }
1092                 
1093                 if (ext2fs_inode_has_valid_blocks(&inode) &&
1094                     (rfs->bmap || pb.is_dir)) {
1095                         pb.ino = ino;
1096                         retval = ext2fs_block_iterate2(rfs->old_fs,
1097                                                        ino, 0, block_buf,
1098                                                        process_block, &pb);
1099                         if (retval)
1100                                 goto errout;
1101                         if (pb.error) {
1102                                 retval = pb.error;
1103                                 goto errout;
1104                         }
1105                 }
1106
1107                 if (ino <= start_to_move)
1108                         continue; /* Don't need to move it. */
1109
1110                 /*
1111                  * Find a new inode
1112                  */
1113                 while (1) { 
1114                         if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map, 
1115                                                       new_inode))
1116                                 break;
1117                         new_inode++;
1118                         if (new_inode > rfs->new_fs->super->s_inodes_count) {
1119                                 retval = ENOSPC;
1120                                 goto errout;
1121                         }
1122                 }
1123                 ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new_inode);
1124                 if (pb.changed) {
1125                         /* Get the new version of the inode */
1126                         retval = ext2fs_read_inode(rfs->old_fs, ino, &inode);
1127                         if (retval) goto errout;
1128                 }
1129                 retval = ext2fs_write_inode(rfs->old_fs, new_inode, &inode);
1130                 if (retval) goto errout;
1131
1132                 group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
1133                 if (LINUX_S_ISDIR(inode.i_mode))
1134                         rfs->new_fs->group_desc[group].bg_used_dirs_count++;
1135                 
1136 #ifdef RESIZE2FS_DEBUG
1137                 if (rfs->flags & RESIZE_DEBUG_INODEMAP)
1138                         printf(_("Inode moved %u->%u\n"), ino, new_inode);
1139 #endif
1140                 if (!rfs->imap) {
1141                         retval = ext2fs_create_extent_table(&rfs->imap, 0);
1142                         if (retval)
1143                                 goto errout;
1144                 }
1145                 ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
1146         }
1147         io_channel_flush(rfs->old_fs->io);
1148
1149 errout:
1150         rfs->old_fs->super->s_blocks_count = orig_size;
1151         if (rfs->bmap) {
1152                 ext2fs_free_extent_table(rfs->bmap);
1153                 rfs->bmap = 0;
1154         }
1155         if (scan)
1156                 ext2fs_close_inode_scan(scan);
1157         if (block_buf)
1158                 ext2fs_free_mem((void **) &block_buf);
1159         return retval;
1160 }
1161
1162 /* --------------------------------------------------------------------
1163  *
1164  * Resize processing, phase 4.
1165  *
1166  * --------------------------------------------------------------------
1167  */
1168
1169 struct istruct {
1170         ext2_resize_t rfs;
1171         errcode_t       err;
1172         unsigned long   max_dirs;
1173         int             num;
1174 };
1175
1176 static int check_and_change_inodes(ext2_ino_t dir, int entry,
1177                                    struct ext2_dir_entry *dirent, int offset,
1178                                    int  blocksize, char *buf, void *priv_data)
1179 {
1180         struct istruct *is = (struct istruct *) priv_data;
1181         ext2_ino_t      new_inode;
1182
1183         if (is->rfs->progress && offset == 0) {
1184                 io_channel_flush(is->rfs->old_fs->io);
1185                 is->err = (is->rfs->progress)(is->rfs,
1186                                               E2_RSZ_INODE_REF_UPD_PASS,
1187                                               ++is->num, is->max_dirs);
1188                 if (is->err)
1189                         return DIRENT_ABORT;
1190         }
1191
1192         if (!dirent->inode)
1193                 return 0;
1194
1195         new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
1196
1197         if (!new_inode)
1198                 return 0;
1199 #ifdef RESIZE2FS_DEBUG
1200         if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
1201                 printf(_("Inode translate (dir=%u, name=%.*s, %u->%u)\n"),
1202                        dir, dirent->name_len, dirent->name,
1203                        dirent->inode, new_inode);
1204 #endif
1205
1206         dirent->inode = new_inode;
1207
1208         return DIRENT_CHANGED;
1209 }
1210
1211 static errcode_t inode_ref_fix(ext2_resize_t rfs)
1212 {
1213         errcode_t               retval;
1214         struct istruct          is;
1215         
1216         if (!rfs->imap)
1217                 return 0;
1218        
1219         /*
1220          * Now, we iterate over all of the directories to update the
1221          * inode references
1222          */
1223         is.num = 0;
1224         is.max_dirs = ext2fs_dblist_count(rfs->old_fs->dblist);
1225         is.rfs = rfs;
1226         is.err = 0;
1227
1228         if (rfs->progress) {
1229                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
1230                                          0, is.max_dirs);
1231                 if (retval)
1232                         goto errout;
1233         }
1234         
1235         retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
1236                                            DIRENT_FLAG_INCLUDE_EMPTY, 0,
1237                                            check_and_change_inodes, &is);
1238         if (retval)
1239                 goto errout;
1240         if (is.err) {
1241                 retval = is.err;
1242                 goto errout;
1243         }
1244
1245 errout:
1246         ext2fs_free_extent_table(rfs->imap);
1247         rfs->imap = 0;
1248         return retval;
1249 }
1250
1251
1252 /* --------------------------------------------------------------------
1253  *
1254  * Resize processing, phase 5.
1255  *
1256  * In this phase we actually move the inode table around, and then
1257  * update the summary statistics.  This is scary, since aborting here
1258  * will potentially scramble the filesystem.  (We are moving the
1259  * inode tables around in place, and so the potential for lost data,
1260  * or at the very least scrambling the mapping between filenames and
1261  * inode numbers is very high in case of a power failure here.)
1262  * --------------------------------------------------------------------
1263  */
1264
1265
1266 /*
1267  * A very scary routine --- this one moves the inode table around!!!
1268  *
1269  * After this you have to use the rfs->new_fs file handle to read and
1270  * write inodes.
1271  */
1272 static errcode_t move_itables(ext2_resize_t rfs)
1273 {
1274         int             i, n, num, max_groups, size, diff;
1275         ext2_filsys     fs = rfs->new_fs;
1276         char            *cp;
1277         blk_t           old_blk, new_blk;
1278         errcode_t       retval;
1279         int             to_move, moved;
1280
1281         max_groups = fs->group_desc_count;
1282         if (max_groups > rfs->old_fs->group_desc_count)
1283                 max_groups = rfs->old_fs->group_desc_count;
1284
1285         size = fs->blocksize * fs->inode_blocks_per_group;
1286         if (!rfs->itable_buf) {
1287                 retval = ext2fs_get_mem(size, (void **) &rfs->itable_buf);
1288                 if (retval)
1289                         return retval;
1290         }
1291
1292         /*
1293          * Figure out how many inode tables we need to move
1294          */
1295         to_move = moved = 0;
1296         for (i=0; i < max_groups; i++)
1297                 if (rfs->old_fs->group_desc[i].bg_inode_table !=
1298                     fs->group_desc[i].bg_inode_table)
1299                         to_move++;
1300
1301         if (to_move == 0)
1302                 return 0;
1303
1304         if (rfs->progress) {
1305                 retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1306                                        0, to_move);
1307                 if (retval)
1308                         goto errout;
1309         }
1310
1311         rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
1312
1313         for (i=0; i < max_groups; i++) {
1314                 old_blk = rfs->old_fs->group_desc[i].bg_inode_table;
1315                 new_blk = fs->group_desc[i].bg_inode_table;
1316                 diff = new_blk - old_blk;
1317                 
1318 #ifdef RESIZE2FS_DEBUG
1319                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
1320                         printf(_("Itable move group %d block "
1321                                "%u->%u (diff %d)\n"), 
1322                                i, old_blk, new_blk, diff);
1323 #endif
1324                 
1325                 if (!diff)
1326                         continue;
1327
1328                 retval = io_channel_read_blk(fs->io, old_blk,
1329                                              fs->inode_blocks_per_group,
1330                                              rfs->itable_buf);
1331                 if (retval) 
1332                         goto errout;
1333                 /*
1334                  * The end of the inode table segment often contains
1335                  * all zeros, and we're often only moving the inode
1336                  * table down a block or two.  If so, we can optimize
1337                  * things by not rewriting blocks that we know to be zero
1338                  * already.
1339                  */
1340                 for (cp = rfs->itable_buf+size, n=0; n < size; n++, cp--)
1341                         if (*cp)
1342                                 break;
1343                 n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
1344 #ifdef RESIZE2FS_DEBUG
1345                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
1346                         printf(_("%d blocks of zeros...\n"), n);
1347 #endif
1348                 num = fs->inode_blocks_per_group;
1349                 if (n > diff)
1350                         num -= n;
1351
1352                 retval = io_channel_write_blk(fs->io, new_blk,
1353                                               num, rfs->itable_buf);
1354                 if (retval) {
1355                         io_channel_write_blk(fs->io, old_blk,
1356                                              num, rfs->itable_buf);
1357                         goto errout;
1358                 }
1359                 if (n > diff) {
1360                         retval = io_channel_write_blk(fs->io,
1361                               old_blk + fs->inode_blocks_per_group,
1362                               diff, (rfs->itable_buf +
1363                                      (fs->inode_blocks_per_group - diff) *
1364                                      fs->blocksize));
1365                         if (retval)
1366                                 goto errout;
1367                 }
1368                 rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
1369                 ext2fs_mark_super_dirty(rfs->old_fs);
1370                 if (rfs->progress) {
1371                         ext2fs_flush(rfs->old_fs);
1372                         retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1373                                                ++moved, to_move);
1374                         if (retval)
1375                                 goto errout;
1376                 }
1377         }
1378         ext2fs_flush(fs);
1379 #ifdef RESIZE2FS_DEBUG
1380         if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
1381                 printf(_("Inode table move finished.\n"));
1382 #endif
1383         return 0;
1384         
1385 errout:
1386         return retval;
1387 }
1388
1389 /*
1390  * Finally, recalculate the summary information
1391  */
1392 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1393 {
1394         blk_t           blk;
1395         ext2_ino_t      ino;
1396         int             group = 0;
1397         int             count = 0;
1398         int             total_free = 0;
1399         int             group_free = 0;
1400
1401         /*
1402          * First calculate the block statistics
1403          */
1404         for (blk = fs->super->s_first_data_block;
1405              blk < fs->super->s_blocks_count; blk++) {
1406                 if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
1407                         group_free++;
1408                         total_free++;
1409                 }
1410                 count++;
1411                 if ((count == fs->super->s_blocks_per_group) ||
1412                     (blk == fs->super->s_blocks_count-1)) {
1413                         fs->group_desc[group++].bg_free_blocks_count =
1414                                 group_free;
1415                         count = 0;
1416                         group_free = 0;
1417                 }
1418         }
1419         fs->super->s_free_blocks_count = total_free;
1420         
1421         /*
1422          * Next, calculate the inode statistics
1423          */
1424         group_free = 0;
1425         total_free = 0;
1426         count = 0;
1427         group = 0;
1428         for (ino = 1; ino <= fs->super->s_inodes_count; ino++) {
1429                 if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
1430                         group_free++;
1431                         total_free++;
1432                 }
1433                 count++;
1434                 if ((count == fs->super->s_inodes_per_group) ||
1435                     (ino == fs->super->s_inodes_count)) {
1436                         fs->group_desc[group++].bg_free_inodes_count =
1437                                 group_free;
1438                         count = 0;
1439                         group_free = 0;
1440                 }
1441         }
1442         fs->super->s_free_inodes_count = total_free;
1443         ext2fs_mark_super_dirty(fs);
1444         return 0;
1445 }