Whamcloud - gitweb
Many files:
[tools/e2fsprogs.git] / resize / resize2fs.c
1 /*
2  * resize2fs.c --- ext2 main routine
3  *
4  * Copyright (C) 1997 Theodore Ts'o
5  * 
6  * %Begin-Header%
7  * All rights reserved.
8  * %End-Header%
9  */
10
11 /*
12  * Resizing a filesystem consists of the following phases:
13  *
14  *      1.  Adjust superblock and (*) write out new parts of the inode
15  *              table
16  *      2.  Determine blocks which need to be relocated.
17  *      3.  (*) Relocate blocks which must be moved, adjusting entries
18  *              in the filesystem in the process.
19  *      4.  (*) Move inodes which must be moved (only when shrinking a
20  *              filesystem)
21  *      5.  (*) Move the inode tables, if necessary.
22  */
23 #include "resize2fs.h"
24
25 /*
26  * This routine adjusts the superblock and other data structures...
27  */
28 static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
29 {
30         ext2_filsys fs;
31         int             overhead = 0;
32         int             rem, adj = 0;
33         errcode_t       retval;
34         ino_t           real_end;
35         blk_t           blk, group_block;
36         unsigned long   i, j;
37         struct ext2_group_desc *new;
38         int             old_numblocks, numblocks, adjblocks;
39         ext2_sim_progmeter progress = 0;
40         
41         fs = rfs->new_fs;
42         fs->super->s_blocks_count = new_size;
43         ext2fs_mark_super_dirty(fs);
44         ext2fs_mark_bb_dirty(fs);
45         ext2fs_mark_ib_dirty(fs);
46
47 retry:
48         fs->group_desc_count = (fs->super->s_blocks_count -
49                                 fs->super->s_first_data_block +
50                                 EXT2_BLOCKS_PER_GROUP(fs->super) - 1)
51                 / EXT2_BLOCKS_PER_GROUP(fs->super);
52         if (fs->group_desc_count == 0)
53                 return EXT2_ET_TOOSMALL;
54         fs->desc_blocks = (fs->group_desc_count +
55                            EXT2_DESC_PER_BLOCK(fs->super) - 1)
56                 / EXT2_DESC_PER_BLOCK(fs->super);
57
58         /*
59          * Overhead is the number of bookkeeping blocks per group.  It
60          * includes the superblock backup, the group descriptor
61          * backups, the inode bitmap, the block bitmap, and the inode
62          * table.
63          *
64          * XXX Not all block groups need the descriptor blocks, but
65          * being clever is tricky...
66          */
67         overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
68         
69         /*
70          * See if the last group is big enough to support the
71          * necessary data structures.  If not, we need to get rid of
72          * it.
73          */
74         rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
75                 fs->super->s_blocks_per_group;
76         if ((fs->group_desc_count == 1) && rem && (rem < overhead))
77                 return EXT2_ET_TOOSMALL;
78         if (rem && (rem < overhead+50)) {
79                 fs->super->s_blocks_count -= rem;
80                 goto retry;
81         }
82         /*
83          * Adjust the number of inodes
84          */
85         fs->super->s_inodes_count = fs->super->s_inodes_per_group *
86                 fs->group_desc_count;
87
88         /*
89          * Adjust the number of free blocks
90          */
91         blk = rfs->old_fs->super->s_blocks_count;
92         if (blk > fs->super->s_blocks_count)
93                 fs->super->s_free_blocks_count -=
94                         (blk - fs->super->s_blocks_count);
95         else
96                 fs->super->s_free_blocks_count +=
97                         (fs->super->s_blocks_count - blk);
98
99         /*
100          * Adjust the number of reserved blocks
101          */
102         blk = rfs->old_fs->super->s_r_blocks_count * 100 /
103                 rfs->old_fs->super->s_blocks_count;
104         fs->super->s_r_blocks_count = ((fs->super->s_blocks_count * blk)
105                                        / 100);
106
107         /*
108          * Adjust the bitmaps for size
109          */
110         retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
111                                             fs->super->s_inodes_count,
112                                             fs->inode_map);
113         if (retval) goto errout;
114         
115         real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
116                      * fs->group_desc_count)) - 1 +
117                              fs->super->s_first_data_block;
118         retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
119                                             real_end, fs->block_map);
120
121         if (retval) goto errout;
122
123         /*
124          * Reallocate the group descriptors as necessary.
125          */
126         if (rfs->old_fs->desc_blocks != fs->desc_blocks) {
127                 new = realloc(fs->group_desc,
128                               fs->desc_blocks * fs->blocksize);
129                 if (!new)
130                         return ENOMEM;
131                 fs->group_desc = new;
132         }
133
134         /*
135          * Fix the count of the last (old) block group
136          */
137         if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
138                 retval = 0;
139                 goto errout;
140         }
141         old_numblocks = (rfs->old_fs->super->s_blocks_count -
142                          rfs->old_fs->super->s_first_data_block) %
143                                  rfs->old_fs->super->s_blocks_per_group;
144         if (!old_numblocks)
145                 old_numblocks = rfs->old_fs->super->s_blocks_per_group;
146         if (rfs->old_fs->group_desc_count == fs->group_desc_count) {
147                 numblocks = (rfs->new_fs->super->s_blocks_count -
148                              rfs->new_fs->super->s_first_data_block) %
149                                      rfs->new_fs->super->s_blocks_per_group;
150                 if (!numblocks)
151                         numblocks = rfs->new_fs->super->s_blocks_per_group;
152         } else
153                 numblocks = rfs->new_fs->super->s_blocks_per_group;
154         i = rfs->old_fs->group_desc_count - 1;
155         fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
156                 
157         /*
158          * Initialize the new block group descriptors
159          */
160         if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
161                 retval = 0;
162                 goto errout;
163         }
164         rfs->itable_buf = malloc(fs->blocksize * fs->inode_blocks_per_group);
165         if (!rfs->itable_buf) {
166                 retval = ENOMEM;
167                 goto errout;
168         }
169         memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
170         group_block = fs->super->s_first_data_block +
171                 rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
172
173         if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
174                 adj = rfs->old_fs->group_desc_count;
175                 retval = ext2fs_progress_init(&progress,
176                       "Initializing inode table", 30, 40,
177                       fs->group_desc_count - adj, 0);
178                 if (retval) goto errout;
179         }
180         for (i = rfs->old_fs->group_desc_count;
181              i < fs->group_desc_count; i++) {
182                 memset(&fs->group_desc[i], 0,
183                        sizeof(struct ext2_group_desc));
184                 adjblocks = 0;
185
186                 if (i == fs->group_desc_count-1) {
187                         numblocks = (fs->super->s_blocks_count -
188                                      fs->super->s_first_data_block) %
189                                              fs->super->s_blocks_per_group;
190                         if (!numblocks)
191                                 numblocks = fs->super->s_blocks_per_group;
192                 } else
193                         numblocks = fs->super->s_blocks_per_group;
194
195                 if (ext2fs_bg_has_super(fs, i)) {
196                         for (j=0; j < fs->desc_blocks+1; j++)
197                                 ext2fs_mark_block_bitmap(fs->block_map,
198                                                          group_block + j);
199                         adjblocks = 1 + fs->desc_blocks;
200                 }
201                 adjblocks += 2 + fs->inode_blocks_per_group;
202                 
203                 numblocks -= adjblocks;
204                 fs->super->s_free_blocks_count -= adjblocks;
205                 fs->super->s_free_inodes_count +=
206                         fs->super->s_inodes_per_group;
207                 fs->group_desc[i].bg_free_blocks_count = numblocks;
208                 fs->group_desc[i].bg_free_inodes_count =
209                         fs->super->s_inodes_per_group;
210                 fs->group_desc[i].bg_used_dirs_count = 0;
211
212                 retval = ext2fs_allocate_group_table(fs, i, 0);
213                 if (retval) goto errout;
214
215                 /*
216                  * Write out the new inode table
217                  */
218                 retval = io_channel_write_blk(fs->io,
219                                               fs->group_desc[i].bg_inode_table,
220                                               fs->inode_blocks_per_group,
221                                               rfs->itable_buf);
222                 if (retval) goto errout;
223
224                 /* io_channel_flush(fs->io); */
225                 if (progress)
226                         ext2fs_progress_update(progress, i - adj + 1);
227                 
228                 group_block += fs->super->s_blocks_per_group;
229         }
230         io_channel_flush(fs->io);
231         retval = 0;
232
233 errout:
234         if (progress)
235                 ext2fs_progress_close(progress);
236         return retval;
237 }
238
239 /*
240  * This helper function creates a block bitmap with all of the
241  * filesystem meta-data blocks.
242  */
243 static errcode_t mark_table_blocks(ext2_filsys fs,
244                                    ext2fs_block_bitmap *ret_bmap)
245 {
246         blk_t                   block, b;
247         int                     i,j;
248         ext2fs_block_bitmap     bmap;
249         errcode_t               retval;
250
251         retval = ext2fs_allocate_block_bitmap(fs, "meta-data blocks", &bmap);
252         if (retval)
253                 return retval;
254         
255         block = fs->super->s_first_data_block;
256         for (i = 0; i < fs->group_desc_count; i++) {
257                 if (ext2fs_bg_has_super(fs, i)) {
258                         /*
259                          * Mark this group's copy of the superblock
260                          */
261                         ext2fs_mark_block_bitmap(bmap, block);
262                 
263                         /*
264                          * Mark this group's copy of the descriptors
265                          */
266                         for (j = 0; j < fs->desc_blocks; j++)
267                                 ext2fs_mark_block_bitmap(bmap, block + j + 1);
268                 }
269                 
270                 /*
271                  * Mark the blocks used for the inode table
272                  */
273                 for (j = 0, b = fs->group_desc[i].bg_inode_table;
274                      j < fs->inode_blocks_per_group;
275                      j++, b++)
276                         ext2fs_mark_block_bitmap(bmap, b);
277                             
278                 /*
279                  * Mark block used for the block bitmap 
280                  */
281                 ext2fs_mark_block_bitmap(bmap,
282                                          fs->group_desc[i].bg_block_bitmap);
283                 /*
284                  * Mark block used for the inode bitmap 
285                  */
286                 ext2fs_mark_block_bitmap(bmap,
287                                          fs->group_desc[i].bg_inode_bitmap);
288                 block += fs->super->s_blocks_per_group;
289         }
290         *ret_bmap = bmap;
291         return 0;
292 }
293
294
295
296 /*
297  * Some helper CPP macros
298  */
299 #define FS_BLOCK_BM(fs, i) ((fs)->group_desc[(i)].bg_block_bitmap)
300 #define FS_INODE_BM(fs, i) ((fs)->group_desc[(i)].bg_inode_bitmap)
301 #define FS_INODE_TB(fs, i) ((fs)->group_desc[(i)].bg_inode_table)
302
303 #define IS_BLOCK_BM(fs, i, blk) ((blk) == FS_BLOCK_BM((fs),(i)))
304 #define IS_INODE_BM(fs, i, blk) ((blk) == FS_INODE_BM((fs),(i)))
305
306 #define IS_INODE_TB(fs, i, blk) (((blk) >= FS_INODE_TB((fs), (i))) && \
307                                  ((blk) < (FS_INODE_TB((fs), (i)) + \
308                                            (fs)->inode_blocks_per_group)))
309
310 /*
311  * This routine marks and unmarks reserved blocks in the new block
312  * bitmap.  It also determines which blocks need to be moved and
313  * places this information into the move_blocks bitmap.
314  */
315 static errcode_t blocks_to_move(ext2_resize_t rfs)
316 {
317         int     i, j, max;
318         blk_t   blk, group_blk;
319         unsigned long old_blocks, new_blocks;
320         errcode_t       retval;
321         ext2_filsys     fs, old_fs;
322         ext2fs_block_bitmap     meta_bmap;
323
324         fs = rfs->new_fs;
325         old_fs = rfs->old_fs;
326         if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
327                 fs = rfs->old_fs;
328         
329         retval = ext2fs_allocate_block_bitmap(fs, "reserved blocks",
330                                               &rfs->reserve_blocks);
331         if (retval)
332                 return retval;
333
334         retval = ext2fs_allocate_block_bitmap(fs, "blocks to be moved",
335                                               &rfs->move_blocks);
336         if (retval)
337                 return retval;
338
339         retval = mark_table_blocks(fs, &meta_bmap);
340         if (retval)
341                 return retval;
342
343         fs = rfs->new_fs;
344         
345         /*
346          * If we're shrinking the filesystem, we need to move all of
347          * the blocks that don't fit any more
348          */
349         for (blk = fs->super->s_blocks_count;
350              blk < old_fs->super->s_blocks_count; blk++) {
351                 if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
352                     !ext2fs_test_block_bitmap(meta_bmap, blk)) {
353                         ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
354                         rfs->needed_blocks++;
355                 }
356                 ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
357         }
358         
359         old_blocks = old_fs->desc_blocks;
360         new_blocks = fs->desc_blocks;
361
362         if (old_blocks == new_blocks) {
363                 retval = 0;
364                 goto errout;
365         }
366
367         max = fs->group_desc_count;
368         if (max > old_fs->group_desc_count)
369                 max = old_fs->group_desc_count;
370         group_blk = old_fs->super->s_first_data_block;
371         /*
372          * If we're reducing the number of descriptor blocks, this
373          * makes life easy.  :-)   We just have to mark some extra
374          * blocks as free.
375          */
376         if (old_blocks > new_blocks) {
377                 for (i = 0; i < max; i++) {
378                         if (!ext2fs_bg_has_super(fs, i)) {
379                                 group_blk += fs->super->s_blocks_per_group;
380                                 continue;
381                         }
382                         for (blk = group_blk+1+new_blocks;
383                              blk < group_blk+1+old_blocks; blk++) {
384                                 ext2fs_unmark_block_bitmap(fs->block_map,
385                                                            blk);
386                                 rfs->needed_blocks--;
387                         }
388                         group_blk += fs->super->s_blocks_per_group;
389                 }
390                 retval = 0;
391                 goto errout;
392         }
393         /*
394          * If we're increasing the number of descriptor blocks, life
395          * gets interesting....  
396          */
397         for (i = 0; i < max; i++) {
398                 if (!ext2fs_bg_has_super(fs, i))
399                         goto next_group;
400
401                 for (blk = group_blk;
402                      blk < group_blk + 1 + new_blocks; blk++) {
403                         ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
404                         ext2fs_mark_block_bitmap(fs->block_map, blk);
405
406                         /*
407                          * Check to see if we overlap with the inode
408                          * or block bitmap, or the inode tables.  If
409                          * not, and the block is in use, then mark it
410                          * as a block to be moved.
411                          */
412                         if (IS_BLOCK_BM(fs, i, blk)) {
413                                 FS_BLOCK_BM(fs, i) = 0;
414                                 rfs->needed_blocks++;
415                         } else if (IS_INODE_BM(fs, i, blk)) {
416                                 FS_INODE_BM(fs, i) = 0;
417                                 rfs->needed_blocks++;
418                         } else if (IS_INODE_TB(fs, i, blk)) {
419                                 FS_INODE_TB(fs, i) = 0;
420                                 rfs->needed_blocks++;
421                         } else if (ext2fs_test_block_bitmap(old_fs->block_map,
422                                                             blk) &&
423                                    !ext2fs_test_block_bitmap(meta_bmap, blk)) {
424                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
425                                                          blk);
426                                 rfs->needed_blocks++;
427                         }
428                 }
429                 if (fs->group_desc[i].bg_inode_table &&
430                     fs->group_desc[i].bg_inode_bitmap &&
431                     fs->group_desc[i].bg_block_bitmap)
432                         goto next_group;
433
434                 /*
435                  * Reserve the existing meta blocks that we know
436                  * aren't to be moved.
437                  */
438                 if (fs->group_desc[i].bg_block_bitmap)
439                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
440                                  fs->group_desc[i].bg_block_bitmap);
441                 if (fs->group_desc[i].bg_inode_bitmap)
442                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
443                                  fs->group_desc[i].bg_inode_bitmap);
444                 if (fs->group_desc[i].bg_inode_table)
445                         for (blk = fs->group_desc[i].bg_inode_table, j=0;
446                              j < fs->inode_blocks_per_group ; j++, blk++)
447                                 ext2fs_mark_block_bitmap(rfs->reserve_blocks,
448                                                          blk);
449
450                 /*
451                  * Allocate the missing data structures
452                  */
453                 retval = ext2fs_allocate_group_table(fs, i,
454                                                      rfs->reserve_blocks);
455                 if (retval)
456                         goto errout;
457
458                 /*
459                  * For those structures that have changed, we need to
460                  * do bookkeepping.
461                  */
462                 if (FS_BLOCK_BM(old_fs, i) !=
463                     (blk = FS_BLOCK_BM(fs, i))) {
464                         ext2fs_mark_block_bitmap(fs->block_map, blk);
465                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
466                             !ext2fs_test_block_bitmap(meta_bmap, blk))
467                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
468                                                          blk);
469                 }
470                 if (FS_INODE_BM(old_fs, i) !=
471                     (blk = FS_INODE_BM(fs, i))) {
472                         ext2fs_mark_block_bitmap(fs->block_map, blk);
473                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
474                             !ext2fs_test_block_bitmap(meta_bmap, blk))
475                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
476                                                          blk);
477                 }
478
479                 /*
480                  * The inode table, if we need to relocate it, is
481                  * handled specially.  We have to reserve the blocks
482                  * for both the old and the new inode table, since we
483                  * can't have the inode table be destroyed during the
484                  * block relocation phase.
485                  */
486                 if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
487                         goto next_group; /* inode table not moved */
488
489                 rfs->needed_blocks += fs->inode_blocks_per_group;
490
491                 /*
492                  * Mark the new inode table as in use in the new block
493                  * allocation bitmap, and move any blocks that might 
494                  * be necessary.
495                  */
496                 for (blk = fs->group_desc[i].bg_inode_table, j=0;
497                      j < fs->inode_blocks_per_group ; j++, blk++) {
498                         ext2fs_mark_block_bitmap(fs->block_map, blk);
499                         if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
500                             !ext2fs_test_block_bitmap(meta_bmap, blk))
501                                 ext2fs_mark_block_bitmap(rfs->move_blocks,
502                                                          blk);
503                 }
504                 
505                 /*
506                  * Make sure the old inode table is reserved in the
507                  * block reservation bitmap.
508                  */
509                 for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
510                      j < fs->inode_blocks_per_group ; j++, blk++)
511                         ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
512                 
513         next_group:
514                 group_blk += rfs->new_fs->super->s_blocks_per_group;
515         }
516         retval = 0;
517
518 errout:
519         if (meta_bmap)
520                 ext2fs_free_block_bitmap(meta_bmap);
521         
522         return retval;
523 }
524
525
526 /*
527  * A very scary routine --- this one moves the inode table around!!!
528  *
529  * After this you have to use the rfs->new_fs file handle to read and
530  * write inodes.
531  */
532 static errcode_t move_itables(ext2_resize_t rfs)
533 {
534         int             i, n, num, max, size, diff;
535         ext2_filsys     fs = rfs->new_fs;
536         char            *cp;
537         blk_t           old, new;
538         errcode_t       retval, err;
539         ext2_sim_progmeter progress = 0;
540         int             to_move, moved;
541
542         max = fs->group_desc_count;
543         if (max > rfs->old_fs->group_desc_count)
544                 max = rfs->old_fs->group_desc_count;
545
546         size = fs->blocksize * fs->inode_blocks_per_group;
547         if (!rfs->itable_buf) {
548                 rfs->itable_buf = malloc(size);
549                 if (!rfs->itable_buf)
550                         return ENOMEM;
551         }
552
553         /*
554          * Figure out how many inode tables we need to move
555          */
556         to_move = moved = 0;
557         for (i=0; i < max; i++)
558                 if (rfs->old_fs->group_desc[i].bg_inode_table !=
559                     fs->group_desc[i].bg_inode_table)
560                         to_move++;
561
562         if (to_move == 0)
563                 return 0;
564
565         if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
566                 retval = ext2fs_progress_init(&progress,
567                       "Moving inode table", 30, 40, to_move, 0);
568                 if (retval)
569                         return retval;
570         }
571         
572         for (i=0; i < max; i++) {
573                 old = rfs->old_fs->group_desc[i].bg_inode_table;
574                 new = fs->group_desc[i].bg_inode_table;
575                 diff = new - old;
576                 
577 #ifdef RESIZE2FS_DEBUG
578                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
579                         printf("Itable move group %d block "
580                                "%u->%u (diff %d)\n", 
581                                i, old, new, diff);
582 #endif
583                 
584                 if (!diff)
585                         continue;
586
587                 retval = io_channel_read_blk(fs->io, old,
588                                              fs->inode_blocks_per_group,
589                                              rfs->itable_buf);
590                 if (retval) 
591                         goto backout;
592                 /*
593                  * The end of the inode table segment often contains
594                  * all zeros.  Find out if we have several blocks of
595                  * zeros so we can optimize the write.
596                  */
597                 for (cp = rfs->itable_buf+size, n=0; n < size; n++, cp--)
598                         if (*cp)
599                                 break;
600                 n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
601 #ifdef RESIZE2FS_DEBUG
602                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
603                         printf("%d blocks of zeros...\n", n);
604 #endif
605                 num = fs->inode_blocks_per_group;
606                 if (n > diff)
607                         num -= n;
608
609                 retval = io_channel_write_blk(fs->io, new,
610                                               num, rfs->itable_buf);
611                 if (retval) {
612                         io_channel_write_blk(fs->io, old,
613                                              num, rfs->itable_buf);
614                         goto backout;
615                 }
616                 if (n > diff) {
617                         retval = io_channel_write_blk(fs->io,
618                               old + fs->inode_blocks_per_group,
619                               diff, rfs->itable_buf - fs->blocksize * diff);
620                         if (retval)
621                                 goto backout;
622                 }
623                 io_channel_flush(fs->io);
624                 if (progress)
625                         ext2fs_progress_update(progress, ++moved);
626         }
627         ext2fs_flush(rfs->new_fs);
628         io_channel_flush(fs->io);
629 #ifdef RESIZE2FS_DEBUG
630         if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
631                 printf("Inode table move finished.\n");
632 #endif
633         if (progress)
634                 ext2fs_progress_close(progress);
635         return 0;
636         
637 backout:
638         if (progress)
639                 ext2fs_progress_close(progress);
640 #ifdef RESIZE2FS_DEBUG
641         if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
642                 printf("Error: %s; now backing out!\n", error_message(retval));
643 #endif
644         while (--i >= 0) {
645 #ifdef RESIZE2FS_DEBUG
646                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
647                         printf("Group %d block %u->%u\n", i, new, old);
648 #endif
649                 old = rfs->old_fs->group_desc[i].bg_inode_table;
650                 new = fs->group_desc[i].bg_inode_table;
651                 
652                 err = io_channel_read_blk(fs->io, new,
653                                           fs->inode_blocks_per_group,
654                                           rfs->itable_buf);
655                 if (err)
656                         continue;
657                 err = io_channel_write_blk(fs->io, old,
658                                            fs->inode_blocks_per_group,
659                                            rfs->itable_buf);
660         }
661         return retval;
662 }
663
664 /*
665  * Finally, recalculate the summary information
666  */
667 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
668 {
669         blk_t   blk;
670         ino_t   ino;
671         int     group = 0;
672         int     count = 0;
673         int     total_free = 0;
674         int     group_free = 0;
675
676         /*
677          * First calculate the block statistics
678          */
679         for (blk = fs->super->s_first_data_block;
680              blk < fs->super->s_blocks_count; blk++) {
681                 if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
682                         group_free++;
683                         total_free++;
684                 }
685                 count++;
686                 if ((count == fs->super->s_blocks_per_group) ||
687                     (blk == fs->super->s_blocks_count-1)) {
688                         fs->group_desc[group++].bg_free_blocks_count =
689                                 group_free;
690                         count = 0;
691                         group_free = 0;
692                 }
693         }
694         fs->super->s_free_blocks_count = total_free;
695         
696         /*
697          * Next, calculate the inode statistics
698          */
699         group_free = 0;
700         total_free = 0;
701         count = 0;
702         group = 0;
703         for (ino = 1; ino <= fs->super->s_inodes_count; ino++) {
704                 if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
705                         group_free++;
706                         total_free++;
707                 }
708                 count++;
709                 if ((count == fs->super->s_inodes_per_group) ||
710                     (ino == fs->super->s_inodes_count)) {
711                         fs->group_desc[group++].bg_free_inodes_count =
712                                 group_free;
713                         count = 0;
714                         group_free = 0;
715                 }
716         }
717         fs->super->s_free_inodes_count = total_free;
718         ext2fs_mark_super_dirty(fs);
719         return 0;
720 }
721
722
723
724 /*
725  * This is the top-level routine which does the dirty deed....
726  */
727 errcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags)
728 {
729         ext2_resize_t   rfs;
730         errcode_t       retval;
731
732         retval = ext2fs_read_bitmaps(fs);
733         if (retval)
734                 return retval;
735         
736         /*
737          * Create the data structure
738          */
739         rfs = malloc(sizeof(struct ext2_resize_struct));
740         if (!rfs)
741                 return ENOMEM;
742         memset(rfs, 0, sizeof(struct ext2_resize_struct));
743
744         rfs->old_fs = fs;
745         rfs->flags = flags;
746         rfs->itable_buf  = 0;
747         retval = ext2fs_dup_handle(fs, &rfs->new_fs);
748         if (retval)
749                 goto errout;
750
751         retval = adjust_superblock(rfs, new_size);
752         if (retval)
753                 goto errout;
754
755         retval = blocks_to_move(rfs);
756         if (retval)
757                 goto errout;
758
759 #ifdef RESIZE2FS_DEBUG
760         if (rfs->flags & RESIZE_DEBUG_BMOVE)
761                 printf("Number of free blocks: %d/%d, Needed: %d\n",
762                        rfs->old_fs->super->s_free_blocks_count,
763                        rfs->new_fs->super->s_free_blocks_count,
764                        rfs->needed_blocks);
765 #endif
766         
767         retval = ext2fs_block_move(rfs);
768         if (retval)
769                 goto errout;
770
771         retval = ext2fs_inode_move(rfs);
772         if (retval)
773                 goto errout;
774
775         retval = move_itables(rfs);
776         if (retval)
777                 goto errout;
778
779         retval = ext2fs_calculate_summary_stats(rfs->new_fs);
780         if (retval)
781                 goto errout;
782         
783         retval = ext2fs_close(rfs->new_fs);
784         if (retval)
785                 goto errout;
786
787         rfs->flags = flags;
788         
789         ext2fs_free(rfs->old_fs);
790         if (rfs->itable_buf)
791                 free(rfs->itable_buf);
792         free(rfs);
793         
794         return 0;
795
796 errout:
797         if (rfs->new_fs)
798                 ext2fs_free(rfs->new_fs);
799         if (rfs->itable_buf)
800                 free(rfs->itable_buf);
801         free(rfs);
802         return retval;
803 }