Whamcloud - gitweb
libext2fs: always refuse to open a file system with a zero s_desc_size
[tools/e2fsprogs.git] / e2fsck / extents.c
1 /*
2  * extents.c --- rebuild extent tree
3  *
4  * Copyright (C) 2014 Oracle.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License, version 2.
9  * %End-Header%
10  */
11
12 #include "config.h"
13 #include <string.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include "e2fsck.h"
17 #include "problem.h"
18
19 #undef DEBUG
20 #undef DEBUG_SUMMARY
21 #undef DEBUG_FREE
22
23 #define NUM_EXTENTS     341     /* about one ETB' worth of extents */
24
25 static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino);
26
27 /* Schedule an inode to have its extent tree rebuilt during pass 1E. */
28 errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino)
29 {
30         errcode_t retval = 0;
31
32         if (!ext2fs_has_feature_extents(ctx->fs->super) ||
33             (ctx->options & E2F_OPT_NO) ||
34             (ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino))
35                 return 0;
36
37         if (ctx->flags & E2F_FLAG_ALLOC_OK)
38                 return e2fsck_rebuild_extents(ctx, ino);
39
40         if (!ctx->inodes_to_rebuild)
41                 retval = e2fsck_allocate_inode_bitmap(ctx->fs,
42                                              _("extent rebuild inode map"),
43                                              EXT2FS_BMAP64_RBTREE,
44                                              "inodes_to_rebuild",
45                                              &ctx->inodes_to_rebuild);
46         if (retval)
47                 return retval;
48
49         ext2fs_mark_inode_bitmap2(ctx->inodes_to_rebuild, ino);
50         return 0;
51 }
52
53 /* Ask if an inode will have its extents rebuilt during pass 1E. */
54 int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx, ext2_ino_t ino)
55 {
56         if (!ctx->inodes_to_rebuild)
57                 return 0;
58         return ext2fs_test_inode_bitmap2(ctx->inodes_to_rebuild, ino);
59 }
60
61 static errcode_t load_extents(e2fsck_t ctx, struct extent_list *list)
62 {
63         ext2_filsys             fs = ctx->fs;
64         ext2_extent_handle_t    handle;
65         struct ext2fs_extent    extent;
66         errcode_t               retval;
67
68         retval = ext2fs_extent_open(fs, list->ino, &handle);
69         if (retval)
70                 return retval;
71
72         retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent);
73         if (retval)
74                 goto out;
75
76         do {
77                 if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
78                         goto next;
79
80                 /* Internal node; free it and we'll re-allocate it later */
81                 if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
82 #if defined(DEBUG) || defined(DEBUG_FREE)
83                         printf("ino=%d free=%llu bf=%llu\n", list->ino,
84                                         extent.e_pblk, list->blocks_freed + 1);
85 #endif
86                         list->blocks_freed++;
87                         ext2fs_block_alloc_stats2(fs, extent.e_pblk, -1);
88                         goto next;
89                 }
90
91                 list->ext_read++;
92                 /* Can we attach it to the previous extent? */
93                 if (list->count) {
94                         struct ext2fs_extent *last = list->extents +
95                                                      list->count - 1;
96                         blk64_t end = last->e_len + extent.e_len;
97
98                         if (last->e_pblk + last->e_len == extent.e_pblk &&
99                             last->e_lblk + last->e_len == extent.e_lblk &&
100                             (last->e_flags & EXT2_EXTENT_FLAGS_UNINIT) ==
101                             (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
102                             end < (1ULL << 32)) {
103                                 last->e_len += extent.e_len;
104 #ifdef DEBUG
105                                 printf("R: ino=%d len=%u\n", list->ino,
106                                                 last->e_len);
107 #endif
108                                 goto next;
109                         }
110                 }
111
112                 /* Do we need to expand? */
113                 if (list->count == list->size) {
114                         unsigned int new_size = (list->size + NUM_EXTENTS) *
115                                                 sizeof(struct ext2fs_extent);
116                         retval = ext2fs_resize_mem(0, new_size, &list->extents);
117                         if (retval)
118                                 goto out;
119                         list->size += NUM_EXTENTS;
120                 }
121
122                 /* Add a new extent */
123                 memcpy(list->extents + list->count, &extent, sizeof(extent));
124 #ifdef DEBUG
125                 printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino,
126                                 extent.e_pblk, extent.e_lblk, extent.e_len);
127 #endif
128                 list->count++;
129 next:
130                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent);
131         } while (retval == 0);
132
133 out:
134         /* Ok if we run off the end */
135         if (retval == EXT2_ET_EXTENT_NO_NEXT)
136                 retval = 0;
137         ext2fs_extent_free(handle);
138         return retval;
139 }
140
141 static int find_blocks(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt,
142                        blk64_t ref_blk EXT2FS_ATTR((unused)),
143                        int ref_offset EXT2FS_ATTR((unused)), void *priv_data)
144 {
145         struct extent_list *list = priv_data;
146
147         /* Internal node? */
148         if (blockcnt < 0) {
149 #if defined(DEBUG) || defined(DEBUG_FREE)
150                 printf("ino=%d free=%llu bf=%llu\n", list->ino, *blocknr,
151                                 list->blocks_freed + 1);
152 #endif
153                 list->blocks_freed++;
154                 ext2fs_block_alloc_stats2(fs, *blocknr, -1);
155                 return 0;
156         }
157
158         /* Can we attach it to the previous extent? */
159         if (list->count) {
160                 struct ext2fs_extent *last = list->extents +
161                                              list->count - 1;
162                 blk64_t end = last->e_len + 1;
163
164                 if (last->e_lblk + last->e_len == (__u64) blockcnt &&
165                     last->e_pblk + last->e_len == *blocknr &&
166                     end < (1ULL << 32)) {
167                         last->e_len++;
168 #ifdef DEBUG
169                         printf("R: ino=%d len=%u\n", list->ino, last->e_len);
170 #endif
171                         return 0;
172                 }
173         }
174
175         /* Do we need to expand? */
176         if (list->count == list->size) {
177                 unsigned int new_size = (list->size + NUM_EXTENTS) *
178                                         sizeof(struct ext2fs_extent);
179                 list->retval = ext2fs_resize_mem(0, new_size, &list->extents);
180                 if (list->retval)
181                         return BLOCK_ABORT;
182                 list->size += NUM_EXTENTS;
183         }
184
185         /* Add a new extent */
186         list->extents[list->count].e_pblk = *blocknr;
187         list->extents[list->count].e_lblk = blockcnt;
188         list->extents[list->count].e_len = 1;
189         list->extents[list->count].e_flags = 0;
190 #ifdef DEBUG
191         printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino, *blocknr,
192                         blockcnt, 1);
193 #endif
194         list->count++;
195
196         return 0;
197 }
198
199 static errcode_t rewrite_extent_replay(e2fsck_t ctx, struct extent_list *list,
200                                        struct ext2_inode_large *inode)
201 {
202         errcode_t               retval;
203         ext2_extent_handle_t    handle;
204         unsigned int            i;
205 #if defined(DEBUG) || defined(DEBUG_SUMMARY)
206         unsigned int            ext_written = 0;
207 #endif
208         struct ext2fs_extent    *ex, extent;
209         blk64_t                 start_val, delta;
210
211         /* Reset extent tree */
212         inode->i_flags &= ~EXT4_EXTENTS_FL;
213         memset(inode->i_block, 0, sizeof(inode->i_block));
214
215         /* Make a note of freed blocks */
216         quota_data_sub(ctx->qctx, inode, list->ino,
217                        list->blocks_freed * ctx->fs->blocksize);
218         retval = ext2fs_iblk_sub_blocks(ctx->fs, EXT2_INODE(inode),
219                                         list->blocks_freed);
220         if (retval)
221                 return retval;
222
223         /* Now stuff extents into the file */
224         retval = ext2fs_extent_open2(ctx->fs, list->ino, EXT2_INODE(inode),
225                                         &handle);
226         if (retval)
227                 return retval;
228
229         start_val = ext2fs_get_stat_i_blocks(ctx->fs, EXT2_INODE(inode));
230
231         for (i = 0, ex = list->extents; i < list->count; i++, ex++) {
232                 if (ex->e_len == 0)
233                         continue;
234                 memcpy(&extent, ex, sizeof(struct ext2fs_extent));
235                 extent.e_flags &= EXT2_EXTENT_FLAGS_UNINIT;
236                 if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
237                         if (extent.e_len > EXT_UNINIT_MAX_LEN) {
238                                 extent.e_len = EXT_UNINIT_MAX_LEN;
239                                 ex->e_pblk += EXT_UNINIT_MAX_LEN;
240                                 ex->e_lblk += EXT_UNINIT_MAX_LEN;
241                                 ex->e_len -= EXT_UNINIT_MAX_LEN;
242                                 ex--;
243                                 i--;
244                         }
245                 } else {
246                         if (extent.e_len > EXT_INIT_MAX_LEN) {
247                                 extent.e_len = EXT_INIT_MAX_LEN;
248                                 ex->e_pblk += EXT_INIT_MAX_LEN;
249                                 ex->e_lblk += EXT_INIT_MAX_LEN;
250                                 ex->e_len -= EXT_INIT_MAX_LEN;
251                                 ex--;
252                                 i--;
253                         }
254                 }
255
256 #ifdef DEBUG
257                 printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino,
258                                 extent.e_pblk, extent.e_lblk, extent.e_len);
259 #endif
260                 retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER,
261                                               &extent);
262                 if (retval)
263                         goto err;
264                 retval = ext2fs_extent_fix_parents(handle);
265                 if (retval)
266                         goto err;
267 #if defined(DEBUG) || defined(DEBUG_SUMMARY)
268                 ext_written++;
269 #endif
270         }
271
272         delta = ext2fs_get_stat_i_blocks(ctx->fs, EXT2_INODE(inode)) -
273                 start_val;
274         if (delta)
275                 quota_data_add(ctx->qctx, inode, list->ino, delta << 9);
276
277 #if defined(DEBUG) || defined(DEBUG_SUMMARY)
278         printf("rebuild: ino=%d extents=%d->%d\n", ino, list->ext_read,
279                ext_written);
280 #endif
281         e2fsck_write_inode(ctx, list->ino, EXT2_INODE(inode),
282                                 "rebuild_extents");
283
284 err:
285         ext2fs_extent_free(handle);
286         return retval;
287 }
288
289 errcode_t e2fsck_rewrite_extent_tree(e2fsck_t ctx, struct extent_list *list)
290 {
291         struct ext2_inode_large inode;
292         blk64_t blk_count;
293         errcode_t err;
294
295         memset(&inode, 0, sizeof(inode));
296         err = ext2fs_read_inode_full(ctx->fs, list->ino, EXT2_INODE(&inode),
297                                      sizeof(inode));
298         if (err)
299                 return err;
300
301         /* Skip deleted inodes and inline data files */
302         if (inode.i_flags & EXT4_INLINE_DATA_FL)
303                 return 0;
304
305         err = rewrite_extent_replay(ctx, list, &inode);
306         if (err)
307                 return err;
308
309         err = ext2fs_count_blocks(ctx->fs, list->ino, EXT2_INODE(&inode),
310                                   &blk_count);
311         if (err)
312                 return err;
313         err = ext2fs_iblk_set(ctx->fs, EXT2_INODE(&inode), blk_count);
314         if (err)
315                 return err;
316         return ext2fs_write_inode_full(ctx->fs, list->ino, EXT2_INODE(&inode),
317                                        sizeof(inode));
318 }
319
320 errcode_t e2fsck_read_extents(e2fsck_t ctx, struct extent_list *extents)
321 {
322         struct ext2_inode_large inode;
323         errcode_t               retval;
324
325         extents->extents = NULL;
326         extents->count = 0;
327         extents->blocks_freed = 0;
328         extents->ext_read = 0;
329         extents->size = NUM_EXTENTS;
330         retval = ext2fs_get_array(NUM_EXTENTS, sizeof(struct ext2fs_extent),
331                                   &extents->extents);
332         if (retval)
333                 return ENOMEM;
334
335         retval = ext2fs_read_inode(ctx->fs, extents->ino, EXT2_INODE(&inode));
336         if (retval)
337                 goto err_out;
338
339         retval = load_extents(ctx, extents);
340         if (!retval)
341                 return 0;
342 err_out:
343         ext2fs_free_mem(&extents->extents);
344         extents->size = 0;
345         extents->count = 0;
346         return retval;
347 }
348
349 static errcode_t rebuild_extent_tree(e2fsck_t ctx, struct extent_list *list,
350                                      ext2_ino_t ino)
351 {
352         struct ext2_inode_large inode;
353         errcode_t               retval;
354
355         list->count = 0;
356         list->blocks_freed = 0;
357         list->ino = ino;
358         list->ext_read = 0;
359         e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode), sizeof(inode),
360                                "rebuild_extents");
361
362         /* Skip deleted inodes and inline data files */
363         if (inode.i_links_count == 0 ||
364             inode.i_flags & EXT4_INLINE_DATA_FL)
365                 return 0;
366
367         /* Collect lblk->pblk mappings */
368         if (inode.i_flags & EXT4_EXTENTS_FL) {
369                 retval = load_extents(ctx, list);
370                 if (retval)
371                         return retval;
372                 return rewrite_extent_replay(ctx, list, &inode);
373         }
374
375         retval = ext2fs_block_iterate3(ctx->fs, ino, BLOCK_FLAG_READ_ONLY, 0,
376                                        find_blocks, list);
377
378         return retval || list->retval ||
379                 rewrite_extent_replay(ctx, list, &inode);
380 }
381
382 /* Rebuild the extents immediately */
383 static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino)
384 {
385         struct extent_list list = { 0 };
386         errcode_t err;
387
388         if (!ext2fs_has_feature_extents(ctx->fs->super) ||
389             (ctx->options & E2F_OPT_NO) ||
390             (ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino))
391                 return 0;
392
393         e2fsck_read_bitmaps(ctx);
394         err = ext2fs_get_array(NUM_EXTENTS, sizeof(struct ext2fs_extent),
395                                &list.extents);
396         if (err)
397                 return err;
398         list.size = NUM_EXTENTS;
399         err = rebuild_extent_tree(ctx, &list, ino);
400         ext2fs_free_mem(&list.extents);
401
402         return err;
403 }
404
405 static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header)
406 {
407         struct problem_context  pctx;
408 #ifdef RESOURCE_TRACK
409         struct resource_track   rtrack;
410 #endif
411         struct extent_list      list = { 0 };
412         int                     first = 1;
413         ext2_ino_t              ino = 0;
414         errcode_t               retval;
415
416         if (!ext2fs_has_feature_extents(ctx->fs->super) ||
417             !ext2fs_test_valid(ctx->fs) ||
418             ctx->invalid_bitmaps) {
419                 if (ctx->inodes_to_rebuild)
420                         ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild);
421                 ctx->inodes_to_rebuild = NULL;
422         }
423
424         if (ctx->inodes_to_rebuild == NULL)
425                 return;
426
427         init_resource_track(&rtrack, ctx->fs->io);
428         clear_problem_context(&pctx);
429         e2fsck_read_bitmaps(ctx);
430
431         list.size = NUM_EXTENTS;
432         retval = ext2fs_get_array(sizeof(struct ext2fs_extent),
433                                   list.size, &list.extents);
434         if (retval)
435                 return;
436         while (1) {
437                 retval = ext2fs_find_first_set_inode_bitmap2(
438                                 ctx->inodes_to_rebuild, ino + 1,
439                                 ctx->fs->super->s_inodes_count, &ino);
440                 if (retval)
441                         break;
442                 pctx.ino = ino;
443                 if (first) {
444                         fix_problem(ctx, pr_header, &pctx);
445                         first = 0;
446                 }
447                 pctx.errcode = rebuild_extent_tree(ctx, &list, ino);
448                 if (pctx.errcode) {
449                         end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT);
450                         fix_problem(ctx, PR_1E_OPTIMIZE_EXT_ERR, &pctx);
451                 }
452                 if (ctx->progress && !ctx->progress_fd)
453                         e2fsck_simple_progress(ctx, "Rebuilding extents",
454                                         100.0 * (float) ino /
455                                         (float) ctx->fs->super->s_inodes_count,
456                                         ino);
457         }
458         end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT);
459
460         ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild);
461         ctx->inodes_to_rebuild = NULL;
462         ext2fs_free_mem(&list.extents);
463
464         print_resource_track(ctx, pass_name, &rtrack, ctx->fs->io);
465 }
466
467 /* Scan a file to see if we should rebuild its extent tree */
468 errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino,
469                                   struct ext2_inode *inode,
470                                   struct problem_context *pctx)
471 {
472         struct extent_tree_info eti;
473         struct ext2_extent_info info, top_info;
474         struct ext2fs_extent    extent;
475         ext2_extent_handle_t    ehandle;
476         ext2_filsys             fs = ctx->fs;
477         errcode_t               retval;
478
479         /* block map file and we want extent conversion */
480         if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
481             !(inode->i_flags & EXT4_INLINE_DATA_FL) &&
482             (ctx->options & E2F_OPT_CONVERT_BMAP)) {
483                 return e2fsck_rebuild_extents_later(ctx, ino);
484         }
485
486         if (!(inode->i_flags & EXT4_EXTENTS_FL))
487                 return 0;
488         memset(&eti, 0, sizeof(eti));
489         eti.ino = ino;
490
491         /* Otherwise, go scan the extent tree... */
492         retval = ext2fs_extent_open2(fs, ino, inode, &ehandle);
493         if (retval)
494                 return 0;
495
496         retval = ext2fs_extent_get_info(ehandle, &top_info);
497         if (retval)
498                 goto out;
499
500         /* Check maximum extent depth */
501         pctx->ino = ino;
502         pctx->blk = top_info.max_depth;
503         pctx->blk2 = ext2fs_max_extent_depth(ehandle);
504         if (pctx->blk2 < pctx->blk &&
505             fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx))
506                 eti.force_rebuild = 1;
507
508         /* Can we collect extent tree level stats? */
509         pctx->blk = MAX_EXTENT_DEPTH_COUNT;
510         if (pctx->blk2 > pctx->blk)
511                 fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx);
512
513         /* We need to fix tree depth problems, but the scan isn't a fix. */
514         if (ctx->options & E2F_OPT_FIXES_ONLY)
515                 goto out;
516
517         retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_ROOT, &extent);
518         if (retval)
519                 goto out;
520
521         do {
522                 retval = ext2fs_extent_get_info(ehandle, &info);
523                 if (retval)
524                         break;
525
526                 /*
527                  * If this is the first extent in an extent block that we
528                  * haven't visited, collect stats on the block.
529                  */
530                 if (info.curr_entry == 1 &&
531                     !(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
532                     !eti.force_rebuild &&
533                     info.curr_level < MAX_EXTENT_DEPTH_COUNT) {
534                         struct extent_tree_level *etl;
535
536                         etl = eti.ext_info + info.curr_level;
537                         etl->num_extents += info.num_entries;
538                         etl->max_extents += info.max_entries;
539                         /*
540                          * Implementation wart: Splitting extent blocks when
541                          * appending will leave the old block with one free
542                          * entry.  Therefore unless the node is totally full,
543                          * pretend that a non-root extent block can hold one
544                          * fewer entry than it actually does, so that we don't
545                          * repeatedly rebuild the extent tree.
546                          */
547                         if (info.curr_level &&
548                             info.num_entries < info.max_entries)
549                                 etl->max_extents--;
550                 }
551
552                 /* Skip to the end of a block of leaf nodes */
553                 if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) {
554                         retval = ext2fs_extent_get(ehandle,
555                                                     EXT2_EXTENT_LAST_SIB,
556                                                     &extent);
557                         if (retval)
558                                 break;
559                 }
560
561                 retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_NEXT, &extent);
562         } while (retval == 0);
563 out:
564         ext2fs_extent_free(ehandle);
565         return e2fsck_should_rebuild_extents(ctx, pctx, &eti, &top_info);
566 }
567
568 /* Having scanned a file's extent tree, decide if we should rebuild it */
569 errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx,
570                                    struct problem_context *pctx,
571                                    struct extent_tree_info *eti,
572                                    struct ext2_extent_info *info)
573 {
574         struct extent_tree_level *ei;
575         int i, j, op;
576         unsigned int extents_per_block;
577
578         if (eti->force_rebuild)
579                 goto rebuild;
580
581         if (ctx->options & E2F_OPT_NOOPT_EXTENTS)
582                 return 0;
583
584         extents_per_block = (ctx->fs->blocksize -
585                              sizeof(struct ext3_extent_header)) /
586                             sizeof(struct ext3_extent);
587
588         /* If the extent tree is too deep, then rebuild it. */
589         if (info->max_depth > MAX_EXTENT_DEPTH_COUNT-1) {
590                 pctx->blk = info->max_depth;
591                 op = PR_1E_CAN_COLLAPSE_EXTENT_TREE;
592                 goto rebuild;
593         }
594         /*
595          * If we can consolidate a level or shorten the tree, schedule the
596          * extent tree to be rebuilt.
597          */
598         for (i = 0, ei = eti->ext_info; i < info->max_depth + 1; i++, ei++) {
599                 if (ei->max_extents - ei->num_extents > extents_per_block) {
600                         pctx->blk = i;
601                         op = PR_1E_CAN_NARROW_EXTENT_TREE;
602                         goto rebuild;
603                 }
604                 for (j = 0; j < i; j++) {
605                         if (ei->num_extents < eti->ext_info[j].max_extents) {
606                                 pctx->blk = i;
607                                 op = PR_1E_CAN_COLLAPSE_EXTENT_TREE;
608                                 goto rebuild;
609                         }
610                 }
611         }
612         return 0;
613
614 rebuild:
615         if (eti->force_rebuild || fix_problem(ctx, op, pctx))
616                 return e2fsck_rebuild_extents_later(ctx, eti->ino);
617         return 0;
618 }
619
620 void e2fsck_pass1e(e2fsck_t ctx)
621 {
622         rebuild_extents(ctx, "Pass 1E", PR_1E_PASS_HEADER);
623 }