]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
Merge branch 'maint' into next
authorTheodore Ts'o <tytso@mit.edu>
Mon, 30 Nov 2015 23:16:36 +0000 (18:16 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 30 Nov 2015 23:16:36 +0000 (18:16 -0500)
12 files changed:
1  2 
e2fsck/e2fsck.c
e2fsck/e2fsck.h
e2fsck/pass1.c
e2fsck/pass2.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/rehash.c
e2fsck/unix.c
lib/ext2fs/punch.c
misc/chattr.1.in
misc/tune2fs.c
tests/f_extents/expect.1

diff --cc e2fsck/e2fsck.c
index dd8150be6a85ac9b90af7c410f98634587423a0d,2002dc00a0de5392eb3b090ee142b74b7834bf3b..6fb2f40a31aad02ada85f61d05929e27e2c6c7f7
@@@ -206,11 -200,9 +206,9 @@@ void e2fsck_free_context(e2fsck_t ctx
  typedef void (*pass_t)(e2fsck_t ctx);
  
  static pass_t e2fsck_passes[] = {
 -      e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
 -      e2fsck_pass5, 0 };
 +      e2fsck_pass1, e2fsck_pass1e, e2fsck_pass2, e2fsck_pass3,
 +      e2fsck_pass4, e2fsck_pass5, 0 };
  
- #define E2F_FLAG_RUN_RETURN   (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
  int e2fsck_run(e2fsck_t ctx)
  {
        int     i;
diff --cc e2fsck/e2fsck.h
Simple merge
diff --cc e2fsck/pass1.c
index 0a8e23ece64b3986a41347eec3d77a5605565a72,2370bb0e71c9871077ea2575d5c6b501dbe708f6..5a8d4a1984bf1ace088befb6e1da9ad42e590966
@@@ -1162,43 -768,10 +1166,43 @@@ void e2fsck_pass1(e2fsck_t ctx
                old_op = ehandler_operation(_("getting next inode from scan"));
                pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
                                                          inode, inode_size);
 +              if (ino > ino_threshold)
 +                      pass1_readahead(ctx, &ra_group, &ino_threshold);
                ehandler_operation(old_op);
                if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
-                       return;
+                       goto endit;
                if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
 +                      /*
 +                       * If badblocks says badblocks is bad, offer to clear
 +                       * the list, update the in-core bb list, and restart
 +                       * the inode scan.
 +                       */
 +                      if (ino == EXT2_BAD_INO &&
 +                          fix_problem(ctx, PR_1_BADBLOCKS_IN_BADBLOCKS,
 +                                      &pctx)) {
 +                              errcode_t err;
 +
 +                              e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
 +                              ext2fs_badblocks_list_free(ctx->fs->badblocks);
 +                              ctx->fs->badblocks = NULL;
 +                              err = ext2fs_read_bb_inode(ctx->fs,
 +                                                      &ctx->fs->badblocks);
 +                              if (err) {
 +                                      fix_problem(ctx, PR_1_ISCAN_ERROR,
 +                                                  &pctx);
 +                                      ctx->flags |= E2F_FLAG_ABORT;
 +                                      goto endit;
 +                              }
 +                              err = ext2fs_inode_scan_goto_blockgroup(scan,
 +                                                                      0);
 +                              if (err) {
 +                                      fix_problem(ctx, PR_1_ISCAN_ERROR,
 +                                                  &pctx);
 +                                      ctx->flags |= E2F_FLAG_ABORT;
 +                                      goto endit;
 +                              }
 +                              continue;
 +                      }
                        if (!ctx->inode_bb_map)
                                alloc_bb_map(ctx);
                        ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino);
@@@ -1839,16 -1279,11 +1843,18 @@@ endit
        if (inode)
                ext2fs_free_mem(&inode);
  
 +      /*
 +       * The l+f inode may have been cleared, so zap it now and
 +       * later passes will recalculate it if necessary
 +       */
 +      ctx->lost_and_found = 0;
 +
        if ((ctx->flags & E2F_FLAG_SIGNAL_MASK) == 0)
                print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io);
+       else
+               ctx->invalid_bitmaps++;
  }
 +#undef FINISH_INODE_LOOP
  
  /*
   * When the inode_scan routines call this callback at the end of the
diff --cc e2fsck/pass2.c
index 532b0ebd9f55aba17b7bcf0bdd462945aa23b20a,b8f7e33a4fcfa916b346e5d40d71cab178de07b9..6a7215add65d4d5ef2cfdb19c8a3d32fb76f033a
@@@ -155,20 -143,19 +155,20 @@@ void e2fsck_pass2(e2fsck_t ctx
        if (ctx->progress)
                (void) (ctx->progress)(ctx, 2, 0, cd.max);
  
 -      if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
 +      if (ext2fs_has_feature_dir_index(fs->super))
                ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp);
  
 -      cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_block,
 +      check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block;
 +      cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func,
                                                 &cd);
-       if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
-               return;
        if (ctx->flags & E2F_FLAG_RESTART_LATER) {
                ctx->flags |= E2F_FLAG_RESTART;
-               return;
+               ctx->flags &= ~E2F_FLAG_RESTART_LATER;
        }
  
+       if (ctx->flags & E2F_FLAG_RUN_RETURN)
+               return;
        if (cd.pctx.errcode) {
                fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
                ctx->flags |= E2F_FLAG_ABORT;
@@@ -910,19 -734,12 +910,19 @@@ static int check_dir_block(ext2_filsys 
        struct problem_context  pctx;
        int     dups_found = 0;
        int     ret;
 +      int     dx_csum_size = 0, de_csum_size = 0;
 +      int     failed_csum = 0;
 +      int     is_leaf = 1;
 +      size_t  inline_data_size = 0;
 +      int     filetype = 0;
 +      int     encrypted = 0;
 +      size_t  max_block_size;
  
        cd = (struct check_dir_struct *) priv_data;
 -      buf = cd->buf;
 +      ibuf = buf = cd->buf;
        ctx = cd->ctx;
  
-       if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
+       if (ctx->flags & E2F_FLAG_RUN_RETURN)
                return DIRENT_ABORT;
  
        if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
index f761ec98f237a7b5917227987a21d12961f84316,e7831481725c9ff9e8be9d27ce51a2ebabd72ae2..a7da94dc1174c44fd8a5c42ca7edab087ef47887
@@@ -1053,67 -987,11 +1053,72 @@@ static struct e2fsck_problem problem_ta
          N_("@i %i logical @b %b (physical @b %c) violates cluster allocation rules.\nWill fix in pass 1B.\n"),
          PROMPT_NONE, 0 },
  
 +      /* Inode has INLINE_DATA_FL flag but extended attribute not found */
 +      { PR_1_INLINE_DATA_NO_ATTR,
 +        N_("@i %i has INLINE_DATA_FL flag but @a not found.  "),
 +        PROMPT_TRUNCATE, 0 },
 +
 +      /* Extents/inlinedata flag set on a device or socket inode */
 +      { PR_1_SPECIAL_EXTENTS_IDATA,
 +        N_("Special (@v/socket/fifo) file (@i %i) has extents\n"
 +           "or inline-data flag set.  "),
 +        PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
 +
 +      /* Inode has extent header but inline data flag is set */
 +      { PR_1_CLEAR_INLINE_DATA_FOR_EXTENT,
 +        N_("@i %i has @x header but inline data flag is set.\n"),
 +        PROMPT_FIX, 0 },
 +
 +      /* Inode seems to have inline data but extent flag is set */
 +      { PR_1_CLEAR_EXTENT_FOR_INLINE_DATA,
 +        N_("@i %i seems to have inline data but @x flag is set.\n"),
 +        PROMPT_FIX, 0 },
 +
 +      /* Inode seems to have block map but inline data and extent flags set */
 +      { PR_1_CLEAR_EXTENT_INLINE_DATA_FLAGS,
 +        N_("@i %i seems to have @b map but inline data and @x flags set.\n"),
 +        PROMPT_FIX, 0 },
 +
 +      /* Inode has inline data and extent flags but i_block contains junk */
 +      { PR_1_CLEAR_EXTENT_INLINE_DATA_INODE,
 +        N_("@i %i has inline data and @x flags set but i_block contains junk.\n"),
 +        PROMPT_CLEAR_INODE, 0 },
 +
 +      /* Bad block list says the bad block list inode is bad */
 +      { PR_1_BADBLOCKS_IN_BADBLOCKS,
 +        N_("Bad block list says the bad block list @i is bad.  "),
 +        PROMPT_CLEAR_INODE, 0 },
 +
 +      /* Error allocating extent region allocation structure */
 +      { PR_1_EXTENT_ALLOC_REGION_ABORT,
 +        N_("@A @x region allocation structure.  "),
 +        PROMPT_NONE, PR_FATAL},
 +
 +      /* Inode has a duplicate extent mapping */
 +      { PR_1_EXTENT_COLLISION,
 +        N_("@i %i has a duplicate @x mapping\n\t(logical @b %c, @n physical @b %b, len %N)\n"),
 +        PROMPT_CLEAR, 0 },
 +
 +      /* Error allocating memory for encrypted directory list */
 +      { PR_1_ALLOCATE_ENCRYPTED_DIRLIST,
 +        N_("@A memory for encrypted @d list\n"),
 +        PROMPT_NONE, PR_FATAL },
 +
 +      /* Inode extent tree could be more shallow */
 +      { PR_1_EXTENT_BAD_MAX_DEPTH,
 +        N_("@i %i @x tree could be more shallow (%b; could be <= %c)\n"),
 +        PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK },
 +
 +      /* Inode extent tree could be more shallow */
 +      { PR_1_NO_BIGALLOC_BLOCKMAP_FILES,
 +        N_("@i %i on bigalloc @f cannot be @b mapped.  "),
 +        PROMPT_FIX, 0 },
 +
+       /* Inode has corrupt extent header */
+       { PR_1_MISSING_EXTENT_HEADER,
+         N_("@i %i has corrupt @x header.  "),
+         PROMPT_CLEAR_INODE, 0 },
        /* Pass 1b errors */
  
        /* Pass 1B: Rescan for duplicate/bad blocks */
Simple merge
diff --cc e2fsck/rehash.c
index 15d3dd937ae006ef9ab0515d15409b8096f80829,52d99a3ccbc2ebb908d0c9d5dfecbba1d9a60da4..1285adb0e06f0fc130439eea3a112a03e3ac24e0
  #include "e2fsck.h"
  #include "problem.h"
  
 +/* Schedule a dir to be rebuilt during pass 3A. */
 +void e2fsck_rehash_dir_later(e2fsck_t ctx, ext2_ino_t ino)
 +{
 +      if (!ctx->dirs_to_hash)
 +              ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
 +      if (ctx->dirs_to_hash)
 +              ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
 +}
 +
 +/* Ask if a dir will be rebuilt during pass 3A. */
 +int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino)
 +{
 +      if (ctx->options & E2F_OPT_COMPRESS_DIRS)
 +              return 1;
 +      if (!ctx->dirs_to_hash)
 +              return 0;
 +      return ext2fs_u32_list_test(ctx->dirs_to_hash, ino);
 +}
 +
+ #undef REHASH_DEBUG
  struct fill_dir_struct {
        char *buf;
        struct ext2_inode *inode;
@@@ -684,9 -628,8 +686,9 @@@ static errcode_t calculate_tree(ext2_fi
  struct write_dir_struct {
        struct out_dir *outdir;
        errcode_t       err;
+       ext2_ino_t      ino;
        e2fsck_t        ctx;
-       blk64_t         cleared;
 +      ext2_ino_t      dir;
  };
  
  /*
@@@ -701,42 -644,37 +703,41 @@@ static int write_dir_block(ext2_filsys 
  {
        struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
        blk64_t blk;
 -      char    *dir;
 +      char    *dir, *buf = 0;
  
-       if (*block_nr == 0)
-               return 0;
-       if (blockcnt < 0)
+ #ifdef REHASH_DEBUG
+       printf("%u: write_dir_block %lld:%lld", wd->ino, blockcnt, *block_nr);
+ #endif
 -      if (*block_nr == 0) {
++      if ((*block_nr == 0) || (blockcnt < 0)) {
+ #ifdef REHASH_DEBUG
+               printf(" - skip\n");
+ #endif
                return 0;
 -      /* Don't free blocks at the end of the directory, they will be
 -       * truncated by the caller. */
 -      if (blockcnt >= wd->outdir->num) {
+       }
-               /* We don't need this block, so release it */
-               e2fsck_read_bitmaps(wd->ctx);
-               blk = *block_nr;
-               /*
-                * In theory, we only release blocks from the end of the
-                * directory file, so it's fine to clobber a whole cluster at
-                * once.
-                */
-               if (blk % EXT2FS_CLUSTER_RATIO(fs) == 0) {
-                       ext2fs_block_alloc_stats2(fs, blk, -1);
-                       wd->cleared++;
-               }
-               *block_nr = 0;
-               return BLOCK_CHANGED;
 +      if (blockcnt < wd->outdir->num)
 +              dir = wd->outdir->buf + (blockcnt * fs->blocksize);
 +      else if (wd->ctx->lost_and_found == wd->dir) {
 +              /* Don't release any extra directory blocks for lost+found */
 +              wd->err = ext2fs_new_dir_block(fs, 0, 0, &buf);
 +              if (wd->err)
 +                      return BLOCK_ABORT;
 +              dir = buf;
 +              wd->outdir->num++;
 +      } else {
++              /* Don't free blocks at the end of the directory, they
++               * will be truncated by the caller. */
+ #ifdef REHASH_DEBUG
+               printf(" - not freed\n");
+ #endif
+               return 0;
        }
 -      if (blockcnt < 0) {
 -#ifdef REHASH_DEBUG
 -              printf(" - skip\n");
 -#endif
 -              return 0;
 -      }
 +      wd->err = ext2fs_write_dir_block4(fs, *block_nr, dir, 0, wd->dir);
 +      if (buf)
 +              ext2fs_free_mem(&buf);
  
 -      dir = wd->outdir->buf + (blockcnt * fs->blocksize);
 -      wd->err = ext2fs_write_dir_block3(fs, *block_nr, dir, 0);
+ #ifdef REHASH_DEBUG
+       printf(" - write (%d)\n", wd->err);
+ #endif
        if (wd->err)
                return BLOCK_ABORT;
        return 0;
@@@ -756,53 -694,46 +757,52 @@@ static errcode_t write_directory(e2fsck
  
        wd.outdir = outdir;
        wd.err = 0;
+       wd.ino = ino;
        wd.ctx = ctx;
-       wd.cleared = 0;
 +      wd.dir = ino;
  
-       retval = ext2fs_block_iterate3(fs, ino, 0, 0,
+       retval = ext2fs_block_iterate3(fs, ino, 0, NULL,
                                       write_dir_block, &wd);
        if (retval)
                return retval;
        if (wd.err)
                return wd.err;
  
 -      e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
 +      e2fsck_read_inode(ctx, ino, inode, "rehash_dir");
        if (compress)
 -              inode.i_flags &= ~EXT2_INDEX_FL;
 +              inode->i_flags &= ~EXT2_INDEX_FL;
        else
 -              inode.i_flags |= EXT2_INDEX_FL;
 +              inode->i_flags |= EXT2_INDEX_FL;
-       retval = ext2fs_inode_size_set(fs, inode,
-                                      outdir->num * fs->blocksize);
+ #ifdef REHASH_DEBUG
+       printf("%u: set inode size to %u blocks = %u bytes\n",
+              ino, outdir->num, outdir->num * fs->blocksize);
+ #endif
 -      retval = ext2fs_inode_size_set(fs, &inode, (ext2_off64_t)outdir->num *
++      retval = ext2fs_inode_size_set(fs, inode, (ext2_off64_t)outdir->num *
+                                                  fs->blocksize);
        if (retval)
                return retval;
-       ext2fs_iblk_sub_blocks(fs, inode, wd.cleared);
-       e2fsck_write_inode(ctx, ino, inode, "rehash_dir");
  
-       return 0;
+       /* ext2fs_punch() calls ext2fs_write_inode() which writes the size */
 -      return ext2fs_punch(fs, ino, &inode, NULL, outdir->num, ~0ULL);
++      return ext2fs_punch(fs, ino, inode, NULL, outdir->num, ~0ULL);
  }
  
 -errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
 +errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
 +                          struct problem_context *pctx)
  {
        ext2_filsys             fs = ctx->fs;
        errcode_t               retval;
        struct ext2_inode       inode;
        char                    *dir_buf = 0;
-       struct fill_dir_struct  fd;
-       struct out_dir          outdir;
+       struct fill_dir_struct  fd = { NULL };
+       struct out_dir          outdir = { 0 };
  
-       outdir.max = outdir.num = 0;
-       outdir.buf = 0;
-       outdir.hashes = 0;
        e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
  
 +      if (ext2fs_has_feature_inline_data(fs->super) &&
 +         (inode.i_flags & EXT4_INLINE_DATA_FL))
 +              return 0;
 +
        retval = ENOMEM;
-       fd.harray = 0;
        dir_buf = malloc(inode.i_size);
        if (!dir_buf)
                goto errout;
        fd.ctx = ctx;
        fd.buf = dir_buf;
        fd.inode = &inode;
-       fd.ino = ino;
-       fd.err = 0;
-       fd.dir_size = 0;
-       fd.compress = 0;
 -      if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
 +      fd.dir = ino;
 +      if (!ext2fs_has_feature_dir_index(fs->super) ||
            (inode.i_size / fs->blocksize) < 2)
                fd.compress = 1;
        fd.parent = 0;
diff --cc e2fsck/unix.c
Simple merge
index db4aa19153e0b77f2b6256ed709b0b2a5a63586d,62ddd50aad10d05ff625046f3a312e11466aafe7..85f45d4bc4b2558e1b70e2e8407146e1e66c4ca6
@@@ -433,35 -439,10 +444,35 @@@ errout
        ext2fs_extent_free(handle);
        return retval;
  }
 +      
 +static errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino,
 +                                        struct ext2_inode *inode,
 +                                        blk64_t start,
 +                                        blk64_t end EXT2FS_ATTR((unused)))
 +{
 +      errcode_t retval;
 +
 +      /*
 +       * In libext2fs ext2fs_punch is based on block unit.  So that
 +       * means that if start > 0 we don't need to do nothing.  Due
 +       * to this we will remove all inline data in ext2fs_punch()
 +       * now.
 +       */
 +      if (start > 0)
 +              return 0;
 +
 +      memset((char *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
 +      inode->i_size = 0;
 +      retval = ext2fs_write_inode(fs, ino, inode);
 +      if (retval)
 +              return retval;
 +
 +      return ext2fs_inline_data_ea_remove(fs, ino);
 +}
  
  /*
-  * Deallocate all logical blocks starting at start to end, inclusive.
-  * If end is ~0, then this is effectively truncate.
+  * Deallocate all logical _blocks_ starting at start to end, inclusive.
+  * If end is ~0ULL, then this is effectively truncate.
   */
  errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
                       struct ext2_inode *inode,
                        return retval;
                inode = &inode_buf;
        }
 -      if (inode->i_flags & EXT4_EXTENTS_FL)
 +      if (inode->i_flags & EXT4_INLINE_DATA_FL)
 +              return ext2fs_punch_inline_data(fs, ino, inode, start, end);
 +      else if (inode->i_flags & EXT4_EXTENTS_FL)
                retval = ext2fs_punch_extent(fs, ino, inode, start, end);
-       else {
-               blk_t   count;
-               if (start > ~0U)
-                       return 0;
-               if (end > ~0U)
-                       end = ~0U;
-               count = ((end - start + 1) < ~0U) ? (end - start + 1) : ~0U;
-               retval = ext2fs_punch_ind(fs, inode, block_buf, 
-                                         (blk_t) start, count);
-       }
+       else
+               retval = ext2fs_punch_ind(fs, inode, block_buf, start, end);
        if (retval)
                return retval;
  
Simple merge
diff --cc misc/tune2fs.c
Simple merge
index e9d9e5b3f967ffd309a61e6599fa605321010c8a,882c321b68665b2ee5298a7f5c5571b18b4cd739..da65f9496b08d49d289755cbe66cd8c370727da0
@@@ -23,12 -15,9 +23,11 @@@ Inode 17 has an invalid exten
        (logical block 0, invalid physical block 22011707397135, len 15)
  Clear? yes
  
 +Inode 17 extent tree (at level 1) could be shorter.  Fix? yes
 +
  Inode 17, i_blocks is 32, should be 0.  Fix? yes
  
- Error while reading over extent tree in inode 18: Corrupt extent header
- Clear inode? yes
+ Inode 18 has corrupt extent header.  Clear inode? yes
  
  Inode 18, i_blocks is 2, should be 0.  Fix? yes