Whamcloud - gitweb
ChangeLog, Makefile.in, version.h:
[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;
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         
40         fs = rfs->new_fs;
41         fs->super->s_blocks_count = new_size;
42         ext2fs_mark_super_dirty(fs);
43         ext2fs_mark_bb_dirty(fs);
44         ext2fs_mark_ib_dirty(fs);
45
46 retry:
47         fs->group_desc_count = (fs->super->s_blocks_count -
48                                 fs->super->s_first_data_block +
49                                 EXT2_BLOCKS_PER_GROUP(fs->super) - 1)
50                 / EXT2_BLOCKS_PER_GROUP(fs->super);
51         if (fs->group_desc_count == 0)
52                 return EXT2_ET_TOOSMALL;
53         fs->desc_blocks = (fs->group_desc_count +
54                            EXT2_DESC_PER_BLOCK(fs->super) - 1)
55                 / EXT2_DESC_PER_BLOCK(fs->super);
56
57         /*
58          * Overhead is the number of bookkeeping blocks per group.  It
59          * includes the superblock backup, the group descriptor
60          * backups, the inode bitmap, the block bitmap, and the inode
61          * table.
62          *
63          * XXX Not all block groups need the descriptor blocks, but
64          * being clever is tricky...
65          */
66         overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
67         
68         /*
69          * See if the last group is big enough to support the
70          * necessary data structures.  If not, we need to get rid of
71          * it.
72          */
73         rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
74                 fs->super->s_blocks_per_group;
75         if ((fs->group_desc_count == 1) && rem && (rem < overhead))
76                 return EXT2_ET_TOOSMALL;
77         if (rem && (rem < overhead+50)) {
78                 fs->super->s_blocks_count -= rem;
79                 goto retry;
80         }
81         /*
82          * Adjust the number of inodes
83          */
84         fs->super->s_inodes_count = fs->super->s_inodes_per_group *
85                 fs->group_desc_count;
86
87         /*
88          * Adjust the number of free blocks
89          */
90         blk = rfs->old_fs->super->s_blocks_count;
91         if (blk > fs->super->s_blocks_count)
92                 fs->super->s_free_blocks_count -=
93                         (blk - fs->super->s_blocks_count);
94         else
95                 fs->super->s_free_blocks_count +=
96                         (fs->super->s_blocks_count - blk);
97
98         /*
99          * Adjust the bitmaps for size
100          */
101         retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
102                                             fs->super->s_inodes_count,
103                                             fs->inode_map);
104         if (retval)
105                 return retval;
106         
107         real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
108                      * fs->group_desc_count)) - 1 +
109                              fs->super->s_first_data_block;
110         retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
111                                             real_end, fs->block_map);
112
113         if (retval)
114                 return retval;
115
116         /*
117          * Reallocate the group descriptors as necessary.
118          */
119         if (rfs->old_fs->desc_blocks != fs->desc_blocks) {
120                 new = realloc(fs->group_desc,
121                               fs->desc_blocks * fs->blocksize);
122                 if (!new)
123                         return ENOMEM;
124                 fs->group_desc = new;
125         }
126
127         /*
128          * Fix the count of the last (old) block group
129          */
130         if (rfs->old_fs->group_desc_count > fs->group_desc_count)
131                 return 0;
132         old_numblocks = (rfs->old_fs->super->s_blocks_count -
133                          rfs->old_fs->super->s_first_data_block) %
134                                  rfs->old_fs->super->s_blocks_per_group;
135         if (!old_numblocks)
136                 old_numblocks = rfs->old_fs->super->s_blocks_per_group;
137         if (rfs->old_fs->group_desc_count == fs->group_desc_count) {
138                 numblocks = (rfs->new_fs->super->s_blocks_count -
139                              rfs->new_fs->super->s_first_data_block) %
140                                      rfs->new_fs->super->s_blocks_per_group;
141                 if (!numblocks)
142                         numblocks = rfs->new_fs->super->s_blocks_per_group;
143         } else
144                 numblocks = rfs->new_fs->super->s_blocks_per_group;
145         i = rfs->old_fs->group_desc_count - 1;
146         fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
147                 
148         /*
149          * Initialize the new block group descriptors
150          */
151         if (rfs->old_fs->group_desc_count >= fs->group_desc_count)
152                 return 0;
153         rfs->itable_buf = malloc(fs->blocksize * fs->inode_blocks_per_group);
154         if (!rfs->itable_buf)
155                 return ENOMEM;
156         memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
157         group_block = fs->super->s_first_data_block +
158                 rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
159         for (i = rfs->old_fs->group_desc_count;
160              i < fs->group_desc_count; i++) {
161                 memset(&fs->group_desc[i], 0,
162                        sizeof(struct ext2_group_desc));
163                 adjblocks = 0;
164
165                 if (i == fs->group_desc_count-1) {
166                         numblocks = (fs->super->s_blocks_count -
167                                      fs->super->s_first_data_block) %
168                                              fs->super->s_blocks_per_group;
169                         if (!numblocks)
170                                 numblocks = fs->super->s_blocks_per_group;
171                 } else
172                         numblocks = fs->super->s_blocks_per_group;
173
174                 if (ext2fs_bg_has_super(fs, i)) {
175                         for (j=0; j < fs->desc_blocks+1; j++)
176                                 ext2fs_mark_block_bitmap(fs->block_map,
177                                                          group_block + j);
178                         adjblocks = 1 + fs->desc_blocks;
179                 }
180                 adjblocks += 2 + fs->inode_blocks_per_group;
181                 
182                 numblocks -= adjblocks;
183                 fs->super->s_free_blocks_count -= adjblocks;
184                 fs->super->s_free_inodes_count +=
185                         fs->super->s_inodes_per_group;
186                 fs->group_desc[i].bg_free_blocks_count = numblocks;
187                 fs->group_desc[i].bg_free_inodes_count =
188                         fs->super->s_inodes_per_group;
189                 fs->group_desc[i].bg_used_dirs_count = 0;
190
191                 retval = ext2fs_allocate_group_table(fs, i, 0);
192                 if (retval)
193                         return retval;
194
195                 /*
196                  * Write out the new inode table
197                  */
198                 retval = io_channel_write_blk(fs->io,
199                                               fs->group_desc[i].bg_inode_table,
200                                               fs->inode_blocks_per_group,
201                                               rfs->itable_buf);
202                 if (retval)
203                         return retval;
204                 
205                 group_block += fs->super->s_blocks_per_group;
206         }
207         return 0;
208 }
209
210 /*
211  * This routine marks and unmarks reserved blocks in the new block
212  * bitmap.  It also determines which blocks need to be moved and
213  * places this information into the move_blocks bitmap.
214  */
215 static errcode_t determine_relocations(ext2_resize_t rfs)
216 {
217         int     i, j, max, adj;
218         blk_t   blk, group_blk;
219         unsigned long old_blocks, new_blocks;
220         errcode_t       retval;
221         ext2_filsys     fs = rfs->new_fs;
222
223         retval = ext2fs_allocate_block_bitmap(rfs->old_fs,
224                                               "blocks to be moved",
225                                               &rfs->reserve_blocks);
226         if (retval)
227                 return retval;
228
229         /*
230          * If we're shrinking the filesystem, we need to move all of
231          * the blocks that don't fit any more
232          */
233         for (blk = fs->super->s_blocks_count;
234              blk < rfs->old_fs->super->s_blocks_count; blk++) {
235                 if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk))
236                         rfs->needed_blocks++;
237                 ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
238         }
239         
240         old_blocks = rfs->old_fs->desc_blocks;
241         new_blocks = fs->desc_blocks;
242
243         if (old_blocks == new_blocks)
244                 return 0;
245
246         max = fs->group_desc_count;
247         if (max > rfs->old_fs->group_desc_count)
248                 max = rfs->old_fs->group_desc_count;
249         group_blk = rfs->old_fs->super->s_first_data_block;
250         /*
251          * If we're reducing the number of descriptor blocks, this
252          * makes life easy.  :-)   We just have to mark some extra
253          * blocks as free.
254          */
255         if (old_blocks > new_blocks) {
256                 for (i = 0; i < max; i++) {
257                         if (!ext2fs_bg_has_super(fs, i)) {
258                                 group_blk += fs->super->s_blocks_per_group;
259                                 continue;
260                         }
261                         for (blk = group_blk+1+old_blocks;
262                              blk < group_blk+1+new_blocks; blk++) {
263                                 ext2fs_unmark_block_bitmap(fs->block_map,
264                                                            blk);
265                                 rfs->needed_blocks--;
266                         }
267                         group_blk += fs->super->s_blocks_per_group;
268                 }
269                 return 0;
270         }
271         /*
272          * If we're increasing the number of descriptor blocks, life
273          * gets interesting....  
274          */
275         for (i = 0; i < max; i++) {
276                 if (!ext2fs_bg_has_super(fs, i))
277                         goto next_group;
278
279                 for (blk = group_blk;
280                      blk < group_blk + 1 + new_blocks; blk++) {
281                         ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
282                         ext2fs_mark_block_bitmap(fs->block_map, blk);
283
284                         /*
285                          * Check to see if we overlap with the inode
286                          * or block bitmap
287                          */
288                         if (blk == fs->group_desc[i].bg_block_bitmap) {
289                                 fs->group_desc[i].bg_block_bitmap = 0;
290                                 rfs->needed_blocks++;
291                         }
292                         if (blk == fs->group_desc[i].bg_inode_bitmap) {
293                                 fs->group_desc[i].bg_inode_bitmap = 0;
294                                 rfs->needed_blocks++;
295                         }
296                         /*
297                          * Check to see if we overlap with the inode
298                          * table
299                          */
300                         if (blk < fs->group_desc[i].bg_inode_table)
301                                 continue;
302                         if (blk >= (fs->group_desc[i].bg_inode_table +
303                                     fs->inode_blocks_per_group))
304                                 continue;
305                         blk = fs->group_desc[i].bg_inode_table +
306                                 fs->inode_blocks_per_group - 1;
307                         fs->group_desc[i].bg_inode_table = 0;
308                 }
309                 if (fs->group_desc[i].bg_inode_table &&
310                     fs->group_desc[i].bg_inode_bitmap &&
311                     fs->group_desc[i].bg_block_bitmap)
312                         goto next_group;
313
314                 /*
315                  * Allocate the missing bitmap and inode table
316                  * structures, passing in rfs->reserve_blocks to
317                  * prevent a conflict.  
318                  */
319                 if (fs->group_desc[i].bg_block_bitmap)
320                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
321                                  fs->group_desc[i].bg_block_bitmap);
322                 if (fs->group_desc[i].bg_inode_bitmap)
323                         ext2fs_mark_block_bitmap(rfs->reserve_blocks,
324                                  fs->group_desc[i].bg_inode_bitmap);
325                 if (fs->group_desc[i].bg_inode_table)
326                         for (blk = fs->group_desc[i].bg_inode_table, j=0;
327                              j < fs->inode_blocks_per_group ; j++, blk++)
328                                 ext2fs_mark_block_bitmap(rfs->reserve_blocks,
329                                                          blk);
330
331                 retval = ext2fs_allocate_group_table(fs, i,
332                                                      rfs->reserve_blocks);
333                 if (retval)
334                         return retval;
335
336                 /*
337                  * Now make sure these blocks are reserved in the new
338                  * block bitmap
339                  */
340                 ext2fs_mark_block_bitmap(fs->block_map,
341                                          fs->group_desc[i].bg_block_bitmap);
342                 ext2fs_mark_block_bitmap(fs->block_map,
343                                          fs->group_desc[i].bg_inode_bitmap);
344
345                 /*
346                  * The inode table, if we need to relocate it, is
347                  * handled specially.  We have to reserve the blocks
348                  * for both the old and the new inode table, since we
349                  * can't have the inode table be destroyed during the
350                  * block relocation phase.
351                  */
352                 adj = fs->group_desc[i].bg_inode_table -
353                         rfs->old_fs->group_desc[i].bg_inode_table;
354                 if (!adj)
355                         goto next_group; /* inode table not moved */
356
357                 /*
358                  * Figure out how many blocks we need to have free.
359                  * This takes into account that we need to reserve
360                  * both inode tables, which may be overallping.
361                  */
362                 if (adj < 0)
363                         adj = -adj;
364                 if (adj > fs->inode_blocks_per_group)
365                         adj = fs->inode_blocks_per_group;
366                 rfs->needed_blocks += fs->inode_blocks_per_group + adj;
367
368                 /*
369                  * Mark the new inode table as in use in the new block
370                  * allocation bitmap.
371                  */
372                 for (blk = fs->group_desc[i].bg_inode_table, j=0;
373                      j < fs->inode_blocks_per_group ; j++, blk++)
374                         ext2fs_mark_block_bitmap(fs->block_map, blk);
375                 /*
376                  * Make sure the old inode table is reserved in the
377                  * block reservation bitmap.
378                  */
379                 for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
380                      j < fs->inode_blocks_per_group ; j++, blk++)
381                         ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
382                 
383         next_group:
384                 group_blk += rfs->new_fs->super->s_blocks_per_group;
385         }
386         return 0;
387 }
388
389
390 /*
391  * A very scary routine --- this one moves the inode table around!!!
392  *
393  * After this you have to use the rfs->new_fs file handle to read and
394  * write inodes.
395  */
396 errcode_t move_itables(ext2_resize_t rfs)
397 {
398         int             i, n, num, max, size, diff;
399         ext2_filsys     fs = rfs->new_fs;
400         char            *cp;
401         blk_t           old, new;
402         errcode_t       retval, err;
403
404         max = fs->group_desc_count;
405         if (max > rfs->old_fs->group_desc_count)
406                 max = rfs->old_fs->group_desc_count;
407
408         size = fs->blocksize * fs->inode_blocks_per_group;
409         if (!rfs->itable_buf) {
410                 rfs->itable_buf = malloc(size);
411                 if (!rfs->itable_buf)
412                         return ENOMEM;
413         }
414         
415         for (i=0; i < max; i++) {
416                 old = rfs->old_fs->group_desc[i].bg_inode_table;
417                 new = fs->group_desc[i].bg_inode_table;
418                 diff = new - old;
419                 
420                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
421                         printf("Itable move group %d block "
422                                "%ld->%ld (diff %d)\n", 
423                                i, old, new, diff);
424                 
425                 if (!diff)
426                         continue;
427
428                 retval = io_channel_read_blk(fs->io, old,
429                                              fs->inode_blocks_per_group,
430                                              rfs->itable_buf);
431                 if (retval) 
432                         goto backout;
433                 /*
434                  * The end of the inode table segment often contains
435                  * all zeros.  Find out if we have several blocks of
436                  * zeros so we can optimize the write.
437                  */
438                 for (cp = rfs->itable_buf+size, n=0; n < size; n++, cp--)
439                         if (*cp)
440                                 break;
441                 n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
442                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
443                         printf("%d blocks of zeros...\n", n);
444                 num = fs->inode_blocks_per_group;
445                 if (n > diff)
446                         num -= n;
447
448                 retval = io_channel_write_blk(fs->io, new,
449                                               num, rfs->itable_buf);
450                 if (retval) {
451                         io_channel_write_blk(fs->io, old,
452                                              num, rfs->itable_buf);
453                         goto backout;
454                 }
455                 if (n > diff) {
456                         retval = io_channel_write_blk(fs->io,
457                               old + fs->inode_blocks_per_group,
458                               diff, rfs->itable_buf - fs->blocksize * diff);
459                         if (retval)
460                                 goto backout;
461                 } 
462                 io_channel_flush(fs->io);
463         }
464         ext2fs_flush(rfs->new_fs);
465         if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
466                 printf("Inode table move finished.\n");
467         return 0;
468         
469 backout:
470         if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
471                 printf("Error: %s; now backing out!\n", error_message(retval));
472         while (--i >= 0) {
473                 if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) 
474                         printf("Group %d block %ld->%ld\n", i, new, old);
475                 old = rfs->old_fs->group_desc[i].bg_inode_table;
476                 new = fs->group_desc[i].bg_inode_table;
477                 
478                 err = io_channel_read_blk(fs->io, new,
479                                           fs->inode_blocks_per_group,
480                                           rfs->itable_buf);
481                 if (err)
482                         continue;
483                 err = io_channel_write_blk(fs->io, old,
484                                            fs->inode_blocks_per_group,
485                                            rfs->itable_buf);
486         }
487         return retval;
488 }
489
490 /*
491  * Finally, recalculate the summary information
492  */
493 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
494 {
495         blk_t   blk;
496         ino_t   ino;
497         int     group = 0;
498         int     count = 0;
499         int     total_free = 0;
500         int     group_free = 0;
501
502         /*
503          * First calculate the block statistics
504          */
505         for (blk = fs->super->s_first_data_block;
506              blk < fs->super->s_blocks_count; blk++) {
507                 if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
508                         group_free++;
509                         total_free++;
510                 }
511                 count++;
512                 if ((count == fs->super->s_blocks_per_group) ||
513                     (blk == fs->super->s_blocks_count-1)) {
514                         fs->group_desc[group++].bg_free_blocks_count =
515                                 group_free;
516                         count = 0;
517                         group_free = 0;
518                 }
519         }
520         fs->super->s_free_blocks_count = total_free;
521         
522         /*
523          * Next, calculate the inode statistics
524          */
525         group_free = 0;
526         total_free = 0;
527         count = 0;
528         group = 0;
529         for (ino = 1; ino <= fs->super->s_inodes_count; ino++) {
530                 if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
531                         group_free++;
532                         total_free++;
533                 }
534                 count++;
535                 if ((count == fs->super->s_inodes_per_group) ||
536                     (ino == fs->super->s_inodes_count)) {
537                         fs->group_desc[group++].bg_free_inodes_count =
538                                 group_free;
539                         count = 0;
540                         group_free = 0;
541                 }
542         }
543         fs->super->s_free_inodes_count = total_free;
544         ext2fs_mark_super_dirty(fs);
545         return 0;
546 }
547
548
549
550 /*
551  * This is the top-level routine which does the dirty deed....
552  */
553 errcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags)
554 {
555         ext2_resize_t   rfs;
556         errcode_t       retval;
557         int             bmove_flags;
558
559         retval = ext2fs_read_bitmaps(fs);
560         if (retval)
561                 return retval;
562         
563         /*
564          * Create the data structure
565          */
566         rfs = malloc(sizeof(struct ext2_resize_struct));
567         if (!rfs)
568                 return ENOMEM;
569         memset(rfs, 0, sizeof(struct ext2_resize_struct));
570
571         rfs->old_fs = fs;
572         rfs->flags = flags;
573         rfs->itable_buf  = 0;
574         retval = ext2fs_dup_handle(fs, &rfs->new_fs);
575         if (retval)
576                 goto errout;
577
578         retval = adjust_superblock(rfs, new_size);
579         if (retval)
580                 goto errout;
581
582         retval = determine_relocations(rfs);
583         if (retval)
584                 goto errout;
585
586         if (rfs->flags & RESIZE_DEBUG_BMOVE)
587                 printf("Number of free blocks: %d, Needed: %d\n",
588                        fs->super->s_free_blocks_count, rfs->needed_blocks);
589         
590         if (rfs->needed_blocks > fs->super->s_free_blocks_count) {
591                 retval = ENOSPC;
592                 goto errout;
593         }
594
595         bmove_flags = EXT2_BMOVE_GET_DBLIST;
596         if (rfs->flags & RESIZE_DEBUG_BMOVE)
597                 bmove_flags |= EXT2_BMOVE_DEBUG;
598         retval = ext2fs_move_blocks(rfs->old_fs, rfs->reserve_blocks,
599                                     rfs->new_fs->block_map, bmove_flags);
600         if (retval)
601                 goto errout;
602
603         retval = ext2fs_inode_move(rfs);
604         if (retval)
605                 goto errout;
606
607         retval = move_itables(rfs);
608         if (retval)
609                 goto errout;
610
611         retval = ext2fs_calculate_summary_stats(rfs->new_fs);
612         if (retval)
613                 goto errout;
614         
615         retval = ext2fs_close(rfs->new_fs);
616         if (retval)
617                 goto errout;
618
619         rfs->flags = flags;
620         
621         ext2fs_free(rfs->old_fs);
622         if (rfs->itable_buf)
623                 free(rfs->itable_buf);
624         free(rfs);
625         
626         return 0;
627
628 errout:
629         if (rfs->new_fs)
630                 ext2fs_free(rfs->new_fs);
631         if (rfs->itable_buf)
632                 free(rfs->itable_buf);
633         free(rfs);
634         return retval;
635 }