]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
Merge branch 'maint' into next
authorTheodore Ts'o <tytso@mit.edu>
Fri, 27 Jan 2023 17:42:47 +0000 (12:42 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 27 Jan 2023 17:42:47 +0000 (12:42 -0500)
1  2 
debugfs/debugfs.8.in
e2fsck/e2fsck.h
e2fsck/journal.c
e2fsck/pass1.c
e2fsck/pass2.c
e2fsck/rehash.c
lib/ext2fs/ext2fs.h
lib/ext2fs/ismounted.c
misc/mke2fs.c
misc/tune2fs.c

diff --combined debugfs/debugfs.8.in
index a3227a80ab24aeeba2356ab998576b2f081908d7,637d22b3f23467e344527134bbcbd78ae5da73c0..5b5329c38d6e70ebb1a90c27956d1dbef42d3018
@@@ -280,7 -280,7 +280,7 @@@ The hash seed specified wit
  must be in UUID format.
  .TP
  .BI dump_extents " [-n] [-l] filespec"
- Dump the the extent tree of the inode
+ Dump the extent tree of the inode
  .IR filespec .
  The
  .I -n
@@@ -505,7 -505,7 +505,7 @@@ which is a hard link t
  .IR filespec .
  Note this does not adjust the inode reference counts.
  .TP
 -.BI logdump " [-acsOS] [-b block] [-i filespec] [-f journal_file] [output_file]"
 +.BI logdump " [-acsOS] [-b block] [-n num_trans ] [-i filespec] [-f journal_file] [output_file]"
  Dump the contents of the ext3 journal.  By default, dump the journal inode as
  specified in the superblock.  However, this can be overridden with the
  .I \-i
@@@ -528,7 -528,7 +528,7 @@@ Th
  .I \-a
  option causes the
  .B logdump
 -program to print the contents of all of the descriptor blocks.
 +to print the contents of all of the descriptor blocks.
  The
  .I \-b
  option causes
@@@ -548,15 -548,6 +548,15 @@@ Th
  option causes logdump to display old (checkpointed) journal entries.
  This can be used to try to track down journal problems even after the
  journal has been replayed.
 +.IP
 +The
 +.I \-n
 +option causes
 +.B logdump
 +to continue past a journal block which is missing a magic number.
 +Instead, it will stop only when the entire log is printed or after
 +.I num_trans
 +transactions.
  .TP
  .BI ls " [-l] [-c] [-d] [-p] [-r] filespec"
  Print a listing of the files in the directory
diff --combined e2fsck/e2fsck.h
index 252a17db2d23942b87403970d3d2b7b222f3739d,b8caa43b79726a2b8a7e30971ed4b20de90cb51d..3f2dc3084c40c95fd314d2d50d32b373d31dc42a
@@@ -236,7 -236,7 +236,7 @@@ typedef struct e2fsck_struct *e2fsck_t
  #define MAX_EXTENT_DEPTH_COUNT 8
  
  /*
-  * This strucutre is used to manage the list of extents in a file. Placing
+  * This structure is used to manage the list of extents in a file. Placing
   * it here since this is used by fast_commit.h.
   */
  struct extent_list {
@@@ -656,7 -656,6 +656,7 @@@ void sigcatcher_setup(void)
  void check_super_block(e2fsck_t ctx);
  int check_backup_super_block(e2fsck_t ctx);
  void check_resize_inode(e2fsck_t ctx);
 +int check_init_orphan_file(e2fsck_t ctx);
  
  /* util.c */
  extern void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned long size,
diff --combined e2fsck/journal.c
index d802c5e9fd036b41037893efda468af09fbcbf97,bb86f52820d98ef6683fd4f3124e2c376adba68c..c7868d8945c6c964b1dd3ed4aae9b766da653046
@@@ -578,7 -578,7 +578,7 @@@ static int ext4_del_extent_from_list(e2
        return ext4_modify_extent_list(ctx, list, ex, 1 /* delete */);
  }
  
 -static int ext4_fc_read_extents(e2fsck_t ctx, ino_t ino)
 +static int ext4_fc_read_extents(e2fsck_t ctx, ext2_ino_t ino)
  {
        struct extent_list *extent_list = &ctx->fc_replay_state.fc_extent_list;
  
   * for the inode so that we can flush all of them at once and it also saves us
   * from continuously growing and shrinking the extent tree.
   */
 -static void ext4_fc_flush_extents(e2fsck_t ctx, ino_t ino)
 +static void ext4_fc_flush_extents(e2fsck_t ctx, ext2_ino_t ino)
  {
        struct extent_list *extent_list = &ctx->fc_replay_state.fc_extent_list;
  
  
  /* Helper struct for dentry replay routines */
  struct dentry_info_args {
 -      ino_t parent_ino;
 -      int dname_len;
 -      ino_t ino;
 -      char *dname;
 +      ext2_ino_t      parent_ino;
 +      ext2_ino_t      ino;
 +      int             dname_len;
 +      char            *dname;
  };
  
  static inline int tl_to_darg(struct dentry_info_args *darg,
               val + sizeof(struct ext4_fc_dentry_info),
               darg->dname_len);
        darg->dname[darg->dname_len] = 0;
 -      jbd_debug(1, "%s: %s, ino %lu, parent %lu\n",
 +      jbd_debug(1, "%s: %s, ino %u, parent %u\n",
                  le16_to_cpu(tl->fc_tag) == EXT4_FC_TAG_CREAT ? "create" :
                  (le16_to_cpu(tl->fc_tag) == EXT4_FC_TAG_LINK ? "link" :
                   (le16_to_cpu(tl->fc_tag) == EXT4_FC_TAG_UNLINK ? "unlink" :
@@@ -809,7 -809,7 +809,7 @@@ static int ext4_fc_handle_add_extent(e2
  {
        struct ext2fs_extent extent;
        struct ext4_fc_add_range add_range;
 -      ino_t ino;
 +      ext2_ino_t ino;
        int ret = 0;
  
        memcpy(&add_range, val, sizeof(add_range));
@@@ -888,7 -888,7 +888,7 @@@ static int ext4_fc_replay(journal_t *jo
                /*
                 * Mark the file system to indicate it contains errors. That's
                 * because the updates performed by fast commit replay code are
-                * not atomic and may result in incosistent file system if it
+                * not atomic and may result in inconsistent file system if it
                 * crashes before the replay is complete.
                 */
                ctx->fs->super->s_state |= EXT2_ERROR_FS;
@@@ -1039,7 -1039,8 +1039,8 @@@ static errcode_t e2fsck_get_journal(e2f
                        tried_backup_jnl++;
                }
                if (!j_inode->i_ext2.i_links_count ||
-                   !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
+                   !LINUX_S_ISREG(j_inode->i_ext2.i_mode) ||
+                   (j_inode->i_ext2.i_flags & EXT4_ENCRYPT_FL)) {
                        retval = EXT2_ET_NO_JOURNAL;
                        goto try_backup_journal;
                }
diff --combined e2fsck/pass1.c
index 73909c391548e6aaa990d7820f4550f36da395d6,f8dcf61af9c1a130c788082a5f65b8479631be07..591acad53ca8392bbb3f50ba4be4ed6b38d3dfb4
@@@ -79,8 -79,8 +79,8 @@@ static void check_blocks(e2fsck_t ctx, 
  static void mark_table_blocks(e2fsck_t ctx);
  static void alloc_bb_map(e2fsck_t ctx);
  static void alloc_imagic_map(e2fsck_t ctx);
 -static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
 -static void add_casefolded_dir(e2fsck_t ctx, ino_t ino);
 +static void mark_inode_bad(e2fsck_t ctx, ext2_ino_t ino);
 +static void add_casefolded_dir(e2fsck_t ctx, ext2_ino_t ino);
  static void handle_fs_bad_blocks(e2fsck_t ctx);
  static void process_inodes(e2fsck_t ctx, char *block_buf);
  static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
@@@ -914,7 -914,6 +914,7 @@@ static void reserve_block_for_lnf_repai
  }
  
  static errcode_t get_inline_data_ea_size(ext2_filsys fs, ext2_ino_t ino,
 +                                       struct ext2_inode *inode,
                                         size_t *sz)
  {
        void *p;
        if (retval)
                return retval;
  
 -      retval = ext2fs_xattrs_read(handle);
 +      retval = ext2fs_xattrs_read_inode(handle,
 +                                        (struct ext2_inode_large *)inode);
        if (retval)
                goto err;
  
@@@ -1331,7 -1329,7 +1331,7 @@@ void e2fsck_pass1(e2fsck_t ctx
                goto endit;
        }
        block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
-                                                   "block interate buffer");
+                                                   "block iterate buffer");
        if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
                e2fsck_use_inode_shortcuts(ctx, 1);
        e2fsck_intercept_block_allocations(ctx);
                    (ino >= EXT2_FIRST_INODE(fs->super))) {
                        size_t size = 0;
  
 -                      pctx.errcode = get_inline_data_ea_size(fs, ino, &size);
 +                      pctx.errcode = get_inline_data_ea_size(fs, ino, inode,
 +                                                             &size);
                        if (!pctx.errcode &&
                            fix_problem(ctx, PR_1_INLINE_DATA_FEATURE, &pctx)) {
                                ext2fs_set_feature_inline_data(sb);
                        flags = fs->flags;
                        if (failed_csum)
                                fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
 -                      err = get_inline_data_ea_size(fs, ino, &size);
 +                      err = get_inline_data_ea_size(fs, ino, inode, &size);
                        fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
                                    (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
  
                                                        inode_size, "pass1");
                                failed_csum = 0;
                        }
 +              } else if (ino == fs->super->s_orphan_file_inum) {
 +                      ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
 +                      if (ext2fs_has_feature_orphan_file(fs->super)) {
 +                              if (!LINUX_S_ISREG(inode->i_mode) &&
 +                                  fix_problem(ctx, PR_1_ORPHAN_FILE_BAD_MODE,
 +                                              &pctx)) {
 +                                      inode->i_mode = LINUX_S_IFREG;
 +                                      e2fsck_write_inode(ctx, ino, inode,
 +                                                         "pass1");
 +                                      failed_csum = 0;
 +                              }
 +                              check_blocks(ctx, &pctx, block_buf, NULL);
 +                              FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
 +                              continue;
 +                      }
 +                      if ((inode->i_links_count ||
 +                           inode->i_blocks || inode->i_block[0]) &&
 +                          fix_problem(ctx, PR_1_ORPHAN_FILE_NOT_CLEAR,
 +                                      &pctx)) {
 +                              memset(inode, 0, inode_size);
 +                              ext2fs_icount_store(ctx->inode_link_info, ino,
 +                                                  0);
 +                              e2fsck_write_inode_full(ctx, ino, inode,
 +                                                      inode_size, "pass1");
 +                              failed_csum = 0;
 +                      }
                } else if (ino < EXT2_FIRST_INODE(fs->super)) {
                        problem_t problem = 0;
  
@@@ -2234,7 -2205,7 +2234,7 @@@ static EXT2_QSORT_TYPE process_inode_cm
  /*
   * Mark an inode as being bad in some what
   */
 -static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
 +static void mark_inode_bad(e2fsck_t ctx, ext2_ino_t ino)
  {
        struct          problem_context pctx;
  
        ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino);
  }
  
 -static void add_casefolded_dir(e2fsck_t ctx, ino_t ino)
 +static void add_casefolded_dir(e2fsck_t ctx, ext2_ino_t ino)
  {
        struct          problem_context pctx;
  
@@@ -3516,7 -3487,6 +3516,7 @@@ static void check_blocks(e2fsck_t ctx, 
        }
  
        if (ino != quota_type2inum(PRJQUOTA, fs->super) &&
 +          ino != fs->super->s_orphan_file_inum &&
            (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) &&
            !(inode->i_flags & EXT4_EA_INODE_FL)) {
                quota_data_add(ctx->qctx, (struct ext2_inode_large *) inode,
diff --combined e2fsck/pass2.c
index bc6ffa1829035247331a7f123d4b0d2821d75f30,28736094355e5502b04a96baa4af4cb2b0f9e444..410edd1167590ff33c64611f914e46ed4a870fcd
@@@ -1446,8 -1446,7 +1446,8 @@@ skip_checksum
                    (dirent->inode > fs->super->s_inodes_count) ||
                    (dirent->inode == fs->super->s_usr_quota_inum) ||
                    (dirent->inode == fs->super->s_grp_quota_inum) ||
 -                  (dirent->inode == fs->super->s_prj_quota_inum)) {
 +                  (dirent->inode == fs->super->s_prj_quota_inum) ||
 +                  (dirent->inode == fs->super->s_orphan_file_inum)) {
                        problem = PR_2_BAD_INO;
                } else if (ctx->inode_bb_map &&
                           (ext2fs_test_inode_bitmap2(ctx->inode_bb_map,
@@@ -1812,7 -1811,7 +1812,7 @@@ struct del_block 
  };
  
  /*
-  * This function is called to deallocate a block, and is an interator
+  * This function is called to deallocate a block, and is an iterator
   * functioned called by deallocate inode via ext2fs_iterate_block().
   */
  static int deallocate_inode_block(ext2_filsys fs,
diff --combined e2fsck/rehash.c
index f7b19f62f92f78e6dc4de97351cd5be41e3cc150,c79a5acf9401c38a3ae9c799bc29aada446aa2e7..c1da7d52724e9644a9e7ac45fc469868eb93f376
@@@ -89,9 -89,9 +89,9 @@@ struct fill_dir_struct 
  };
  
  struct hash_entry {
 -      ext2_dirhash_t  hash;
 -      ext2_dirhash_t  minor_hash;
 -      ino_t           ino;
 +      ext2_dirhash_t          hash;
 +      ext2_dirhash_t          minor_hash;
 +      ext2_ino_t              ino;
        struct ext2_dir_entry   *dir;
  };
  
@@@ -1053,13 -1053,11 +1053,11 @@@ retry_nohash
        /* Sort the list */
  resort:
        if (fd.compress && fd.num_array > 1)
-               sort_r_simple(fd.harray+2, fd.num_array-2,
-                             sizeof(struct hash_entry),
-                             hash_cmp, &name_cmp_ctx);
+               sort_r(fd.harray+2, fd.num_array-2, sizeof(struct hash_entry),
+                      hash_cmp, &name_cmp_ctx);
        else
-               sort_r_simple(fd.harray, fd.num_array,
-                             sizeof(struct hash_entry),
-                             hash_cmp, &name_cmp_ctx);
+               sort_r(fd.harray, fd.num_array, sizeof(struct hash_entry),
+                      hash_cmp, &name_cmp_ctx);
  
        /*
         * Look for duplicates
diff --combined lib/ext2fs/ext2fs.h
index 9cc994b16517ef9de7fffdfac301e3c77ef1b15f,59f24ca98943715355f537f37ff4ffd2b0410d61..80206870d5c015159ea17c9d6332d3449db7149c
@@@ -355,9 -355,9 +355,9 @@@ struct struct_ext2_filsys 
  #define BLOCK_INLINE_DATA_CHANGED     8
  
  /*
-  * Block interate flags
+  * Block iterate flags
   *
-  * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the interator
+  * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the iterator
   * function should be called on blocks where the block number is zero.
   * This is used by ext2fs_expand_dir() to be able to add a new block
   * to an inode.  It can also be used for programs that want to be able
@@@ -532,7 -532,6 +532,7 @@@ typedef struct ext2_struct_inode_scan *
  #define EXT2_MF_READONLY      4
  #define EXT2_MF_SWAP          8
  #define EXT2_MF_BUSY          16
 +#define EXT2_MF_EXTFS         32
  
  /*
   * Ext2/linux mode flags.  We define them here so that we don't need
@@@ -634,8 -633,7 +634,8 @@@ typedef struct ext2_icount *ext2_icount
                                         EXT2_FEATURE_COMPAT_EXT_ATTR|\
                                         EXT4_FEATURE_COMPAT_SPARSE_SUPER2|\
                                         EXT4_FEATURE_COMPAT_FAST_COMMIT|\
 -                                       EXT4_FEATURE_COMPAT_STABLE_INODES)
 +                                       EXT4_FEATURE_COMPAT_STABLE_INODES|\
 +                                       EXT4_FEATURE_COMPAT_ORPHAN_FILE)
  
  #ifdef CONFIG_MMP
  #define EXT4_LIB_INCOMPAT_MMP         EXT4_FEATURE_INCOMPAT_MMP
                                         EXT4_FEATURE_RO_COMPAT_READONLY |\
                                         EXT4_FEATURE_RO_COMPAT_PROJECT |\
                                         EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS |\
 -                                       EXT4_FEATURE_RO_COMPAT_VERITY)
 +                                       EXT4_FEATURE_RO_COMPAT_VERITY |\
 +                                       EXT4_FEATURE_RO_COMPAT_ORPHAN_PRESENT)
  
  /*
   * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed
@@@ -1292,8 -1289,6 +1292,8 @@@ extern errcode_t ext2fs_adjust_ea_refco
                                           ext2_ino_t inum);
  errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle);
  errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle);
 +errcode_t ext2fs_xattrs_read_inode(struct ext2_xattr_handle *handle,
 +                                 struct ext2_inode_large *inode);
  errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
                                int (*func)(char *name, char *value,
                                            size_t value_len, void *data),
@@@ -1705,19 -1700,6 +1705,19 @@@ errcode_t ext2fs_get_data_io(ext2_filsy
  errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io);
  errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io);
  
 +/* orphan.c */
 +extern errcode_t ext2fs_create_orphan_file(ext2_filsys fs, blk_t num_blocks);
 +extern errcode_t ext2fs_truncate_orphan_file(ext2_filsys fs);
 +extern e2_blkcnt_t ext2fs_default_orphan_file_blocks(ext2_filsys fs);
 +extern __u32 ext2fs_do_orphan_file_block_csum(ext2_filsys fs, ext2_ino_t ino,
 +                                            __u32 gen, blk64_t blk,
 +                                            char *buf);
 +extern errcode_t ext2fs_orphan_file_block_csum_set(ext2_filsys fs,
 +                                                 ext2_ino_t ino, blk64_t blk,
 +                                                 char *buf);
 +extern int ext2fs_orphan_file_block_csum_verify(ext2_filsys fs, ext2_ino_t ino,
 +                                              blk64_t blk, char *buf);
 +
  /* get_pathname.c */
  extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
                               char **name);
@@@ -1871,9 -1853,7 +1871,9 @@@ extern int ext2fs_dirent_file_type(cons
  extern void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type);
  extern struct ext2_inode *ext2fs_inode(struct ext2_inode_large * large_inode);
  extern const struct ext2_inode *ext2fs_const_inode(const struct ext2_inode_large * large_inode);
 -
 +extern int ext2fs_inodes_per_orphan_block(ext2_filsys fs);
 +extern struct ext4_orphan_block_tail *ext2fs_orphan_block_tail(ext2_filsys fs,
 +                                                             char *buf);
  #endif
  
  /*
@@@ -2183,19 -2163,6 +2183,19 @@@ ext2fs_const_inode(const struct ext2_in
        return (const struct ext2_inode *) large_inode;
  }
  
 +_INLINE_ int ext2fs_inodes_per_orphan_block(ext2_filsys fs)
 +{
 +      return (fs->blocksize - sizeof(struct ext4_orphan_block_tail)) /
 +              sizeof(__u32);
 +}
 +
 +_INLINE_ struct ext4_orphan_block_tail *
 +ext2fs_orphan_block_tail(ext2_filsys fs, char *buf)
 +{
 +      return (struct ext4_orphan_block_tail *)(buf + fs->blocksize -
 +              sizeof(struct ext4_orphan_block_tail));
 +}
 +
  #undef _INLINE_
  #endif
  
diff --combined lib/ext2fs/ismounted.c
index f4fcdfd02cc4893dcb12fc1c073e8c8b1e40a039,fe64e8bb345a78846ce8a2d320530d43e60011dd..22bc8352bec128af2bd96e7b18c21780c0d5a5b0
@@@ -97,7 -97,7 +97,7 @@@ static errcode_t check_mntent_file(cons
                                   int *mount_flags, char *mtpt, int mtlen)
  {
        struct mntent   *mnt;
-       struct stat     st_buf;
+       struct stat     st_buf, dir_st_buf;
        errcode_t       retval = 0;
        dev_t           file_dev=0, file_rdev=0;
        ino_t           file_ino=0;
                if (stat(mnt->mnt_fsname, &st_buf) == 0) {
                        if (ext2fsP_is_disk_device(st_buf.st_mode)) {
  #ifndef __GNU__
-                               if (file_rdev && (file_rdev == st_buf.st_rdev))
-                                       break;
+                               if (file_rdev &&
+                                   (file_rdev == st_buf.st_rdev)) {
+                                       if (stat(mnt->mnt_dir,
+                                                &dir_st_buf) != 0)
+                                               continue;
+                                       if (file_rdev == dir_st_buf.st_dev)
+                                               break;
+                               }
                                if (check_loop_mounted(mnt->mnt_fsname,
                                                st_buf.st_rdev, file_dev,
                                                file_ino) == 1)
@@@ -207,12 -213,6 +213,12 @@@ is_root
                        close(fd);
                (void) unlink(TEST_FILE);
        }
 +
 +      if (mnt && mnt->mnt_type &&
 +          (!strcmp(mnt->mnt_type, "ext4") ||
 +           !strcmp(mnt->mnt_type, "ext3") ||
 +           !strcmp(mnt->mnt_type, "ext2")))
 +              *mount_flags |= EXT2_MF_EXTFS;
        retval = 0;
  errout:
        endmntent (f);
diff --combined misc/mke2fs.c
index bde1e582e3fac6734a18ffb6600df73e12dc5cbc,ba5f179a2539941bd9b5a3697e48f567712763ea..4a9c1b0924a9b09151a11995f82d22323a846ed7
@@@ -94,9 -94,7 +94,9 @@@ static gid_t  root_gid
  int   journal_size;
  int   journal_flags;
  int   journal_fc_size;
 +static e2_blkcnt_t    orphan_file_blocks;
  static int    lazy_itable_init;
 +static int    assume_storage_prezeroed;
  static int    packed_meta_blocks;
  int           no_copy_xattrs;
  static char   *bad_blocks_filename = NULL;
@@@ -1014,11 -1012,6 +1014,11 @@@ static void parse_extended_opts(struct 
                                lazy_itable_init = strtoul(arg, &p, 0);
                        else
                                lazy_itable_init = 1;
 +              } else if (!strcmp(token, "assume_storage_prezeroed")) {
 +                      if (arg)
 +                              assume_storage_prezeroed = strtoul(arg, &p, 0);
 +                      else
 +                              assume_storage_prezeroed = 1;
                } else if (!strcmp(token, "lazy_journal_init")) {
                        if (arg)
                                journal_flags |= strtoul(arg, &p, 0) ?
                                continue;
                        }
                        encoding_flags = arg;
 +              } else if (!strcmp(token, "orphan_file_size")) {
 +                      if (!arg) {
 +                              r_usage++;
 +                              badopt = token;
 +                              continue;
 +                      }
 +                      orphan_file_blocks = parse_num_blocks2(arg,
 +                                              fs_param.s_log_block_size);
 +                      if (orphan_file_blocks == 0) {
 +                              fprintf(stderr,
 +                                      _("Invalid size of orphan file %s\n"),
 +                                      arg);
 +                              r_usage++;
 +                              continue;
 +                      }
                } else {
                        r_usage++;
                        badopt = token;
                        "\tnodiscard\n"
                        "\tencoding=<encoding>\n"
                        "\tencoding_flags=<flags>\n"
 -                      "\tquotatype=<quota type(s) to be enabled>\n\n"),
 +                      "\tquotatype=<quota type(s) to be enabled>\n"
 +                      "\tassume_storage_prezeroed=<0 to disable, 1 to enable>\n\n"),
                        badopt ? badopt : "");
                free(buf);
                exit(1);
@@@ -1179,8 -1156,7 +1179,8 @@@ static __u32 ok_features[3] = 
                EXT2_FEATURE_COMPAT_EXT_ATTR |
                EXT4_FEATURE_COMPAT_SPARSE_SUPER2 |
                EXT4_FEATURE_COMPAT_FAST_COMMIT |
 -              EXT4_FEATURE_COMPAT_STABLE_INODES,
 +              EXT4_FEATURE_COMPAT_STABLE_INODES |
 +              EXT4_FEATURE_COMPAT_ORPHAN_FILE,
        /* Incompat */
        EXT2_FEATURE_INCOMPAT_FILETYPE|
                EXT3_FEATURE_INCOMPAT_EXTENTS|
@@@ -1506,7 -1482,7 +1506,7 @@@ extern const char *mke2fs_default_profi
  static const char *default_files[] = { "<default>", 0 };
  
  struct device_param {
-       unsigned long min_io;           /* prefered minimum IO size */
+       unsigned long min_io;           /* preferred minimum IO size */
        unsigned long opt_io;           /* optimal IO size */
        unsigned long alignment_offset; /* alignment offset wrt physical block size */
        unsigned int dax:1;             /* supports dax? */
@@@ -1575,8 -1551,6 +1575,8 @@@ static void PRS(int argc, char *argv[]
        int             lsector_size = 0, psector_size = 0;
        int             show_version_only = 0, is_device = 0;
        unsigned long long num_inodes = 0; /* unsigned long long to catch too-large input */
 +      int             default_orphan_file = 0;
 +      int             default_csum_seed = 0;
        errcode_t       retval;
        char *          oldpath = getenv("PATH");
        char *          extended_opts = 0;
         * Finally, we complain about fs_blocks_count > 2^32 on a non-64bit fs.
         */
        blk64_t         fs_blocks_count = 0;
-       long            sysval;
        int             s_opt = -1, r_opt = -1;
        char            *fs_features = 0;
        int             fs_features_size = 0;
  #define _SC_PAGESIZE _SC_PAGE_SIZE
  #endif
  #ifdef _SC_PAGESIZE
-       sysval = sysconf(_SC_PAGESIZE);
-       if (sysval > 0)
-               sys_page_size = sysval;
+       {
+               long sysval = sysconf(_SC_PAGESIZE);
+               if (sysval > 0)
+                       sys_page_size = sysval;
+       }
  #endif /* _SC_PAGESIZE */
  #endif /* HAVE_SYSCONF */
  
@@@ -1950,10 -1926,10 +1952,10 @@@ profile_error
  #ifdef CONFIG_TESTIO_DEBUG
                if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
                        io_ptr = test_io_manager;
-                       test_io_backing_manager = unix_io_manager;
+                       test_io_backing_manager = default_io_manager;
                } else
  #endif
-                       io_ptr = unix_io_manager;
+                       io_ptr = default_io_manager;
                retval = ext2fs_open(journal_device,
                                     EXT2_FLAG_JOURNAL_DEV_OK, 0,
                                     0, io_ptr, &jfs);
                ext2fs_clear_feature_ea_inode(&fs_param);
                ext2fs_clear_feature_casefold(&fs_param);
        }
 -      edit_feature(fs_features ? fs_features : tmp,
 -                   &fs_param.s_feature_compat);
 +      if (!fs_features && tmp)
 +              edit_feature(tmp, &fs_param.s_feature_compat);
 +      /*
 +       * Now all the defaults are incorporated in fs_param. Check the state
 +       * of orphan_file feature so that we know whether we should silently
 +       * disabled in case journal gets disabled.
 +       */
 +      if (ext2fs_has_feature_orphan_file(&fs_param))
 +              default_orphan_file = 1;
 +      if (ext2fs_has_feature_csum_seed(&fs_param))
 +              default_csum_seed = 1;
 +      if (fs_features)
 +              edit_feature(fs_features, &fs_param.s_feature_compat);
 +      /* Silently disable orphan_file if user chose fs without journal */
 +      if (default_orphan_file && !ext2fs_has_feature_journal(&fs_param))
 +              ext2fs_clear_feature_orphan_file(&fs_param);
 +      if (default_csum_seed && !ext2fs_has_feature_metadata_csum(&fs_param))
 +              ext2fs_clear_feature_csum_seed(&fs_param);
        if (tmp)
                free(tmp);
        (void) ext2fs_free_mem(&fs_features);
@@@ -2736,7 -2696,7 +2738,7 @@@ static int should_do_undo(const char *n
        io_channel channel;
        __u16   s_magic;
        struct ext2_super_block super;
-       io_manager manager = unix_io_manager;
+       io_manager manager = default_io_manager;
        int csum_flag, force_undo;
  
        csum_flag = ext2fs_has_feature_metadata_csum(&fs_param) ||
@@@ -3041,10 -3001,10 +3043,10 @@@ int main (int argc, char *argv[]
  #ifdef CONFIG_TESTIO_DEBUG
        if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
                io_ptr = test_io_manager;
-               test_io_backing_manager = unix_io_manager;
+               test_io_backing_manager = default_io_manager;
        } else
  #endif
-               io_ptr = unix_io_manager;
+               io_ptr = default_io_manager;
  
        if (undo_file != NULL || should_do_undo(device_name)) {
                retval = mke2fs_setup_tdb(device_name, &io_ptr);
                io_channel_set_options(fs->io, opt_string);
        }
  
 +      if (assume_storage_prezeroed) {
 +              if (verbose)
 +                      printf("%s",
 +                             _("Assuming the storage device is prezeroed "
 +                             "- skipping inode table and journal wipe\n"));
 +
 +              lazy_itable_init = 1;
 +              itable_zeroed = 1;
 +              zero_hugefile = 0;
 +              journal_flags |= EXT2_MKJOURNAL_LAZYINIT;
 +      }
 +
        /* Can't undo discard ... */
        if (!noaction && discard && dev_size && (io_ptr != undo_io_manager)) {
                retval = mke2fs_discard_device(fs);
  
                retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
                                     EXT2_FLAG_JOURNAL_DEV_OK, 0,
-                                    fs->blocksize, unix_io_manager, &jfs);
+                                    fs->blocksize, default_io_manager, &jfs);
                if (retval) {
                        com_err(program_name, retval,
                                _("while trying to open journal device %s\n"),
  
                if (!jparams.num_journal_blocks) {
                        ext2fs_clear_feature_journal(fs->super);
 +                      ext2fs_clear_feature_orphan_file(fs->super);
 +                      ext2fs_clear_feature_journal(&fs_param);
 +                      ext2fs_clear_feature_orphan_file(&fs_param);
                        goto no_journal;
                }
                if (!quiet) {
@@@ -3528,23 -3473,6 +3530,23 @@@ no_journal
                fix_cluster_bg_counts(fs);
        if (ext2fs_has_feature_quota(&fs_param))
                create_quota_inodes(fs);
 +      if (ext2fs_has_feature_orphan_file(&fs_param)) {
 +              if (!ext2fs_has_feature_journal(&fs_param)) {
 +                      com_err(program_name, 0, _("cannot set orphan_file "
 +                              "feature without a journal."));
 +                      exit(1);
 +              }
 +              if (!orphan_file_blocks) {
 +                      orphan_file_blocks =
 +                              ext2fs_default_orphan_file_blocks(fs);
 +              }
 +              retval = ext2fs_create_orphan_file(fs, orphan_file_blocks);
 +              if (retval) {
 +                      com_err(program_name, retval,
 +                              _("while creating orphan file"));
 +                      exit(1);
 +              }
 +      }
  
        retval = mk_hugefiles(fs, device_name);
        if (retval)
diff --combined misc/tune2fs.c
index 088f87e5349796ad93304fc80bf58b0919d90d0a,cb5f575a3b5c236d4109244da5e8af7e084ab741..5fe22e6a583a386cf7823e4d2842093e1570797c
@@@ -52,9 -52,6 +52,9 @@@ extern int optind
  #include <sys/types.h>
  #include <libgen.h>
  #include <limits.h>
 +#ifdef HAVE_SYS_IOCTL_H
 +#include <sys/ioctl.h>
 +#endif
  
  #include "ext2fs/ext2_fs.h"
  #include "ext2fs/ext2fs.h"
  #define QOPT_ENABLE   (1)
  #define QOPT_DISABLE  (-1)
  
 +#ifndef FS_IOC_SETFSLABEL
 +#define FSLABEL_MAX 256
 +#define FS_IOC_SETFSLABEL     _IOW(0x94, 50, char[FSLABEL_MAX])
 +#endif
 +
 +#ifndef FS_IOC_GETFSLABEL
 +#define FS_IOC_GETFSLABEL     _IOR(0x94, 49, char[FSLABEL_MAX])
 +#endif
 +
 +struct fsuuid {
 +      __u32   fsu_len;
 +      __u32   fsu_flags;
 +      __u8    fsu_uuid[];
 +};
 +
 +#ifndef EXT4_IOC_GETFSUUID
 +#define EXT4_IOC_GETFSUUID    _IOR('f', 44, struct fsuuid)
 +#endif
 +
 +#ifndef EXT4_IOC_SETFSUUID
 +#define EXT4_IOC_SETFSUUID    _IOW('f', 44, struct fsuuid)
 +#endif
 +
  extern int ask_yn(const char *string, int def);
  
  const char *program_name = "tune2fs";
  char *device_name;
 -char *new_label, *new_last_mounted, *new_UUID;
 +char *new_label, *new_last_mounted, *requested_uuid;
  char *io_options;
  static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
  static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
@@@ -133,7 -107,6 +133,7 @@@ int enabling_casefold
  int journal_size, journal_fc_size, journal_flags;
  char *journal_device;
  static blk64_t journal_location = ~0LL;
 +static e2_blkcnt_t orphan_file_blocks;
  
  static struct list_head blk_move_list;
  
@@@ -180,8 -153,7 +180,8 @@@ static __u32 ok_features[3] = 
        EXT3_FEATURE_COMPAT_HAS_JOURNAL |
                EXT2_FEATURE_COMPAT_DIR_INDEX |
                EXT4_FEATURE_COMPAT_FAST_COMMIT |
 -              EXT4_FEATURE_COMPAT_STABLE_INODES,
 +              EXT4_FEATURE_COMPAT_STABLE_INODES |
 +              EXT4_FEATURE_COMPAT_ORPHAN_FILE,
        /* Incompat */
        EXT2_FEATURE_INCOMPAT_FILETYPE |
                EXT3_FEATURE_INCOMPAT_EXTENTS |
@@@ -212,15 -184,13 +212,15 @@@ static __u32 clear_ok_features[3] = 
        EXT3_FEATURE_COMPAT_HAS_JOURNAL |
                EXT2_FEATURE_COMPAT_RESIZE_INODE |
                EXT2_FEATURE_COMPAT_DIR_INDEX |
 -              EXT4_FEATURE_COMPAT_FAST_COMMIT,
 +              EXT4_FEATURE_COMPAT_FAST_COMMIT |
 +              EXT4_FEATURE_COMPAT_ORPHAN_FILE,
        /* Incompat */
        EXT2_FEATURE_INCOMPAT_FILETYPE |
                EXT4_FEATURE_INCOMPAT_FLEX_BG |
                EXT4_FEATURE_INCOMPAT_MMP |
                EXT4_FEATURE_INCOMPAT_64BIT |
 -              EXT4_FEATURE_INCOMPAT_CSUM_SEED,
 +              EXT4_FEATURE_INCOMPAT_CSUM_SEED |
 +              EXT4_FEATURE_INCOMPAT_CASEFOLD,
        /* R/O compat */
        EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
                EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@@ -960,7 -930,7 +960,7 @@@ static void rewrite_inodes(ext2_filsys 
        ext2fs_free_mem(&ctx.ea_buf);
  }
  
- static void rewrite_metadata_checksums(ext2_filsys fs, unsigned int flags)
+ static errcode_t rewrite_metadata_checksums(ext2_filsys fs, unsigned int flags)
  {
        errcode_t retval;
        dgrp_t i;
        rewrite_inodes(fs, flags);
        ext2fs_mark_ib_dirty(fs);
        ext2fs_mark_bb_dirty(fs);
-       ext2fs_mmp_update2(fs, 1);
+       retval = ext2fs_mmp_update2(fs, 1);
+       if (retval)
+               return retval;
        fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
        fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
        if (ext2fs_has_feature_metadata_csum(fs->super))
        else
                fs->super->s_checksum_type = 0;
        ext2fs_mark_super_dirty(fs);
+       return 0;
  }
  
  static void enable_uninit_bg(ext2_filsys fs)
        return retval;
  }
  
 +static int has_casefold_inode(ext2_filsys fs)
 +{
 +      int length = EXT2_INODE_SIZE(fs->super);
 +      struct ext2_inode *inode = NULL;
 +      ext2_inode_scan scan;
 +      errcode_t       retval;
 +      ext2_ino_t      ino;
 +      int found_casefold = 0;
 +
 +      retval = ext2fs_get_mem(length, &inode);
 +      if (retval)
 +              fatal_err(retval, "while allocating memory");
 +
 +      retval = ext2fs_open_inode_scan(fs, 0, &scan);
 +      if (retval)
 +              fatal_err(retval, "while opening inode scan");
 +
 +      do {
 +              retval = ext2fs_get_next_inode_full(scan, &ino, inode, length);
 +              if (retval)
 +                      fatal_err(retval, "while getting next inode");
 +              if (!ino)
 +                      break;
 +
 +              if(inode->i_flags & EXT4_CASEFOLD_FL) {
 +                      found_casefold = 1;
 +                      break;
 +              }
 +      } while(1);
 +
 +      ext2fs_free_mem(&inode);
 +      ext2fs_close_inode_scan(scan);
 +      return found_casefold;
 +}
 +
  static errcode_t disable_uninit_bg(ext2_filsys fs, __u32 csum_feature_flag)
  {
        struct ext2_group_desc *gd;
@@@ -1211,56 -1149,6 +1214,56 @@@ static int update_feature_set(ext2_fils
                }
        }
  
 +      if (FEATURE_OFF(E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_ORPHAN_FILE)) {
 +              ext2_ino_t ino;
 +
 +              if (mount_flags & EXT2_MF_MOUNTED) {
 +                      fputs(_("The orphan_file feature may only be cleared "
 +                              "when the filesystem is unmounted.\n"), stderr);
 +                      return 1;
 +              }
 +              if (ext2fs_has_feature_orphan_present(sb) && f_flag < 2) {
 +                      fputs(_("The orphan_present feature is set. Please "
 +                              "run e2fsck before clearing orphan_file "
 +                              "feature.\n"),
 +                            stderr);
 +                      return 1;
 +              }
 +              err = ext2fs_read_bitmaps(fs);
 +              if (err) {
 +                      com_err(program_name, err, "%s",
 +                              _("while loading bitmaps"));
 +                      return 1;
 +              }
 +              err = ext2fs_truncate_orphan_file(fs);
 +              if (err) {
 +                      com_err(program_name, err,
 +                              _("\n\twhile trying to delete orphan file\n"));
 +                      return 1;
 +              }
 +              ino = sb->s_orphan_file_inum;
 +              sb->s_orphan_file_inum = 0;
 +              ext2fs_inode_alloc_stats2(fs, ino, -1, 0);
 +              ext2fs_clear_feature_orphan_file(sb);
 +              ext2fs_clear_feature_orphan_present(sb);
 +              ext2fs_mark_super_dirty(fs);
 +      }
 +
 +      if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_ORPHAN_FILE)) {
 +              if (!ext2fs_has_feature_journal(sb)) {
 +                      fputs(_("orphan_file feature can be set only for "
 +                              "filesystems with journal.\n"), stderr);
 +                      return 1;
 +              }
 +              /*
 +               * If adding an orphan file, let the create orphan file
 +               * code below handle setting the flag and creating it.
 +               * We supply a default size if necessary.
 +               */
 +              orphan_file_blocks = ext2fs_default_orphan_file_blocks(fs);
 +              ext2fs_set_feature_orphan_file(sb);
 +      }
 +
        if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
                EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
                if (ext2fs_has_feature_meta_bg(sb)) {
@@@ -1605,22 -1493,6 +1608,22 @@@ mmp_error
                enabling_casefold = 1;
        }
  
 +      if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD)) {
 +              if (mount_flags & EXT2_MF_MOUNTED) {
 +                      fputs(_("The casefold feature may only be disabled when "
 +                              "the filesystem is unmounted.\n"), stderr);
 +                      return 1;
 +              }
 +              if (has_casefold_inode(fs)) {
 +                      fputs(_("The casefold feature can't be cleared when "
 +                                      "there are inodes with +F flag.\n"), stderr);
 +                      return 1;
 +              }
 +              fs->super->s_encoding = 0;
 +              fs->super->s_encoding_flags = 0;
 +              enabling_casefold = 0;
 +      }
 +
        if (FEATURE_ON(E2P_FEATURE_INCOMPAT,
                EXT4_FEATURE_INCOMPAT_CSUM_SEED)) {
                if (!ext2fs_has_feature_metadata_csum(sb)) {
@@@ -2169,7 -2041,7 +2172,7 @@@ static void parse_tune2fs_options(int a
                                open_flag = EXT2_FLAG_RW;
                                break;
                case 'U':
 -                      new_UUID = optarg;
 +                      requested_uuid = optarg;
                        U_flag = 1;
                        open_flag = EXT2_FLAG_RW |
                                EXT2_FLAG_JOURNAL_DEV_OK;
@@@ -2401,21 -2273,6 +2404,21 @@@ static int parse_extended_opts(ext2_fil
                                continue;
                        }
                        encoding_flags = arg;
 +              } else if (!strcmp(token, "orphan_file_size")) {
 +                      if (!arg) {
 +                              r_usage++;
 +                              continue;
 +                      }
 +                      orphan_file_blocks = parse_num_blocks2(arg,
 +                                               fs->super->s_log_block_size);
 +
 +                      if (orphan_file_blocks < 1) {
 +                              fprintf(stderr,
 +                                      _("Invalid size of orphan file %s\n"),
 +                                      arg);
 +                              r_usage++;
 +                              continue;
 +                      }
                } else
                        r_usage++;
        }
@@@ -3076,79 -2933,6 +3079,79 @@@ fs_update_journal_user(struct ext2_supe
        return 0;
  }
  
 +/*
 + * Use FS_IOC_SETFSLABEL or FS_IOC_GETFSLABEL to set/get file system label
 + * Return:    0 on success
 + *            1 on error
 + *            -1 when the old method should be used
 + */
 +int handle_fslabel(int setlabel) {
 +      errcode_t ret;
 +      int mnt_flags, fd;
 +      char label[FSLABEL_MAX];
 +      int maxlen = FSLABEL_MAX - 1;
 +      char mntpt[PATH_MAX + 1];
 +
 +#ifdef __linux__
 +      ret = ext2fs_check_mount_point(device_name, &mnt_flags,
 +                                        mntpt, sizeof(mntpt));
 +      if (ret) {
 +              com_err(device_name, ret, _("while checking mount status"));
 +              return 1;
 +      }
 +      if (!(mnt_flags & EXT2_MF_MOUNTED) ||
 +          (setlabel && (mnt_flags & EXT2_MF_READONLY)))
 +              return -1;
 +
 +      if (!mntpt[0]) {
 +              fprintf(stderr,_("Unknown mount point for %s\n"), device_name);
 +              return 1;
 +      }
 +
 +      fd = open(mntpt, O_RDONLY);
 +      if (fd < 0) {
 +              com_err(mntpt, errno, _("while opening mount point"));
 +              return 1;
 +      }
 +
 +      /* Get fs label */
 +      if (!setlabel) {
 +              if (ioctl(fd, FS_IOC_GETFSLABEL, &label)) {
 +                      close(fd);
 +                      if (errno == ENOTTY)
 +                              return -1;
 +                      com_err(mntpt, errno, _("while trying to get fs label"));
 +                      return 1;
 +              }
 +              close(fd);
 +              printf("%.*s\n", EXT2_LEN_STR(label));
 +              return 0;
 +      }
 +
 +      /* If it's extN file system, truncate the label to appropriate size */
 +      if (mnt_flags & EXT2_MF_EXTFS)
 +              maxlen = EXT2_LABEL_LEN;
 +      if (strlen(new_label) > maxlen) {
 +              fputs(_("Warning: label too long, truncating.\n"),
 +                    stderr);
 +              new_label[maxlen] = '\0';
 +      }
 +
 +      /* Set fs label */
 +      if (ioctl(fd, FS_IOC_SETFSLABEL, new_label)) {
 +              close(fd);
 +              if (errno == ENOTTY)
 +                      return -1;
 +              com_err(mntpt, errno, _("while trying to set fs label"));
 +              return 1;
 +      }
 +      close(fd);
 +      return 0;
 +#else
 +      return -1;
 +#endif
 +}
 +
  #ifndef BUILD_AS_LIB
  int main(int argc, char **argv)
  #else
@@@ -3161,9 -2945,6 +3164,9 @@@ int tune2fs_main(int argc, char **argv
        io_manager io_ptr, io_ptr_orig = NULL;
        int rc = 0;
        char default_undo_file[1] = { 0 };
 +      char mntpt[PATH_MAX + 1] = { 0 };
 +      int fd = -1;
 +      struct fsuuid *fsuuid = NULL;
  
  #ifdef ENABLE_NLS
        setlocale(LC_MESSAGES, "");
  #endif
                io_ptr = unix_io_manager;
  
 +      /*
 +       * Try the get/set fs label using ioctls before we even attempt
 +       * to open the file system.
 +       */
 +      if (L_flag || print_label) {
 +              rc = handle_fslabel(L_flag);
 +              if (rc != -1) {
 +#ifndef BUILD_AS_LIB
 +                      exit(rc);
 +#endif
 +                      return rc;
 +              }
 +              rc = 0;
 +      }
 +
  retry_open:
        if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag)
                open_flag |= EXT2_FLAG_SKIP_MMP;
                goto closefs;
        }
  
 -      retval = ext2fs_check_if_mounted(device_name, &mount_flags);
 +      retval = ext2fs_check_mount_point(device_name, &mount_flags,
 +                                      mntpt, sizeof(mntpt));
        if (retval) {
 -              com_err("ext2fs_check_if_mount", retval,
 +              com_err("ext2fs_check_mount_point", retval,
                        _("while determining whether %s is mounted."),
                        device_name);
                rc = 1;
@@@ -3343,7 -3108,9 +3346,9 @@@ _("Warning: The journal is dirty. You m
                if (retval) {
                        com_err("tune2fs", retval,
                                "while recovering journal.\n");
-                       printf(_("Please run e2fsck -fy %s.\n"), argv[1]);
+                       printf(_("Please run e2fsck -fy %s.\n"), device_name);
+                       if (!fs)
+                               exit(1);
                        rc = 1;
                        goto closefs;
                }
                if (rc)
                        goto closefs;
        }
 +      if (orphan_file_blocks) {
 +              errcode_t err;
 +
 +              err = ext2fs_read_bitmaps(fs);
 +              if (err) {
 +                      com_err(program_name, err, "%s",
 +                              _("while loading bitmaps"));
 +                      rc = 1;
 +                      goto closefs;
 +              }
 +              err = ext2fs_create_orphan_file(fs, orphan_file_blocks);
 +              if (err) {
 +                      com_err(program_name, err, "%s",
 +                              _("while creating orphan file"));
 +                      rc = 1;
 +                      goto closefs;
 +              }
 +      }
  
        if (Q_flag) {
                if (mount_flags & EXT2_MF_MOUNTED) {
                dgrp_t i;
                char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8)));
                __u8 old_uuid[UUID_SIZE];
 +              uuid_t new_uuid;
 +              errcode_t ret = -1;
  
                if (ext2fs_has_feature_stable_inodes(fs->super)) {
                        fputs(_("Cannot change the UUID of this filesystem "
                                set_csum = 1;
                }
  
 -              memcpy(old_uuid, sb->s_uuid, UUID_SIZE);
 -              if ((strcasecmp(new_UUID, "null") == 0) ||
 -                  (strcasecmp(new_UUID, "clear") == 0)) {
 -                      uuid_clear(sb->s_uuid);
 -              } else if (strcasecmp(new_UUID, "time") == 0) {
 -                      uuid_generate_time(sb->s_uuid);
 -              } else if (strcasecmp(new_UUID, "random") == 0) {
 -                      uuid_generate(sb->s_uuid);
 -              } else if (uuid_parse(new_UUID, sb->s_uuid)) {
 +#ifdef __linux__
 +              if ((mount_flags & EXT2_MF_MOUNTED) &&
 +                  !(mount_flags & EXT2_MF_READONLY) && mntpt[0]) {
 +                      fd = open(mntpt, O_RDONLY);
 +                      if (fd >= 0)
 +                              fsuuid = malloc(sizeof(*fsuuid) + UUID_SIZE);
 +                      if (fsuuid) {
 +                              fsuuid->fsu_len = UUID_SIZE;
 +                              fsuuid->fsu_flags = 0;
 +                              ret = ioctl(fd, EXT4_IOC_GETFSUUID, fsuuid);
 +                              if (ret || fsuuid->fsu_len != UUID_SIZE) {
 +                                      free(fsuuid);
 +                                      fsuuid = NULL;
 +                              }
 +                      }
 +              }
 +#endif
 +
 +              memcpy(old_uuid, fsuuid ? fsuuid->fsu_uuid : sb->s_uuid,
 +                     UUID_SIZE);
 +              if ((strcasecmp(requested_uuid, "null") == 0) ||
 +                  (strcasecmp(requested_uuid, "clear") == 0)) {
 +                      uuid_clear(new_uuid);
 +              } else if (strcasecmp(requested_uuid, "time") == 0) {
 +                      uuid_generate_time(new_uuid);
 +              } else if (strcasecmp(requested_uuid, "random") == 0) {
 +                      uuid_generate(new_uuid);
 +              } else if (uuid_parse(requested_uuid, new_uuid)) {
                        com_err(program_name, 0, "%s",
                                _("Invalid UUID format\n"));
                        rc = 1;
                        goto closefs;
                }
 -              ext2fs_init_csum_seed(fs);
 -              if (set_csum) {
 -                      for (i = 0; i < fs->group_desc_count; i++)
 -                              ext2fs_group_desc_csum_set(fs, i);
 -                      fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
 +
 +              ret = -1;
 +#ifdef __linux__
 +              if (fsuuid) {
 +                      fsuuid->fsu_len - UUID_SIZE;
 +                      fsuuid->fsu_flags = 0;
 +                      memcpy(&fsuuid->fsu_uuid, new_uuid, UUID_SIZE);
 +                      ret = ioctl(fd, EXT4_IOC_SETFSUUID, fsuuid);
 +              }
 +#endif
 +              /*
 +               * If we can't set the UUID via the ioctl, fall
 +               * back to directly modifying the superblock
 +               .*/
 +              if (ret) {
 +                      memcpy(sb->s_uuid, new_uuid, UUID_SIZE);
 +                      ext2fs_init_csum_seed(fs);
 +                      if (set_csum) {
 +                              for (i = 0; i < fs->group_desc_count; i++)
 +                                      ext2fs_group_desc_csum_set(fs, i);
 +                              fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
 +                      }
 +                      ext2fs_mark_super_dirty(fs);
                }
  
                /* If this is a journal dev, we need to copy UUID into jsb */
                        if ((rc = fs_update_journal_user(sb, old_uuid)))
                                goto closefs;
                }
 -
 -              ext2fs_mark_super_dirty(fs);
        }
  
        if (I_flag) {
                }
        }
  
-       if (rewrite_checksums)
-               rewrite_metadata_checksums(fs, rewrite_checksums);
+       if (rewrite_checksums) {
+               retval = rewrite_metadata_checksums(fs, rewrite_checksums);
+               if (retval != 0) {
+                       printf("Failed to rewrite metadata checksums\n");
+                       rc = 1;
+                       goto closefs;
+               }
+       }
  
        if (l_flag)
                list_super(sb);
        remove_error_table(&et_ext2_error_table);
  
  closefs:
 +      if (fd >= 0)
 +              close(fd);
 +      if (fsuuid)
 +              free(fsuuid);
        if (rc) {
                ext2fs_mmp_stop(fs);
  #ifndef BUILD_AS_LIB
  
        if (feature_64bit)
                convert_64bit(fs, feature_64bit);
-       return (ext2fs_close_free(&fs) ? 1 : rc);
+       retval = ext2fs_close_free(&fs);
+       if (retval) {
+               com_err("tune2fs", retval,
+                       _("while writing out and closing file system"));
+               rc = 1;
+       }
+       return rc;
  }