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
.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
.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
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
#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 {
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,
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" :
{
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));
/*
* 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;
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;
}
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);
}
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;
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;
/*
* 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;
}
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,
(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,
};
/*
- * 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,
};
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;
};
/* 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
#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
#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
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
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),
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);
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
/*
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
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)
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);
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;
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);
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|
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? */
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 */
#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);
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) ||
#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) {
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)
#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;
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;
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 |
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|
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;
}
}
+ 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)) {
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)) {
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;
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++;
}
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
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;
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;
}