.TP
.BI no_optimize_extents
Do not offer to optimize the extent tree by eliminating unnecessary
-width or depth.
+width or depth. This can also be enabled in the options section of
+.BR /etc/e2fsck.conf .
+.TP
+.BI optimize_extents
+Offer to optimize the extent tree by eliminating unnecessary
+width or depth. This is the default unless otherwise specified in
+.BR /etc/e2fsck.conf .
+.TP
+.BI inode_count_fullmap
+Trade off using memory for speed when checking a file system with a
+large number of hard-linked files. The amount of memory required is
+proportional to the number of inodes in the file system. For large file
+systems, this can be gigabytes of memory. (For example, a 40TB file system
+with 2.8 billion inodes will consume an additional 5.7 GB memory if this
+optimization is enabled.) This optimization can also be enabled in the
+options section of
+.BR /etc/e2fsck.conf .
+.TP
+.BI no_inode_count_fullmap
+Disable the
+.B inode_count_fullmap
+optimization. This is the default unless otherwise specified in
+.BR /etc/e2fsck.conf .
.TP
.BI readahead_kb
Use this many KiB of memory to pre-fetch metadata in the hopes of reducing
higher, more efficient level. This relation defaults to 20
percent.
.TP
+.I inode_count_fullmap
+If this boolean relation is true, trade off using memory for speed when
+checking a file system with a large number of hard-linked files. The
+amount of memory required is proportional to the number of inodes in the
+file system. For large file systems, this can be gigabytes of memory.
+(For example a 40TB file system with 2.8 billion inodes will consume an
+additional 5.7 GB memory if this optimization is enabled.) This setting
+defaults to false.
+.TP
.I log_dir
If the
.I log_filename
end up delaying the boot process for a long time (potentially hours).
.TP
.I no_optimize_extents
-Do not offer to optimize the extent tree by eliminating unnecessary
-width or depth.
+If this boolean relation is true, do not offer to optimize the extent
+tree by reducing the tree's width or depth. This setting defaults to false.
.TP
.I readahead_mem_pct
Use this percentage of memory to try to read in metadata blocks ahead of the
#define E2F_OPT_CONVERT_BMAP 0x4000 /* convert blockmap to extent */
#define E2F_OPT_FIXES_ONLY 0x8000 /* skip all optimizations */
#define E2F_OPT_NOOPT_EXTENTS 0x10000 /* don't optimize extents */
+#define E2F_OPT_ICOUNT_FULLMAP 0x20000 /* use an array for inode counts */
/*
* E2fsck flags
errcode_t retval;
char *tdb_dir;
int enable;
+ int full_map;
*ret = 0;
}
e2fsck_set_bitmap_type(ctx->fs, EXT2FS_BMAP64_RBTREE, icount_name,
&save_type);
+ if (ctx->options & E2F_OPT_ICOUNT_FULLMAP)
+ flags |= EXT2_ICOUNT_OPT_FULLMAP;
retval = ext2fs_create_icount2(ctx->fs, flags, 0, hint, ret);
ctx->fs->default_bitmap_type = save_type;
return retval;
} else if (strcmp(token, "nodiscard") == 0) {
ctx->options &= ~E2F_OPT_DISCARD;
continue;
+ } else if (strcmp(token, "optimize_extents") == 0) {
+ ctx->options &= ~E2F_OPT_NOOPT_EXTENTS;
+ continue;
} else if (strcmp(token, "no_optimize_extents") == 0) {
ctx->options |= E2F_OPT_NOOPT_EXTENTS;
continue;
+ } else if (strcmp(token, "inode_count_fullmap") == 0) {
+ ctx->options |= E2F_OPT_ICOUNT_FULLMAP;
+ continue;
+ } else if (strcmp(token, "no_inode_count_fullmap") == 0) {
+ ctx->options &= ~E2F_OPT_ICOUNT_FULLMAP;
+ continue;
} else if (strcmp(token, "log_filename") == 0) {
if (!arg)
extended_usage++;
free(buf);
if (extended_usage) {
- fputs(("\nExtended options are separated by commas, "
+ fputs(_("\nExtended options are separated by commas, "
"and may take an argument which\n"
"is set off by an equals ('=') sign. "
- "Valid extended options are:\n"), stderr);
- fputs(("\tea_ver=<ea_version (1 or 2)>\n"), stderr);
- fputs(("\tfragcheck\n"), stderr);
- fputs(("\tjournal_only\n"), stderr);
- fputs(("\tdiscard\n"), stderr);
- fputs(("\tnodiscard\n"), stderr);
- fputs(("\treadahead_kb=<buffer size>\n"), stderr);
- fputs(("\tbmap2extent\n"), stderr);
+ "Valid extended options are:\n\n"), stderr);
+ fputs(_("\tea_ver=<ea_version (1 or 2)>\n"), stderr);
+ fputs("\tfragcheck\n", stderr);
+ fputs("\tjournal_only\n", stderr);
+ fputs("\tdiscard\n", stderr);
+ fputs("\tnodiscard\n", stderr);
+ fputs("\toptimize_extents\n", stderr);
+ fputs("\tno_optimize_extents\n", stderr);
+ fputs("\tinode_count_fullmap\n", stderr);
+ fputs("\tno_inode_count_fullmap\n", stderr);
+ fputs(_("\treadahead_kb=<buffer size>\n"), stderr);
+ fputs("\tbmap2extent\n", stderr);
fputc('\n', stderr);
exit(1);
}
if (c)
ctx->options |= E2F_OPT_NOOPT_EXTENTS;
+ profile_get_boolean(ctx->profile, "options", "inode_count_fullmap",
+ 0, 0, &c);
+ if (c)
+ ctx->options |= E2F_OPT_ICOUNT_FULLMAP;
+
if (ctx->readahead_kb == ~0ULL) {
profile_get_integer(ctx->profile, "options",
"readahead_mem_pct", 0, -1, &c);
* ext2_icount_t abstraction
*/
#define EXT2_ICOUNT_OPT_INCREMENT 0x01
+#define EXT2_ICOUNT_OPT_FULLMAP 0x02
typedef struct ext2_icount *ext2_icount_t;
char *tdb_fn;
TDB_CONTEXT *tdb;
#endif
+ __u16 *fullmap;
};
/*
}
#endif
+ if (icount->fullmap)
+ ext2fs_free_mem(&icount->fullmap);
+
ext2fs_free_mem(&icount);
}
if (retval)
return retval;
memset(icount, 0, sizeof(struct ext2_icount));
+ icount->magic = EXT2_ET_MAGIC_ICOUNT;
+ icount->num_inodes = fs->super->s_inodes_count;
+
+ if ((flags & EXT2_ICOUNT_OPT_FULLMAP) &&
+ (flags & EXT2_ICOUNT_OPT_INCREMENT)) {
+ unsigned sz = sizeof(*icount->fullmap) * icount->num_inodes;
+
+ retval = ext2fs_get_mem(sz, &icount->fullmap);
+ /* If we can't allocate, fall back */
+ if (!retval) {
+ memset(icount->fullmap, 0, sz);
+ *ret = icount;
+ return 0;
+ }
+ }
retval = ext2fs_allocate_inode_bitmap(fs, "icount", &icount->single);
if (retval)
} else
icount->multiple = 0;
- icount->magic = EXT2_ET_MAGIC_ICOUNT;
- icount->num_inodes = fs->super->s_inodes_count;
-
*ret = icount;
return 0;
if (retval)
return retval;
+ if (icount->fullmap)
+ goto successout;
+
if (size) {
icount->size = size;
} else {
icount->count = hint->count;
}
+successout:
*ret = icount;
return 0;
return 0;
}
#endif
+ if (icount->fullmap) {
+ icount->fullmap[ino] = icount_16_xlate(count);
+ return 0;
+ }
+
el = get_icount_el(icount, ino, 1);
if (!el)
return EXT2_ET_NO_MEMORY;
return 0;
}
#endif
+ if (icount->fullmap) {
+ *count = icount->fullmap[ino];
+ return 0;
+ }
+
el = get_icount_el(icount, ino, 0);
if (!el) {
*count = 0;
if (!ino || (ino > icount->num_inodes))
return EXT2_ET_INVALID_ARGUMENT;
- if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
- *ret = 1;
- return 0;
- }
- if (icount->multiple &&
- !ext2fs_test_inode_bitmap2(icount->multiple, ino)) {
- *ret = 0;
- return 0;
+ if (!icount->fullmap) {
+ if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
+ *ret = 1;
+ return 0;
+ }
+ if (icount->multiple &&
+ !ext2fs_test_inode_bitmap2(icount->multiple, ino)) {
+ *ret = 0;
+ return 0;
+ }
}
get_inode_count(icount, ino, &val);
*ret = icount_16_xlate(val);
if (!ino || (ino > icount->num_inodes))
return EXT2_ET_INVALID_ARGUMENT;
- if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
+ if (icount->fullmap) {
+ curr_value = icount_16_xlate(icount->fullmap[ino] + 1);
+ icount->fullmap[ino] = curr_value;
+ } else if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
/*
* If the existing count is 1, then we know there is
* no entry in the list.
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+ if (icount->fullmap) {
+ if (!icount->fullmap[ino])
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ curr_value = --icount->fullmap[ino];
+ if (ret)
+ *ret = icount_16_xlate(curr_value);
+ return 0;
+ }
+
if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
ext2fs_unmark_inode_bitmap2(icount->single, ino);
if (icount->multiple)
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+ if (icount->fullmap)
+ return set_inode_count(icount, ino, count);
+
if (count == 1) {
ext2fs_mark_inode_bitmap2(icount->single, ino);
if (icount->multiple)