Whamcloud - gitweb
Merge branch 'maint'
[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         rfs->new_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;        
142         retval = ext2fs_close(rfs->new_fs);
143         if (retval)
144                 goto errout;
145
146         rfs->flags = flags;
147         
148         ext2fs_free(rfs->old_fs);
149         if (rfs->itable_buf)
150                 ext2fs_free_mem(&rfs->itable_buf);
151         ext2fs_free_mem(&rfs);
152         
153         return 0;
154
155 errout:
156         if (rfs->new_fs)
157                 ext2fs_free(rfs->new_fs);
158         if (rfs->itable_buf)
159                 ext2fs_free_mem(&rfs->itable_buf);
160         ext2fs_free_mem(&rfs);
161         return retval;
162 }
163
164 /* --------------------------------------------------------------------
165  *
166  * Resize processing, phase 1.
167  *
168  * In this phase we adjust the in-memory superblock information, and
169  * initialize any new parts of the inode table.  The new parts of the
170  * inode table are created in virgin disk space, so we can abort here
171  * without any side effects.
172  * --------------------------------------------------------------------
173  */
174
175 /*
176  * This routine is shared by the online and offline resize routines.
177  * All of the information which is adjusted in memory is done here.
178  */
179 errcode_t adjust_fs_info(ext2_filsys fs, ext2_filsys old_fs, blk_t new_size)
180 {
181         errcode_t       retval;
182         int             overhead = 0;
183         int             rem;
184         blk_t           blk, group_block;
185         ext2_ino_t      real_end;
186         int             adj, old_numblocks, numblocks, adjblocks;
187         unsigned long   i, j, old_desc_blocks, max_group;
188         unsigned int    meta_bg, meta_bg_size;
189         int             has_super;
190         unsigned long long new_inodes;  /* u64 to check for overflow */
191
192         fs->super->s_blocks_count = new_size;
193
194 retry:
195         fs->group_desc_count = ext2fs_div_ceil(fs->super->s_blocks_count -
196                                        fs->super->s_first_data_block,
197                                        EXT2_BLOCKS_PER_GROUP(fs->super));
198         if (fs->group_desc_count == 0)
199                 return EXT2_ET_TOOSMALL;
200         fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count, 
201                                           EXT2_DESC_PER_BLOCK(fs->super));
202
203         /*
204          * Overhead is the number of bookkeeping blocks per group.  It
205          * includes the superblock backup, the group descriptor
206          * backups, the inode bitmap, the block bitmap, and the inode
207          * table.
208          */
209         overhead = (int) (2 + fs->inode_blocks_per_group);
210
211         if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
212                 overhead += 1 + fs->desc_blocks + 
213                         fs->super->s_reserved_gdt_blocks;
214
215         /*
216          * See if the last group is big enough to support the
217          * necessary data structures.  If not, we need to get rid of
218          * it.
219          */
220         rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
221                 fs->super->s_blocks_per_group;
222         if ((fs->group_desc_count == 1) && rem && (rem < overhead))
223                 return EXT2_ET_TOOSMALL;
224         if (rem && (rem < overhead+50)) {
225                 fs->super->s_blocks_count -= rem;
226                 goto retry;
227         }
228         /*
229          * Adjust the number of inodes
230          */
231         new_inodes =(unsigned long long) fs->super->s_inodes_per_group * fs->group_desc_count;
232         if (new_inodes > ~0U) {
233                 fprintf(stderr, _("inodes (%llu) must be less than %u"),
234                                    new_inodes, ~0U);
235                 return EXT2_ET_TOO_MANY_INODES;
236         }
237         fs->super->s_inodes_count = fs->super->s_inodes_per_group *
238                 fs->group_desc_count;
239
240         /*
241          * Adjust the number of free blocks
242          */
243         blk = old_fs->super->s_blocks_count;
244         if (blk > fs->super->s_blocks_count)
245                 fs->super->s_free_blocks_count -=
246                         (blk - fs->super->s_blocks_count);
247         else
248                 fs->super->s_free_blocks_count +=
249                         (fs->super->s_blocks_count - blk);
250
251         /*
252          * Adjust the number of reserved blocks
253          */
254         blk = (__u64)old_fs->super->s_r_blocks_count * 100 /
255                 old_fs->super->s_blocks_count;
256         fs->super->s_r_blocks_count = e2p_percent(blk, 
257                                                   fs->super->s_blocks_count);
258
259         /*
260          * Adjust the bitmaps for size
261          */
262         retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
263                                             fs->super->s_inodes_count,
264                                             fs->inode_map);
265         if (retval) goto errout;
266         
267         real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
268                      * fs->group_desc_count)) - 1 +
269                              fs->super->s_first_data_block;
270         retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
271                                             real_end, fs->block_map);
272
273         if (retval) goto errout;
274
275         /*
276          * Reallocate the group descriptors as necessary.
277          */
278         if (old_fs->desc_blocks != fs->desc_blocks) {
279                 retval = ext2fs_resize_mem(old_fs->desc_blocks *
280                                            fs->blocksize,
281                                            fs->desc_blocks * fs->blocksize,
282                                            &fs->group_desc);
283                 if (retval)
284                         goto errout;
285                 if (fs->desc_blocks > old_fs->desc_blocks) 
286                         memset((char *) fs->group_desc + 
287                                (old_fs->desc_blocks * fs->blocksize), 0,
288                                (fs->desc_blocks - old_fs->desc_blocks) *
289                                fs->blocksize);
290         }
291
292         /*
293          * If the resize_inode feature is set, and we are changing the
294          * number of descriptor blocks, then adjust
295          * s_reserved_gdt_blocks if possible to avoid needing to move
296          * the inode table either now or in the future.
297          */
298         if ((fs->super->s_feature_compat & 
299              EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
300             (old_fs->desc_blocks != fs->desc_blocks)) {
301                 int new;
302
303                 new = ((int) fs->super->s_reserved_gdt_blocks) + 
304                         (old_fs->desc_blocks - fs->desc_blocks);
305                 if (new < 0)
306                         new = 0;
307                 if (new > (int) fs->blocksize/4)
308                         new = fs->blocksize/4;
309                 fs->super->s_reserved_gdt_blocks = new;
310                 if (new == 0)
311                         fs->super->s_feature_compat &= 
312                                 ~EXT2_FEATURE_COMPAT_RESIZE_INODE;
313         }
314
315         /*
316          * If we are shrinking the number block groups, we're done and
317          * can exit now.
318          */
319         if (old_fs->group_desc_count > fs->group_desc_count) {
320                 retval = 0;
321                 goto errout;
322         }
323
324         /*
325          * Fix the count of the last (old) block group
326          */
327         old_numblocks = (old_fs->super->s_blocks_count -
328                          old_fs->super->s_first_data_block) %
329                                  old_fs->super->s_blocks_per_group;
330         if (!old_numblocks)
331                 old_numblocks = old_fs->super->s_blocks_per_group;
332         if (old_fs->group_desc_count == fs->group_desc_count) {
333                 numblocks = (fs->super->s_blocks_count -
334                              fs->super->s_first_data_block) %
335                         fs->super->s_blocks_per_group;
336                 if (!numblocks)
337                         numblocks = fs->super->s_blocks_per_group;
338         } else
339                 numblocks = fs->super->s_blocks_per_group;
340         i = old_fs->group_desc_count - 1;
341         fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
342                 
343         /*
344          * If the number of block groups is staying the same, we're
345          * done and can exit now.  (If the number block groups is
346          * shrinking, we had exited earlier.)
347          */
348         if (old_fs->group_desc_count >= fs->group_desc_count) {
349                 retval = 0;
350                 goto errout;
351         }
352
353         /*
354          * Initialize the new block group descriptors
355          */
356         group_block = fs->super->s_first_data_block +
357                 old_fs->group_desc_count * fs->super->s_blocks_per_group;
358
359         adj = old_fs->group_desc_count;
360         max_group = fs->group_desc_count - adj;
361         if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
362                 old_desc_blocks = fs->super->s_first_meta_bg;
363         else
364                 old_desc_blocks = fs->desc_blocks + 
365                         fs->super->s_reserved_gdt_blocks;
366         for (i = old_fs->group_desc_count;
367              i < fs->group_desc_count; i++) {
368                 memset(&fs->group_desc[i], 0,
369                        sizeof(struct ext2_group_desc));
370                 adjblocks = 0;
371
372                 if (i == fs->group_desc_count-1) {
373                         numblocks = (fs->super->s_blocks_count -
374                                      fs->super->s_first_data_block) %
375                                              fs->super->s_blocks_per_group;
376                         if (!numblocks)
377                                 numblocks = fs->super->s_blocks_per_group;
378                 } else
379                         numblocks = fs->super->s_blocks_per_group;
380
381                 has_super = ext2fs_bg_has_super(fs, i);
382                 if (has_super) {
383                         ext2fs_mark_block_bitmap(fs->block_map, group_block);
384                         adjblocks++;
385                 }
386                 meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
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_array(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 = EXT2_DESC_PER_BLOCK(fs->super);
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 = EXT2_DESC_PER_BLOCK(fs->super);
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_array(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 = NULL;
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         int                     inode_size;
1119         
1120         if ((rfs->old_fs->group_desc_count <=
1121              rfs->new_fs->group_desc_count) &&
1122             !rfs->bmap)
1123                 return 0;
1124
1125         /*
1126          * Save the original size of the old filesystem, and
1127          * temporarily set the size to be the new size if the new size
1128          * is larger.  We need to do this to avoid catching an error
1129          * by the block iterator routines
1130          */
1131         orig_size = rfs->old_fs->super->s_blocks_count;
1132         if (orig_size < rfs->new_fs->super->s_blocks_count)
1133                 rfs->old_fs->super->s_blocks_count =
1134                         rfs->new_fs->super->s_blocks_count;
1135
1136         retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
1137         if (retval) goto errout;
1138
1139         retval = ext2fs_init_dblist(rfs->old_fs, 0);
1140         if (retval) goto errout;
1141         retval = ext2fs_get_array(rfs->old_fs->blocksize, 3, &block_buf);
1142         if (retval) goto errout;
1143
1144         start_to_move = (rfs->new_fs->group_desc_count *
1145                          rfs->new_fs->super->s_inodes_per_group);
1146         
1147         if (rfs->progress) {
1148                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
1149                                          0, rfs->old_fs->group_desc_count);
1150                 if (retval)
1151                         goto errout;
1152         }
1153         ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
1154         pb.rfs = rfs;
1155         pb.inode = inode;
1156         pb.error = 0;
1157         new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
1158         inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
1159         inode = malloc(inode_size);
1160         if (!inode) {
1161                 retval = ENOMEM;
1162                 goto errout;
1163         }
1164         /*
1165          * First, copy all of the inodes that need to be moved
1166          * elsewhere in the inode table
1167          */
1168         while (1) {
1169                 retval = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
1170                 if (retval) goto errout;
1171                 if (!ino)
1172                         break;
1173
1174                 if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
1175                         continue; /* inode not in use */
1176
1177                 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
1178                 pb.changed = 0;
1179
1180                 if (inode->i_file_acl && rfs->bmap) {
1181                         new_block = ext2fs_extent_translate(rfs->bmap, 
1182                                                             inode->i_file_acl);
1183                         if (new_block) {
1184                                 inode->i_file_acl = new_block;
1185                                 retval = ext2fs_write_inode_full(rfs->old_fs, 
1186                                                             ino, inode, inode_size);
1187                                 if (retval) goto errout;
1188                         }
1189                 }
1190                 
1191                 if (ext2fs_inode_has_valid_blocks(inode) &&
1192                     (rfs->bmap || pb.is_dir)) {
1193                         pb.ino = ino;
1194                         retval = ext2fs_block_iterate2(rfs->old_fs,
1195                                                        ino, 0, block_buf,
1196                                                        process_block, &pb);
1197                         if (retval)
1198                                 goto errout;
1199                         if (pb.error) {
1200                                 retval = pb.error;
1201                                 goto errout;
1202                         }
1203                 }
1204
1205                 if (ino <= start_to_move)
1206                         continue; /* Don't need to move it. */
1207
1208                 /*
1209                  * Find a new inode
1210                  */
1211                 while (1) { 
1212                         if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map, 
1213                                                       new_inode))
1214                                 break;
1215                         new_inode++;
1216                         if (new_inode > rfs->new_fs->super->s_inodes_count) {
1217                                 retval = ENOSPC;
1218                                 goto errout;
1219                         }
1220                 }
1221                 ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new_inode);
1222                 if (pb.changed) {
1223                         /* Get the new version of the inode */
1224                         retval = ext2fs_read_inode_full(rfs->old_fs, ino,
1225                                                 inode, inode_size);
1226                         if (retval) goto errout;
1227                 }
1228                 inode->i_ctime = time(0);
1229                 retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
1230                                                 inode, inode_size);
1231                 if (retval) goto errout;
1232
1233                 group = (new_inode-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
1234                 if (LINUX_S_ISDIR(inode->i_mode))
1235                         rfs->new_fs->group_desc[group].bg_used_dirs_count++;
1236                 
1237 #ifdef RESIZE2FS_DEBUG
1238                 if (rfs->flags & RESIZE_DEBUG_INODEMAP)
1239                         printf("Inode moved %u->%u\n", ino, new_inode);
1240 #endif
1241                 if (!rfs->imap) {
1242                         retval = ext2fs_create_extent_table(&rfs->imap, 0);
1243                         if (retval)
1244                                 goto errout;
1245                 }
1246                 ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
1247         }
1248         io_channel_flush(rfs->old_fs->io);
1249
1250 errout:
1251         rfs->old_fs->super->s_blocks_count = orig_size;
1252         if (rfs->bmap) {
1253                 ext2fs_free_extent_table(rfs->bmap);
1254                 rfs->bmap = 0;
1255         }
1256         if (scan)
1257                 ext2fs_close_inode_scan(scan);
1258         if (block_buf)
1259                 ext2fs_free_mem(&block_buf);
1260         if (inode)
1261                 free(inode);
1262         return retval;
1263 }
1264
1265 /* --------------------------------------------------------------------
1266  *
1267  * Resize processing, phase 4.
1268  *
1269  * --------------------------------------------------------------------
1270  */
1271
1272 struct istruct {
1273         ext2_resize_t rfs;
1274         errcode_t       err;
1275         unsigned long   max_dirs;
1276         int             num;
1277 };
1278
1279 static int check_and_change_inodes(ext2_ino_t dir, 
1280                                    int entry EXT2FS_ATTR((unused)),
1281                                    struct ext2_dir_entry *dirent, int offset,
1282                                    int  blocksize EXT2FS_ATTR((unused)),
1283                                    char *buf EXT2FS_ATTR((unused)), 
1284                                    void *priv_data)
1285 {
1286         struct istruct *is = (struct istruct *) priv_data;
1287         struct ext2_inode       inode;
1288         ext2_ino_t              new_inode;
1289         errcode_t               retval;
1290
1291         if (is->rfs->progress && offset == 0) {
1292                 io_channel_flush(is->rfs->old_fs->io);
1293                 is->err = (is->rfs->progress)(is->rfs,
1294                                               E2_RSZ_INODE_REF_UPD_PASS,
1295                                               ++is->num, is->max_dirs);
1296                 if (is->err)
1297                         return DIRENT_ABORT;
1298         }
1299
1300         if (!dirent->inode)
1301                 return 0;
1302
1303         new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
1304
1305         if (!new_inode)
1306                 return 0;
1307 #ifdef RESIZE2FS_DEBUG
1308         if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
1309                 printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
1310                        dir, dirent->name_len&0xFF, dirent->name,
1311                        dirent->inode, new_inode);
1312 #endif
1313
1314         dirent->inode = new_inode;
1315
1316         /* Update the directory mtime and ctime */
1317         retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
1318         if (retval == 0) {
1319                 inode.i_mtime = inode.i_ctime = time(0);
1320                 is->err = ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
1321                 if (is->err)
1322                         return DIRENT_ABORT;
1323         }
1324
1325         return DIRENT_CHANGED;
1326 }
1327
1328 static errcode_t inode_ref_fix(ext2_resize_t rfs)
1329 {
1330         errcode_t               retval;
1331         struct istruct          is;
1332         
1333         if (!rfs->imap)
1334                 return 0;
1335        
1336         /*
1337          * Now, we iterate over all of the directories to update the
1338          * inode references
1339          */
1340         is.num = 0;
1341         is.max_dirs = ext2fs_dblist_count(rfs->old_fs->dblist);
1342         is.rfs = rfs;
1343         is.err = 0;
1344
1345         if (rfs->progress) {
1346                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
1347                                          0, is.max_dirs);
1348                 if (retval)
1349                         goto errout;
1350         }
1351         
1352         retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
1353                                            DIRENT_FLAG_INCLUDE_EMPTY, 0,
1354                                            check_and_change_inodes, &is);
1355         if (retval)
1356                 goto errout;
1357         if (is.err) {
1358                 retval = is.err;
1359                 goto errout;
1360         }
1361
1362 errout:
1363         ext2fs_free_extent_table(rfs->imap);
1364         rfs->imap = 0;
1365         return retval;
1366 }
1367
1368
1369 /* --------------------------------------------------------------------
1370  *
1371  * Resize processing, phase 5.
1372  *
1373  * In this phase we actually move the inode table around, and then
1374  * update the summary statistics.  This is scary, since aborting here
1375  * will potentially scramble the filesystem.  (We are moving the
1376  * inode tables around in place, and so the potential for lost data,
1377  * or at the very least scrambling the mapping between filenames and
1378  * inode numbers is very high in case of a power failure here.)
1379  * --------------------------------------------------------------------
1380  */
1381
1382
1383 /*
1384  * A very scary routine --- this one moves the inode table around!!!
1385  *
1386  * After this you have to use the rfs->new_fs file handle to read and
1387  * write inodes.
1388  */
1389 static errcode_t move_itables(ext2_resize_t rfs)
1390 {
1391         int             n, num, size, diff;
1392         dgrp_t          i, max_groups;
1393         ext2_filsys     fs = rfs->new_fs;
1394         char            *cp;
1395         blk_t           old_blk, new_blk, blk;
1396         errcode_t       retval;
1397         int             j, to_move, moved;
1398
1399         max_groups = fs->group_desc_count;
1400         if (max_groups > rfs->old_fs->group_desc_count)
1401                 max_groups = rfs->old_fs->group_desc_count;
1402
1403         size = fs->blocksize * fs->inode_blocks_per_group;
1404         if (!rfs->itable_buf) {
1405                 retval = ext2fs_get_mem(size, &rfs->itable_buf);
1406                 if (retval)
1407                         return retval;
1408         }
1409
1410         /*
1411          * Figure out how many inode tables we need to move
1412          */
1413         to_move = moved = 0;
1414         for (i=0; i < max_groups; i++)
1415                 if (rfs->old_fs->group_desc[i].bg_inode_table !=
1416                     fs->group_desc[i].bg_inode_table)
1417                         to_move++;
1418
1419         if (to_move == 0)
1420                 return 0;
1421
1422         if (rfs->progress) {
1423                 retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1424                                        0, to_move);
1425                 if (retval)
1426                         goto errout;
1427         }
1428
1429         rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
1430
1431         for (i=0; i < max_groups; i++) {
1432                 old_blk = rfs->old_fs->group_desc[i].bg_inode_table;
1433                 new_blk = fs->group_desc[i].bg_inode_table;
1434                 diff = new_blk - old_blk;
1435                 
1436 #ifdef RESIZE2FS_DEBUG
1437                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
1438                         printf("Itable move group %d block %u->%u (diff %d)\n",
1439                                i, old_blk, new_blk, diff);
1440 #endif
1441                 
1442                 if (!diff)
1443                         continue;
1444
1445                 retval = io_channel_read_blk(fs->io, old_blk,
1446                                              fs->inode_blocks_per_group,
1447                                              rfs->itable_buf);
1448                 if (retval) 
1449                         goto errout;
1450                 /*
1451                  * The end of the inode table segment often contains
1452                  * all zeros, and we're often only moving the inode
1453                  * table down a block or two.  If so, we can optimize
1454                  * things by not rewriting blocks that we know to be zero
1455                  * already.
1456                  */
1457                 for (cp = rfs->itable_buf+size-1, n=0; n < size; n++, cp--)
1458                         if (*cp)
1459                                 break;
1460                 n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
1461 #ifdef RESIZE2FS_DEBUG
1462                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
1463                         printf("%d blocks of zeros...\n", n);
1464 #endif
1465                 num = fs->inode_blocks_per_group;
1466                 if (n > diff)
1467                         num -= n;
1468
1469                 retval = io_channel_write_blk(fs->io, new_blk,
1470                                               num, rfs->itable_buf);
1471                 if (retval) {
1472                         io_channel_write_blk(fs->io, old_blk,
1473                                              num, rfs->itable_buf);
1474                         goto errout;
1475                 }
1476                 if (n > diff) {
1477                         retval = io_channel_write_blk(fs->io,
1478                               old_blk + fs->inode_blocks_per_group,
1479                               diff, (rfs->itable_buf +
1480                                      (fs->inode_blocks_per_group - diff) *
1481                                      fs->blocksize));
1482                         if (retval)
1483                                 goto errout;
1484                 }
1485
1486                 for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
1487                      j < fs->inode_blocks_per_group ; j++, blk++)
1488                         ext2fs_unmark_block_bitmap(fs->block_map, blk);
1489
1490                 rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
1491                 ext2fs_mark_super_dirty(rfs->old_fs);
1492                 ext2fs_flush(rfs->old_fs);
1493
1494                 if (rfs->progress) {
1495                         retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1496                                                ++moved, to_move);
1497                         if (retval)
1498                                 goto errout;
1499                 }
1500         }
1501         mark_table_blocks(fs, fs->block_map);
1502         ext2fs_flush(fs);
1503 #ifdef RESIZE2FS_DEBUG
1504         if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
1505                 printf("Inode table move finished.\n");
1506 #endif
1507         return 0;
1508         
1509 errout:
1510         return retval;
1511 }
1512
1513 /*
1514  * Fix the resize inode 
1515  */
1516 static errcode_t fix_resize_inode(ext2_filsys fs)
1517 {
1518         struct ext2_inode       inode;
1519         errcode_t               retval;
1520         char *                  block_buf;
1521
1522         if (!(fs->super->s_feature_compat & 
1523               EXT2_FEATURE_COMPAT_RESIZE_INODE))
1524                 return 0;
1525
1526         retval = ext2fs_get_mem(fs->blocksize, &block_buf);
1527         if (retval) goto errout;
1528
1529         retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
1530         if (retval) goto errout;
1531
1532         inode.i_blocks = fs->blocksize/512;
1533
1534         retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
1535         if (retval) goto errout;
1536
1537         if (!inode.i_block[EXT2_DIND_BLOCK]) {
1538                 /* 
1539                  * Avoid zeroing out block #0; that's rude.  This
1540                  * should never happen anyway since the filesystem
1541                  * should be fsck'ed and we assume it is consistent.
1542                  */
1543                 fprintf(stderr, 
1544                         _("Should never happen: resize inode corrupt!\n"));
1545                 exit(1);
1546         }
1547
1548         memset(block_buf, 0, fs->blocksize);
1549
1550         retval = io_channel_write_blk(fs->io, inode.i_block[EXT2_DIND_BLOCK],
1551                                       1, block_buf);
1552         if (retval) goto errout;
1553         
1554         retval = ext2fs_create_resize_inode(fs);
1555         if (retval)
1556                 goto errout;
1557
1558 errout:
1559         if (block_buf)
1560                 ext2fs_free_mem(&block_buf);
1561         return retval;
1562 }
1563
1564 /*
1565  * Finally, recalculate the summary information
1566  */
1567 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1568 {
1569         blk_t           blk;
1570         ext2_ino_t      ino;
1571         unsigned int    group = 0;
1572         unsigned int    count = 0;
1573         int             total_free = 0;
1574         int             group_free = 0;
1575
1576         /*
1577          * First calculate the block statistics
1578          */
1579         for (blk = fs->super->s_first_data_block;
1580              blk < fs->super->s_blocks_count; blk++) {
1581                 if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
1582                         group_free++;
1583                         total_free++;
1584                 }
1585                 count++;
1586                 if ((count == fs->super->s_blocks_per_group) ||
1587                     (blk == fs->super->s_blocks_count-1)) {
1588                         fs->group_desc[group++].bg_free_blocks_count =
1589                                 group_free;
1590                         count = 0;
1591                         group_free = 0;
1592                 }
1593         }
1594         fs->super->s_free_blocks_count = total_free;
1595         
1596         /*
1597          * Next, calculate the inode statistics
1598          */
1599         group_free = 0;
1600         total_free = 0;
1601         count = 0;
1602         group = 0;
1603
1604         /* Protect loop from wrap-around if s_inodes_count maxed */
1605         for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
1606                 if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
1607                         group_free++;
1608                         total_free++;
1609                 }
1610                 count++;
1611                 if ((count == fs->super->s_inodes_per_group) ||
1612                     (ino == fs->super->s_inodes_count)) {
1613                         fs->group_desc[group++].bg_free_inodes_count =
1614                                 group_free;
1615                         count = 0;
1616                         group_free = 0;
1617                 }
1618         }
1619         fs->super->s_free_inodes_count = total_free;
1620         ext2fs_mark_super_dirty(fs);
1621         return 0;
1622 }