OSDN Git Service

am 3e60e44f: Merge "Xcode 4.3 compatibility checkin"
[android-x86/external-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 void fix_uninit_block_bitmaps(ext2_filsys fs);
44 static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size);
45 static errcode_t blocks_to_move(ext2_resize_t rfs);
46 static errcode_t block_mover(ext2_resize_t rfs);
47 static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
48 static errcode_t inode_ref_fix(ext2_resize_t rfs);
49 static errcode_t move_itables(ext2_resize_t rfs);
50 static errcode_t fix_resize_inode(ext2_filsys fs);
51 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
52 static errcode_t fix_sb_journal_backup(ext2_filsys fs);
53
54 /*
55  * Some helper CPP macros
56  */
57 #define FS_BLOCK_BM(fs, i) ((fs)->group_desc[(i)].bg_block_bitmap)
58 #define FS_INODE_BM(fs, i) ((fs)->group_desc[(i)].bg_inode_bitmap)
59 #define FS_INODE_TB(fs, i) ((fs)->group_desc[(i)].bg_inode_table)
60
61 #define IS_BLOCK_BM(fs, i, blk) ((blk) == FS_BLOCK_BM((fs),(i)))
62 #define IS_INODE_BM(fs, i, blk) ((blk) == FS_INODE_BM((fs),(i)))
63
64 #define IS_INODE_TB(fs, i, blk) (((blk) >= FS_INODE_TB((fs), (i))) && \
65                                  ((blk) < (FS_INODE_TB((fs), (i)) + \
66                                            (fs)->inode_blocks_per_group)))
67
68 #define META_OVERHEAD(fs) (2 + (fs)->inode_blocks_per_group)
69 #define SUPER_OVERHEAD(fs) (1 + (fs)->desc_blocks +\
70                             (fs)->super->s_reserved_gdt_blocks)
71
72 /*
73  * This is the top-level routine which does the dirty deed....
74  */
75 errcode_t resize_fs(ext2_filsys fs, blk_t *new_size, int flags,
76                     errcode_t (*progress)(ext2_resize_t rfs, int pass,
77                                           unsigned long cur,
78                                           unsigned long max_val))
79 {
80         ext2_resize_t   rfs;
81         errcode_t       retval;
82
83         retval = ext2fs_read_bitmaps(fs);
84         if (retval)
85                 return retval;
86
87         fs->super->s_state |= EXT2_ERROR_FS;
88         ext2fs_mark_super_dirty(fs);
89         ext2fs_flush(fs);
90
91         /*
92          * Create the data structure
93          */
94         retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct), &rfs);
95         if (retval)
96                 return retval;
97         memset(rfs, 0, sizeof(struct ext2_resize_struct));
98
99         fix_uninit_block_bitmaps(fs);
100         fs->priv_data = rfs;
101         rfs->old_fs = fs;
102         rfs->flags = flags;
103         rfs->itable_buf  = 0;
104         rfs->progress = progress;
105         retval = ext2fs_dup_handle(fs, &rfs->new_fs);
106         if (retval)
107                 goto errout;
108
109         retval = adjust_superblock(rfs, *new_size);
110         if (retval)
111                 goto errout;
112
113         fix_uninit_block_bitmaps(rfs->new_fs);
114         /* Clear the block bitmap uninit flag for the last block group */
115         rfs->new_fs->group_desc[rfs->new_fs->group_desc_count-1].bg_flags &=
116                 ~EXT2_BG_BLOCK_UNINIT;
117
118         *new_size = rfs->new_fs->super->s_blocks_count;
119
120         retval = blocks_to_move(rfs);
121         if (retval)
122                 goto errout;
123
124 #ifdef RESIZE2FS_DEBUG
125         if (rfs->flags & RESIZE_DEBUG_BMOVE)
126                 printf("Number of free blocks: %u/%u, Needed: %d\n",
127                        rfs->old_fs->super->s_free_blocks_count,
128                        rfs->new_fs->super->s_free_blocks_count,
129                        rfs->needed_blocks);
130 #endif
131
132         retval = block_mover(rfs);
133         if (retval)
134                 goto errout;
135
136         retval = inode_scan_and_fix(rfs);
137         if (retval)
138                 goto errout;
139
140         retval = inode_ref_fix(rfs);
141         if (retval)
142                 goto errout;
143
144         retval = move_itables(rfs);
145         if (retval)
146                 goto errout;
147
148         retval = ext2fs_calculate_summary_stats(rfs->new_fs);
149         if (retval)
150                 goto errout;
151
152         retval = fix_resize_inode(rfs->new_fs);
153         if (retval)
154                 goto errout;
155
156         retval = fix_sb_journal_backup(rfs->new_fs);
157         if (retval)
158                 goto errout;
159
160         rfs->new_fs->super->s_state &= ~EXT2_ERROR_FS;
161         rfs->new_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
162         retval = ext2fs_close(rfs->new_fs);
163         if (retval)
164                 goto errout;
165
166         rfs->flags = flags;
167
168         ext2fs_free(rfs->old_fs);
169         if (rfs->itable_buf)
170                 ext2fs_free_mem(&rfs->itable_buf);
171         if (rfs->reserve_blocks)
172                 ext2fs_free_block_bitmap(rfs->reserve_blocks);
173         if (rfs->move_blocks)
174                 ext2fs_free_block_bitmap(rfs->move_blocks);
175         ext2fs_free_mem(&rfs);
176
177         return 0;
178
179 errout:
180         if (rfs->new_fs)
181                 ext2fs_free(rfs->new_fs);
182         if (rfs->itable_buf)
183                 ext2fs_free_mem(&rfs->itable_buf);
184         ext2fs_free_mem(&rfs);
185         return retval;
186 }
187
188 /*
189  * Clean up the bitmaps for unitialized bitmaps
190  */
191 static void fix_uninit_block_bitmaps(ext2_filsys fs)
192 {
193         blk_t           i, blk, super_blk, old_desc_blk, new_desc_blk;
194         int             old_desc_blocks;
195         dgrp_t          g;
196
197         if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
198                                          EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
199                 return;
200
201         for (g=0; g < fs->group_desc_count; g++) {
202                 if (!(fs->group_desc[g].bg_flags & EXT2_BG_BLOCK_UNINIT))
203                         continue;
204
205                 blk = (g * fs->super->s_blocks_per_group) +
206                         fs->super->s_first_data_block;
207
208                 ext2fs_super_and_bgd_loc(fs, g, &super_blk,
209                                          &old_desc_blk, &new_desc_blk, 0);
210
211                 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
212                         old_desc_blocks = fs->super->s_first_meta_bg;
213                 else
214                         old_desc_blocks = fs->desc_blocks +
215                                 fs->super->s_reserved_gdt_blocks;
216
217                 for (i=0; i < fs->super->s_blocks_per_group; i++, blk++) {
218                         if (blk >= fs->super->s_blocks_count)
219                                 break;
220                         if ((blk == super_blk) ||
221                             (old_desc_blk && old_desc_blocks &&
222                              (blk >= old_desc_blk) &&
223                              (blk < old_desc_blk + old_desc_blocks)) ||
224                             (new_desc_blk && (blk == new_desc_blk)) ||
225                             (blk == fs->group_desc[g].bg_block_bitmap) ||
226                             (blk == fs->group_desc[g].bg_inode_bitmap) ||
227                             (blk >= fs->group_desc[g].bg_inode_table &&
228                              (blk < fs->group_desc[g].bg_inode_table
229                               + fs->inode_blocks_per_group)))
230                                 ext2fs_fast_mark_block_bitmap(fs->block_map, blk);
231                         else
232                                 ext2fs_fast_unmark_block_bitmap(fs->block_map, blk);
233                 }
234         }
235 }
236
237 /* --------------------------------------------------------------------
238  *
239  * Resize processing, phase 1.
240  *
241  * In this phase we adjust the in-memory superblock information, and
242  * initialize any new parts of the inode table.  The new parts of the
243  * inode table are created in virgin disk space, so we can abort here
244  * without any side effects.
245  * --------------------------------------------------------------------
246  */
247
248 /*
249  * If the group descriptor's bitmap and inode table blocks are valid,
250  * release them in the new filesystem data structure, and mark them as
251  * reserved so the old inode table blocks don't get overwritten.
252  */
253 static void free_gdp_blocks(ext2_filsys fs,
254                             ext2fs_block_bitmap reserve_blocks,
255                             struct ext2_group_desc *gdp)
256 {
257         blk_t   blk;
258         int     j;
259
260         if (gdp->bg_block_bitmap &&
261             (gdp->bg_block_bitmap < fs->super->s_blocks_count)) {
262                 ext2fs_block_alloc_stats(fs, gdp->bg_block_bitmap, -1);
263                 ext2fs_mark_block_bitmap(reserve_blocks,
264                                          gdp->bg_block_bitmap);
265         }
266
267         if (gdp->bg_inode_bitmap &&
268             (gdp->bg_inode_bitmap < fs->super->s_blocks_count)) {
269                 ext2fs_block_alloc_stats(fs, gdp->bg_inode_bitmap, -1);
270                 ext2fs_mark_block_bitmap(reserve_blocks,
271                                          gdp->bg_inode_bitmap);
272         }
273
274         if (gdp->bg_inode_table == 0 ||
275             (gdp->bg_inode_table >= fs->super->s_blocks_count))
276                 return;
277
278         for (blk = gdp->bg_inode_table, j = 0;
279              j < fs->inode_blocks_per_group; j++, blk++) {
280                 if (blk >= fs->super->s_blocks_count)
281                         break;
282                 ext2fs_block_alloc_stats(fs, blk, -1);
283                 ext2fs_mark_block_bitmap(reserve_blocks, blk);
284         }
285 }
286
287 /*
288  * This routine is shared by the online and offline resize routines.
289  * All of the information which is adjusted in memory is done here.
290  *
291  * The reserve_blocks parameter is only needed when shrinking the
292  * filesystem.
293  */
294 errcode_t adjust_fs_info(ext2_filsys fs, ext2_filsys old_fs,
295                          ext2fs_block_bitmap reserve_blocks, blk_t new_size)
296 {
297         errcode_t       retval;
298         int             overhead = 0;
299         int             rem;
300         blk_t           blk, group_block;
301         ext2_ino_t      real_end;
302         int             adj, old_numblocks, numblocks, adjblocks;
303         unsigned long   i, j, old_desc_blocks, max_group;
304         unsigned int    meta_bg, meta_bg_size;
305         int             has_super, csum_flag;
306         unsigned long long new_inodes;  /* u64 to check for overflow */
307         double          percent;
308
309         fs->super->s_blocks_count = new_size;
310
311 retry:
312         fs->group_desc_count = ext2fs_div_ceil(fs->super->s_blocks_count -
313                                        fs->super->s_first_data_block,
314                                        EXT2_BLOCKS_PER_GROUP(fs->super));
315         if (fs->group_desc_count == 0)
316                 return EXT2_ET_TOOSMALL;
317         fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
318                                           EXT2_DESC_PER_BLOCK(fs->super));
319
320         /*
321          * Overhead is the number of bookkeeping blocks per group.  It
322          * includes the superblock backup, the group descriptor
323          * backups, the inode bitmap, the block bitmap, and the inode
324          * table.
325          */
326         overhead = (int) (2 + fs->inode_blocks_per_group);
327
328         if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
329                 overhead += 1 + fs->desc_blocks +
330                         fs->super->s_reserved_gdt_blocks;
331
332         /*
333          * See if the last group is big enough to support the
334          * necessary data structures.  If not, we need to get rid of
335          * it.
336          */
337         rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
338                 fs->super->s_blocks_per_group;
339         if ((fs->group_desc_count == 1) && rem && (rem < overhead))
340                 return EXT2_ET_TOOSMALL;
341         if (rem && (rem < overhead+50)) {
342                 fs->super->s_blocks_count -= rem;
343                 goto retry;
344         }
345         /*
346          * Adjust the number of inodes
347          */
348         new_inodes =(unsigned long long) fs->super->s_inodes_per_group * fs->group_desc_count;
349         if (new_inodes > ~0U) {
350                 fprintf(stderr, _("inodes (%llu) must be less than %u"),
351                                    new_inodes, ~0U);
352                 return EXT2_ET_TOO_MANY_INODES;
353         }
354         fs->super->s_inodes_count = fs->super->s_inodes_per_group *
355                 fs->group_desc_count;
356
357         /*
358          * Adjust the number of free blocks
359          */
360         blk = old_fs->super->s_blocks_count;
361         if (blk > fs->super->s_blocks_count)
362                 fs->super->s_free_blocks_count -=
363                         (blk - fs->super->s_blocks_count);
364         else
365                 fs->super->s_free_blocks_count +=
366                         (fs->super->s_blocks_count - blk);
367
368         /*
369          * Adjust the number of reserved blocks
370          */
371         percent = (old_fs->super->s_r_blocks_count * 100.0) /
372                 old_fs->super->s_blocks_count;
373         fs->super->s_r_blocks_count = (unsigned int) (percent *
374                                         fs->super->s_blocks_count / 100.0);
375
376         /*
377          * Adjust the bitmaps for size
378          */
379         retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
380                                             fs->super->s_inodes_count,
381                                             fs->inode_map);
382         if (retval) goto errout;
383
384         real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
385                      * fs->group_desc_count)) - 1 +
386                              fs->super->s_first_data_block;
387         retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
388                                             real_end, fs->block_map);
389
390         if (retval) goto errout;
391
392         /*
393          * Reallocate the group descriptors as necessary.
394          */
395         if (old_fs->desc_blocks != fs->desc_blocks) {
396                 retval = ext2fs_resize_mem(old_fs->desc_blocks *
397                                            fs->blocksize,
398                                            fs->desc_blocks * fs->blocksize,
399                                            &fs->group_desc);
400                 if (retval)
401                         goto errout;
402                 if (fs->desc_blocks > old_fs->desc_blocks)
403                         memset((char *) fs->group_desc +
404                                (old_fs->desc_blocks * fs->blocksize), 0,
405                                (fs->desc_blocks - old_fs->desc_blocks) *
406                                fs->blocksize);
407         }
408
409         /*
410          * If the resize_inode feature is set, and we are changing the
411          * number of descriptor blocks, then adjust
412          * s_reserved_gdt_blocks if possible to avoid needing to move
413          * the inode table either now or in the future.
414          */
415         if ((fs->super->s_feature_compat &
416              EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
417             (old_fs->desc_blocks != fs->desc_blocks)) {
418                 int new;
419
420                 new = ((int) fs->super->s_reserved_gdt_blocks) +
421                         (old_fs->desc_blocks - fs->desc_blocks);
422                 if (new < 0)
423                         new = 0;
424                 if (new > (int) fs->blocksize/4)
425                         new = fs->blocksize/4;
426                 fs->super->s_reserved_gdt_blocks = new;
427         }
428
429         /*
430          * If we are shrinking the number of block groups, we're done
431          * and can exit now.
432          */
433         if (old_fs->group_desc_count > fs->group_desc_count) {
434                 /*
435                  * Check the block groups that we are chopping off
436                  * and free any blocks associated with their metadata
437                  */
438                 for (i = fs->group_desc_count;
439                      i < old_fs->group_desc_count; i++) {
440                         free_gdp_blocks(fs, reserve_blocks,
441                                         &old_fs->group_desc[i]);
442                 }
443                 retval = 0;
444                 goto errout;
445         }
446
447         /*
448          * Fix the count of the last (old) block group
449          */
450         old_numblocks = (old_fs->super->s_blocks_count -
451                          old_fs->super->s_first_data_block) %
452                                  old_fs->super->s_blocks_per_group;
453         if (!old_numblocks)
454                 old_numblocks = old_fs->super->s_blocks_per_group;
455         if (old_fs->group_desc_count == fs->group_desc_count) {
456                 numblocks = (fs->super->s_blocks_count -
457                              fs->super->s_first_data_block) %
458                         fs->super->s_blocks_per_group;
459                 if (!numblocks)
460                         numblocks = fs->super->s_blocks_per_group;
461         } else
462                 numblocks = fs->super->s_blocks_per_group;
463         i = old_fs->group_desc_count - 1;
464         fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
465         ext2fs_group_desc_csum_set(fs, i);
466
467         /*
468          * If the number of block groups is staying the same, we're
469          * done and can exit now.  (If the number block groups is
470          * shrinking, we had exited earlier.)
471          */
472         if (old_fs->group_desc_count >= fs->group_desc_count) {
473                 retval = 0;
474                 goto errout;
475         }
476
477         /*
478          * Initialize the new block group descriptors
479          */
480         group_block = fs->super->s_first_data_block +
481                 old_fs->group_desc_count * fs->super->s_blocks_per_group;
482
483         csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
484                                                EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
485         adj = old_fs->group_desc_count;
486         max_group = fs->group_desc_count - adj;
487         if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
488                 old_desc_blocks = fs->super->s_first_meta_bg;
489         else
490                 old_desc_blocks = fs->desc_blocks +
491                         fs->super->s_reserved_gdt_blocks;
492         for (i = old_fs->group_desc_count;
493              i < fs->group_desc_count; i++) {
494                 memset(&fs->group_desc[i], 0,
495                        sizeof(struct ext2_group_desc));
496                 adjblocks = 0;
497
498                 fs->group_desc[i].bg_flags = 0;
499                 if (csum_flag)
500                         fs->group_desc[i].bg_flags |= EXT2_BG_INODE_UNINIT |
501                                 EXT2_BG_INODE_ZEROED;
502                 if (i == fs->group_desc_count-1) {
503                         numblocks = (fs->super->s_blocks_count -
504                                      fs->super->s_first_data_block) %
505                                              fs->super->s_blocks_per_group;
506                         if (!numblocks)
507                                 numblocks = fs->super->s_blocks_per_group;
508                 } else {
509                         numblocks = fs->super->s_blocks_per_group;
510                         if (csum_flag)
511                                 fs->group_desc[i].bg_flags |=
512                                         EXT2_BG_BLOCK_UNINIT;
513                 }
514
515                 has_super = ext2fs_bg_has_super(fs, i);
516                 if (has_super) {
517                         ext2fs_block_alloc_stats(fs, group_block, +1);
518                         adjblocks++;
519                 }
520                 meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
521                 meta_bg = i / meta_bg_size;
522                 if (!(fs->super->s_feature_incompat &
523                       EXT2_FEATURE_INCOMPAT_META_BG) ||
524                     (meta_bg < fs->super->s_first_meta_bg)) {
525                         if (has_super) {
526                                 for (j=0; j < old_desc_blocks; j++)
527                                         ext2fs_block_alloc_stats(fs,
528                                                  group_block + 1 + j, +1);
529                                 adjblocks += old_desc_blocks;
530                         }
531                 } else {
532                         if (has_super)
533                                 has_super = 1;
534                         if (((i % meta_bg_size) == 0) ||
535                             ((i % meta_bg_size) == 1) ||
536                             ((i % meta_bg_size) == (meta_bg_size-1)))
537                                 ext2fs_block_alloc_stats(fs,
538                                                  group_block + has_super, +1);
539                 }
540
541                 adjblocks += 2 + fs->inode_blocks_per_group;
542
543                 numblocks -= adjblocks;
544                 fs->super->s_free_blocks_count -= adjblocks;
545                 fs->super->s_free_inodes_count +=
546                         fs->super->s_inodes_per_group;
547                 fs->group_desc[i].bg_free_blocks_count = numblocks;
548                 fs->group_desc[i].bg_free_inodes_count =
549                         fs->super->s_inodes_per_group;
550                 fs->group_desc[i].bg_used_dirs_count = 0;
551                 ext2fs_group_desc_csum_set(fs, i);
552
553                 retval = ext2fs_allocate_group_table(fs, i, 0);
554                 if (retval) goto errout;
555
556                 group_block += fs->super->s_blocks_per_group;
557         }
558         retval = 0;
559
560 errout:
561         return (retval);
562 }
563
564 /*
565  * This routine adjusts the superblock and other data structures, both
566  * in disk as well as in memory...
567  */
568 static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
569 {
570         ext2_filsys fs;
571         int             adj = 0;
572         errcode_t       retval;
573         blk_t           group_block;
574         unsigned long   i;
575         unsigned long   max_group;
576
577         fs = rfs->new_fs;
578         ext2fs_mark_super_dirty(fs);
579         ext2fs_mark_bb_dirty(fs);
580         ext2fs_mark_ib_dirty(fs);
581
582         retval = ext2fs_allocate_block_bitmap(fs, _("reserved blocks"),
583                                               &rfs->reserve_blocks);
584         if (retval)
585                 return retval;
586
587         retval = adjust_fs_info(fs, rfs->old_fs, rfs->reserve_blocks, new_size);
588         if (retval)
589                 goto errout;
590
591         /*
592          * Check to make sure there are enough inodes
593          */
594         if ((rfs->old_fs->super->s_inodes_count -
595              rfs->old_fs->super->s_free_inodes_count) >
596             rfs->new_fs->super->s_inodes_count) {
597                 retval = ENOSPC;
598                 goto errout;
599         }
600
601         /*
602          * If we are shrinking the number block groups, we're done and
603          * can exit now.
604          */
605         if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
606                 retval = 0;
607                 goto errout;
608         }
609
610         /*
611          * If the number of block groups is staying the same, we're
612          * done and can exit now.  (If the number block groups is
613          * shrinking, we had exited earlier.)
614          */
615         if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
616                 retval = 0;
617                 goto errout;
618         }
619
620         /*
621          * Initialize the new block group descriptors
622          */
623         retval = ext2fs_get_array(fs->blocksize, fs->inode_blocks_per_group,
624                                 &rfs->itable_buf);
625         if (retval)
626                 goto errout;
627
628         memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
629         group_block = fs->super->s_first_data_block +
630                 rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
631
632         adj = rfs->old_fs->group_desc_count;
633         max_group = fs->group_desc_count - adj;
634         if (rfs->progress) {
635                 retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
636                                        0, max_group);
637                 if (retval)
638                         goto errout;
639         }
640         for (i = rfs->old_fs->group_desc_count;
641              i < fs->group_desc_count; i++) {
642                 /*
643                  * Write out the new inode table
644                  */
645                 retval = io_channel_write_blk(fs->io,
646                                               fs->group_desc[i].bg_inode_table,
647                                               fs->inode_blocks_per_group,
648                                               rfs->itable_buf);
649                 if (retval) goto errout;
650
651                 io_channel_flush(fs->io);
652                 if (rfs->progress) {
653                         retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
654                                                i - adj + 1, max_group);
655                         if (retval)
656                                 goto errout;
657                 }
658                 group_block += fs->super->s_blocks_per_group;
659         }
660         io_channel_flush(fs->io);
661         retval = 0;
662
663 errout:
664         return retval;
665 }
666
667 /* --------------------------------------------------------------------
668  *
669  * Resize processing, phase 2.
670  *
671  * In this phase we adjust determine which blocks need to be moved, in
672  * blocks_to_move().  We then copy the blocks to their ultimate new
673  * destinations using block_mover().  Since we are copying blocks to
674  * their new locations, again during this pass we can abort without
675  * any problems.
676  * --------------------------------------------------------------------
677  */
678
679 /*
680  * This helper function creates a block bitmap with all of the
681  * filesystem meta-data blocks.
682  */
683 static errcode_t mark_table_blocks(ext2_filsys fs,
684                                    ext2fs_block_bitmap bmap)
685 {
686         blk_t                   b;
687         unsigned int            j;
688         dgrp_t                  i;
689         unsigned long           meta_bg_size;
690         unsigned int            old_desc_blocks;
691
692         meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
693         if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
694                 old_desc_blocks = fs->super->s_first_meta_bg;
695         else
696                 old_desc_blocks = fs->desc_blocks +
697                         fs->super->s_reserved_gdt_blocks;
698         for (i = 0; i < fs->group_desc_count; i++) {
699                 ext2fs_reserve_super_and_bgd(fs, i, bmap);
700
701                 /*
702                  * Mark the blocks used for the inode table
703                  */
704                 for (j = 0, b = fs->group_desc[i].bg_inode_table;
705                      j < (unsigned int) fs->inode_blocks_per_group;
706                      j++, b++)
707                         ext2fs_mark_block_bitmap(bmap, b);
708
709                 /*
710                  * Mark block used for the block bitmap
711                  */
712                 ext2fs_mark_block_bitmap(bmap,
713                                          fs->group_desc[i].bg_block_bitmap);
714
715                 /*
716                  * Mark block used for the inode bitmap
717                  */
718                 ext2fs_mark_block_bitmap(bmap,
719                                          fs->group_desc[i].bg_inode_bitmap);
720         }
721         return 0;
722 }
723
724 /*
725  * This function checks to see if a particular block (either a
726  * superblock or a block group descriptor) overlaps with an inode or
727  * block bitmap block, or with the inode table.
728  */
729 static void mark_fs_metablock(ext2_resize_t rfs,
730                               ext2fs_block_bitmap meta_bmap,
731                               int group, blk_t blk)
732 {
733         ext2_filsys     fs = rfs->new_fs;
734
735         ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
736         ext2fs_block_alloc_stats(fs, blk, +1);
737
738         /*
739          * Check to see if we overlap with the inode or block bitmap,
740          * or the inode tables.  If not, and the block is in use, then
741          * mark it as a block to be moved.
742          */
743         if (IS_BLOCK_BM(fs, group, blk)) {
744                 FS_BLOCK_BM(fs, group) = 0;
745                 rfs->needed_blocks++;
746         } else if (IS_INODE_BM(fs, group, blk)) {
747                 FS_INODE_BM(fs, group) = 0;
748                 rfs->needed_blocks++;
749         } else if (IS_INODE_TB(fs, group, blk)) {
750                 FS_INODE_TB(fs, group) = 0;
751                 rfs->needed_blocks++;
752         } else if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
753                                               EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
754                    (fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT)) {
755                 /*
756                  * If the block bitmap is uninitialized, which means
757                  * nothing other than standard metadata in use.
758                  */
759                 return;
760         } else if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk) &&
761                    !ext2fs_test_block_bitmap(meta_bmap, blk)) {
762                 ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
763                 rfs->needed_blocks++;
764         }
765 }
766
767
768 /*
769  * This routine marks and unmarks reserved blocks in the new block
770  * bitmap.  It also determines which blocks need to be moved and
771  * places this information into the move_blocks bitmap.
772  */
773 static errcode_t blocks_to_move(ext2_resize_t rfs)
774 {
775         int             j, has_super;
776         dgrp_t          i, max_groups, g;
777         blk_t           blk, group_blk;
778         unsigned long   old_blocks, new_blocks;
779         unsigned int    meta_bg, meta_bg_size;
780         errcode_t       retval;
781         ext2_filsys     fs, old_fs;
782         ext2fs_block_bitmap     meta_bmap;
783         __u32           save_incompat_flag;
784
785         fs = rfs->new_fs;
786         old_fs = rfs->old_fs;
787         if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
788                 fs = rfs->old_fs;
789
790         retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
791                                               &rfs->move_blocks);
792         if (retval)
793                 return retval;
794
795         retval = ext2fs_allocate_block_bitmap(fs, _("meta-data blocks"),
796                                               &meta_bmap);
797         if (retval)
798                 return retval;
799
800         retval = mark_table_blocks(old_fs, meta_bmap);
801         if (retval)
802                 return retval;
803
804         fs = rfs->new_fs;
805
806         /*
807          * If we're shrinking the filesystem, we need to move all of
808          * the blocks that don't fit any more
809          */
810         for (blk = fs->super->s_blocks_count;
811              blk < old_fs->super->s_blocks_count; blk++) {
812                 g = ext2fs_group_of_blk(fs, blk);
813                 if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
814                                                EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
815                     (old_fs->group_desc[g].bg_flags & EXT2_BG_BLOCK_UNINIT)) {
816                         /*
817                          * The block bitmap is uninitialized, so skip
818                          * to the next block group.
819                          */
820                         blk = ((g+1) * fs->super->s_blocks_per_group) +
821                                 fs->super->s_first_data_block - 1;
822                         continue;
823                 }
824                 if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
825                     !ext2fs_test_block_bitmap(meta_bmap, blk)) {
826                         ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
827                         rfs->needed_blocks++;
828                 }
829                 ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
830         }
831
832         if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) {
833                 old_blocks = old_fs->super->s_first_meta_bg;
834                 new_blocks = fs->super->s_first_meta_bg;
835         } else {
836                 old_blocks = old_fs->desc_blocks + old_fs->super->s_reserved_gdt_blocks;
837                 new_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
838         }
839
840         if (old_blocks == new_blocks) {
841                 retval = 0;
842                 goto errout;
843         }
844
845         max_groups = fs->group_desc_count;
846         if (max_groups > old_fs->group_desc_count)
847                 max_groups = old_fs->group_desc_count;
848         group_blk = old_fs->super->s_first_data_block;
849         /*
850          * If we're reducing the number of descriptor blocks, this
851          * makes life easy.  :-)   We just have to mark some extra
852          * blocks as free.
853          */
854         if (old_blocks > new_blocks) {
855                 for (i = 0; i < max_groups; i++) {
856                         if (!ext2fs_bg_has_super(fs, i)) {
857                                 group_blk += fs->super->s_blocks_per_group;
858                                 continue;
859                         }
860                         for (blk = group_blk+1+new_blocks;
861                              blk < group_blk+1+old_blocks; blk++) {
862                                 ext2fs_block_alloc_stats(fs, blk, -1);
863                                 rfs->needed_blocks--;
864                         }
865                         group_blk += fs->super->s_blocks_per_group;
866                 }
867                 retval = 0;
868                 goto errout;
869         }
870         /*
871          * If we're increasing the number of descriptor blocks, life
872          * gets interesting....
873          */
874         meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
875         for (i = 0; i < max_groups; i++) {
876                 has_super = ext2fs_bg_has_super(fs, i);
877                 if (has_super)
878                         mark_fs_metablock(rfs, meta_bmap, i, group_blk);
879
880                 meta_bg = i / meta_bg_size;
881                 if (!(fs->super->s_feature_incompat &
882                       EXT2_FEATURE_INCOMPAT_META_BG) ||
883                     (meta_bg < fs->super->s_first_meta_bg)) {
884                         if (has_super) {
885                                 for (blk = group_blk+1;
886                                      blk < group_blk + 1 + new_blocks; blk++)
887                                         mark_fs_metablock(rfs, meta_bmap,
888                                                           i, blk);
889                         }
890                 } else {
891                         if (has_super)
892                                 has_super = 1;
893                         if (((i % meta_bg_size) == 0) ||
894                             ((i % meta_bg_size) == 1) ||
895                             ((i % meta_bg_size) == (meta_bg_size-1)))
896                                 mark_fs_metablock(rfs, meta_bmap, i,
897                                                   group_blk + has_super);
898                 }
899
900                 if (fs->group_desc[i].bg_inode_table &&
901                     fs->group_desc[i].bg_inode_bitmap &&
902                     fs->group_desc[i].bg_block_bitmap)
903                         goto next_group;
904
905                 /*
906                  * Reserve the existing meta blocks that we know
907                  * aren't to be moved.
908                  */
909                 if (fs->group_desc[i].bg_block_bitmap)
910                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
911                                  fs->group_desc[i].bg_block_bitmap);
912                 if (fs->group_desc[i].bg_inode_bitmap)
913                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
914                                  fs->group_desc[i].bg_inode_bitmap);
915                 if (fs->group_desc[i].bg_inode_table)
916                         for (blk = fs->group_desc[i].bg_inode_table, j=0;
917                              j < fs->inode_blocks_per_group ; j++, blk++)
918                                 ext2fs_mark_block_bitmap(rfs->reserve_blocks,
919                                                          blk);
920
921                 /*
922                  * Allocate the missing data structures
923                  *
924                  * XXX We have a problem with FLEX_BG and off-line
925                  * resizing where we are growing the size of the
926                  * filesystem.  ext2fs_allocate_group_table() will try
927                  * to reserve the inode table in the desired flex_bg
928                  * location.  However, passing rfs->reserve_blocks
929                  * doesn't work since it only has reserved the blocks
930                  * that will be used in the new block group -- and
931                  * with flex_bg, we can and will allocate the tables
932                  * outside of the block group.  And we can't pass in
933                  * the fs->block_map because it doesn't handle
934                  * overlapping inode table movements right.  So for
935                  * now, we temporarily disable flex_bg to force
936                  * ext2fs_allocate_group_tables() to allocate the bg
937                  * metadata in side the block group, and the restore
938                  * it afterwards.  Ugly, until we can fix this up
939                  * right later.
940                  */
941                 save_incompat_flag = fs->super->s_feature_incompat;
942                 fs->super->s_feature_incompat &= ~EXT4_FEATURE_INCOMPAT_FLEX_BG;
943                 retval = ext2fs_allocate_group_table(fs, i,
944                                                      rfs->reserve_blocks);
945                 fs->super->s_feature_incompat = save_incompat_flag;
946                 if (retval)
947                         goto errout;
948
949                 /*
950                  * For those structures that have changed, we need to
951                  * do bookkeepping.
952                  */
953                 if (FS_BLOCK_BM(old_fs, i) !=
954                     (blk = FS_BLOCK_BM(fs, i))) {
955                         ext2fs_block_alloc_stats(fs, blk, +1);
956                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
957                             !ext2fs_test_block_bitmap(meta_bmap, blk))
958                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
959                                                          blk);
960                 }
961                 if (FS_INODE_BM(old_fs, i) !=
962                     (blk = FS_INODE_BM(fs, i))) {
963                         ext2fs_block_alloc_stats(fs, blk, +1);
964                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
965                             !ext2fs_test_block_bitmap(meta_bmap, blk))
966                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
967                                                          blk);
968                 }
969
970                 /*
971                  * The inode table, if we need to relocate it, is
972                  * handled specially.  We have to reserve the blocks
973                  * for both the old and the new inode table, since we
974                  * can't have the inode table be destroyed during the
975                  * block relocation phase.
976                  */
977                 if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
978                         goto next_group; /* inode table not moved */
979
980                 rfs->needed_blocks += fs->inode_blocks_per_group;
981
982                 /*
983                  * Mark the new inode table as in use in the new block
984                  * allocation bitmap, and move any blocks that might
985                  * be necessary.
986                  */
987                 for (blk = fs->group_desc[i].bg_inode_table, j=0;
988                      j < fs->inode_blocks_per_group ; j++, blk++) {
989                         ext2fs_block_alloc_stats(fs, blk, +1);
990                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
991                             !ext2fs_test_block_bitmap(meta_bmap, blk))
992                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
993                                                          blk);
994                 }
995
996                 /*
997                  * Make sure the old inode table is reserved in the
998                  * block reservation bitmap.
999                  */
1000                 for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
1001                      j < fs->inode_blocks_per_group ; j++, blk++)
1002                         ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
1003
1004         next_group:
1005                 group_blk += rfs->new_fs->super->s_blocks_per_group;
1006         }
1007         retval = 0;
1008
1009 errout:
1010         if (meta_bmap)
1011                 ext2fs_free_block_bitmap(meta_bmap);
1012
1013         return retval;
1014 }
1015
1016 /*
1017  * This helper function tries to allocate a new block.  We try to
1018  * avoid hitting the original group descriptor blocks at least at
1019  * first, since we want to make it possible to recover from a badly
1020  * aborted resize operation as much as possible.
1021  *
1022  * In the future, I may further modify this routine to balance out
1023  * where we get the new blocks across the various block groups.
1024  * Ideally we would allocate blocks that corresponded with the block
1025  * group of the containing inode, and keep contiguous blocks
1026  * together.  However, this very difficult to do efficiently, since we
1027  * don't have the necessary information up front.
1028  */
1029
1030 #define AVOID_OLD       1
1031 #define DESPERATION     2
1032
1033 static void init_block_alloc(ext2_resize_t rfs)
1034 {
1035         rfs->alloc_state = AVOID_OLD;
1036         rfs->new_blk = rfs->new_fs->super->s_first_data_block;
1037 #if 0
1038         /* HACK for testing */
1039         if (rfs->new_fs->super->s_blocks_count >
1040             rfs->old_fs->super->s_blocks_count)
1041                 rfs->new_blk = rfs->old_fs->super->s_blocks_count;
1042 #endif
1043 }
1044
1045 static blk_t get_new_block(ext2_resize_t rfs)
1046 {
1047         ext2_filsys     fs = rfs->new_fs;
1048
1049         while (1) {
1050                 if (rfs->new_blk >= fs->super->s_blocks_count) {
1051                         if (rfs->alloc_state == DESPERATION)
1052                                 return 0;
1053
1054 #ifdef RESIZE2FS_DEBUG
1055                         if (rfs->flags & RESIZE_DEBUG_BMOVE)
1056                                 printf("Going into desperation mode "
1057                                        "for block allocations\n");
1058 #endif
1059                         rfs->alloc_state = DESPERATION;
1060                         rfs->new_blk = fs->super->s_first_data_block;
1061                         continue;
1062                 }
1063                 if (ext2fs_test_block_bitmap(fs->block_map, rfs->new_blk) ||
1064                     ext2fs_test_block_bitmap(rfs->reserve_blocks,
1065                                              rfs->new_blk) ||
1066                     ((rfs->alloc_state == AVOID_OLD) &&
1067                      (rfs->new_blk < rfs->old_fs->super->s_blocks_count) &&
1068                      ext2fs_test_block_bitmap(rfs->old_fs->block_map,
1069                                               rfs->new_blk))) {
1070                         rfs->new_blk++;
1071                         continue;
1072                 }
1073                 return rfs->new_blk;
1074         }
1075 }
1076
1077 static errcode_t resize2fs_get_alloc_block(ext2_filsys fs, blk64_t goal,
1078                                            blk64_t *ret)
1079 {
1080         ext2_resize_t rfs = (ext2_resize_t) fs->priv_data;
1081         blk_t blk;
1082
1083         blk = get_new_block(rfs);
1084         if (!blk)
1085                 return ENOSPC;
1086
1087 #ifdef RESIZE2FS_DEBUG
1088         if (rfs->flags & 0xF)
1089                 printf("get_alloc_block allocating %u\n", blk);
1090 #endif
1091
1092         ext2fs_mark_block_bitmap(rfs->old_fs->block_map, blk);
1093         ext2fs_mark_block_bitmap(rfs->new_fs->block_map, blk);
1094         *ret = (blk64_t) blk;
1095         return 0;
1096 }
1097
1098 static errcode_t block_mover(ext2_resize_t rfs)
1099 {
1100         blk_t                   blk, old_blk, new_blk;
1101         ext2_filsys             fs = rfs->new_fs;
1102         ext2_filsys             old_fs = rfs->old_fs;
1103         errcode_t               retval;
1104         int                     size, c;
1105         int                     to_move, moved;
1106         ext2_badblocks_list     badblock_list = 0;
1107         int                     bb_modified = 0;
1108
1109         fs->get_alloc_block = resize2fs_get_alloc_block;
1110         old_fs->get_alloc_block = resize2fs_get_alloc_block;
1111
1112         retval = ext2fs_read_bb_inode(old_fs, &badblock_list);
1113         if (retval)
1114                 return retval;
1115
1116         new_blk = fs->super->s_first_data_block;
1117         if (!rfs->itable_buf) {
1118                 retval = ext2fs_get_array(fs->blocksize,
1119                                         fs->inode_blocks_per_group,
1120                                         &rfs->itable_buf);
1121                 if (retval)
1122                         return retval;
1123         }
1124         retval = ext2fs_create_extent_table(&rfs->bmap, 0);
1125         if (retval)
1126                 return retval;
1127
1128         /*
1129          * The first step is to figure out where all of the blocks
1130          * will go.
1131          */
1132         to_move = moved = 0;
1133         init_block_alloc(rfs);
1134         for (blk = old_fs->super->s_first_data_block;
1135              blk < old_fs->super->s_blocks_count; blk++) {
1136                 if (!ext2fs_test_block_bitmap(old_fs->block_map, blk))
1137                         continue;
1138                 if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk))
1139                         continue;
1140                 if (ext2fs_badblocks_list_test(badblock_list, blk)) {
1141                         ext2fs_badblocks_list_del(badblock_list, blk);
1142                         bb_modified++;
1143                         continue;
1144                 }
1145
1146                 new_blk = get_new_block(rfs);
1147                 if (!new_blk) {
1148                         retval = ENOSPC;
1149                         goto errout;
1150                 }
1151                 ext2fs_block_alloc_stats(fs, new_blk, +1);
1152                 ext2fs_add_extent_entry(rfs->bmap, blk, new_blk);
1153                 to_move++;
1154         }
1155
1156         if (to_move == 0) {
1157                 if (rfs->bmap) {
1158                         ext2fs_free_extent_table(rfs->bmap);
1159                         rfs->bmap = 0;
1160                 }
1161                 retval = 0;
1162                 goto errout;
1163         }
1164
1165         /*
1166          * Step two is to actually move the blocks
1167          */
1168         retval =  ext2fs_iterate_extent(rfs->bmap, 0, 0, 0);
1169         if (retval) goto errout;
1170
1171         if (rfs->progress) {
1172                 retval = (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS,
1173                                          0, to_move);
1174                 if (retval)
1175                         goto errout;
1176         }
1177         while (1) {
1178                 retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size);
1179                 if (retval) goto errout;
1180                 if (!size)
1181                         break;
1182 #ifdef RESIZE2FS_DEBUG
1183                 if (rfs->flags & RESIZE_DEBUG_BMOVE)
1184                         printf("Moving %d blocks %u->%u\n",
1185                                size, old_blk, new_blk);
1186 #endif
1187                 do {
1188                         c = size;
1189                         if (c > fs->inode_blocks_per_group)
1190                                 c = fs->inode_blocks_per_group;
1191                         retval = io_channel_read_blk(fs->io, old_blk, c,
1192                                                      rfs->itable_buf);
1193                         if (retval) goto errout;
1194                         retval = io_channel_write_blk(fs->io, new_blk, c,
1195                                                       rfs->itable_buf);
1196                         if (retval) goto errout;
1197                         size -= c;
1198                         new_blk += c;
1199                         old_blk += c;
1200                         moved += c;
1201                         if (rfs->progress) {
1202                                 io_channel_flush(fs->io);
1203                                 retval = (rfs->progress)(rfs,
1204                                                 E2_RSZ_BLOCK_RELOC_PASS,
1205                                                 moved, to_move);
1206                                 if (retval)
1207                                         goto errout;
1208                         }
1209                 } while (size > 0);
1210                 io_channel_flush(fs->io);
1211         }
1212
1213 errout:
1214         if (badblock_list) {
1215                 if (!retval && bb_modified)
1216                         retval = ext2fs_update_bb_inode(old_fs,
1217                                                         badblock_list);
1218                 ext2fs_badblocks_list_free(badblock_list);
1219         }
1220         return retval;
1221 }
1222
1223
1224 /* --------------------------------------------------------------------
1225  *
1226  * Resize processing, phase 3
1227  *
1228  * --------------------------------------------------------------------
1229  */
1230
1231
1232 struct process_block_struct {
1233         ext2_resize_t           rfs;
1234         ext2_ino_t              ino;
1235         struct ext2_inode *     inode;
1236         errcode_t               error;
1237         int                     is_dir;
1238         int                     changed;
1239 };
1240
1241 static int process_block(ext2_filsys fs, blk_t  *block_nr,
1242                          e2_blkcnt_t blockcnt,
1243                          blk_t ref_block EXT2FS_ATTR((unused)),
1244                          int ref_offset EXT2FS_ATTR((unused)), void *priv_data)
1245 {
1246         struct process_block_struct *pb;
1247         errcode_t       retval;
1248         blk_t           block, new_block;
1249         int             ret = 0;
1250
1251         pb = (struct process_block_struct *) priv_data;
1252         block = *block_nr;
1253         if (pb->rfs->bmap) {
1254                 new_block = ext2fs_extent_translate(pb->rfs->bmap, block);
1255                 if (new_block) {
1256                         *block_nr = new_block;
1257                         ret |= BLOCK_CHANGED;
1258                         pb->changed = 1;
1259 #ifdef RESIZE2FS_DEBUG
1260                         if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
1261                                 printf("ino=%u, blockcnt=%lld, %u->%u\n",
1262                                        pb->ino, blockcnt, block, new_block);
1263 #endif
1264                         block = new_block;
1265                 }
1266         }
1267         if (pb->is_dir) {
1268                 retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
1269                                               block, (int) blockcnt);
1270                 if (retval) {
1271                         pb->error = retval;
1272                         ret |= BLOCK_ABORT;
1273                 }
1274         }
1275         return ret;
1276 }
1277
1278 /*
1279  * Progress callback
1280  */
1281 static errcode_t progress_callback(ext2_filsys fs,
1282                                    ext2_inode_scan scan EXT2FS_ATTR((unused)),
1283                                    dgrp_t group, void * priv_data)
1284 {
1285         ext2_resize_t rfs = (ext2_resize_t) priv_data;
1286         errcode_t               retval;
1287
1288         /*
1289          * This check is to protect against old ext2 libraries.  It
1290          * shouldn't be needed against new libraries.
1291          */
1292         if ((group+1) == 0)
1293                 return 0;
1294
1295         if (rfs->progress) {
1296                 io_channel_flush(fs->io);
1297                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
1298                                          group+1, fs->group_desc_count);
1299                 if (retval)
1300                         return retval;
1301         }
1302
1303         return 0;
1304 }
1305
1306 static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
1307 {
1308         struct process_block_struct     pb;
1309         ext2_ino_t              ino, new_inode;
1310         struct ext2_inode       *inode = NULL;
1311         ext2_inode_scan         scan = NULL;
1312         errcode_t               retval;
1313         char                    *block_buf = 0;
1314         ext2_ino_t              start_to_move;
1315         blk_t                   orig_size, new_block;
1316         int                     inode_size;
1317
1318         if ((rfs->old_fs->group_desc_count <=
1319              rfs->new_fs->group_desc_count) &&
1320             !rfs->bmap)
1321                 return 0;
1322
1323         /*
1324          * Save the original size of the old filesystem, and
1325          * temporarily set the size to be the new size if the new size
1326          * is larger.  We need to do this to avoid catching an error
1327          * by the block iterator routines
1328          */
1329         orig_size = rfs->old_fs->super->s_blocks_count;
1330         if (orig_size < rfs->new_fs->super->s_blocks_count)
1331                 rfs->old_fs->super->s_blocks_count =
1332                         rfs->new_fs->super->s_blocks_count;
1333
1334         retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
1335         if (retval) goto errout;
1336
1337         retval = ext2fs_init_dblist(rfs->old_fs, 0);
1338         if (retval) goto errout;
1339         retval = ext2fs_get_array(rfs->old_fs->blocksize, 3, &block_buf);
1340         if (retval) goto errout;
1341
1342         start_to_move = (rfs->new_fs->group_desc_count *
1343                          rfs->new_fs->super->s_inodes_per_group);
1344
1345         if (rfs->progress) {
1346                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
1347                                          0, rfs->old_fs->group_desc_count);
1348                 if (retval)
1349                         goto errout;
1350         }
1351         ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
1352         pb.rfs = rfs;
1353         pb.inode = inode;
1354         pb.error = 0;
1355         new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
1356         inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
1357         inode = malloc(inode_size);
1358         if (!inode) {
1359                 retval = ENOMEM;
1360                 goto errout;
1361         }
1362         /*
1363          * First, copy all of the inodes that need to be moved
1364          * elsewhere in the inode table
1365          */
1366         while (1) {
1367                 retval = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
1368                 if (retval) goto errout;
1369                 if (!ino)
1370                         break;
1371
1372                 if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
1373                         continue; /* inode not in use */
1374
1375                 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
1376                 pb.changed = 0;
1377
1378                 if (inode->i_file_acl && rfs->bmap) {
1379                         new_block = ext2fs_extent_translate(rfs->bmap,
1380                                                             inode->i_file_acl);
1381                         if (new_block) {
1382                                 inode->i_file_acl = new_block;
1383                                 retval = ext2fs_write_inode_full(rfs->old_fs,
1384                                                             ino, inode, inode_size);
1385                                 if (retval) goto errout;
1386                         }
1387                 }
1388
1389                 if (ext2fs_inode_has_valid_blocks(inode) &&
1390                     (rfs->bmap || pb.is_dir)) {
1391                         pb.ino = ino;
1392                         retval = ext2fs_block_iterate2(rfs->old_fs,
1393                                                        ino, 0, block_buf,
1394                                                        process_block, &pb);
1395                         if (retval)
1396                                 goto errout;
1397                         if (pb.error) {
1398                                 retval = pb.error;
1399                                 goto errout;
1400                         }
1401                 }
1402
1403                 if (ino <= start_to_move)
1404                         continue; /* Don't need to move it. */
1405
1406                 /*
1407                  * Find a new inode
1408                  */
1409                 retval = ext2fs_new_inode(rfs->new_fs, 0, 0, 0, &new_inode);
1410                 if (retval)
1411                         goto errout;
1412
1413                 ext2fs_inode_alloc_stats2(rfs->new_fs, new_inode, +1,
1414                                           pb.is_dir);
1415                 if (pb.changed) {
1416                         /* Get the new version of the inode */
1417                         retval = ext2fs_read_inode_full(rfs->old_fs, ino,
1418                                                 inode, inode_size);
1419                         if (retval) goto errout;
1420                 }
1421                 inode->i_ctime = time(0);
1422                 retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
1423                                                 inode, inode_size);
1424                 if (retval) goto errout;
1425
1426 #ifdef RESIZE2FS_DEBUG
1427                 if (rfs->flags & RESIZE_DEBUG_INODEMAP)
1428                         printf("Inode moved %u->%u\n", ino, new_inode);
1429 #endif
1430                 if (!rfs->imap) {
1431                         retval = ext2fs_create_extent_table(&rfs->imap, 0);
1432                         if (retval)
1433                                 goto errout;
1434                 }
1435                 ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
1436         }
1437         io_channel_flush(rfs->old_fs->io);
1438
1439 errout:
1440         rfs->old_fs->super->s_blocks_count = orig_size;
1441         if (rfs->bmap) {
1442                 ext2fs_free_extent_table(rfs->bmap);
1443                 rfs->bmap = 0;
1444         }
1445         if (scan)
1446                 ext2fs_close_inode_scan(scan);
1447         if (block_buf)
1448                 ext2fs_free_mem(&block_buf);
1449         free(inode);
1450         return retval;
1451 }
1452
1453 /* --------------------------------------------------------------------
1454  *
1455  * Resize processing, phase 4.
1456  *
1457  * --------------------------------------------------------------------
1458  */
1459
1460 struct istruct {
1461         ext2_resize_t rfs;
1462         errcode_t       err;
1463         unsigned int    max_dirs;
1464         unsigned int    num;
1465 };
1466
1467 static int check_and_change_inodes(ext2_ino_t dir,
1468                                    int entry EXT2FS_ATTR((unused)),
1469                                    struct ext2_dir_entry *dirent, int offset,
1470                                    int  blocksize EXT2FS_ATTR((unused)),
1471                                    char *buf EXT2FS_ATTR((unused)),
1472                                    void *priv_data)
1473 {
1474         struct istruct *is = (struct istruct *) priv_data;
1475         struct ext2_inode       inode;
1476         ext2_ino_t              new_inode;
1477         errcode_t               retval;
1478
1479         if (is->rfs->progress && offset == 0) {
1480                 io_channel_flush(is->rfs->old_fs->io);
1481                 is->err = (is->rfs->progress)(is->rfs,
1482                                               E2_RSZ_INODE_REF_UPD_PASS,
1483                                               ++is->num, is->max_dirs);
1484                 if (is->err)
1485                         return DIRENT_ABORT;
1486         }
1487
1488         if (!dirent->inode)
1489                 return 0;
1490
1491         new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
1492
1493         if (!new_inode)
1494                 return 0;
1495 #ifdef RESIZE2FS_DEBUG
1496         if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
1497                 printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
1498                        dir, dirent->name_len&0xFF, dirent->name,
1499                        dirent->inode, new_inode);
1500 #endif
1501
1502         dirent->inode = new_inode;
1503
1504         /* Update the directory mtime and ctime */
1505         retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
1506         if (retval == 0) {
1507                 inode.i_mtime = inode.i_ctime = time(0);
1508                 is->err = ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
1509                 if (is->err)
1510                         return DIRENT_ABORT;
1511         }
1512
1513         return DIRENT_CHANGED;
1514 }
1515
1516 static errcode_t inode_ref_fix(ext2_resize_t rfs)
1517 {
1518         errcode_t               retval;
1519         struct istruct          is;
1520
1521         if (!rfs->imap)
1522                 return 0;
1523
1524         /*
1525          * Now, we iterate over all of the directories to update the
1526          * inode references
1527          */
1528         is.num = 0;
1529         is.max_dirs = ext2fs_dblist_count(rfs->old_fs->dblist);
1530         is.rfs = rfs;
1531         is.err = 0;
1532
1533         if (rfs->progress) {
1534                 retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
1535                                          0, is.max_dirs);
1536                 if (retval)
1537                         goto errout;
1538         }
1539
1540         retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
1541                                            DIRENT_FLAG_INCLUDE_EMPTY, 0,
1542                                            check_and_change_inodes, &is);
1543         if (retval)
1544                 goto errout;
1545         if (is.err) {
1546                 retval = is.err;
1547                 goto errout;
1548         }
1549
1550         if (rfs->progress && (is.num < is.max_dirs))
1551                 (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
1552                                 is.max_dirs, is.max_dirs);
1553
1554 errout:
1555         ext2fs_free_extent_table(rfs->imap);
1556         rfs->imap = 0;
1557         return retval;
1558 }
1559
1560
1561 /* --------------------------------------------------------------------
1562  *
1563  * Resize processing, phase 5.
1564  *
1565  * In this phase we actually move the inode table around, and then
1566  * update the summary statistics.  This is scary, since aborting here
1567  * will potentially scramble the filesystem.  (We are moving the
1568  * inode tables around in place, and so the potential for lost data,
1569  * or at the very least scrambling the mapping between filenames and
1570  * inode numbers is very high in case of a power failure here.)
1571  * --------------------------------------------------------------------
1572  */
1573
1574
1575 /*
1576  * A very scary routine --- this one moves the inode table around!!!
1577  *
1578  * After this you have to use the rfs->new_fs file handle to read and
1579  * write inodes.
1580  */
1581 static errcode_t move_itables(ext2_resize_t rfs)
1582 {
1583         int             n, num, size, diff;
1584         dgrp_t          i, max_groups;
1585         ext2_filsys     fs = rfs->new_fs;
1586         char            *cp;
1587         blk_t           old_blk, new_blk, blk;
1588         errcode_t       retval;
1589         int             j, to_move, moved;
1590
1591         max_groups = fs->group_desc_count;
1592         if (max_groups > rfs->old_fs->group_desc_count)
1593                 max_groups = rfs->old_fs->group_desc_count;
1594
1595         size = fs->blocksize * fs->inode_blocks_per_group;
1596         if (!rfs->itable_buf) {
1597                 retval = ext2fs_get_mem(size, &rfs->itable_buf);
1598                 if (retval)
1599                         return retval;
1600         }
1601
1602         /*
1603          * Figure out how many inode tables we need to move
1604          */
1605         to_move = moved = 0;
1606         for (i=0; i < max_groups; i++)
1607                 if (rfs->old_fs->group_desc[i].bg_inode_table !=
1608                     fs->group_desc[i].bg_inode_table)
1609                         to_move++;
1610
1611         if (to_move == 0)
1612                 return 0;
1613
1614         if (rfs->progress) {
1615                 retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1616                                        0, to_move);
1617                 if (retval)
1618                         goto errout;
1619         }
1620
1621         rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
1622
1623         for (i=0; i < max_groups; i++) {
1624                 old_blk = rfs->old_fs->group_desc[i].bg_inode_table;
1625                 new_blk = fs->group_desc[i].bg_inode_table;
1626                 diff = new_blk - old_blk;
1627
1628 #ifdef RESIZE2FS_DEBUG
1629                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1630                         printf("Itable move group %d block %u->%u (diff %d)\n",
1631                                i, old_blk, new_blk, diff);
1632 #endif
1633
1634                 if (!diff)
1635                         continue;
1636
1637                 retval = io_channel_read_blk(fs->io, old_blk,
1638                                              fs->inode_blocks_per_group,
1639                                              rfs->itable_buf);
1640                 if (retval)
1641                         goto errout;
1642                 /*
1643                  * The end of the inode table segment often contains
1644                  * all zeros, and we're often only moving the inode
1645                  * table down a block or two.  If so, we can optimize
1646                  * things by not rewriting blocks that we know to be zero
1647                  * already.
1648                  */
1649                 for (cp = rfs->itable_buf+size-1, n=0; n < size; n++, cp--)
1650                         if (*cp)
1651                                 break;
1652                 n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
1653 #ifdef RESIZE2FS_DEBUG
1654                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1655                         printf("%d blocks of zeros...\n", n);
1656 #endif
1657                 num = fs->inode_blocks_per_group;
1658                 if (n > diff)
1659                         num -= n;
1660
1661                 retval = io_channel_write_blk(fs->io, new_blk,
1662                                               num, rfs->itable_buf);
1663                 if (retval) {
1664                         io_channel_write_blk(fs->io, old_blk,
1665                                              num, rfs->itable_buf);
1666                         goto errout;
1667                 }
1668                 if (n > diff) {
1669                         retval = io_channel_write_blk(fs->io,
1670                               old_blk + fs->inode_blocks_per_group,
1671                               diff, (rfs->itable_buf +
1672                                      (fs->inode_blocks_per_group - diff) *
1673                                      fs->blocksize));
1674                         if (retval)
1675                                 goto errout;
1676                 }
1677
1678                 for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
1679                      j < fs->inode_blocks_per_group ; j++, blk++)
1680                         ext2fs_block_alloc_stats(fs, blk, -1);
1681
1682                 rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
1683                 ext2fs_group_desc_csum_set(rfs->old_fs, i);
1684                 ext2fs_mark_super_dirty(rfs->old_fs);
1685                 ext2fs_flush(rfs->old_fs);
1686
1687                 if (rfs->progress) {
1688                         retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
1689                                                ++moved, to_move);
1690                         if (retval)
1691                                 goto errout;
1692                 }
1693         }
1694         mark_table_blocks(fs, fs->block_map);
1695         ext2fs_flush(fs);
1696 #ifdef RESIZE2FS_DEBUG
1697         if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
1698                 printf("Inode table move finished.\n");
1699 #endif
1700         return 0;
1701
1702 errout:
1703         return retval;
1704 }
1705
1706 /*
1707  * Fix the resize inode
1708  */
1709 static errcode_t fix_resize_inode(ext2_filsys fs)
1710 {
1711         struct ext2_inode       inode;
1712         errcode_t               retval;
1713         char *                  block_buf;
1714         blk_t                   blk;
1715
1716         if (!(fs->super->s_feature_compat &
1717               EXT2_FEATURE_COMPAT_RESIZE_INODE))
1718                 return 0;
1719
1720         retval = ext2fs_get_mem(fs->blocksize, &block_buf);
1721         if (retval) goto errout;
1722
1723         retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
1724         if (retval) goto errout;
1725
1726         if (fs->super->s_reserved_gdt_blocks == 0) {
1727                 fs->super->s_feature_compat &=
1728                         ~EXT2_FEATURE_COMPAT_RESIZE_INODE;
1729                 ext2fs_mark_super_dirty(fs);
1730
1731                 if ((blk = inode.i_block[EXT2_DIND_BLOCK]) != 0)
1732                         ext2fs_block_alloc_stats(fs, blk, -1);
1733
1734                 memset(&inode, 0, sizeof(inode));
1735
1736                 retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
1737                 goto errout;
1738         }
1739
1740         ext2fs_iblk_set(fs, &inode, 1);
1741
1742         retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
1743         if (retval) goto errout;
1744
1745         if (!inode.i_block[EXT2_DIND_BLOCK]) {
1746                 /*
1747                  * Avoid zeroing out block #0; that's rude.  This
1748                  * should never happen anyway since the filesystem
1749                  * should be fsck'ed and we assume it is consistent.
1750                  */
1751                 fprintf(stderr,
1752                         _("Should never happen: resize inode corrupt!\n"));
1753                 exit(1);
1754         }
1755
1756         memset(block_buf, 0, fs->blocksize);
1757
1758         retval = io_channel_write_blk(fs->io, inode.i_block[EXT2_DIND_BLOCK],
1759                                       1, block_buf);
1760         if (retval) goto errout;
1761
1762         retval = ext2fs_create_resize_inode(fs);
1763         if (retval)
1764                 goto errout;
1765
1766 errout:
1767         if (block_buf)
1768                 ext2fs_free_mem(&block_buf);
1769         return retval;
1770 }
1771
1772 /*
1773  * Finally, recalculate the summary information
1774  */
1775 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1776 {
1777         blk_t           blk;
1778         ext2_ino_t      ino;
1779         unsigned int    group = 0;
1780         unsigned int    count = 0;
1781         int             total_free = 0;
1782         int             group_free = 0;
1783         int             uninit = 0;
1784         blk_t           super_blk, old_desc_blk, new_desc_blk;
1785         int             old_desc_blocks;
1786
1787         /*
1788          * First calculate the block statistics
1789          */
1790         uninit = fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT;
1791         ext2fs_super_and_bgd_loc(fs, group, &super_blk, &old_desc_blk,
1792                                  &new_desc_blk, 0);
1793         if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
1794                 old_desc_blocks = fs->super->s_first_meta_bg;
1795         else
1796                 old_desc_blocks = fs->desc_blocks +
1797                         fs->super->s_reserved_gdt_blocks;
1798         for (blk = fs->super->s_first_data_block;
1799              blk < fs->super->s_blocks_count; blk++) {
1800                 if ((uninit &&
1801                      !((blk == super_blk) ||
1802                        ((old_desc_blk && old_desc_blocks &&
1803                          (blk >= old_desc_blk) &&
1804                          (blk < old_desc_blk + old_desc_blocks))) ||
1805                        ((new_desc_blk && (blk == new_desc_blk))) ||
1806                        (blk == fs->group_desc[group].bg_block_bitmap) ||
1807                        (blk == fs->group_desc[group].bg_inode_bitmap) ||
1808                        ((blk >= fs->group_desc[group].bg_inode_table &&
1809                          (blk < fs->group_desc[group].bg_inode_table
1810                           + fs->inode_blocks_per_group))))) ||
1811                     (!ext2fs_fast_test_block_bitmap(fs->block_map, blk))) {
1812                         group_free++;
1813                         total_free++;
1814                 }
1815                 count++;
1816                 if ((count == fs->super->s_blocks_per_group) ||
1817                     (blk == fs->super->s_blocks_count-1)) {
1818                         fs->group_desc[group].bg_free_blocks_count =
1819                                 group_free;
1820                         ext2fs_group_desc_csum_set(fs, group);
1821                         group++;
1822                         if (group >= fs->group_desc_count)
1823                                 break;
1824                         count = 0;
1825                         group_free = 0;
1826                         uninit = (fs->group_desc[group].bg_flags &
1827                                   EXT2_BG_BLOCK_UNINIT);
1828                         ext2fs_super_and_bgd_loc(fs, group, &super_blk,
1829                                                  &old_desc_blk,
1830                                                  &new_desc_blk, 0);
1831                         if (fs->super->s_feature_incompat &
1832                             EXT2_FEATURE_INCOMPAT_META_BG)
1833                                 old_desc_blocks = fs->super->s_first_meta_bg;
1834                         else
1835                                 old_desc_blocks = fs->desc_blocks +
1836                                         fs->super->s_reserved_gdt_blocks;
1837                 }
1838         }
1839         fs->super->s_free_blocks_count = total_free;
1840
1841         /*
1842          * Next, calculate the inode statistics
1843          */
1844         group_free = 0;
1845         total_free = 0;
1846         count = 0;
1847         group = 0;
1848
1849         /* Protect loop from wrap-around if s_inodes_count maxed */
1850         uninit = fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT;
1851         for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
1852                 if (uninit ||
1853                     !ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
1854                         group_free++;
1855                         total_free++;
1856                 }
1857                 count++;
1858                 if ((count == fs->super->s_inodes_per_group) ||
1859                     (ino == fs->super->s_inodes_count)) {
1860                         fs->group_desc[group].bg_free_inodes_count =
1861                                 group_free;
1862                         ext2fs_group_desc_csum_set(fs, group);
1863                         group++;
1864                         if (group >= fs->group_desc_count)
1865                                 break;
1866                         count = 0;
1867                         group_free = 0;
1868                         uninit = (fs->group_desc[group].bg_flags &
1869                                   EXT2_BG_INODE_UNINIT);
1870                 }
1871         }
1872         fs->super->s_free_inodes_count = total_free;
1873         ext2fs_mark_super_dirty(fs);
1874         return 0;
1875 }
1876
1877 /*
1878  *  Journal may have been relocated; update the backup journal blocks
1879  *  in the superblock.
1880  */
1881 static errcode_t fix_sb_journal_backup(ext2_filsys fs)
1882 {
1883         errcode_t         retval;
1884         struct ext2_inode inode;
1885
1886         if (!(fs->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
1887                 return 0;
1888
1889         /* External journal? Nothing to do. */
1890         if (fs->super->s_journal_dev && !fs->super->s_journal_inum)
1891                 return 0;
1892
1893         retval = ext2fs_read_inode(fs, fs->super->s_journal_inum, &inode);
1894         if (retval)
1895                 return retval;
1896         memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
1897         fs->super->s_jnl_blocks[16] = inode.i_size;
1898         fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
1899         ext2fs_mark_super_dirty(fs);
1900         return 0;
1901 }
1902
1903 /*
1904  * calcluate the minimum number of blocks the given fs can be resized to
1905  */
1906 blk_t calculate_minimum_resize_size(ext2_filsys fs)
1907 {
1908         blk_t inode_count, blks_needed, groups, data_blocks;
1909         blk_t grp, data_needed, last_start;
1910         int overhead = 0, num_of_superblocks = 0;
1911         int extra_groups = 0;
1912         int flexbg_size = 1 << fs->super->s_log_groups_per_flex;
1913
1914         /*
1915          * first figure out how many group descriptors we need to
1916          * handle the number of inodes we have
1917          */
1918         inode_count = fs->super->s_inodes_count -
1919                 fs->super->s_free_inodes_count;
1920         blks_needed = ext2fs_div_ceil(inode_count,
1921                                       fs->super->s_inodes_per_group) *
1922                 EXT2_BLOCKS_PER_GROUP(fs->super);
1923         groups = ext2fs_div_ceil(blks_needed,
1924                                  EXT2_BLOCKS_PER_GROUP(fs->super));
1925
1926         /*
1927          * we need to figure out how many backup superblocks we have so we can
1928          * account for that in the metadata
1929          */
1930         for (grp = 0; grp < fs->group_desc_count; grp++) {
1931                 if (ext2fs_bg_has_super(fs, grp))
1932                         num_of_superblocks++;
1933         }
1934
1935         /* calculate how many blocks are needed for data */
1936         data_needed = fs->super->s_blocks_count -
1937                 fs->super->s_free_blocks_count;
1938         data_needed -= SUPER_OVERHEAD(fs) * num_of_superblocks;
1939         data_needed -= META_OVERHEAD(fs) * fs->group_desc_count;
1940
1941         if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) {
1942                 /*
1943                  * For ext4 we need to allow for up to a flex_bg worth
1944                  * of inode tables of slack space so the resize
1945                  * operation can be guaranteed to finish.
1946                  */
1947                 extra_groups = flexbg_size - (groups & (flexbg_size - 1));
1948                 data_needed += META_OVERHEAD(fs) * extra_groups;
1949                 extra_groups = groups % flexbg_size;
1950         }
1951
1952         /*
1953          * figure out how many data blocks we have given the number of groups
1954          * we need for our inodes
1955          */
1956         data_blocks = groups * EXT2_BLOCKS_PER_GROUP(fs->super);
1957         last_start = 0;
1958         for (grp = 0; grp < groups; grp++) {
1959                 overhead = META_OVERHEAD(fs);
1960
1961                 if (ext2fs_bg_has_super(fs, grp))
1962                         overhead += SUPER_OVERHEAD(fs);
1963
1964                 /*
1965                  * we want to keep track of how much data we can store in
1966                  * the groups leading up to the last group so we can determine
1967                  * how big the last group needs to be
1968                  */
1969                 if (grp != (groups - 1))
1970                         last_start += EXT2_BLOCKS_PER_GROUP(fs->super) -
1971                                 overhead;
1972
1973                 data_blocks -= overhead;
1974         }
1975
1976         /*
1977          * if we need more group descriptors in order to accomodate our data
1978          * then we need to add them here
1979          */
1980         while (data_needed > data_blocks) {
1981                 blk_t remainder = data_needed - data_blocks;
1982                 blk_t extra_grps;
1983
1984                 /* figure out how many more groups we need for the data */
1985                 extra_grps = ext2fs_div_ceil(remainder,
1986                                              EXT2_BLOCKS_PER_GROUP(fs->super));
1987
1988                 data_blocks += extra_grps * EXT2_BLOCKS_PER_GROUP(fs->super);
1989
1990                 /* ok we have to account for the last group */
1991                 overhead = META_OVERHEAD(fs);
1992                 if (ext2fs_bg_has_super(fs, groups-1))
1993                         overhead += SUPER_OVERHEAD(fs);
1994                 last_start += EXT2_BLOCKS_PER_GROUP(fs->super) - overhead;
1995
1996                 for (grp = groups; grp < groups+extra_grps; grp++) {
1997                         overhead = META_OVERHEAD(fs);
1998                         if (ext2fs_bg_has_super(fs, grp))
1999                                 overhead += SUPER_OVERHEAD(fs);
2000
2001                         /*
2002                          * again, we need to see how much data we cram into
2003                          * all of the groups leading up to the last group
2004                          */
2005                         if (grp != (groups + extra_grps - 1))
2006                                 last_start += EXT2_BLOCKS_PER_GROUP(fs->super)
2007                                         - overhead;
2008
2009                         data_blocks -= overhead;
2010                 }
2011
2012                 groups += extra_grps;
2013                 extra_groups += extra_grps;
2014                 if (fs->super->s_feature_incompat
2015                         & EXT4_FEATURE_INCOMPAT_FLEX_BG
2016                     && extra_groups > flexbg_size) {
2017                         /*
2018                          * For ext4 we need to allow for up to a flex_bg worth
2019                          * of inode tables of slack space so the resize
2020                          * operation can be guaranteed to finish.
2021                          */
2022                         extra_groups = flexbg_size -
2023                                                 (groups & (flexbg_size - 1));
2024                         data_needed += META_OVERHEAD(fs) * extra_groups;
2025                         extra_groups = groups % flexbg_size;
2026                 }
2027         }
2028
2029         /* now for the fun voodoo */
2030         overhead = META_OVERHEAD(fs);
2031
2032         /*
2033          * if this is the case then the last group is going to have data in it
2034          * so we need to adjust the size of the last group accordingly
2035          */
2036         if (last_start < data_needed) {
2037                 blk_t remainder = data_needed - last_start;
2038
2039                 /*
2040                  * 50 is a magic number that mkfs/resize uses to see if its
2041                  * even worth making/resizing the fs.  basically you need to
2042                  * have at least 50 blocks in addition to the blocks needed
2043                  * for the metadata in the last group
2044                  */
2045                 if (remainder > 50)
2046                         overhead += remainder;
2047                 else
2048                         overhead += 50;
2049         } else
2050                 overhead += 50;
2051
2052         if (ext2fs_bg_has_super(fs, groups-1))
2053                 overhead += SUPER_OVERHEAD(fs);
2054
2055         /*
2056          * since our last group doesn't have to be BLOCKS_PER_GROUP large, we
2057          * only do groups-1, and then add the number of blocks needed to
2058          * handle the group descriptor metadata+data that we need
2059          */
2060         blks_needed = (groups-1) * EXT2_BLOCKS_PER_GROUP(fs->super);
2061         blks_needed += overhead;
2062
2063         /*
2064          * If at this point we've already added up more "needed" than
2065          * the current size, just return current size as minimum.
2066          */
2067         if (blks_needed >= fs->super->s_blocks_count)
2068                 return fs->super->s_blocks_count;
2069         /*
2070          * We need to reserve a few extra blocks if extents are
2071          * enabled, in case we need to grow the extent tree.  The more
2072          * we shrink the file system, the more space we need.
2073          */
2074         if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
2075                 blks_needed += (fs->super->s_blocks_count - blks_needed)/500;
2076
2077         return blks_needed;
2078 }