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