2017-11-14 07:04:46

by Artem Blagodarenko

[permalink] [raw]
Subject: [PATCH v2 0/7] 64bit inode e2fsprogs support

With current hardware clusters faced with the trouble of
creating enough inodes on partitions. Lustre has 0-size
files to store some information about files. Current
MDS disk sizes allow to store large amount of such files, but
EXT4 limits this number to ~4 billions.

Lustre FS has features like DNE to distribute metadata over many targets
(disks), but disks are used not effectively. It would be great to have
ability to store more then ~4 billions inodes on one EXT4 file system.

These patches add 64bit inodes support for e2fsprogs.

Second version of patches set. Changes since v1:
* code style fixes
* allow to store multiple FIDs in the dirent
* fixed PR_2_CLEAR_DIRDATA problem number
* excluded fix "e2fsck Fix access after free for dx_db structure"
* corrected "ls" output
* super_fields accept a 64-bit value directly
* feature renamed to EXT4_FEATURE_INCOMPAT_64INODE
* removed 64-bit badblock inodes code. Should send as
separate feature
* new fields type changed to __le32
* don't change ext2_ino_t type, but add ext2_ino64_t
* use explicit ext2_ino64_t type, not unsigned long
* fixed fields order check
* fixed "inode_ratio" calculation
* quota_sb_inump renamed to quota_sb_inum

Andreas Dilger (2):
e2fsck: add support for dirdata feature
tests: add basic tests for dirdata feature

Artem Blagodarenko (4):
debugfs: 64bit inode support
ext2fs: add EXT4_FEATURE_INCOMPAT_64INODE support
quota: swapping s_prj_quota_inum superblock field
quota: quota 64bit inode number cleanup

Bobi Jam (1):
tests: e2fsck -D does not change dirdata

debugfs/debugfs.c | 2 +-
debugfs/htree.c | 2 +-
debugfs/ls.c | 46 +++-
debugfs/set_fields.c | 3 +-
debugfs/util.c | 5 +-
e2fsck/extents.c | 8 +-
e2fsck/journal.c | 2 +-
e2fsck/pass1.c | 22 +-
e2fsck/pass1b.c | 2 +-
e2fsck/pass2.c | 137 ++++++++--
e2fsck/pass3.c | 8 +
e2fsck/pass4.c | 2 +-
e2fsck/pass5.c | 20 +-
e2fsck/problem.c | 5 +
e2fsck/problem.h | 3 +
e2fsck/quota.c | 10 +-
e2fsck/rehash.c | 78 +++---
e2fsck/super.c | 18 +-
e2fsck/unix.c | 17 +-
ext2ed/inode_com.c | 7 +-
ext2ed/super_com.c | 6 +-
lib/e2p/feature.c | 2 +
lib/e2p/ls.c | 12 +-
lib/ext2fs/alloc.c | 8 +-
lib/ext2fs/alloc_stats.c | 6 +-
lib/ext2fs/bitmaps.c | 2 +-
lib/ext2fs/dirblock.c | 34 +++
lib/ext2fs/ext2_fs.h | 27 +-
lib/ext2fs/ext2fs.h | 66 ++++-
lib/ext2fs/extent.c | 2 +-
lib/ext2fs/gen_bitmap64.c | 3 +-
lib/ext2fs/get_num_dirs.c | 4 +-
lib/ext2fs/icount.c | 7 +-
lib/ext2fs/initialize.c | 19 +-
lib/ext2fs/inline_data.c | 16 +-
lib/ext2fs/inode.c | 8 +-
lib/ext2fs/lfsck.h | 42 ++++
lib/ext2fs/link.c | 10 +-
lib/ext2fs/newdir.c | 4 +-
lib/ext2fs/openfs.c | 4 +-
lib/ext2fs/rw_bitmaps.c | 2 +-
lib/ext2fs/swapfs.c | 4 +
lib/ext2fs/tst_bitmaps.c | 7 +-
lib/ext2fs/tst_iscan.c | 2 +-
lib/ext2fs/tst_super_size.c | 5 +-
lib/support/mkquota.c | 10 +-
lib/support/quotaio.c | 2 +-
lib/support/quotaio.h | 39 ++-
misc/findsuper.c | 8 +-
misc/fuse2fs.c | 6 +-
misc/mke2fs.c | 30 ++-
misc/tune2fs.c | 16 +-
resize/main.c | 3 +-
resize/resize2fs.c | 30 +--
tests/f_dir_optimize/expect.1 | 511 ++++++++++++++++++++++++++++++++++++++
tests/f_dir_optimize/expect.2 | 511 ++++++++++++++++++++++++++++++++++++++
tests/f_dir_optimize/image.gz | Bin 0 -> 102520 bytes
tests/f_dir_optimize/name | 1 +
tests/f_dir_optimize/script | 36 +++
tests/f_dirdata/expect.1 | 15 ++
tests/f_dirdata/expect.2 | 7 +
tests/f_dirdata/image.gz | Bin 0 -> 72169 bytes
tests/f_dirdata/name | 1 +
tests/f_dirdata_optimize/expect.1 | 10 +
tests/f_dirdata_optimize/expect.2 | 7 +
tests/f_dirdata_optimize/image.gz | Bin 0 -> 32121 bytes
tests/f_dirdata_optimize/name | 1 +
tests/f_dirdata_optimize/script | 3 +
tests/progs/test_icount.c | 4 +-
69 files changed, 1723 insertions(+), 227 deletions(-)
create mode 100644 lib/ext2fs/lfsck.h
create mode 100644 tests/f_dir_optimize/expect.1
create mode 100644 tests/f_dir_optimize/expect.2
create mode 100644 tests/f_dir_optimize/image.gz
create mode 100644 tests/f_dir_optimize/name
create mode 100644 tests/f_dir_optimize/script
create mode 100644 tests/f_dirdata/expect.1
create mode 100644 tests/f_dirdata/expect.2
create mode 100644 tests/f_dirdata/image.gz
create mode 100644 tests/f_dirdata/name
create mode 100644 tests/f_dirdata_optimize/expect.1
create mode 100644 tests/f_dirdata_optimize/expect.2
create mode 100644 tests/f_dirdata_optimize/image.gz
create mode 100644 tests/f_dirdata_optimize/name
create mode 100644 tests/f_dirdata_optimize/script

--
2.13.6 (Apple Git-96)


2017-11-14 07:04:50

by Artem Blagodarenko

[permalink] [raw]
Subject: [PATCH v2 1/7] e2fsck: add support for dirdata feature

From: Andreas Dilger <[email protected]>

Add support for the INCOMPAT_DIRDATA feature, which allows
storing extra data in the directory entry beyond the name.
This allows the Lustre File IDentifier to be accessed in
an efficient manner, and would be useful for expanding a
filesystem to allow more than 2^32 inodes in the future.

Include this patches:

e2fsck: e2fsck -D does not change dirdata content

Fix dir optimization to preserve dirdata content for dot
and dotdot entries.

Lustre-bug: https://jira.hpdd.intel.com/browse/LU-1774
Signed-off-by: Bobi Jam <[email protected]>
Change-Id: Iae190794da75a2080a8e5cc5b95a49e0c894f72f

e2fsprogs: Consider DIRENT_LUFID flag in link_proc().

While adding the new file entry in directory block, link_proc()
calculates minimum record length of the existing directory entry
without considering the dirent data size and which leads to
corruption. Changed the code to use EXT2_DIR_REC_LEN() which will
return correct record length including dirent data size.

Lustre-bug: https://jira.hpdd.intel.com/browse/LU-2462
Signed-off-by: Manisha Salve <[email protected]>
Change-Id: Ic593c558c47a78183143ec8e99d8385ac94d06f7

libext2fs, e2fsck: don't use ext2_dir_entry_2

Due to endian issues, do not use ext2_dir_entry_2 because it will
have the wrong byte order on directory entries that are swabbed.
Instead, use the standard practice of mask-and-shift to access the
file_type and dirdata flags.

Lustre-bug: https://jira.hpdd.intel.com/browse/LU-4677
Signed-off-by: Pravin Shelar <[email protected]>
Signed-off-by: Andreas Dilger <[email protected]>

Signed-off-by: Artem Blagodarenko <[email protected]>
---
debugfs/htree.c | 2 +-
debugfs/ls.c | 44 +++++++++++++++-
e2fsck/pass1.c | 4 +-
e2fsck/pass2.c | 133 +++++++++++++++++++++++++++++++++++++++--------
e2fsck/pass3.c | 8 +++
e2fsck/problem.c | 5 ++
e2fsck/problem.h | 3 ++
e2fsck/rehash.c | 78 ++++++++++++++++-----------
lib/ext2fs/dirblock.c | 34 ++++++++++++
lib/ext2fs/ext2_fs.h | 16 +++++-
lib/ext2fs/ext2fs.h | 22 +++++++-
lib/ext2fs/inline_data.c | 14 ++---
lib/ext2fs/lfsck.h | 42 +++++++++++++++
lib/ext2fs/link.c | 10 ++--
lib/ext2fs/newdir.c | 4 +-
misc/mke2fs.c | 1 +
misc/tune2fs.c | 2 +
17 files changed, 349 insertions(+), 73 deletions(-)

diff --git a/debugfs/htree.c b/debugfs/htree.c
index cf7d78aa..b7f1add0 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -278,7 +278,7 @@ void do_htree_dump(int argc, char *argv[])
goto errout;
}

- rootnode = (struct ext2_dx_root_info *) (buf + 24);
+ rootnode = get_ext2_dx_root_info(current_fs, buf);

fprintf(pager, "Root node dump:\n");
fprintf(pager, "\t Reserved zero: %u\n", rootnode->reserved_zero);
diff --git a/debugfs/ls.c b/debugfs/ls.c
index 61b63196..5655933e 100644
--- a/debugfs/ls.c
+++ b/debugfs/ls.c
@@ -24,6 +24,7 @@ extern char *optarg;
#endif

#include "debugfs.h"
+#include "ext2fs/lfsck.h"

/*
* list directory
@@ -32,6 +33,7 @@ extern char *optarg;
#define LONG_OPT 0x0001
#define PARSE_OPT 0x0002
#define RAW_OPT 0x0004
+#define DIRDATA_OPT 0x0008
#define ENCRYPT_OPT 0x8000

struct list_dir_struct {
@@ -44,6 +46,41 @@ struct list_dir_struct {
static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

+static void list_dirdata(struct list_dir_struct *ls,
+ struct ext2_dir_entry *dirent)
+{
+ unsigned char *data;
+ int dlen;
+ __u8 dirdata_mask;
+ __u8 file_type = dirent->name_len >> 8;
+
+ data = (unsigned char *)dirent->name +
+ (dirent->name_len & EXT2_NAME_LEN) + 1;
+
+ for (dirdata_mask = EXT2_FT_MASK + 1;
+ dirdata_mask != 0; dirdata_mask <<= 1) {
+ if ((dirdata_mask & file_type) == 0)
+ continue;
+
+ dlen = data[0];
+
+ if (dirdata_mask == EXT2_DIRENT_LUFID) {
+ struct lu_fid *fid = (struct lu_fid *)(data + 1);
+
+ fid_be_to_cpu(fid, fid);
+ fprintf(ls->f, DFID, PFID(fid));
+ } else {
+ int i;
+
+ for (i = 1; i < dlen; i++)
+ fprintf(ls->f, "%02x", data[i]);
+ }
+
+ fprintf(ls->f, " ");
+ data += dlen;
+ }
+}
+
static int print_filename(FILE *f, struct ext2_dir_entry *dirent, int options)
{
unsigned char ch;
@@ -157,6 +194,8 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
else
fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode));
fprintf(ls->f, " %s ", datestr);
+ if ((ls->options & DIRDATA_OPT) != 0)
+ list_dirdata(ls, dirent);
print_filename(ls->f, dirent, options);
fputc('\n', ls->f);
} else {
@@ -204,7 +243,7 @@ void do_list_dir(int argc, char *argv[])
return;

reset_getopt();
- while ((c = getopt (argc, argv, "cdlpr")) != EOF) {
+ while ((c = getopt(argc, argv, "cdDlpr")) != EOF) {
switch (c) {
case 'c':
flags |= DIRENT_FLAG_INCLUDE_CSUM;
@@ -212,6 +251,9 @@ void do_list_dir(int argc, char *argv[])
case 'l':
ls.options |= LONG_OPT;
break;
+ case 'D':
+ ls.options |= DIRDATA_OPT;
+ break;
case 'd':
flags |= DIRENT_FLAG_INCLUDE_REMOVED;
break;
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 5015d938..686c2019 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -719,7 +719,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
*/
memcpy(&dotdot, inode->i_block, sizeof(dotdot));
memcpy(&de, ((char *)inode->i_block) + EXT4_INLINE_DATA_DOTDOT_SIZE,
- EXT2_DIR_REC_LEN(0));
+ __EXT2_DIR_REC_LEN(0));
dotdot = ext2fs_le32_to_cpu(dotdot);
de.inode = ext2fs_le32_to_cpu(de.inode);
de.rec_len = ext2fs_le16_to_cpu(de.rec_len);
@@ -2646,7 +2646,7 @@ static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
return 1;

/* XXX should check that beginning matches a directory */
- root = (struct ext2_dx_root_info *) (block_buf + 24);
+ root = get_ext2_dx_root_info(fs, block_buf);

if ((root->reserved_zero || root->info_length < 8) &&
fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 1b0504c8..1a719b2f 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -366,13 +366,88 @@ static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
return (int) (db_a->blockcnt - db_b->blockcnt);
}

+void ext2_fix_dirent_dirdata(struct ext2_dir_entry *de)
+{
+ __u16 file_type = de->name_len & (EXT2_FT_MASK << 8);
+ __u8 de_flags = (de->name_len >> 8) & ~EXT2_FT_MASK;
+ __u8 name_len = de->name_len & EXT2_NAME_LEN;
+ __u8 new_flag = 0;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ __u8 flags = new_flag | (1 << i) << 4;
+
+ /* new_flag is accumulating flags that are set in de_flags
+ * and still fit inside rec_len. ext2_get_dirent_dirdata_size()
+ * returns the size of all the dirdata entries in flags, and
+ * chops off any that are beyond rec_len.
+ */
+ if ((de_flags & flags) == flags) {
+ int dirdatalen = ext2_get_dirent_dirdata_size(de,
+ flags);
+ int rlen = __EXT2_DIR_REC_LEN(name_len + dirdatalen);
+
+ if (rlen > de->rec_len)
+ break;
+
+ new_flag |= flags;
+ }
+ }
+
+ de->name_len = name_len | file_type | (new_flag << 8);
+}
+
+/*
+ * check for dirent data in ext3 dirent.
+ * return 0 if dirent data is ok.
+ * return 1 if dirent data does not exist.
+ * return 2 if dirent was modified due to error.
+ */
+int e2fsck_check_dirent_data(e2fsck_t ctx, struct ext2_dir_entry *de,
+ unsigned int offset, struct problem_context *pctx)
+{
+ if (!(ctx->fs->super->s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_DIRDATA)) {
+ if ((de->name_len >> 8) & ~EXT2_FT_MASK) {
+ /* clear dirent extra data flags. */
+ if (fix_problem(ctx, PR_2_CLEAR_DIRDATA, pctx)) {
+ de->name_len &= (EXT2_FT_MASK << 8) |
+ EXT2_NAME_LEN;
+ return 2;
+ }
+ }
+ return 1;
+ }
+ if ((de->name_len >> 8) & ~EXT2_FT_MASK) {
+ if (de->rec_len >= EXT2_DIR_REC_LEN(de) ||
+ de->rec_len + offset == EXT2_BLOCK_SIZE(ctx->fs->super)) {
+ if (ext2_get_dirent_dirdata_size(de,
+ EXT2_DIRENT_LUFID) %
+ EXT2_DIRENT_LUFID_SIZE == 1 /*size*/ + 1 /*NULL*/)
+ return 0;
+ }
+ /* just clear dirent data flags for now, we should fix FID data
+ * in lustre specific pass.
+ */
+ if (fix_problem(ctx, PR_2_CLEAR_DIRDATA, pctx)) {
+ ext2_fix_dirent_dirdata(de);
+ if (ext2_get_dirent_dirdata_size(de,
+ EXT2_DIRENT_LUFID) !=
+ EXT2_DIRENT_LUFID_SIZE)
+ de->name_len &= ~(EXT2_DIRENT_LUFID << 8);
+
+ return 2;
+ }
+ }
+ return 1;
+}

/*
* Make sure the first entry in the directory is '.', and that the
* directory entry is sane.
*/
static int check_dot(e2fsck_t ctx,
- struct ext2_dir_entry *dirent,
+ struct ext2_dir_entry *dirent, unsigned int offset,
ext2_ino_t ino, struct problem_context *pctx)
{
struct ext2_dir_entry *nextdir;
@@ -380,6 +455,7 @@ static int check_dot(e2fsck_t ctx,
int status = 0;
int created = 0;
problem_t problem = 0;
+ int dir_data_error;

if (!dirent->inode)
problem = PR_2_MISSING_DOT;
@@ -389,10 +465,12 @@ static int check_dot(e2fsck_t ctx,
else if (dirent->name[1] != '\0')
problem = PR_2_DOT_NULL_TERM;

+ dir_data_error = e2fsck_check_dirent_data(ctx, dirent, offset, pctx);
+
(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (problem) {
if (fix_problem(ctx, problem, pctx)) {
- if (rec_len < 12)
+ if (rec_len < 12 && dir_data_error)
rec_len = dirent->rec_len = 12;
dirent->inode = ino;
ext2fs_dirent_set_name_len(dirent, 1);
@@ -411,7 +489,7 @@ static int check_dot(e2fsck_t ctx,
}
if (rec_len > 12) {
new_len = rec_len - 12;
- if (new_len > 12) {
+ if (new_len > 12 && dir_data_error) {
if (created ||
fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
nextdir = (struct ext2_dir_entry *)
@@ -436,11 +514,12 @@ static int check_dot(e2fsck_t ctx,
* here; this gets done in pass 3.
*/
static int check_dotdot(e2fsck_t ctx,
- struct ext2_dir_entry *dirent,
+ struct ext2_dir_entry *dirent, unsigned int offset,
ext2_ino_t ino, struct problem_context *pctx)
{
problem_t problem = 0;
unsigned int rec_len;
+ int dir_data_error;

if (!dirent->inode)
problem = PR_2_MISSING_DOT_DOT;
@@ -451,10 +530,12 @@ static int check_dotdot(e2fsck_t ctx,
else if (dirent->name[2] != '\0')
problem = PR_2_DOT_DOT_NULL_TERM;

+ dir_data_error = e2fsck_check_dirent_data(ctx, dirent, offset, pctx);
+
(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (problem) {
if (fix_problem(ctx, problem, pctx)) {
- if (rec_len < 12)
+ if (rec_len < 12 && dir_data_error)
dirent->rec_len = 12;
/*
* Note: we don't have the parent inode just
@@ -528,6 +609,13 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
int filetype = ext2fs_dirent_file_type(dirent);
int should_be = EXT2_FT_UNKNOWN;
struct ext2_inode inode;
+ __u8 dirdata = 0;
+
+ if (ctx->fs->super->s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_DIRDATA) {
+ dirdata = filetype & ~EXT2_FT_MASK;
+ filetype = filetype & EXT2_FT_MASK;
+ }

if (!ext2fs_has_feature_filetype(ctx->fs->super)) {
if (filetype == 0 ||
@@ -559,7 +647,7 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
pctx) == 0)
return 0;

- ext2fs_dirent_set_file_type(dirent, should_be);
+ ext2fs_dirent_set_file_type(dirent, should_be | dirdata);
return 1;
}

@@ -581,7 +669,7 @@ static void parse_int_node(ext2_filsys fs,
int csum_size = 0;

if (db->blockcnt == 0) {
- root = (struct ext2_dx_root_info *) (block_buf + 24);
+ root = get_ext2_dx_root_info(fs, block_buf);

#ifdef DX_DEBUG
printf("Root node dump:\n");
@@ -591,8 +679,8 @@ static void parse_int_node(ext2_filsys fs,
printf("\t Indirect levels: %d\n", root->indirect_levels);
printf("\t Flags: %d\n", root->unused_flags);
#endif
-
- ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
+ ent = (struct ext2_dx_entry *)((char *)root +
+ root->info_length);

if (failed_csum &&
(e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
@@ -600,7 +688,7 @@ static void parse_int_node(ext2_filsys fs,
&cd->pctx)))
goto clear_and_exit;
} else {
- ent = (struct ext2_dx_entry *) (block_buf+8);
+ ent = (struct ext2_dx_entry *)(block_buf + 8);

if (failed_csum &&
(e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
@@ -608,8 +696,7 @@ static void parse_int_node(ext2_filsys fs,
&cd->pctx)))
goto clear_and_exit;
}
-
- limit = (struct ext2_dx_countlimit *) ent;
+ limit = (struct ext2_dx_countlimit *)ent;

#ifdef DX_DEBUG
printf("Number of entries (count): %d\n",
@@ -794,7 +881,7 @@ static errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf)
d = NEXT_DIRENT(d);

if (d != top) {
- unsigned int min_size = EXT2_DIR_REC_LEN(
+ unsigned int min_size = __EXT2_DIR_REC_LEN(
ext2fs_dirent_name_len(dirbuf));
if (min_size > (char *)top - (char *)d)
return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
@@ -828,7 +915,7 @@ static errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino,
*/
if (old_size > EXT4_MIN_INLINE_DATA_SIZE &&
old_size < EXT4_MIN_INLINE_DATA_SIZE +
- EXT2_DIR_REC_LEN(1)) {
+ __EXT2_DIR_REC_LEN(1)) {
old_size = EXT4_MIN_INLINE_DATA_SIZE;
new_size = old_size;
} else
@@ -1035,7 +1122,7 @@ inline_read_fail:
if (((inline_data_size & 3) ||
(inline_data_size > EXT4_MIN_INLINE_DATA_SIZE &&
inline_data_size < EXT4_MIN_INLINE_DATA_SIZE +
- EXT2_DIR_REC_LEN(1))) &&
+ __EXT2_DIR_REC_LEN(1))) &&
fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) {
errcode_t err = fix_inline_dir_size(ctx, ino,
&inline_data_size, &pctx,
@@ -1085,7 +1172,7 @@ inline_read_fail:
(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
limit = (struct ext2_dx_countlimit *) (buf+8);
if (db->blockcnt == 0) {
- root = (struct ext2_dx_root_info *) (buf + 24);
+ root = get_ext2_dx_root_info(fs, buf);
dx_db->type = DX_DIRBLOCK_ROOT;
dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
if ((root->reserved_zero ||
@@ -1165,7 +1252,7 @@ skip_checksum:
* force salvaging this dir.
*/
if (max_block_size - offset < EXT2_DIR_ENTRY_HEADER_LEN)
- rec_len = EXT2_DIR_REC_LEN(1);
+ rec_len = __EXT2_DIR_REC_LEN(1);
else
(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
cd->pctx.dirent = dirent;
@@ -1227,7 +1314,7 @@ skip_checksum:
memset(&dot, 0, sizeof(dot));
dirent = &dot;
dirent->inode = ino;
- dirent->rec_len = EXT2_DIR_REC_LEN(1);
+ dirent->rec_len = __EXT2_DIR_REC_LEN(1);
dirent->name_len = 1 | filetype;
dirent->name[0] = '.';
} else if (dot_state == 1) {
@@ -1235,7 +1322,7 @@ skip_checksum:
dirent = &dotdot;
dirent->inode =
((struct ext2_dir_entry *)buf)->inode;
- dirent->rec_len = EXT2_DIR_REC_LEN(2);
+ dirent->rec_len = __EXT2_DIR_REC_LEN(2);
dirent->name_len = 2 | filetype;
dirent->name[0] = '.';
dirent->name[1] = '.';
@@ -1247,10 +1334,10 @@ skip_checksum:
}

if (dot_state == 0) {
- if (check_dot(ctx, dirent, ino, &cd->pctx))
+ if (check_dot(ctx, dirent, offset, ino, &cd->pctx))
dir_modified++;
} else if (dot_state == 1) {
- ret = check_dotdot(ctx, dirent, ino, &cd->pctx);
+ ret = check_dotdot(ctx, dirent, offset, ino, &cd->pctx);
if (ret < 0)
goto abort_free_dict;
if (ret)
@@ -1266,6 +1353,10 @@ skip_checksum:
if (!dirent->inode)
goto next;

+ ret = e2fsck_check_dirent_data(ctx, dirent, offset, &cd->pctx);
+ if (ret == 2)
+ dir_modified++;
+
/*
* Make sure the inode listed is a legal one.
*/
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index 6a975b36..8ed871ff 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -698,6 +698,7 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
errcode_t retval;
struct problem_context pctx;
+ __u16 dirdata = 0;

if (ext2fs_dirent_name_len(dirent) != 2)
return 0;
@@ -717,11 +718,18 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
}
dirent->inode = fp->parent;
+
+ dirdata = dirent->name_len & (~EXT2_FT_MASK << 8);
+
if (ext2fs_has_feature_filetype(fp->ctx->fs->super))
ext2fs_dirent_set_file_type(dirent, EXT2_FT_DIR);
else
ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);

+ if (fp->ctx->fs->super->s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_DIRDATA)
+ dirent->name_len |= dirdata;
+
fp->done++;
return DIRENT_ABORT | DIRENT_CHANGED;
}
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index edc9d51f..2a86d528 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1671,6 +1671,11 @@ static struct e2fsck_problem problem_table[] = {
N_("Encrypted @E is too short.\n"),
PROMPT_CLEAR, 0 },

+ /* Directory entry dirdata length set incorrectly */
+ { PR_2_CLEAR_DIRDATA,
+ N_("@E dirdata length set incorrectly.\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
/* Pass 3 errors */

/* Pass 3: Checking directory connectivity */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 482d111a..05214840 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -1004,6 +1004,9 @@ struct problem_context {
/* Encrypted directory entry is too short */
#define PR_2_BAD_ENCRYPTED_NAME 0x020050

+/* Entry dirdata length set incorrectly */
+#define PR_2_CLEAR_DIRDATA 0x020051
+
/*
* Pass 3 errors
*/
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 486e1f21..8656c417 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -85,6 +85,8 @@ struct fill_dir_struct {
int compress;
ino_t parent;
ext2_ino_t dir;
+ struct ext2_dir_entry *dot_de;
+ struct ext2_dir_entry *dotdot_de;
};

struct hash_entry {
@@ -160,11 +162,14 @@ static int fill_dir_block(ext2_filsys fs,
if (dirent->inode == 0)
continue;
if (!fd->compress && (name_len == 1) &&
- (dirent->name[0] == '.'))
+ (dirent->name[0] == '.')) {
+ fd->dot_de = dirent;
continue;
+ }
if (!fd->compress && (name_len == 2) &&
(dirent->name[0] == '.') && (dirent->name[1] == '.')) {
fd->parent = dirent->inode;
+ fd->dotdot_de = dirent;
continue;
}
if (fd->num_array >= fd->max_array) {
@@ -179,7 +184,7 @@ static int fill_dir_block(ext2_filsys fs,
}
ent = fd->harray + fd->num_array++;
ent->dir = dirent;
- fd->dir_size += EXT2_DIR_REC_LEN(name_len);
+ fd->dir_size += EXT2_DIR_REC_LEN(dirent);
ent->ino = dirent->inode;
if (fd->compress)
ent->hash = ent->minor_hash = 0;
@@ -475,7 +480,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
ent = fd->harray + i;
if (ent->dir->inode == 0)
continue;
- rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(ent->dir));
+ rec_len = EXT2_DIR_REC_LEN(ent->dir);
if (rec_len > left) {
if (left) {
left += prev_rec_len;
@@ -510,8 +515,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
if (retval)
return retval;
prev_rec_len = rec_len;
- memcpy(dirent->name, ent->dir->name,
- ext2fs_dirent_name_len(dirent));
+ memcpy(dirent->name, ent->dir->name, rec_len);
offset += rec_len;
left -= rec_len;
if (left < slack) {
@@ -536,45 +540,54 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,


static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
- ext2_ino_t ino, ext2_ino_t parent)
+ ext2_ino_t ino, ext2_ino_t parent,
+ struct ext2_dir_entry *dot_de,
+ struct ext2_dir_entry *dotdot_de)
{
- struct ext2_dir_entry *dir;
- struct ext2_dx_root_info *root;
+ struct ext2_dir_entry *dir;
+ struct ext2_dx_root_info *root;
struct ext2_dx_countlimit *limits;
- int filetype = 0;
int csum_size = 0;
-
- if (ext2fs_has_feature_filetype(fs->super))
- filetype = EXT2_FT_DIR;
+ int offset;
+ int rec_len;

memset(buf, 0, fs->blocksize);
dir = (struct ext2_dir_entry *) buf;
dir->inode = ino;
- dir->name[0] = '.';
- ext2fs_dirent_set_name_len(dir, 1);
- ext2fs_dirent_set_file_type(dir, filetype);
- dir->rec_len = 12;
- dir = (struct ext2_dir_entry *) (buf + 12);
+
+ ext2fs_dirent_set_name_len(dir, dot_de->name_len);
+ dir->rec_len = dot_de->rec_len;
+ rec_len = EXT2_DIR_REC_LEN(dot_de);
+ memcpy(dir->name, dot_de->name, rec_len);
+ offset = rec_len;
+
+ dir = (struct ext2_dir_entry *) (buf + offset);
+ /* set to jump over the index block */
+
dir->inode = parent;
- dir->name[0] = '.';
- dir->name[1] = '.';
- ext2fs_dirent_set_name_len(dir, 2);
- ext2fs_dirent_set_file_type(dir, filetype);
- dir->rec_len = fs->blocksize - 12;

- root = (struct ext2_dx_root_info *) (buf+24);
+ ext2fs_dirent_set_name_len(dir, dotdot_de->name_len);
+ dir->rec_len = fs->blocksize - rec_len;
+ rec_len = EXT2_DIR_REC_LEN(dotdot_de);
+ memcpy(dir->name, dotdot_de->name, rec_len);
+ offset += rec_len;
+
+ root = (struct ext2_dx_root_info *) (buf + offset);
+
root->reserved_zero = 0;
root->hash_version = fs->super->s_def_hash_version;
- root->info_length = 8;
+ root->info_length = sizeof(struct ext2_dx_root_info);
root->indirect_levels = 0;
root->unused_flags = 0;
+ offset += sizeof(struct ext2_dx_root_info);

if (ext2fs_has_feature_metadata_csum(fs->super))
csum_size = sizeof(struct ext2_dx_tail);

- limits = (struct ext2_dx_countlimit *) (buf+32);
- limits->limit = (fs->blocksize - (32 + csum_size)) /
+ limits->limit = (fs->blocksize - (offset + csum_size)) /
sizeof(struct ext2_dx_entry);
+ limits = (struct ext2_dx_countlimit *) (buf + offset);
+
limits->count = 0;

return root;
@@ -647,7 +660,9 @@ static int alloc_blocks(ext2_filsys fs,
static errcode_t calculate_tree(ext2_filsys fs,
struct out_dir *outdir,
ext2_ino_t ino,
- ext2_ino_t parent)
+ ext2_ino_t parent,
+ struct ext2_dir_entry *dot_de,
+ struct ext2_dir_entry *dotdot_de)
{
struct ext2_dx_root_info *root_info;
struct ext2_dx_entry *root, *int_ent, *dx_ent = 0;
@@ -657,7 +672,9 @@ static errcode_t calculate_tree(ext2_filsys fs,
int i, c1, c2, c3, nblks;
int limit_offset, int_offset, root_offset;

- root_info = set_root_node(fs, outdir->buf, ino, parent);
+ root_info = set_root_node(fs, outdir->buf, ino, parent, dot_de,
+ dotdot_de);
+
root_offset = limit_offset = ((char *) root_info - outdir->buf) +
root_info->info_length;
root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
@@ -944,11 +961,10 @@ resort:
if (retval)
goto errout;

- free(dir_buf); dir_buf = 0;
-
if (!fd.compress) {
/* Calculate the interior nodes */
- retval = calculate_tree(fs, &outdir, ino, fd.parent);
+ retval = calculate_tree(fs, &outdir, ino, fd.parent,
+ fd.dot_de, fd.dotdot_de);
if (retval)
goto errout;
}
diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
index 54b27772..e524139b 100644
--- a/lib/ext2fs/dirblock.c
+++ b/lib/ext2fs/dirblock.c
@@ -50,6 +50,40 @@ errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
return ext2fs_read_dir_block4(fs, block, buf, flags, 0);
}

+/*
+ * Compute the total directory entry data length.
+ * This includes the filename and an implicit NUL terminator (always present),
+ * and optional extensions. Each extension has a bit set in the high 4 bits of
+ * de->file_type, and the extension length is the first byte in each entry.
+ */
+int ext2_get_dirent_dirdata_size(struct ext2_dir_entry *de,
+ char dirdata_flags)
+{
+ char *len = de->name + (de->name_len & EXT2_NAME_LEN) + 1 /* NUL */;
+ __u8 extra_data_flags = (de->name_len & ~(EXT2_FT_MASK << 8)) >> 12;
+ int dlen = 0;
+
+ dirdata_flags >>= 4;
+ while ((extra_data_flags & dirdata_flags) != 0) {
+ if (extra_data_flags & 1) {
+ if (dirdata_flags & 1)
+ dlen += *len;
+
+ len += *len;
+ }
+ extra_data_flags >>= 1;
+ dirdata_flags >>= 1;
+ }
+
+ /* add NUL terminator byte to dirdata length */
+ return dlen + (dlen != 0);
+}
+
+int ext2_get_dirent_size(struct ext2_dir_entry *de)
+{
+ return ext2_get_dirent_dirdata_size(de, ~EXT2_FT_MASK);
+}
+
errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
void *buf, int flags EXT2FS_ATTR((unused)))
{
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 2496d16d..f0cab391 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -923,7 +923,8 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, 4, ENCRYPT)
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
EXT4_FEATURE_INCOMPAT_MMP| \
EXT4_FEATURE_INCOMPAT_LARGEDIR| \
- EXT4_FEATURE_INCOMPAT_EA_INODE)
+ EXT4_FEATURE_INCOMPAT_EA_INODE| \
+ EXT4_FEATURE_INCOMPAT_DIRDATA)
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
@@ -1011,6 +1012,7 @@ struct ext2_dir_entry_tail {
#define EXT2_FT_SYMLINK 7

#define EXT2_FT_MAX 8
+#define EXT2_FT_MASK 0x0f

/*
* Annoyingly, e2fsprogs always swab16s ext2_dir_entry.name_len, so we
@@ -1028,11 +1030,18 @@ struct ext2_dir_entry_tail {
#define EXT2_DIR_ENTRY_HEADER_LEN 8
#define EXT2_DIR_PAD 4
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
-#define EXT2_DIR_REC_LEN(name_len) (((name_len) + \
+#define __EXT2_DIR_REC_LEN(name_len) (((name_len) + \
EXT2_DIR_ENTRY_HEADER_LEN + \
EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)

+#define EXT2_DIR_REC_LEN(de) (__EXT2_DIR_REC_LEN(((de)->name_len & \
+ EXT2_NAME_LEN) + \
+ ext2_get_dirent_size(de)))
+/* lu_fid size and NUL char */
+#define EXT2_DIRENT_LUFID_SIZE 16
+#define EXT2_DIRENT_LUFID 0x10
+
/*
* Constants for ext4's extended time encoding
*/
@@ -1091,6 +1100,9 @@ struct mmp_struct {
*/
#define EXT4_MMP_MIN_CHECK_INTERVAL 5

+int ext2_get_dirent_dirdata_size(struct ext2_dir_entry *de, char dirdata_flags);
+int ext2_get_dirent_size(struct ext2_dir_entry *de);
+
/*
* Minimum size of inline data.
*/
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 6774e32c..b653012f 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -600,6 +600,7 @@ typedef struct ext2_icount *ext2_icount_t;
EXT3_FEATURE_INCOMPAT_EXTENTS|\
EXT4_FEATURE_INCOMPAT_FLEX_BG|\
EXT4_FEATURE_INCOMPAT_EA_INODE|\
+ EXT4_FEATURE_INCOMPAT_DIRDATA|\
EXT4_LIB_INCOMPAT_MMP|\
EXT4_FEATURE_INCOMPAT_64BIT|\
EXT4_FEATURE_INCOMPAT_INLINE_DATA|\
@@ -1978,6 +1979,25 @@ _INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks)
return blocks * ((fs->blocksize - 8) / sizeof(struct ext2_dx_entry));
}

+_INLINE_ struct ext2_dx_root_info *get_ext2_dx_root_info(ext2_filsys fs,
+ char *buf)
+{
+ struct ext2_dir_entry *de = (struct ext2_dir_entry *)buf;
+
+ if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA))
+ return (struct ext2_dx_root_info *)(buf +
+ __EXT2_DIR_REC_LEN(1) +
+ __EXT2_DIR_REC_LEN(2));
+
+ /* get dotdot first */
+ de = (struct ext2_dir_entry *)((char *)de + de->rec_len);
+
+ /* dx root info is after dotdot entry */
+ de = (struct ext2_dir_entry *)((char *)de + EXT2_DIR_REC_LEN(de));
+
+ return (struct ext2_dx_root_info *)de;
+}
+
/*
* This is an efficient, overflow safe way of calculating ceil((1.0 * a) / b)
*/
@@ -1997,7 +2017,7 @@ _INLINE_ __u64 ext2fs_div64_ceil(__u64 a, __u64 b)

_INLINE_ int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry)
{
- return entry->name_len & 0xff;
+ return entry->name_len & EXT2_NAME_LEN;
}

_INLINE_ void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len)
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 7215c517..2ce2f6f7 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -149,7 +149,7 @@ int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,
/* we first check '.' and '..' dir */
dirent.inode = ino;
dirent.name_len = 1;
- ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
+ ext2fs_set_rec_len(fs, __EXT2_DIR_REC_LEN(2), &dirent);
dirent.name[0] = '.';
dirent.name[1] = '\0';
ctx->buf = (char *)&dirent;
@@ -160,7 +160,7 @@ int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,

dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]);
dirent.name_len = 2;
- ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
+ ext2fs_set_rec_len(fs, __EXT2_DIR_REC_LEN(3), &dirent);
dirent.name[0] = '.';
dirent.name[1] = '.';
dirent.name[2] = '\0';
@@ -296,14 +296,14 @@ static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
ext2fs_dirent_set_name_len(dir, 1);
ext2fs_dirent_set_file_type(dir, filetype);
dir->name[0] = '.';
- rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
- dir->rec_len = EXT2_DIR_REC_LEN(1);
+ rec_len = (fs->blocksize - csum_size) - __EXT2_DIR_REC_LEN(1);
+ dir->rec_len = __EXT2_DIR_REC_LEN(1);

/*
* Set up entry for '..'
*/
dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len);
- dir->rec_len = EXT2_DIR_REC_LEN(2);
+ dir->rec_len = __EXT2_DIR_REC_LEN(2);
dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]);
ext2fs_dirent_set_name_len(dir, 2);
ext2fs_dirent_set_file_type(dir, filetype);
@@ -313,11 +313,11 @@ static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
/*
* Adjust the last rec_len
*/
- offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2);
+ offset = __EXT2_DIR_REC_LEN(1) + __EXT2_DIR_REC_LEN(2);
dir = (struct ext2_dir_entry *) (bbuf + offset);
memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE,
size - EXT4_INLINE_DATA_DOTDOT_SIZE);
- size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) -
+ size += __EXT2_DIR_REC_LEN(1) + __EXT2_DIR_REC_LEN(2) -
EXT4_INLINE_DATA_DOTDOT_SIZE;

do {
diff --git a/lib/ext2fs/lfsck.h b/lib/ext2fs/lfsck.h
new file mode 100644
index 00000000..9401cd0c
--- /dev/null
+++ b/lib/ext2fs/lfsck.h
@@ -0,0 +1,42 @@
+#ifndef LFSCK_H
+#define LFSCK_H
+
+/* This is unfortunately needed for older lustre_user.h to be usable */
+#define LASSERT(cond) do { } while (0)
+
+#ifdef HAVE_LUSTRE_LUSTREAPI_H
+#include <lustre/lustreapi.h>
+#elif HAVE_LUSTRE_LIBLUSTREAPI_H
+#include <lustre/liblustreapi.h>
+#endif
+
+#ifndef DFID
+#define DFID "[%#llx:0x%x:0x%x]"
+#define PFID(fid) ((unsigned long long)fid_seq(fid),\
+ fid_oid(fid), fid_ver(fid))
+struct lu_fid {
+ __u64 f_seq;
+ __u32 f_oid;
+ __u32 f_ver;
+};
+#endif /* !DFID */
+
+/* Unfortunately, neither the 1.8 or 2.x lustre_idl.h file is suitable
+ * for inclusion by userspace programs because of external dependencies.
+ * Define the minimum set of replacement functions here until that is fixed.
+ */
+#ifndef HAVE_LUSTRE_LUSTRE_IDL_H
+#define fid_seq(fid) ((fid)->f_seq)
+#define fid_oid(fid) ((fid)->f_oid)
+#define fid_ver(fid) ((fid)->f_ver)
+
+static inline void fid_be_to_cpu(struct lu_fid *dst, struct lu_fid *src)
+{
+ dst->f_seq = ext2fs_be64_to_cpu(src->f_seq);
+ dst->f_oid = ext2fs_be32_to_cpu(src->f_oid);
+ dst->f_ver = ext2fs_be32_to_cpu(src->f_ver);
+}
+#endif
+
+#endif /* LFSCK_H */
+
diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
index 65dc8877..5bb1581f 100644
--- a/lib/ext2fs/link.c
+++ b/lib/ext2fs/link.c
@@ -47,7 +47,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
if (ls->done)
return DIRENT_ABORT;

- rec_len = EXT2_DIR_REC_LEN(ls->namelen);
+ rec_len = __EXT2_DIR_REC_LEN(ls->namelen);

ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len);
if (ls->err)
@@ -92,8 +92,8 @@ static int link_proc(struct ext2_dir_entry *dirent,

/* De-convert a dx_root block */
if (csum_size &&
- curr_rec_len == ls->fs->blocksize - EXT2_DIR_REC_LEN(1) &&
- offset == EXT2_DIR_REC_LEN(1) &&
+ curr_rec_len == ls->fs->blocksize - __EXT2_DIR_REC_LEN(1) &&
+ offset == __EXT2_DIR_REC_LEN(1) &&
dirent->name[0] == '.' && dirent->name[1] == '.') {
curr_rec_len -= csum_size;
ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
@@ -110,7 +110,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
* truncate it and return.
*/
if (dirent->inode) {
- min_rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(dirent));
+ min_rec_len = EXT2_DIR_REC_LEN(dirent);
if (curr_rec_len < (min_rec_len + rec_len))
return ret;
rec_len = curr_rec_len - min_rec_len;
@@ -138,7 +138,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
ext2fs_dirent_set_name_len(dirent, ls->namelen);
strncpy(dirent->name, ls->name, ls->namelen);
if (ext2fs_has_feature_filetype(ls->sb))
- ext2fs_dirent_set_file_type(dirent, ls->flags & 0x7);
+ ext2fs_dirent_set_file_type(dirent, ls->flags & EXT2_FT_MASK);

ls->done++;
return DIRENT_ABORT|DIRENT_CHANGED;
diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
index 7f472850..aa88f3e4 100644
--- a/lib/ext2fs/newdir.c
+++ b/lib/ext2fs/newdir.c
@@ -64,8 +64,8 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
ext2fs_dirent_set_name_len(dir, 1);
ext2fs_dirent_set_file_type(dir, filetype);
dir->name[0] = '.';
- rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
- dir->rec_len = EXT2_DIR_REC_LEN(1);
+ rec_len = (fs->blocksize - csum_size) - __EXT2_DIR_REC_LEN(1);
+ dir->rec_len = __EXT2_DIR_REC_LEN(1);

/*
* Set up entry for '..'
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index cfb10bc4..1edc0cd1 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -1084,6 +1084,7 @@ static __u32 ok_features[3] = {
EXT4_FEATURE_INCOMPAT_FLEX_BG|
EXT4_FEATURE_INCOMPAT_EA_INODE|
EXT4_FEATURE_INCOMPAT_MMP |
+ EXT4_FEATURE_INCOMPAT_DIRDATA|
EXT4_FEATURE_INCOMPAT_64BIT|
EXT4_FEATURE_INCOMPAT_INLINE_DATA|
EXT4_FEATURE_INCOMPAT_ENCRYPT |
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index d0a18a18..44dd41a5 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -157,6 +157,7 @@ static __u32 ok_features[3] = {
EXT4_FEATURE_INCOMPAT_FLEX_BG |
EXT4_FEATURE_INCOMPAT_EA_INODE|
EXT4_FEATURE_INCOMPAT_MMP |
+ EXT4_FEATURE_INCOMPAT_DIRDATA |
EXT4_FEATURE_INCOMPAT_64BIT |
EXT4_FEATURE_INCOMPAT_ENCRYPT |
EXT4_FEATURE_INCOMPAT_CSUM_SEED |
@@ -183,6 +184,7 @@ static __u32 clear_ok_features[3] = {
EXT2_FEATURE_INCOMPAT_FILETYPE |
EXT4_FEATURE_INCOMPAT_FLEX_BG |
EXT4_FEATURE_INCOMPAT_MMP |
+ EXT4_FEATURE_INCOMPAT_DIRDATA |
EXT4_FEATURE_INCOMPAT_64BIT |
EXT4_FEATURE_INCOMPAT_CSUM_SEED,
/* R/O compat */
--
2.13.6 (Apple Git-96)

2017-11-14 07:04:55

by Artem Blagodarenko

[permalink] [raw]
Subject: [PATCH v2 4/7] debugfs: 64bit inode support

New dirdata type EXT2_DIRENT_INODE is added.

Lustre-bug: https://jira.hpdd.intel.com/browse/LU-9309
Signed-off-by: Artem Blagodarenko <[email protected]>
---
debugfs/ls.c | 6 ++++--
lib/ext2fs/ext2_fs.h | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/debugfs/ls.c b/debugfs/ls.c
index 5655933e..b67c0800 100644
--- a/debugfs/ls.c
+++ b/debugfs/ls.c
@@ -64,11 +64,13 @@ static void list_dirdata(struct list_dir_struct *ls,

dlen = data[0];

- if (dirdata_mask == EXT2_DIRENT_LUFID) {
+ if (dirdata_mask == EXT2_DIRENT_INODE)
+ fprintf(ls->f, "ino64:%04\n", *(__u32 *)(data + 1));
+ else if (dirdata_mask == EXT2_DIRENT_LUFID) {
struct lu_fid *fid = (struct lu_fid *)(data + 1);

fid_be_to_cpu(fid, fid);
- fprintf(ls->f, DFID, PFID(fid));
+ fprintf(ls->f, "fid:"DFID, PFID(fid));
} else {
int i;

diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index f0cab391..90294ed0 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -1041,6 +1041,7 @@ struct ext2_dir_entry_tail {
/* lu_fid size and NUL char */
#define EXT2_DIRENT_LUFID_SIZE 16
#define EXT2_DIRENT_LUFID 0x10
+#define EXT2_DIRENT_INODE 0x20

/*
* Constants for ext4's extended time encoding
--
2.13.6 (Apple Git-96)

2017-11-14 07:04:57

by Artem Blagodarenko

[permalink] [raw]
Subject: [PATCH v2 6/7] quota: swapping s_prj_quota_inum superblock field

ext2fs_swap_super() swaps s_usr_quota_inum and
s_grp_quota_inum fields but not s_prj_quota_inum.

This patch adds s_prj_quota_inum swapping.

Lustre-bug: https://jira.hpdd.intel.com/browse/LU-9309
Signed-off-by: Artem Blagodarenko <[email protected]>`
---
lib/ext2fs/swapfs.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index b7c01005..60cdf124 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -81,6 +81,7 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
sb->s_snapshot_r_blocks_count =
ext2fs_swab64(sb->s_snapshot_r_blocks_count);
sb->s_snapshot_list = ext2fs_swab32(sb->s_snapshot_list);
+ sb->s_prj_quota_inum = ext2fs_swab32(sb->s_prj_quota_inum);
sb->s_usr_quota_inum = ext2fs_swab32(sb->s_usr_quota_inum);
sb->s_grp_quota_inum = ext2fs_swab32(sb->s_grp_quota_inum);
sb->s_overhead_blocks = ext2fs_swab32(sb->s_overhead_blocks);
--
2.13.6 (Apple Git-96)

2017-11-14 07:04:55

by Artem Blagodarenko

[permalink] [raw]
Subject: [PATCH v2 2/7] tests: add basic tests for dirdata feature

From: Andreas Dilger <[email protected]>

Signed-off-by: Pravin Shelar <[email protected]>
Signed-off-by: Andreas Dilger <[email protected]>
Signed-off-by: Artem Blagodarenko <[email protected]>
---
tests/f_dirdata/expect.1 | 15 +++++++++++++++
tests/f_dirdata/expect.2 | 7 +++++++
tests/f_dirdata/image.gz | Bin 0 -> 72169 bytes
tests/f_dirdata/name | 1 +
4 files changed, 23 insertions(+)

diff --git a/tests/f_dirdata/expect.1 b/tests/f_dirdata/expect.1
new file mode 100644
index 00000000..17e24325
--- /dev/null
+++ b/tests/f_dirdata/expect.1
@@ -0,0 +1,15 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Entry 'foobar2' in /ROOT/dir1 (439) dirdata length set incorrectly.
+Clear? yes
+
+Entry 'foobar1' in /ROOT/dir1 (439) dirdata length set incorrectly.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 543/5000 files (0.9% non-contiguous), 707/5000 blocks
+Exit status is 1
diff --git a/tests/f_dirdata/expect.2 b/tests/f_dirdata/expect.2
new file mode 100644
index 00000000..84cce856
--- /dev/null
+++ b/tests/f_dirdata/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 543/5000 files (0.9% non-contiguous), 707/5000 blocks
+Exit status is 0
diff --git a/tests/f_dirdata/image.gz b/tests/f_dirdata/image.gz
new file mode 100644
index 0000000000000000000000000000000000000000..ccd900e1c6da30a76be4334767922b2babf0f88a
GIT binary patch
literal 72169
zcmZ^Ldt6NEA3u`N5?b12nYGv=X|YM09M_Fpa#<>2C<$S#q*d~eOLFVGx=9!$EsgEQ
zMyaC}EzxvgQmF}>shw(~xzssxp3m<&XZrpA`~By2=IJ?~`{(_+9HP_x`#*Fq@a$u@
zeb?r|fL^Wj7T&*9|7FoJH|waM`;!LO0`DyQ@9gxa`u|~fs*j&$(C~0gfnnpyR~NR;
zJ9G1o7RGP)k5dmkdug-GZ}&k}FYDi1+wLoB-!=W&8ZS{Uj+;5<P>%i*C$-Laa(zkS
zpJ>N~5zEB%NQ9m|^NXHz34d^zmJr~<Ort;UNdC7`ekQ(TRb^#2YMZ?Osb~Fxhm#)-
z)9$LJ{S!Y0jrga_{NUNBk54nU8`Bdch05xyJ2ZorS;rbv=&<)SGs1pZe{koP`oRwQ
z_eTa~y%NosRd~plITRVcvwVv2qk{)meAs+u!l#;?xB-a=E5~?FxJmu_$NFanTkq4I
zHv{EYd^UECKAFBGsn}t(b#2DR-#_Fx4er!CXO?Q4wu-vZ-JCap*yaqn@ISN9^;+~!
zy8aBkg-$t?stfW=oU$QrUrS}`5-+`1nYMKOl0WaN;g7$&r)}tsR&9HxVq9-5`G05r
zKmXu3byDplExau=e3ZPeEvddT`?72o3~-#;b9c|*ncKNGkDby)yG|%im4oTEJwNHJ
z?A2K>jGY;>C8AZ}qT4n71G+Rhp=Q_lqttWn7Am&7OMPI%zg<CBluwq%j&ZxPb&6`r
zYq}-iRpTFj*g2&9UmA7Qui|cfG`~PMGRm@tlgGdAnp}NmKT~&S$qJ{J)$ee3_lxSN
zf`5a~pOI>|A1u1rdsJnDAc5;^P9;It>Cf~x2?LV~ci;WAarRSh|FcfZH;?%De3LW;
zUntN`9tZhB2bEHMu~3GSI_UuqKFK#jbDL=6N6}@qVrg(&XS>s5t>;L}7~~M^cJJjw
z9D2`tsUc=enxp!4UhvI~<ZWG^(-d2Z)!!x#f=B<8I9@2d_9*__Dk^OAYsuZEGni2U
z_vEb^w+9aD{30xgetd6XzO3}%q0W`1TcmLPsUN)1K-Jj?(#^7@rx(rMnqAu2rLq6j
zsk<W4`P>E5!Hy*O`!8d%7qxlA$Ij%Kb>Fkb)gy1P%7|x1&#7Av-OjrCwR+YbeELm?
zr<+U4u1)zTtv^naDi6MzR-@9aTQ&=lGGOc1A9K#epS+LlcRZ##j+DAY#pGUc@~UO&
zPk#ht8;pti2z0S<fr@@`tW!MIx09Zv8yD=-m)q~uX4pJyM^bAtN;_kKD4&m14g~du
z_cM&5UEMBDnW29>1*f*b)0BjF!JOCM3Fu8lkRpCRCz-Y5>)Ck1uCD6nTkOq{B)Mev
zj-;JhDz07G@$58qn-)<&%O8m74*EO%pqS_HFiqj-?=V&2`_#ipQ5R_#5a`>fapC4_
z-yOdtaP#7RzwX+G!sWG=6%HTNDJdtcUhjC%7^5;Q>jIdK0k>4r+PG|Qzw7@!IN;0K
zpHxwuoM_3Q>VSWO4zK#F3@E&({#~8_cKbF){@cNJ&Bc#mF?)2QnQm7>KaX{j%~Hly
z8ZS>^(ML6X=a`zVoMDXJe=K51S5QId3&Kv|tgV-kRU16lkNK;$)O+%;zmJ>$!OwbQ
z4RR==&)n%2XR9LGq#S<tsiLJD?7Ku0y7J#VM|-d2jWcBY{!x?4iJvu;CPet0o-k|Y
z0`KPXf3ki}Pyr{Ga^e>#!P;0_`&ph@-6@UeRA#MNQM!Nbu1d~zWc7aHE|;%NvE0Lq
zgPhz~nK$SeGrp#q2R=skvJ_thUCvUNZM16I+2xzQ{7U)3?JBfH>*|ud9v<vK<w1{L
zD}o;VR%JC{aJyeSte$kTlYUVR;nN=)#_ErJ{_7*EuX**#B2kjuz7`b#gs^Cz_xgj|
zcK$Z6?<Np0egpPzeu7aAiV2;D3Y_t;#=n$)IMs0Hr(^w`t@`h(neuNu=QY%5U;7g{
ztvgti_d?|?(y{bs17y#=^7y%r64VQ0PMwZ9d-u{0dMH}vFrqV<DzTXj;h#ET^a)t*
z-!@ILyD@0<7H(tW#xQKzWjwf}K)E|fF#Djbo=F;TzMZOspbcx`g%qStFXUg_f1PFZ
zOO_Laf6l!(rL+5`yF+XQp15WwEB@i_>N6oj--%x<IO(4OfeWf1y4J5ZIZXJZfE~36
zZ+;*-sJycz4%UDF5WI4npfE9`uVQ!NUp(damg?iWu|_<$UU^Vc;Ftu1PQcIpyXHL{
ze7o)<{5&96^x$QlpXrsIhR@Wd`=TEeV~?S;UJpQxJtZcpd9O}i57HmrdX7}bWi2-o
zn`O=T6IN6A!@Fa`d%aYn55)78I;l_n8BKnO4|nHY{BQOvA_u{XfZ1qtRCw;4Zprd+
z<=w!H&2C_2ne(Qu4klXvvt4?q^kjyv#BUhhuT+mR-#uaxJALp-7oUyy?`O|UjmXv1
z9g*u?DxtV<{u4zo_vpff-kY;_`_NC%>}?Z&q#kt@`g*N}(F>rW7wYUDJ$R=>Sq)|L
zNIAGkGv%{fHw{9kbKOV|U(Cs=L@C|q;3xCDE}=K2GY<Jh4*0m~lI`9b_xvAtmHX9f
zH?|dgccMO{^rwefM*cY9=7UqmjjXJj{XwKFyHvoUcebT{29C@LjCf&mDk|>IU{6WG
z2Z;vfKHVSQZB%hpZkt`&B*r!s9CvHXo%grfw~0+nn%?KxyeonEA0syGz7py7zNr(Y
z!Nvs;HV53THsl8z<byhL&Dij0W3WFrE*k5O;9JmrssN3NM!P3;Y8*bxkLpBowV~#W
z#{OZJMJPP%g}RLFNn@uUS7Oc8UuDsQRc;ShRcx1P<uoY#4i0*Q&jJ+Mj5UXj7NA3i
zse_nXfV+2fyKd=n-SSDkxV6TtS@h=Jy^R^~HH^4bJm<Z%`l&I$_H*bAu715aHqXT7
z(Qe^=IQ6l!nwRy;-i;CqL#TC^>zmJ^FFHbByceH(lVhVbQqK#lLXmqkn(fr7nbHwj
z%y^B}w+<@6OAh|iK!5v4G!@45fk<y)imyamW#Lpu;akpfv9U8f33(ntV`a$9PhMEg
zA<vdWZ@J68@X2n&urAllobS+Z{n2)K=3K+tBy`!Vm<|nn;BRj@SA1pE962~!&ws$$
z^zIt>QR&_&?yFWNzX_hd4YL7N_$_zZ!#MiY3p(QwZKpurW~qLj12@EDatx0BI^18-
z(ns`H3M%1Eu>Vzb_rsAN+VPVK_?*W_<%T#IUcz{e*T3z15!Rmh=21P}_mOBev|l$8
zU!s106TG^)TUk2cQa)N7jpjOaIz9&vKQ3`txIXF%)D@I8D8Fuuxqwz;)frtHrtdfr
z2I_xWu*cvy;gjQyt$1O#c%lq;`^jHkV_^ups2!*FCJfs&q0}r~a?&mLa6817Wg8sF
zeF|MQ9ms3HP(Yt7RYJKj^w-uo?RZKrRBSx`nX-{lIxGL(<}Xoh^*6=!w5*uUyvW}Z
zkcCA<!gmjPi9D478u4HgIbMU+DCSM@C?X&I^P;z0=@R2<yCh__5_^qN!^t<nzT0rP
zqur@|WX@ZP+k$Sfxi8LUX(_qO!VMrUsDCJ&8V1*Qd=$sQnqo%vZ3BpUxq)iQR*iT-
z&szqlHH)+oD>q0yD|%i}XBX2K1ft@zaM=Qw(~QMxS3O?C>zI(bCKJa;<I%)+W7{g;
za_Jt%)5InSNyF9Rm}XJmdYI3A@u6KjsOR=UYK^<r>cmI-_k~fxhKwnn9Ipuy4UwTG
z*O7ZO7CB1`(4fPVA1~)YGUR?8**0S;Kj4c{xHt^X6AiD9gV)7O=yy!i90NFc*09xm
zx*n^9$A2?XLpay@6u9o$(l-=phoL}0!8`mpS8FbR4h8vNI-So)qkCR3T83<{Bd=x*
zWj3vx+QYcymO#CYS{dK09Fzwr>-&U!<koZCO@^GW^9~6&R(}%;%rK}FWcj*;3AJSm
zhZ|t!x8hl$$jfwIYOkOzDrj3Rj`=*Xm8&0*1BgM}LGWY7FrG0)wnNCsGw<6qgL#7{
zk4qTC_l)60J76l)VEA8GK2fhDvBM)e&3vuKtRC`PJsR6J13IGQbfO(}7BhwkjNy0#
zOr5#!$57-LjeG=dA7*0iB<6^t{$W+ahMO6O@<#qJ3tw9RD~K=yE52&SvxmW6f%xuC
z9Ba+7^9`We^>nYnU{2hT*hjY?_xL2<T+UL1p{zma`Ch#7C2zHq40>IMUd^1y>s-u-
zc4aS<W~+OtMa#8TQHOA-ZP=_(I57+c3fDUoGwwsUaaX0_c6-*5d^D~{mg8hF=Q<ky
zBiuXqqJhpTrmvsxHjHROXS49pli2K<3jCIQzt<q?!*iQ!2SJfK(Ne9buNzcvbB@kO
ztE15bf!m9IT*^s&l>EWZ3D4egT#qwiZy37(?3%mj4~zBq<#-(bniq1=37yD8E9z4Z
zY~HeW?aFU@$p1zyTBa2ZtOxhmn>5OK@5KvwZs`%;uz3M&BSH)Q@Jl;(=(*e>3qOv=
zkFR!X{@Y!3pUpkr<+Vm|_2CNYL^JixMQ9JcR8~(r@u8DM04D_+UqSV|2sa--ZJ^H<
z(-#S|Lz~d9Oq{g<hL&>>7W?&EuC9;qU8iQ;bEx&>KAgnkNPsDjzF~7?yS%)F>qjf7
zE6pOydO)?#vH7T%>3YXrYU)(8$bvIEii;<=<F*OdNieja7@g<0ObJo#Flm;-s;^12
z=6;;JHRnFp0P9KvgAJN*KV{q!oX|oBUtLFi_JL&Bg@5X){wC4b9Mg%GXhnkxVBC1s
zH|@A+7_1XCYwpjL4CP9QQ;quVL;-T|QLMWR`d$Zb;>s$Q#C&8MjdqdrXa5|2+RWJw
z<4VYTYm}J=tKPiRdd0!<O`I*ch7ftr_v5by&E!uRDFQixGT3q*`VvdC2>+h^(8uH^
z>PVe*o>tnw06t__9c;%NCg2c3wdzwksfSkDmosYgqguKA-X^=x+svg6<!s6Q?8^~*
z44NsQGSY<mLuIh<I($jIxl`WCh4(TY58K2A4&l<~8Bo-G%Ll9>uB+N4ds_wiz5<QZ
z8pXTnzH7$?JrS@V6X!(ZDq?>93T%ip9X^GwnFfc5(w#}RX{OA=IGbO#3<!nULb{Ls
zOwaZPmj#eiuBLlezhMpWUHL-LskTv5iOrN{7?=1%z{F5EWJ(kCA#XUa0BXuv`eWDR
z5AC8!pF#zK9KTdc7ic|?l|e&MDIwItq+MMJBe!MbN6Mi4v;BQGYO&Exum#J<jN`YA
zoJ5Q6b_YE+>mlDP6I({(&Z`D624RnO{B9WX6x{0XEPVPTUR-X}R41h0XWe_m^WDxK
z^pR_;pC!5o!;LRb&=IvU4+<KkOs*lf*4?AEVCRd%WCwQD&4T2hgzA&8sbOmA={JTx
z+pt$l^NuoX)*J8dkDRk$jtuSgQ(9i@mKy%&bcwTAY%Cc5lFomFhA1ejEX~65PBiDq
zJ@SK@acZY#tX_0RCtuPUK2>W}8U_b}T{InYz1#35>%N)m9LjF&;|4M7@1M(oA&050
zxS$x%&&1u)5st^NK;T~+<u&M!Vx?DwG5j<a<;PhLVK?@3gA8mH1l#!Y5yiN|8(H`%
zONlPIk{NsSqVGQ$R{scvez4gax%(;Yud3kmeCNG-(cq2}0zuxOnF@MHmL{I~FOw+a
z{Kw-#MApgU;dBw>N(eG{1IoC^IuM5Py3AkvnI7s5e-{^e5o0X5>>R8YP5dPJV;i2(
ztz0BSL;aLNSGy&+kMB&jqz~cP@frAK;f2u=8OPh9X-bwpCbr9Y)sJxA=r~v{KJ&)#
z(>AQ0vEM!re&ZRK&@G;&pl4=jbmhj}c=e1joH8DtB?27}qXJ5mQy(j*o<;-wl%vQ?
z<Qd+qZ7<V1hGpUj(GikkS0HNFo3a{ox0sH;-kta_N+Bt~xX^iSr}EZ@P$CX9o@;X1
zQJv$m*6`_CBmH)>Z6IU~gPS`D@H!7?pD>AI^#$f(SQ(LY4`%Wap`I`|Q$|~6Y3>kp
ze!joq5?8Xs$eGBB(K!-*j?x;@<6X{yFrXKDVO;W=9^egoiwkq-%fTSZ)JyF?Np1>4
zS|CFQ{FJUl4N~X!cdZn`EJ<iFb{?P>A9-U~PH^2dc4HZioq%5o_a~pxWh`n9x6v{g
zVQj=DF0F^-o0~ZMp=`sT%dmBsAy_Y+^ht6}c)>3+6yT=}zuGOXE|GC*y-fnTxtU8J
z#x_{KgzI`yV=J}cy>it{WB8)abc;9aC@wV2?WCiJTDY+CUObeYe;!^wV!Uki1)?x6
z_x_8qWqA4oeCJDE5y{cIjJd6BuOFdKKP3o!dKmWchKt38R`WXP)xm=aK@OiJcLaiV
z%8-MfGKvs%8-|wQ=$`XL5WC1@k{_Z1y;=G1UAZfHvyco{(1Wuy<A^=h{q9caG4JyK
zC?@1QVX7zSBfiXoy4SOw)}SlJ^c_LNotap7GD39pBmG2^t@rF>IzC}Dw;?)06!npI
z@*1ORrNr-*%L%_8pXqLI<m{)ky;_YNK3;BYrG@10xftj6QfrpCvg3)M!#iUyaW)=C
zGl5^<lRCq<`iOyHoU_(Oflv3s7kJA$or$j$7kbXmfbT^=J*hz?{TB!XozB7=iworh
z*xgu{=E6GmHc{kI#DrV3vq|D}uJ>=Fe|ax5dCe*rP2xl_;rGq$>6f^~9)%@r<|3ja
zY>EAN9hL9Zi>G|jTouH*S4NAnG@T@t&VCj_0>wa+-zW#l(0o6o%~b=6kiMuzsm0VH
z!Z7jIcyIW*xNtT3p(e)TV=Fz7&xwwN;el%9g*S$U+puqT*?}^gJ^>e<;zfPuDdRj=
zA2A>dXK?00;MAiqCvUh}T<AzBT2{TD2yX3r<;n`))bDvC<fqJ-D~HRjseANd3zLue
zM(HF!x3U9CZDyxgSccUT@MV)gV{{TC>5yif@|Dt?mGm+RXxAeq_gg*JPs>QUE0$d1
zoIQ;5h4XbMb&|!c?4*6z^DX_N23bE6P3JAeT0uKyX@bhTQE*!jIlsi{N`SkBaQ3xY
zdE$*Bx!ee)$Gv8<5}`cvJrBEznA{0^Zp4oOsXFx~F4x1DZ+DTnU+!?V^4y!yNk2lU
z@$x;G(Ie9tGSn+elY6b(Q-|oH8kAp5rwcl+%ffBZ5#p$i)SystQ!8y|^5R@GwP;Z*
zJGxmX-UEcBP;&o7;eKni@<^?-mT`ReZ!&q_qvZXYxuYi|l*cy0*}}3~lv_;a3)kmo
z;iBR~<?)XwIIxh|mQ@eORtnlWOJlg&tvvDbtxKH2!x;WY5)u*mZPcQ9t!xAV8t#X-
zw9!_)j``<SYGu+JgGG5KsKXnG@`)d;7L>+$!<6De2|+T3+v`=Wh`0eCheCUivf+(k
zS93SGszPV7qPQ-D5Uw@fD(F#J8dqYcEyENzs>chWGI4!$1nU11S(?9XY(?JhmA=CL
zkG)|`aUn$tg!s1Id-YTwlTo-v>NG@`{v_%LpSlMtqmgJKpCr!tap6N*OzPdgVh$wc
zz|<ZMOqC&#pHe!nQ+eoh!-rP1{=L%crI96m{J|Rv$qSBN0e>o>4fWwU783^gsFg8q
z3@QRmx}BATu~qMto&rU&-mt<?8G5Z6C0kR3RN@B$$HWb!Zwzk48b964oykfQx}qlW
zItv}C77_bJBvN>Za`aSB>To43kU6caB{^@)N`m#2{U=R^;F&%$L^2mk-fWw!*`ud=
z{J=Fz7enlNg0@o>o@nL5+Ac9Z7VLV-Q^tK5i*3jcDuXvGwJ`a?<r2o~J3Tj?G=8|V
zF*8~5|GKP5*Wu84qo$7n{g9<0+N4oVj0;P0!O%{P?K4=FiB}dEisoscwMjQ15Ka$+
zJ%U)L_;FD~SUfThtbY2Z7KWMZNHa`<?6Ncxl7v2)QBAGL=e@|3JOX4$3%>>@zT22k
zGxCukA#U){8>#+g`A6G#4>2D;Id1oj{QT6^{QTrWJKyY!-WQruIryjPsxzvGOA0i)
zgEIqv-4H&zYh&=c_a&TB8bZU@O>aX<%Jj|)PT)fO;HCIDme{J5zqlAS>;vhqFYcln
zjbi0W^4RgbPIB`SJ0=e@zTVf64O1RTpV8&e=Eo)5s|sWEG<!;%*-HC%KrMe<;;dHA
zb1|6h0}5W;g)u#+NxQ~gb?9URT&XYERzrDoz|+Opj3d{d(n(S-u|xBqWcQwD*|71E
zGO@#kp$lZlx9M$61xJOPC{5rD1Mr}4n#9eZ&%(9TGuvhY>yB-QZKmrN=HRxtU^vze
zPomam5ohX<G~2;E$d&3O8JF0=eUP!{^X&jIJ50r*YvB5b30+afS>}Or*ydWe+Nk`8
zCtdTcTDj82uzDY8@{AV)V1CbO(hpcw#(lwI_~%5m11lO~9Oe3)h+y<q&Xq8At{rlw
zHDtD;z8!&|9ks~a8~%L$Kujv+yx5yu%s{;C?Z4EVW;mCP>*Ipy1r$iM4+Co8t42@L
z^DJB+A571qK>YLDzlbMwNdDuA551(*T)V_NG2POxYumxPhngbB@JktIPo5rVA6<%V
z&0*^~{<XF~u(7r%`3Q%+3-S{<)XSJ;wB(dlG9+nwTX>Zg>qZ(Tv(jP4WP$k0%yifS
zdp$qCQ@Xntd=G<!Mv;H7J~)|${$10%i3UVIQ26|T|6v?@`}OC0t!Q0`<efm*MV%(?
zlI!=)q7BqL-vmzHOE4eJ7iwybOX%csv^nbXO-?=#JJkP6t!Rd_Y-|=ET+)xTuxk18
zaW=R-lKz9PmcwO#&SIkKoEhVsG~%nOY&cLv$EWZlA5fsoz3ul2$**2{Cvc8E_xDj#
z3tS9!%_?ZB$Z}xCUmAS{PBv`eq9&=%MYSWVVNbGJ(EyVg5=nLa{K1D5DSYxTCgl5c
zNInSUC+S3gUUKc-ES~x}tO|SeLf`YkKCTm8yW~1H3@mqa{}lk~k;vDbmqNM>7B#(%
zE@#E5%%{n$*vuqWQgq+l+g`j4k9u`ZQUiI7a3|SlF@RHsDA1X`?c<xdjJB0k*tr+_
z4(5{UkLqB#OXw;scHXq9Pbqdbhy8-qoP8kc`GZ(e75wWrz=2ivF<tMVK$rHm|J%$-
zmM!|O6z7_QUO1lX1D~EhP|j6CTfToS3~rSFOMId|6I;gxr_G@uq-~yGDGoJ<!NT!S
zABZN$7iv(9dOQ)0l}R)PZ&>{N!RqS<dgin9>-4l^SLnVt;uraH#&d1i<$(oIAaYF#
z01K1Jg+F3ESC(;O80;(wt-@C3uzdGt(PS;M@_}3Ao)jfGj7fN#4dZytW|o7SAD1>!
zwVY&td+kYjG`TBuKYxAr3&zu{?DB|u81*u&Bpa+v&g-_B3$#-$k7|dAr)in35ZkDH
zBDf<dif`_1*AgMDe;w+;!WSmHl=^_r^9R$f8tCJ{u3D#ug&i8fUksLN%GV|IXHrBf
zAK!)5J+}vNDm&F7ksBDI(z07&X@}+`Zw7`lI%)bPS8Ilojyk0A(WAkp+f_0+*z`83
z!azAXChO7IuF%j}7($3IVjNeLT{e$^*e!lLO0i>aqS>+Jp7T2KAD3M1!=QAP+t~o{
zibPg|;dsg5yQa6Kv=+aq+wQ>9{Y;t-QlPB8?X9HMxjB71h|S@OpeZ^VFNq6Q%~8Uu
zpv1ClTAog8<o_!3p;Nb+OPr)Ci!Oximz@g&khq9WOfiNVP+_4ArZv5NP|nfHHC0&B
zo48>COCwJF-%wl{AFTS>0MW72y!A0-y9`7D8Z3A2r>5t*<cjjZ@z(DZ*=Q**qfk(d
ziq(lzFS%Off##&4FaW$Gk;u8*O4kkt{j+d7xoe>Ttm~GtCH;)i#;7pz@+=>4dj6o3
zR0((VNt4-<p+@$n=fYi4I&u1?I#E4{Ri!&?s42uoc|OjTG8wDOMjs{}`#*_beLFNN
zJ80mfnmQSTHN8F3%sI+iCMR$ocs@v87^9}=x`Yl11N)z*r3XM)Btn8*yJYZl)7v8A
zU|S#TOyI0d(ZR8|nqKS@+CL0}8e{9T(Yzvbm=7l6c?y)Xw|#{cS06aL9Tu1@dPy-O
zSyMLpL?L|LFgYp!iX&kT;n$j>i)ApQ>Fv8_R+{7!ypFG0tcB;}Ww5{L?NHM3+j(j`
z+=zs41!8W<U~tph?ut$-d+n4`{LB<g63^(Aw=U)P$^)sRv@RR%Ekc<BF?$u%Dwoi?
zKZ4wnB_?NKaz{-j&W{VWnP-5R>ZNSj5M$I#KE0%F;zI3JQ_eI%<=ub$YhZ)PpbJVF
z&C0S3q*vJ)AP=gcQX8pPLY|(W7NuUwx66aXnSr&`a8qblm4#Vy_k0?<-(5JEz$vYb
zQ4gM>`{htj!nl*`&lQ4XeT6a`?ckl4JWt)q8OZY^?XbbWueaWFT$fcS@4ZVNGolq`
z8-_&ywYOk9-0hKMDI@x&Yy;_S2IhWow^h2lLnI`L#B)08#-;op32KlJ-BLrjnaHWk
z!BO$Si3Hr5sg|*ULyYdkXv!gA6BlErnsT}wQC<VHTBSoxg8AA9Ql393y~c_kdS4^7
z+Zf$l_~Qj~Mzp$Y!<c%g-1TFdv?t&vd4u)y2liK4@f`IJr8vnPDoB_bt3^pZ5KDfz
z&WdlXf0w}J^ui19xMSGSQVmD<wtF;VFZTL&kVV2*f=*>JnAr3-zJkkWx!=DO*YxQ0
ztPWPXgbvqol9)-|4s4)}kq+kNQd-7H*OqM<UJoV3Q#RF57A8*jX5zrOV7?i1AbBaP
z`qEe;aN4wmlTT9pNif5xx-W^mEKQs~@P^>$4}u70xc2t=WL7o8SR!!Rw3U<FtNx5`
z2d^nfdV?wXNJVP2*u`K$nv44mZZ5?K`ogE>pGE%?5OBa7O36LfSQNQqA-Tug7%_mS
zv6K;$2tGCs0?+uq%0{z`P^4gxvlVcAZ+lERNBwqsJ3=N4>(0T|alzF;%fWBxlgX?_
ze{4OPhhBZWLH+!Jnt)RatEH@k2{k(YPe&7!;;%JIW~SW_fNzV?dEx3IYP8zLV7m?K
zQg;t1#YHB2vE0f@CaUn4Z73?uZhH;2phMcqhhv++86}aTO&bdQIazOIE(A-lof>($
zgu2~@4Rz^p0q{c+gcCO%!q7h`;L6^1d3h)GIet6r;Z65&IULWyhWKD~?h2%>P57%-
zG`7q0S6)S@H*q366(%h_&5SAjH56r1(dQg&MUIom+WB(5A{+HCLbnCdkI-sqGwPxU
z>KlF$mO7RC=pB1NQ6y@TF6uzCOZl@&#1DOR7mY1K7lpqXtAOae?HLuUIC^%I18ZXn
z_~Ok9ux)y)ysAO}?f+v_4Slkas^|SRqrVzRWa>u(*(d)hys)=`L%ia2==P=ju?(i`
zjHeQ~(*y8y0v`#CI+caxaly{><gilemE9`-ro;BL$WDu%_<-v9gHb6OP~Et_vxYv_
zNL2~<_f^9@mr!dh2Pcl+<d&G!l`&ooBm}J{UCz~io(h0fkuX`X`c*QpZ+iQZ)T3uS
z*OZd6qlui0I&|k!zDpRUy!~tGGmTW8aQ7E#NZ;E&VjGM~Ip9=^1A0y;=zv7rPw5kC
z;pU6ABn-P0p>u+8Tog*L7UjSQNMvQ(;j_sY?Bz_!3MThwR{32@khebL+b(%XEPQ(n
z(jPG;zc9ITDR4Z){+*2$@(TW6Ijq^j`A_8Pu1mr5_QCBn^!Y|gF3>YfE%I#v2c}!(
zT;`R)*_#PDBx9Od<ldqj%o#oNYwn`qMW|39h73~vtfbw-u<DBpNew;8WDd8pvBaKp
zy~?4*bcO@#Wo@((;_w=O?!!dR^*RUciOX0o3zKPvD5%0p+PW5;lR8M+9~lYr1UZhB
zp+2dIR2-VMca8+WMH8p#&luZPOz2z<N_juyZYvyVr2kolkCK|hOhIK;()M{Eukov;
zNANX)cQfqB!i(c@J*m(F7K|&!qJj9d;DWQaaIurP{1g>jvAD@mJ!sKghNh(=E7H%I
zo|Y8=wUIDPpruxZ_NF4wyAZJ=H#z`*>Y?Q^L#Jpp<lV@xu<lhhltjWR;e3n_eCYuV
z+aP%dy&XJFfzL2N4MbX2wZQ0hZ>@pVMJS1vqB2c}JW`SPE;y{a`XB)EdTuXe=rpZ{
zpgE^8N%{=iE=Lo7N-ts3)-ne7PUVc?C8b!}n*`zc$FOF)f;wA?dR-)Q$%}ee-ys&#
zhrvZHUE4wpX@l?2ZX>mlr71E+6ftS58LN3Lof_cltA|w`;uZnSO;AfWwoqTS!G64>
z7VLXYKVbq_Fjl1f^>}nGF)zoijJ<p~NS8B#zc5w{<&chdIk0Gu3HfFCfFT|~CLT}|
zQiYZMak?P#!p+?DiCk2Q1`S)@O`?RE>2jw{T#g;*epQA3Gt~O%C3amIzsACfYY_Ag
z6S#(nSs;gpQA=6pK0II=$ce`(sN_oYWf->6R5xTJ{~~lputk3bm0yW|B>ukk-QWZ+
z*#u`Y2B@X;Tc~~!plr6S!pqDdM1YCQeBhD?Xvz&}gU$ZCt;#P<>Eoq0toMMdW|kf*
z-k;s7Bx2O?a;d(gli$&b$nL@FvWt4sZ4(N+5i(j@iDr>5;#c)G*=R`-Ix3K|L_x(=
zqCR0*bG!UWHtLb$JwL8<B4>MD1zC%#@EvnFOS0<sT6D(;p;Q=88ub+q2tFg7x!>Uj
z!v15%!j7{g7JB;X?gXxGAWjzQ_S$TGgiv0gLE{T|)q-!2ib@%aiCo%M4NUXY?5?3N
zH_|nNLyuOAWLoK|La<D)f1HiNO~>yAa`WSG6=8q)c`adoZin){z~>R2)f&drT@Eq*
zF6uQsvHF}0U8qF;!m#s1MQJv&Ekfx6pSB8WeG6sn2KkgzoAPUu2rv79(F1&%4b;z$
zExT&y(~b1YW%x0P)0S%SoEB<S8&VyrFUdw;Jvb>OfU}&$sYo`wZF!T+AAsuwbIHrX
z$K!A?L4-SYic4|5DKb`H);SV>qV#m4g)XO6Iln_G*m*S>cU;#>V+tYst8_X5u9%!i
z{fx0$!#K`S!jrdKYU#vA+7!}l)Z(Qr^bj{#eeY|MN}NrBD=Y^;iN~kQakZmiPAQJ)
z3yTDIo-IQIQo&DajJXg{OFNnlGub#b4lf~{s!H3VlUakcF_hrJW96Xp=a$%WiA2w;
zXBNJCjTJ$@F(lPu8TvXErfE5GUBOL`fPs90&wiOWARd=ibkc#(#wKt*Xh8C<TD-i4
z?$d^Bqpa?=Qj0p2LecGfQs<bV6-Qrz&ctNBsHc)Ek|Fa{n55;DA5T1<%vudKrU<rj
zA`=gf$LSTFu;?iPY*9V^DLb`zaSPp#!zK4fV<l<;4i_jnk%i;qaS%EE>%F1mv?=yW
z?pLGk-C531@pnn!&ZK2)3V-{6pP(9AC#Oos&z_y5G=BU&E8^h(g6<mbW1u`)`iC<W
zt~7pglB*8RV3RTR>Yw2W?YTIuP1l9mMFs=<2qHZDDdJeoVGwhp7d3t8T=RHs?=g5B
zo($be;{#w-G<@Vbz4Tw@A%kuXMl5IFAe#QxAn8)E^RX2tl>@rcd))Eqo0MYmNEw5h
zlRxK9f234*FH%rxmB_4_n%UU0NR3l^A@LjPk-FPXLFHDWam^^L;Y@{sbGO751nf2I
z4*sZ?y0_2++#qT#F3W?j9*N}Wf7P9&F*`dIww5b3|JMJi;Am^3!Sxv;+m#w`=#>g1
zw4IcqYk-0)>4Sg6^B-P`3E+;#Vc(Ttbo<`NAhPWe?KuxCGE}6EJ0ulmkizMaCR~j_
z^hUE_^G10|4&LkmZKNn~eKt|S+4jd4m;a^Ss=LYl)4UeiOe_AXCir3qL?5QEK>rMt
zwGZ_1fXk$7bL(UaDp3Mt!T2H=(g3)EdadDN=#tLGGBh?7jc=AVF23?Lxzh|6-lx5Q
zO5&YENv6v0*E?yTpb@=UhRxirAUR{Rn$h&*QmU3-++I)m#UyF|^P&4o1%0d%SrJ_3
z<)07&w<2LEL5up|X2<IsQ?)VkI>q-4JJq;~@5ziEBTvi10dY9I!id&vIu`;hk+71l
zd4HQtd^Jt0B>ki|QIbL0o38*nf17<&mvL1a(~nF3;)-*19xN?_3(3Z)@LAGljMpkg
z<IXB?Nnhr)Q<gj~d-v(!2(@@&3+hz>cQRa*d9bqx?#CJ}!gMId2X=VC(QS~cI(z_J
zcsb3<z!EZbo!^4U=D~*A!bf?qz6g#b8^d)d*axiQa1=4`Lq*3GoQhAJ1q^*a22ma`
zj#SMXAAP6Bo#qg``?KaXybR=m?75ihN?3{>KZHIcS`ks^9@c?(3;Ln}%$NJ@tVh=x
z;iz!Cr4M+<<B|#kow~yztDWvos3*5L_;KoqoG0nA)DB2oXAn>BlJ1Q~gvzOEcu)!B
z8JyO#yb~|sMY)kv4pYFARIqBs%9N^UYP`f8M8qimNeAEOOtlvyou`B|1J>`ZM`Zg=
zB|Lx1pcE|(tp`>8j~aS?2i5jHf6-nAeXSBm)hM}`_jeu)?4dqVCy{9>vMU!wttSdk
zZA4F(@j{4~q1CD2vk&O=+u}oD4aq?~kz{7Hz6A}g2kFlj4Pu8bX^23(lUli|1(B-J
zdY{j(dNhcbjgpY~n8{tsh{;s&Oi_@G%@}T!KX}HAEI}tp*U~53p(ytyn_))sIMIgM
z8}@s^64Jie&#Y5pwK;SWZ)|-HcLF(AJI*nM1>1YoJ_cp4t`Efa{(~8r_;MWfB2Aiw
z=XDCsc_6lV%fGhnA0~7qBPM;7jrlKG2@ey<^~v6_+XI4{G4+?apBg8d!)ZaQyS8%S
zc3cLzJ@S8N6<jV~!V>-+WXLfU2JHjo-jau~wg}D(O7-=D*&dMGjM2WQ->Y$5kCtXA
zNZyALc_7ZnsmX)=MUX8Vuk(T49#BWh$?sZ5sIhC$@xco8ze*UK2e#*?Y3S7*^!xEJ
zmgs1?0-dacDWsPCukdvq8qce=I2}%tHta-BLrTwWZ)T`*eqTrzNGF2=cRNm#!lLf*
zk6fskiSl|G*rfuQ5@fgr<%fV<Bse*D8~y`*CiaiRR-}lE`s6BO-FvK^Y-!3WVQ3hP
zS|5@Y0tJx}Vmh9UKg8ph3Rd}Q=I;v5&~rRO1`ATbT8ne{<{W@+MQ}o3w1O=Cq=F}D
z;y4^k3<0jkTqrfQumz@vVG%89fWwWbYB8Qqq-!RFA5+1xnT#>@yVcl&kAT;R0Ol&t
ziAtE52Q;%UCIse3f`dTJ;4GXIhvnr4SiE|HkAeDvL=M8z;2a!G9#<H^C*>t88fui}
z^Y#^bOeam#q9a$}NUC9-ff{H!O{N5vaoCaMRjqv|F6j%df)q#lb2bw>@ii5?9M8&F
zk%h@#N_=2~2UIs3=!;J0{%S|_I%u`vNYQAIL|Wvds2drzxWC(wb<M9AWo#e+dqb*W
zuwV0pA^&TbJ7><tlRx(EJ@ohQmn~S(_eS*L!-ua$^}5z?$nOnhHGxl)g3D$FX(E(r
z*equnZB&<k)qdXCSxA$GLFFG>bhZJ8Mt|f!^g@2bZynF+lrpX72+IaYI(^RDKsj_N
zL$XQu$DtQ>%IjJ~Z*IvHi9S69rXQvXh36-9%G+9lImhMRblXu6vPL9-NlaSlqd>`(
zluH;Gmj9qZgF9^XBpj7x;ktNysF|ZS;0qzp8404@!t)&L8iyyAvr=u^0kAwwWfAue
zB^2J$dJbT03pR$l&4YzSP?*ex>*&*Dvo;k?Du+D@%}N<tVup*!8^yEKw0nzmBngf3
zBm+IZ3tF}kmNdiEv}cQypbf8=a3cizK9as6T3fP-v$Er=uCtN{#Nz^r;7Baz9;Ty9
zWiU4t{iHP@)u}WYEADOlBs{m5!Pr!q3WF$PKm*)vghYW9GF2Fwio&$mb3-RF{{=ml
zZ{cDlanrBTK&ihBtcQz@P%a3?NdfmODUwTq<jDqlaF;b}_zzY4fVBslY37tp?A;I;
z6$#^<`RC5wu-XHb5@D@0oC$&C9;w9YVpcPOKeL(;X^w)E48Sq<tt1ZB`*CtRF6S@~
zlA^!{n9=AdJSBaniCj)3uIj^F&S{s9@1lOq2D=QLSj>o5Fcy(`>fD88z6RQ?>jN9}
z`9Bou4Zo!#f))}tY;Ax)8{w5e_yz?vw?#U-fP5n%&LjgGlRDe8uvZ**DQA^GHC_(^
zsxJfz>cpEk>v-%^p+ZyHm#mW5IIlKV1|g|v%3U}&dbp$>Jd5CgAVbOrl0D#UGbhDw
z9s()Lc>R!Bg>o&UnyZ2A3`ZXWEa^b+1a&$p;9Mo;7zVlfmSwiX5ECV1vaul!cbBV>
zMdx~~!iS*K5D78x4t@i=O*BC72v77!AwHrEy|GAiP;*IS12G~M9nxZ$U40k)A1R|c
ztn~PWzXFa_(!Ih!;&k7y2BI6`c?CgNROc}r`a|nT2A^Jsyc}4HG`6^?F!XVvn&e~X
z$6)uHqNOZlZ4|rKq6>z=D_NN2<GIb8Ts);B8-gE6YtVi2I0wt)vE;ge(w^H6Hjw~~
z=byF6MI(Q>i4#xaEUy`8g-!KjmhMYl;Qkx>I6)2TTEt&PK*p|obpj_IfM=i6i(0rO
zFBu&pZCB>^4}<Va)7oHUN1$HR#3fY=&4QI=pZLOlQgLN_HQ>VCdQodV9E{Dv6XWoc
za+b<rmX+e!#G+u62CFz!O@EMjw1~fn07>`sDqI+e_PVo%c78U2My8?xT8_RmO5&sU
zB-0h)`7<Bb=K<%NSy5CN8Fp%HyI7Z6GB)TW<wuo0x8#}uv}8knVlT9n3<u=S=4#PZ
zts{vxH_R6&aH|L6iQlx5X+rnSEqqm8deuPr#JZ9ndgB*l_#u@{Qc$NW>B&T{idST2
zls3Y+`X}N3Wt`kt3I=4LfdRf0-Sh}VU_AfqqHRvAv>y?IhHzSyiEHBV*sC;B?3<my
zRSm?q-nLQ;n$dQl@Lo|)A1aEz$yN0xp@VcUNSB+`*H-g2=r?mx?BPhX!=1HZq?B6f
z)gn6A06&pNX&UJmah9B;n_4Pv5f9dS?x24n{gN*t(MbNVxSxW)T1oZMQg0n=<=JH4
zL*6QGM!jVu`%=RSAVr>}m)muvh1?~ri-0Yh<wP!pXhQwr%LHyZ&-QVg7|jD^WLW_A
z|J@)>WuFdD)izT8m%iYEa-s!Sy_;pzGMB;R!&DA`%Vutg9cND#k6=#~_Ay7unY9|u
zh}SCUxJvrFFp&34Bkj}vB+l@UNlo{2i+Df*gi0>x<==Oug$ktjb4TNG{9M>xxTMNk
zFXuH(xY@6uerXY#Yh#`%Cfx~uZz54Yfy=>s(JdZc0CP*0u`1q5iAZeKqHEfW6Af_k
zSqte_4>Ov5(?)nF-Eg~96hcam^j1j?Mao=WA`g7vvj>bMrZZYZL^7@`a34=c(`L?o
z5*Kt`gTC-iB%PIw#AV2g;Bz)#72YGB9h<i$vsLQZA^&$PY$ie}VZ7Eb)jw;%)`n2R
z2brh=oFk<cZ)kxTVL)HBCZ+Y^Mrln25v|u@UB)eK27#W9_)G$4*+&q#*Z*`GceEL&
z+u`p&mXg855M$2FTJq9{O`O_}Q(sd;dsG0CU|*9=hN#7!En-mw)+BDJg=IxldJ5rQ
zvrIvgn9-XtQYD|s;LFmaOfRxjbwev55##RzIqUR}le;X41((CX9K0+JpDkxaA(eO0
zP!pG@GVx3Dkl>$9JFW)6^++^>sFJ8*rGh?QNe>`*=dGJjil6X#`rSORf6C;pVw@LB
z!76M=Eq%XHS}$;Ui7a7gB}5Shi!HgW;y%P39JTZ?8FEcU!CEYLxI#k0;vy=FC!F+<
zm2+E^eF`AmdMTSonvnd%FUj&mi;|3o)Fs_64s7BGW3WKCM-Hy=fVCtY#knK~z%-Ky
z#&0IO6P#~~fx=g}Lv|#ZB3Ox!f=;ib2h}2J+dsQ%sIN?PY*Ntqm9#@1$dW&M>q(m+
zIKKwDT!Z78*exEnm21$#@Q?ReMFc{zj<#BQg@Vo{{apro9q-dUnI)Zq1A<*`mLX9p
zve0rFPk+71J?>3n%sj9R<ox5YhLk$<V~q)1DLFivH^L@wz#ed}nbSz~4hKMglfb|8
z=CN{U1xx*!wjCA~QBqzaWJgAHLmTrm0>`h`muI6dO%}USMoMU8OWt=cl`M!rLZej4
zi`y_lO)YIvejR~n^=+XW&U<BiAP<!DugcN#DPNEV|J)A8#;q`P9^Va*A<bhl#h=%h
zOq$z$Nbn)^E3e;mBGShtN{fmjed%FFOF`a~vhWAeI<8=)Tjz}}#qlOC(_b(#UW{Rm
z6q+2wZ?Z`*90myzAFe>xD{0#>I4zmlCLV4Q_-z@CPeqPe>~(6QUk!b+QS>h#Ptu=~
zMF7U|vj$aNy`I3Oo0**9vQBzi8#7l5A+ABS^od5eDOgEAHMOBdX%T^)53ZeBik*50
zdB(_pVGIj3aAV&S2ez7!{h$WjDCb+=1U+XpbK<Vp?NH0-m_^s%^;Ry>o@1{W5SKZO
zc-jb~rK{j+Tgh0TV@X%Gb)s)&HX3bG&wrV?GY)G=7J0Ly3Wu1(cjtIR&XYl(ROqF}
z;<Hl%YUnX0_2|6exCb0*=E%hAZU8WmXr&;M2r{CtL_-)Xg{f6|5TA<XLC_<{aV2B*
zvl9NHZk-8$6Om}DaC*K1B~_ySjM4G#DxXq(w&!>;<LE_t%u;xLXj?6v)hK@Z5~m!)
z)faT)Yg!Re+Q+OSq1{_7JU*rq-_nZCVI0%;4Uzb*M)BXgrBug}!Ms*<1Y?oZo(%4$
zo7lXVg@fYoxC$k7o=etCrgS9=q0lLitDeZYU!$RV>0r`j>~Z4}WWb&Z+q4*|Mv)$C
zYNME76LR-?9?6T2Ho#*t+0X59<Kb%Br-d3(0EtXIxnf<1V;isfpqGqfB@;6r0cAIA
za}7PnB*I<ZaK{742eQeN8tx)r@-=WQ7ZpcxhA$7}Nsk%K>K3fiODwwBA(-4!!brRr
z&p8@Yab_iH4qM^?!PnY+V6+EBlTp~7M|Y8hiOHWbv1>dQU6sSgm_w!6;2KG$=zQE9
ztw5wBHjGhGdB+lSTa{#5%q#hv4929w7A-c2CAF}jh$<F*Z3>U$Df4=Wd^p^JbvN0p
z%}X-OX3)vmAPyzb)V7FvC5R+iNBu$C&WC_4+&rNaUpCpS`UN9e#dyxwK*q#Lq&50o
zR}`^XvgneRiQP#*x`NcU7FC%17XyA!G>;5P8POU>PJE3Txq>v(or|cq!tG~u)Sp^u
z^lb3-y-v2#+D)M_B#`s8<EVKWq#u5h3-6Dcgka?+z<8hLPHCh0YtpDSrOXVHGSjs1
zRRP53{6ctN(h;+V&w@Gu#s{XzA(<m{q@I*n-~+)P;7Ne?uJwaT@zh9kLkL$Vbo5oN
z^yqB(dW=t1HWHZx&Sc_G9`IlrT>e#lm+YBP&tLK&r#eyRxq^`s?*G1Wk8FDI;fFl7
z;b+Q>++71qpL-5`BU!mupv0dC@s?x_+P3U2KT_tiF+)bm@mP9Y4)3=<+*Jc^Mf5{K
zmu?EUS&7KnRmROf{cHX&_%ZW_IuBS#JTtrMF3c&SBl*Lmxr|81lkkq`|F=%xlU<eH
zl38#iOxJdck5uYN7kPxyUI>K!_-QcdbhG0B?5ps6lV6Vdo1s=PjwF`8KBsda@WyCQ
zRQX3aoX94_U|dQ>^_{O-DSpf+%xm*t)Ki99%b;_GP~CZQJG_fT0le2M_bA|2B_d_2
zMfL7&HK?!29maWs$^#tBS$IcYInEp=3E}5=8Q&foNF4C5)ZYVOrAhB+{W!5bM=wx9
z-IrBwvPqkQzAdo%qgoR?&!8zFxm1EySeIh|9@-x>wq6V({ZQ-E%h;IV#&iOm%i(D@
zkIvJ}SyXUfbtxt#IUlb^k$KxHCWFA7&V4UQUEtW|6`I2jXvp$J+Day4E&_}1gLc=T
zS)}5lmNugg0y4kXtN}mYWvu5AV~_x8zR$!h@mNiA>~Qw4%vP$$*`j6Wa3ut3S#j(<
z2QowZwyRnQK@pFbK=N95vWn&=sYSy~av>YOlRaQivlPDiDL*~{o<$-DL5y1z)QT2*
zXat0=t5+nDZzzO};(S~u|5K|xRtWcArJW4`vT;@`2+~SG;V(&!aQ^!){9>}Lo7wn5
zJXR7k8@kB16j$|y-1=5(eKV@^hKC;DK#)fWv7&vXK;-vZZsy=_a{M}H_*l6=feY-9
zLj-@D?hTP1aEI7jTzWwOB$<@-atq%bS6(wvZ4xqY9cEMuwl$l4<1>-VC6ASHWNH^^
zf^N>Ic^nR7BCyS>CbF9;vcx*!ZV{Q##Nj$p*xnnHte293BX2`H`F=H6kexualGJ*(
zktjkCimePyOohQ(9O}sY8Nhdld3f-0GgoTIp#>T^`CAnZHiv$@_2T8te1CXTDl8|h
zgx%J=YS0*>PWn<gNiX=C2W%jsipz=(fbK{%U%31rkHhIv1u$yx1--bJiIP5i?;flf
ztZb;bOtd+v%UST{i06#^M9x6QbC(Be{A$oxlR8P$m>}_jX3ldx(edw%$~Sy?%RQ;f
z_=EJ#8z8MdZ=GIDhCDo%ehNCf5|Iu_l}b&<$J2}GXu<QRE9l#m(2K$1Bdc$6i6+hG
z9@Ay~sfDj2VBF4ip{0B$`6eks$7<<R8CsSKbML}Eq##SA(|B!?sZ~N2z88<_tE|Q)
zGc5q*=42a|PX=-y_{jt2H?!gt4{dfU{f#L{G|7-#Dr_c*Hg9JwSQgO_1X?V4Bn~8p
z2R?~xNZ`DBh#_s~8(JVWOLBIxH$QEbyyJ5rOE#jfYpGKWz|lm815A8+DCne0_=*%y
z=hS3d%f5(C749bA=^n3ynT%1jdkd)%(@pN_`-BJLKyZMHtOsR`F#4KM(ApflD-PQd
zlwWSI$cB+Tn*<ywGRcB7wyj`Azhp`S;9evO612HaK_9JzFA2<le|I~Cm@MTE`5<``
zhuo!5om`{LhU!Q(N;pkQ{JWLZU^0@ZdKg%P$W9htSE+rV%mb>LxtN-OT6DBgsSvbD
zJ`BE1dhQL7HNT&?UP)%Eyf%O4p*WEGy1KQ}%z>2*Gu8<~Xhs$f#Z~17YVG$I^~xUI
zZ{>kF%wmiZ_WIlejvi{PBgj3j9LP|eCEfC?oMBrIfkC97Ex@4M<GPqNjCcX7iN8C4
zGK=iHLWS%WQOX#+n35D4M4B0GbPr0sL%tSHg$Y{BuK8+54Y(G;Xn{@g?d7+rWR4BN
zvwmo!2bna#i^t*+KpIr*-CksaAriR@hYd3LAr*$-g|*RRNHlac$%M4Thk8KzHrRE=
z|5yNs`a-AxRH#gx5{IL=LEE8McVVz80PPog*45?M_5IP`6FBsxG39bAbyrpnhqiDf
z6G_{i3*GvJ;2pAPKl>Po*!zX9wKGYP+sF>+hDc;9kTQjb;_!VKIBQ1}PwvU#`984N
z1AIxF&vzTaozlKgCRn)C8zz#j{WfrmXb|@7`8-S7=d0uK;%%_(q8l-vjYafnA*DF-
zSR7dtfM-=qPAg6JfO#j0kipVa*r3H}%D`GgH!5EXnwRRNsal%&apX8<F8Kh(beMF*
zccy}f44k-s?t(lLIg?6r1f!J8;G0y4Ahm+8Gx<DVE^n~}8V%0okvJkd#sP@~h){+a
z^9A63XftPH$BD=~l=itBiF#vAG9<lo%Xo|k&j06|Dja1FV+1B2%fK%c=9A!d2go)J
z`M#SEg`>$zEV+XmUi_JKh0t(gxDb^O1#pQIIZ=uRc3~oum8PpnN4+#2dy=;NV6Aj#
z4P0ncmhyatp5dW5B5oX;yNvIs^JT1NrkY;W0%TC;JX=Z{dCo<2ZZa3upVK%iP<$nj
zj4!_1U7igCcs@^-!}3fXiaV0q`%GI#*34IR#Qe&`pvzl$EH1vT0dtOonx2X<%^P$c
z;ML4o{W;@hHfSP|NKn0oEVZVRbc(Bg+fhpmHc5OYSzWE9e5ekb+wenuHf%4Vi762p
ze^k>8TQp`&#@UwHBo=;c;<GFh`^MwKtEe)wZxs$S2XEo(|JP7YlS{YPz&9oXS9wF5
z2coptF-S`wNoORYgdPyTd>>UwnKx6rmOS?nmhTDLBf>H@)uS6g`t+inw(BwoO(3#+
zA8OC7K7w_QUl>VQIm>kWCmxEU9p&`D+^`(7sz1!A4CaNh!H+Xc<f^W+^0)5@t{Grb
z=Y&jb5r?;v)sXHFOIh&<qlJJxrsQCYc-%4vE|h;AJehB)3kn*jMvGcBF%3}bq$0cP
zle(+~;IScqtdMe5DN3j<_@PZ|3RmLq)aaKMX>Y9|rhb+@8=Q*J|A;mRaGH^7w7x||
z{!@kDQ$PCZg_b&5|0Ub|aIBIV7Y0-w*&{m9NC}yZZ0}R4TKTaCa2zp(eCT0q(oeDs
zU8<y}Ge#6t<>|mGhmply9+2(MBCDU+hq$*Ub34?Tn5;K-)UR`aUH`sL;9~p2HNnEi
zD<HCx8p2^J<@3l=@|l-_-tr$aCH7nnsbf3cZ*rP}__2T^$UcAHRJ32qLarL0E?^Jm
zq)#&Rn-z3?<9yAKi`qGT`mR_xWXRl!tG*06HssqO{l{O6UX<%s((vfiDf4hmQ*F59
zjlI61OY!1iY);wRoqsn3{?gukMHL!cV)U9eJ&+ERl+_S$?mVc|i0b|D20fhUM0ER4
zAo^k^EUOy>)ZMC}r~{bZegVd%Z3SiSJEKyPR|f88Whm#b6393d_=gJWMs#X2K~uK}
zYjQWJAhx%PK2TQ;)U1|}$Fo4`^a9RLtc6i!!2PK<q8W|G+->3Hi@>}L(Z_Bmd}7RR
zg+VGfqzu9IS9`GUUv4-<mv!w5h(>;dKYIT1n%XECO@6%Rh9&zuMx8i-(axzbg+-6M
zX=?vv$gsEsid}Nh6lh+Omr~@Vl|6rYi@em8ymWiGk?PXTC*M)$UO<T)O?Z*!mx1B`
zu=nPFO<i5zu!2g}Ds3H55u#E=LBOGiGNsl55rwJ@$`masB13{qGUY&Rr793X0Tm%C
zAP7QKhD3%0M+gX!AOwVv$P^$#Bq4;5;k-M*@w)EMdq01`^L*+Lve<j=z1I4!@dQYK
zEeAS9XoIYYcc-&p3=ldvdoq_Vhj)RK0pO%}p$aDOZVIz7K_eD0T5}gX@@WFr73TtV
zIco->j*nm9;5ER~B5>3K9K}Y-p;ygVU0`YTTe;=zZZ+7o;mX4S4$$X%>}s%^eOj6B
z*sSCL5K#a`1_05!vlng@=nhNa5(Fe=N2rp#WEWgnYOSPUo7{nO;0w3m6~{|q^Lwz&
zl_kw{UJ%t~31EUgw*jRBj0ZSpVeBqA+?^$L)W#_-$<|7E@+?++KuYK;mrF6b_sd`*
z_*+u#AqzMaplAY6<V;mR$bv4Y0G{5n_vF!rV?~^@5gPo6M~%77BWe#ot;<K?1~hDL
z9G(de0~E<1B8;=flK_gPAS9l{rm&n->I=>efV0&j3V6b5JQH{)6(A)BNXd*<45<}O
z&<HTs7Q{?AB>0^H_0I$pSuTQFTt+S6P@vX(aJe@FVr^wWsaK?!9Wz=R!=7C_ci>1M
zodFn*heHy;(E1<g&XrBjWpKGGz%qigYFJ8Y+X~knZdTH!FXvmpi3{$*Ps+iweoS{1
z2&=;B;DDq&_)$@Js4@d&LI*$u-CGDE#|#8V`%G{YHG@syiR#X7c&v;VEdX*Gr{w}i
zxR>zdWDv_T;3kM$F9DIm0&ePkbYA5OvI|R!HRH-90Z~dxgGLo}n@0<~E)DNc<wy}b
zRM`oH?he4fkmyg~LW?CLNUlOlb#WfJ803Mh4E#L+-`ZyDdl7~_9aq!4WUz|@yTHe!
zXKW1+9WB}e@Lw|;9}!r<IsnPJ0W!2Z6qC=Rd3_Vg3RPOF!m2z*LF*g?i6<p-w!#Ju
z(*cQ96pJ`#Yowf_5h<)dTYnUB?jr%YbI<~20|eRbO%Sga{q-|&{*@&nTG+MeVxkRF
zQ&+tSt|{k1j<i8N;QU0l_p}C8oMW@WwZY)p>=7x)XeB-bz!3CWPW)y6bXF$<&$Y#Z
z-#6=&z>dl>5EeHPcsq0Wa)~ZZsZkcAkfdng{lQ6JaMH?52G0ehWGBeY7+~qk00NA)
z{tN-PW|ZBA;uUZ#C~z5}nJ^yc<OOz7Q}4mWqAODL*%^g1KrGJ%n>SR|%}X=}%vp(~
z5P3gK$_c2EqCQPb!q+RIKY-Y?K&-`#!p5MO)Xe2UCqSrSx-9@o1qe#z!xnJV(p_+r
z$}yo$2EZ}y=I>$OnY8V!;LA0EIq_hZ(LQz@fE4fzq>N$_`V0UmZ)6N2XlaV&KEJ$&
zhh`3DfEbJiZqxfT3L6wF?f_-WzbPBQlA=J3A^6J#@M0S)pic2=CF6FA0wPv}3Kalc
zZVTc}R$i^-Gwp3G--|e)79Wq7f-vi(^5p_hGX<=PDN<gevI_)vJjgop8B294n&5n3
zsZ%EeLsG_-NTp>tQc{yVdC>b<5xQbz3{Di;px=vV_5dSLWmKiQG9(jL0MBewVb7K?
z2Bv0yGc^yGiU;s^PKaSGlJ>Av(6trzIWiN2Jg^xAaG(Xi{I=SdAb`C+622qMP^IQt
z9QZ{+@K#exr<g!n7I10Qj7uv)3|<ByItDU|Bx?d075EJ#P!v_@5<g5#(%2CgP^Jal
zTVdYeMkTrs^oLPUiJt;P{{Sw%mr2_WFv_0Jwi1Bg2tYp=*rNVPDT9+aI>S<i|7|!p
zZ#u`#K?QIGKGpOGC7yekY5|UZtKt)1EZ_(bWH}(nN*+N0z!q14(JZ>vpdKn?MbPg+
z=vfqifiYc(Rq&kz;7)-p9M~$;fIuBaR|2OJA5M3(FU2CvR<0byoRGt!ZZqKVN+bX$
zKou<k80-a2og<&ZelL<sKvQ2lTaX-CQld3D*)}mngLjW)0Jp@rBWcP3*Zu-FyC*m>
zwXBs4vMCtU!B>wvU>^`G87-ko9tgr0z@_M@36M^->GI781eFfMlA5l@DG92E&uiwW
z@C9{6Yu2YQ@F@h)?*cdPwC=M6V%3po5X2UXXgILRoKV1l5P*SGc3NqgHDjtL$hDri
zJTwWEj;L-q8$>?)+sQzH5*>tK*$5wwf-mIrAPI<F^lSuz1kVNS0uLb6qe2Z^8E_3!
zS1h0M<))xV=7IKU8Z#;ZmP*dwhL_A_Tcs^airL1MJ7Q%@IH(p6$~MG6j#m1BO;FPr
z=R4tu`kNpnG{6X=f4l@1ut7_|4~#iiBQ;eu{MHrdRRdB~*B?rq3AkFj3D)TfRT4l^
z_W_d+%?Cy;70CsyTjBJX>MQU9K{yG5&;|5I;-%i-8So86swF6dL@=Rffs>HWO9D_h
ze&>7m?2N*erC=9$ju8mZXD6UEMRH9)WN3O_(FAV>F?g>WR+8&kKw(MXZMb13dcy_9
zBIr}B2=fu-#mgWx7*J5%$mA0b5ZnP`N#$_MB4rD}J_f|YwV5u%1|5pH8wmB2O+my$
zaIbACQX75*mV5!tm;%NKo#4+5psp=YH&umF3qYw3NF4=IK>!P??x4YV$eC?!zubc>
zu^?ALw3r6Srr<8^c%ZP~Z8&k(Hz3faqlGgu35mNfAifFTvL+jt`WBe_CrCG*zq|n`
z+zfiEYJ36BA_=61HZbS!02yQ+6A7Z_Fj7}^Kxmr+$7q3gp!I%LO<T1<-_}`p%lUE)
zsIaCgc*kif1hELZGETQ#;8iYrL!yhIevq+eu1g7c1)CGpR|g`Faz#ozH&dNzK{qM{
z;`NPrw6?tCp!1?Q2-39xX+N-+?bZawW6Bwz+i$Ps*t>TX5C=3e15ix;Kmp1%2ET2K
z-ctYC3SI`X_BEIcL9JK@QbY`_ZUz^B6__s(%TXV;!mQb#nhSD71iI^!emV4_c}WX!
zh32<`S_4$f3?R23c)0RjDX6D#4$wGoMq>k@u{+pZVa$VC;`qf@??J6XAhXWr%Q;}g
zC;9J&{RD6`sJ55E2r@Mj9M%-D3sQ)50p!8to<iUz6ce#l6AYl?ppX=HX2B;XRdsqV
zIC*9EB#33s4sa4o@z8s|i_U-){RF9Qx^1CK0mxf|FUZUYkt>*O(N(9F=8m9@=YcZ*
z8bF~Apm+xCF|PtJqG!TNHK{j(SwRy>1-%3Oc=lu=ND@@@R@i(NCsoKM&jkqxCPbR}
znHj*zfQ-a59c(@Wn}3zdV61NS0Kn-Mz{z(8r##@ETHu~#om8c}Z<8BvPXy9<%t?GX
z8e|CxJX&A`OTcJ(9N0QAV{7K8P$d!c4#x{J0pu>Im;n6@j{w{VrZ@%|B@Do@fO;yn
z0JpY)>`R+H3XmXz3DD6uO2Imc0nZM^Z+V*sqDc$ra~$Xceci?fWrhK&o4e}4js#Fz
z4Xo)0)|7%Y33j<-14hda(=|!~U@``C9tnue17b1KEa03wAcZ<-Qm6^^Gm_>m*r#*^
zvho{>1Ui+t&9)E0lVTAJ=6_l-7zlD{Ylfw!pi6en)EP1;xHQmsh#jEFM^R}?fZ&&J
z#jO%-f+2+13dSvZd?1*0(Rrtpg4;7KU^h^=8mRjP6fl^*Waruesp+?r-w!sy*bk~(
zEzF7e10+u1YdL3j2nhz^0G?o{3z%Mfz%Srl5)w*H;E8|;#v&dF2kayP*x3U->UUuR
zR%inhM!_x!79K!BF#aeJ6a;%<D9AWfch(0&uLGffmMaLAnJ?(TZD1<pSkE+`T##{m
zPzg?V^3h2hVXCqzMZzH*&yvECHBwqWsEm!WProzZKY>`EnLyG4frJH)yAB+O4$f`_
zF{t%z-ufE|m4WUM1NvEOAr^RzmJdM6oB>INLoL|d3wDFM(H})L3Sy}VutoI%n_e2D
zfQ6NT+dvwh0qV|9A-13fV1Q72)x<E?34qZ5rmY>&HU?<>1h}-tJa9KS=>$%qXUA{d
z)=(u3#xYZDl%iHL5NHN;DxDsiG*opQWHJ^cE9rccf`c;ej=ar-2d_w>Q!~aAfLf))
zrwFpt01ix2-T{KoeiM9h<{8$!Tp^(q6?dEi9XR5(9KCA>;Rf);pbFpu;B-$cm>4k4
zNNsTi5EcNJw}J{Fxx`NZ;HNGT!5?Pgw;054E3nn?lP*lKjOqlt&fjD@v!o=Dsn`p^
z7`aY4s4W=wR#<cPS$!A`M^ONZaxjQor|kv+KSBU5eo+k`m#{3I-D7@2xkl({mZp+B
z(g+^-F)z+ZXjW&wum)Ku#V)lu|Ni?IfqxPB7lD5f_!ohH5%_-$0eJokxtrh5{dd4m
zdzyAMVB5C9QLmHDgs=A7r;UbvdMIM-4h;!7b7rcpKzhSFi7NRq9)*6sN3Ogbr4!M<
z-e4_8DIesVv^Mq#dD*o;@7|01^3>!b@09QBeVhNhQ!;Q1t{!S<-A;3GzcgHTt`|ZZ
z-+{Wj^sk$)>ZqDhROK$VE&qpMF6aw(%!+E0Ur)cq!LG)L+FvKxjQ^9ZiR!rUMO1W)
zU^#GmS$Wpvl!56<i}10k#Rq80o!%XHrIgo6cipLs7xB75U3E*dAs==tbG-%;_f?U!
zTR!R8Ab_7Wm6ncw3ASDj{I=?lpF<=J$A{K(V0G~Q-g6a4RPOAa{%+>~@UV`Js<nUr
z{fofA2>gq{zX<$`z`qFmi@?7K{ENW92>gq{zX<$`z`qFm-;cnRb~kU@v8<Ce1JB@0
z(R*P=Sp(dSJ0lL6055r*j2x!hJDSiiK3m+48m(pH`cYeUhY!7a%WHBcpUFsilDRUA
zc4nwY8ui|ta!R?|-hOAy7L3mZ0@`}}b1w-0@qxh?=Y)hO95|xMI%16OW4gKHKtC%@
zkDnXib1%ASNTg+A5i?pPY`jI#=TPLIV$QHHjL7vxTBfUC_<kCcyf}Bw)FODOgO_x+
z#nvUW?m#&own^G;LnVyZD>Fhj_Lo>W0v}A$j1!{+3#TO6yg4pj<vX`;SK3fyJfhqN
zrP^g=&@PQVd~3hd!wUL>nv$HTIxm@jy(trF>Iz<&S$XN@{7QoI@>JJ#2d|2du~7qt
z`}yFxbLP~*c01BMs?H2B=ld`)AxfsYkHF0P^TWmGOior@dig?>zU5M%T-|4+jG>f`
zn&(~PC1x4y!jV?{5Gz6k{yfejmV~@yUgu>&qg6MxOssH>x7Sx1vqcF~1ENK^(k9r4
z@hMo2fh8Um5S^(X)pYL#Pin8V#p5~e)r&j^#$qfyQ59fHb%QzY&}(r$kF!%1$yoVN
zg`O>X)B~Tn96FObxeMF8JI{Dm%&3%Sx-0Z=;zaq;aud}t@J}AqxN3FB<7mp+Gjbb9
zPcQE<{Q3?&<+MiHlGXy1v|WS`B@tM)oYk@@^hs+^rJ|%89mKBrODR*11Wi1)*D|TN
z|Ca2k98b^}rDs8bwejX-6kYNcna$ZLeeVup`Qar5?5Da(#`0Cw-KVdwuu8gWThb+d
zVUTs{&4XSD>fzJY+d$QsdF-YzU4@N<+sm-%!EhV#m9xRCWLFm}T)djC3IxHg-bf-E
z>fVH+@($Aim40s4rWdVDo7zWQIn_ICOkJ)KjB0zMB$ejypiWHmi^y*5ScmKhH-e*-
zSxP@1w=Fcw4Ci014LvF?tIw$ok7CF|y(|6OzwX*d%~MuM=G~o)%nm*o%4B(p!>FSN
zqel|8sevt`vpxKTrZZ)B7?Ll|Z8x>;N~=wp-~(&Kx~babtCdYrWbu=gq7&7<BL6?o
zk>D>`MiUq%t-ZZ##wG)+K4)<%vI$u6RRxxb53!G4J5DXBKIAT`HJ_p+8PnPlYSVjZ
zsKWGG^5+pNYBTQyR8%a9IDi(o>5y554ZDlG@07FL#)3wc60nIbwXF^?J3lg!t;_io
z)OFH_DLTzwArFtf*$L@9yGK1M;CKDR$TR5_apauOab#Y_SWskqEx8T)BHiwCX=Hrz
zQLX4~bs8gGEchVOzeX7gH=s5dk4Y;18Sr~iu57{sZ4>z6^H`Axi)WYLvk2kWlJ`WD
zw97A16Gr#iZh^(0Znc#dP)W^#;OwMMI0;QtT6RL&lawGUsxc?5S8H^zH^XK~8rmR4
zah?-*u=>TH9_ou0L{{${%er`Tc+AWbrq$Lh_kd}MEn8+{Z_Zb&nfIA9lH^eq?5O=>
zFRKOAi2Ll&-@rR^Ecb+==7WMM_$qK0YY)LIZ+m3*>jg^)-po+AHzHI=@rG3yl*1M)
zvoVsKD<f^6Enrw2b7be3g1wyyeig)5FMKdE3m%pmV0h3gEgBS$;v5Q>OJl<FYQrbE
z1gtPrxr{*S6-9jsI&5{98qE|%rCw4V_TZtL3w@>X(Q@`0DyiR^=9)NC>K4zFs17SI
z8E_x|Wf_Ok%Mhg6DwkQOy)1Thx6az(cQ`WI$dw=%c0Ek<?MXhOa_Phq#W}`3vphLQ
zS|<5&Ij!mX66-Ok32Mlbg&vE*Vrd<xq_QJ|$o5P5%i!#x2#c{$q6L#b_i(hr*JyG|
zyE~4=`RMNZNp~5ib};yl5jzg!3b`fwq)!ejd$pp>w`J_ieCxX>6A3<YhC?)loG@No
ziIrKw63O`mQCW`ECR!tu=knq;oOu^=NH1r!6aLP6HrSPGUxB8E_R_Rl46Lb-yxQN0
zAMu@N8_`LyxWb<)3hd!0;uT_xK-N`W<KupDXJ%04(u>vb1-)>kvURZ6A}lAo8osY6
zT+$;7Y!8ZJcgS2Xdk|>@G+5D96Z4?CHuN2EoZOO0SY;jN|6DE!Y8df660LMU5XqvG
z*-7w#WWPGL_DE0fqafW=AN%+)Yt`znQ?ReYv)Q<)p|KOX6&VJ_Fg7^z^<Y_9_yj-x
z0E+cYubK~QRO2_*@-o|0l1Zq$T^i>_lWoNDXiC4s<fO|r-s}3~<IyK}+XxJG$gYZL
z%8o#ib5C!9jxJ|FFT4+*53_5@7pzb&84r1{`}kv>fuyQ?yw{n&QAMM)yWo}X`)vNl
zGF#<w>*P_i!I@Il)=$0d{!ISV3h}-+)Qjq@gD}JW&ZM0D#!q6>IfiaoHbm7iClK7<
z^j11vC&oYPuFHgZrxR?7o0A&SZt8OGD|(t4;StiZ)*MFX1I*e^AHrG9&>rX)Ht%!~
zKWQS8oHZ`C9KQ~;SOSLN1nm-kl3IReT=68vQo*1rdah7;@RZF)$u$G&=wOvkNVKlw
zm%I$+gb#+g!-nAVrZ&KGZTwC-8rL1zxy!MHy*x9o!^B1~0m?|GqKZ8+78HLeI?7X0
zugPhyCHrRdPCS8|L^1KZnnrgGjV+1n>fV;56@F(t!V*RHDYFdZ=qIIH9+{fTBy^Un
zN$M;a1wPK3q=sdUD-L%ARVr=Lg1fqR4^-RN^2Xi-MU{nPm1CB@qD$$M6u<c14{0Dw
zMEuHkK~dz*7J-75#BfPcC%*}gj|s;fkZNix1n=DRHZu|w-to!ze45sxC$JXVtw(l%
z-qsN{QVrkh*x@6ngsB=|c7;V_b~JWNie>LPQN-POP2E`VaW&o@_pbWG&shH69ZxEo
zGO7ji630$#TRX2RkexDOp4_-o6-1Mo6!8G7%OaBTYDljzF_We^)3ri6ksz6Wz)>r~
zb2FYcc_fp)bqanY_JP(YAS3bFA!;`5<O_5qe%!op+y`2#Xe@|1scQ+5-Jpq{X3mpt
zqT=+px!)=?a6OEwJXO*e<8!ZfMEQm-H@A)?mY5d`ucDSbji8hB0bxfzNjE16FS(<i
zJJZR<!b^VW=V$5U0^!yAp_Tfa=k*2-$NW8o0R_=LzugZwWaFI^zS`~H^Hq0_3Ihs*
ze_E!AC#5i`>e3iJG^x+N@8Sy&6BwPvF%`bm$GG*|?x*JT@m!_N$)?8A`Of&meY|w}
zD?@ZxPyYeBX@O8?i$6^_Ef)4}pyl@wo(OyOXq3KmC+Wgu^z%MKfpD1~EvGNtMXJ65
za-yR=`!y5f%oL1E|1$KVp=NzrRXu9C^sGMZVLfWCv|pe0ydL$FbcH^xpdPhGnyOE$
zs7I}oI_uLO)uVK!t@_a6R7RrwZVI}*9`&Qt`;d}ih~6!%O_Pr~;}7)_jHJtem48ZV
z)8$v4ZN}6eWc@DmD~#^BHf)e4w{yn3^|8|AbZ2~IpQEAlc!4~jj_4uGbCLd8M?5CX
zbC%voMwj(Dl7uB2AU8VkX#Zk8D3VSp6qe{g2k69;{k(m6Pdd@L|M~{#9G&P1j2IA~
z)Q22WiCWSUdu5j)X00^%kh02<IO!Y5FqVo6qaSjmRVlRl^$dbsst=t`b#yv}`CX{x
zEd4u~_OuTG2ktsbCy|8L^`Ia+HeYCa03Sog9P3Zthu=#F4j^2U>+3@&Q!#6#_V!Al
zAr#VQY9uu(kUy`(cnMuyr2WaXhkfQQ(iO?H=Y6CCp^+Z#Ss$rbShxXlreluxyV@#;
zQ#eljtbNM6DKr4wGU*Y0$TJnaQwY!yJ1Z%57+0aWleAY4ilJkRg$DbSS5j!t>WQnQ
zjr!2>RE)M%+g>?f2p#Lg8cN*@<n(0Pi#}|TFmInSErnK8Ph2B)w^vRWLT-InBdKM9
zd?=Y#-6wb=^x3CON}(0jldj7%^`Y=o^bTQos@&RH`J|5HDU`TK0kDpAj%z>Ts=Qhs
zf>P1uLP@Gz-C0>x$H53SU8EvC_*XjGso(S;`DJ|=mrC0z)J&D@IV&I5p*@5I7wL69
z_#hqa($BJ0HmAUjunfK`k&>g<rZ;HN4bZSEobkLm>_2jEefUx;?PnppS!z%q&rOD^
z`iM`2>HC#eQ=o!+jIPwcUO8k4?e8NRN_`5z&r6|-K4OtjTMs@=N4xfuuE|UE;pkMF
zg^-adU+k>BTZhI7O<kl%lA#BEm;xc|fbwk$^r9Z4B~3r1Of`gJ`Y<L^*FyP{WGJ@}
zQz*>PgD=o&Uj5hvxt~6KAeFXRNJ^JyI4cM0Xh(%uXQ}%J_#B<)*^f<>yX(UasWf9D
zHeFuntemK$9Tx)Jb&?@6cw<mu_yN2<ordWbT$4xX!+TO`mO??gJl<KERR{epL^(^N
z^x)HU$fI9yU2dxn+ojUbLR7ju&siB)2OSd<ouwLjurD3*>PKCZ`{={_Q=wf#V!Axt
zS(#i19TmD4%CnQ<=Y6ySAz?q>j}C!IC$S-CA;(Ets|SbD!RKxf|B;*P!=9<ob|EKC
zE^$^qu7g~KXeVi&9vnl5PxKS7$~E=j<EhY2Av#UYa8|ykgPnvlCn--44yMCy{g{8`
zruwjZDzr^VOOp$nmAQ4Wix6^>rt85`bogXH=BgZ}54)y9W<n@UUTz4x^}!aA#Nc7c
z5ez|Io|0z>zq@qrz@e-{c}8+xiesS=yFbgGdMp*P6#D98Uewc;Ne}5`a_ec@(t3SN
zSv~e@bZQF8rJr*>x;2I5)z2YBm!*)7_M`ua7N?L-_M;P`6H`de{pf4ajVUD0esofF
zQ3~mJKl*C)ND9flADtMTnF7iKaX&SX&MFiVZEdRi_^wjZ4H#0Nwv*IU4@2wIc99k(
zV}BPW7RX(bu_uIyg>qIh)=7AzKyIFl^$;E@l#`RO$Apaq^6+G=o3OD^E=k6^2#pKm
zn#ou%p>d&{kc>SlEDGc);6AiLdPD!k7txnQ=>1es)r*B_TPi5?kA<{-)KI#QlN6)J
zdDJHk4TG*nAE1*9g*01g0G&({Li?zm^zeKkbbuN|4}T(r_EY!L1;_fy`>Eda@ZtVt
z>FSRvZ$<MA34fO!r-wfl=9@ptw5R%|)`lkgrl$y8`hz^rd@Ad!bdB)Px)Ww3)pgco
z?SI6!w<)Rbt*9%trAwX&^Q|A<(dQJ__eRo7eds>U5gv@&6NV9?*523nn_8Zv2t50P
zbk5%O6vh-pkJL#_q*Q0BL!azcv_mRMTT0dEkm~bnZSwkLuF}Y4fvZrxAX-r;F_n52
zS_MYkUb;!jF0cwTO&@g=R=P?LBy)=TG+d<bk~!6Vl6>Kj4d|zRK#3!IG+Vl6fv|A{
zc%yO6Vqv2mI=@d+AT-{9ru4--Nz;-!g?;fZ5mjN1@wenp4LKIVz4my4A!noT^&$MF
zRK`E@Zhe|#Dpp(iSs(qdo_t+yqmO=GPbSF!N#T&|!~c=jr2tLC6XaBVbV0q~C#m8P
zJ|tDJTzXU={ir@XNj{i@a__I)hd)dgVEQW$;Qi@@LLqwt4WbiBLdpt^MRA{jlT<eu
zg%K_*j6T<Aa7#Ydnd;LA+ESdeZur8(nwz9{fOvRVbBpvcu=!S+gQ4_tVYHwQ<s<|)
z*dzm6G>e2WdeA{S%B4Se19YB_^6HoES3XT)6bTi2&?P$RXurlj8*-n4tJG5u+DCVM
zEUes*zewjfOWAtp+&<9h;*uFgQn?|`wl6PDUTR45=@Z%GBU3>W_SHvc*J~!p$5Tx6
zg;D$Q2k49^!o3?nvnnaD8Xdmdv_%Tq{uW`$A$(XW$5QyWK02>nlOX?+qM8Es;T`Be
z4ZRH*C!q-Nhu&#2mi7!tV3^OKg8=q0L3LY2&K;^sajlMBUL9LX>2o$+x8HP~@#cuu
z#Rr=gAGEjk6002>S7S=`Ns)6m1KvMpc|%Uq3%!25=Jjhu{_G)74`G4UjfYw{bWhF_
zCdf4e!`b`N)2fE&=M2uzu}z;P8V=1$=tm@6LnNF<BorVLJZCR1{&w*<!gy8!!3ZHt
zRYZ{WsmR~xh5Wh4ff36PYswH=b_hX7h|LJ`7$JNSVhABtBSgils^jkw;t4{0nI=f=
zmSDudU_`nISrH*Ci;<PZ$jWtO<vOw=Muc8LM5G`D6Cs`>gb*PRFvsg>S3<mJQH^v)
zh){$$f&l(_7VzqFgeXP`DndM%CD@4DyHCt|r`ri3zHJ>tR@@N61tGi;;wVBO;nNL1
z`*Av;x)Hy3A4gW)5yBNAFtdcs?+AhDV}s~pgXm*(Oh^#Zz<Y?j34;j%;UE#x8w7_V
zK#15PaMvOZfN#x4Dgg;uM`XnjiDt*tSsq7(hk@`g5FQ4?!$5dU5gt>7#}wf)MR-UE
z4+-HRAv`362aE7v5gshUgGG1*2#)~aaYqc4d?OIsHIWrfWQBmN5Rer|WW^C#VIV6E
zWW^L&F`ZrkrJjsP#~>PF5Dhtqh8%>4gYa+=9yG#(MtIN&4;ta2Av`pMhlcRb5FQBO
zfe;=@r<(C_O5p@TAYeApB64OUJa0C2?#<dIES+7bIyRdyUN2@@Nl2i(&eo&4!dc;c
zt;p#$$o-ATH7>|CmB=+noU@Q?T9DI`$Y}*~de7|X?x(Y-!CW(wH|8cYwXiN@*51A&
z$TjDXYeXs74)Aw3Z+;}HS1tW&QNy1zLvZ0j*4!90CQlxA9g&0-<Zh%OW0Axp&(`6(
z9kVVMmLmcxk<&4Vo=D{os1kJR*s|9mPt_^m8-mrR>B{3MZ_mzDX$qEXKIN*+a+FVI
zd(JNX`l)DUX;lt;cImfI*)vPKa_*=ENA%ck7@4jk*;+Rws_s+QytuAJCFbI|nsB-}
zudR-)3Rmfr<n?QJp6a-*={mu5VF8DDD#-c<=l3a)LrT@fyCdgHV^tP`)6p!1AR~kX
zAx_O+OtnP_pIO3Yx?ciOsOf6dTNXuiMYg6RPPH{%CV>{3s&1xIU7~WOiilUmuu3l(
zqM#n4U^1d06(R5lk&oyVf{1!FYcL8iSTJ2cfz0U+suER;h+2k7xQg627a`&hB4<{D
z{60c(5#k0yd_ah&2=R56up-Z@gMK(mfY$&(5Ce4_RiUL)XS!{wyf@vMfg>XDh%wXg
z0B|EtHxqD(v1#_ubZ1o^nhpz<_oh3v%J<XhqB=Ak#HvGxr0a+9-6K`7<UiRkofcQ%
z&|f(WrZI}4%1V_=JXLb5obh%Rh6uY^mAnuSGE`%TidPHq*L06psk9%#t_OjmZkC8f
zuE9Ia-bXD(0IHZJFw-3rsBMZ!a782-sj@;P!5NV-j9fh3;z7WJp?D_p!Bjj;cpyYH
zLV&?(Iy>-x%o5b;c>rLBp3YMhF<tpo#B`dfh%!V|#4G4(WMw)@0S|a-W5&5eBu9zU
zy&fb3J`54+fDnNQ;e`;0<MGqAPi4;ZG^!$wB0NE}1a*310YW*`g8={xGhL)r1mdJ`
zSb`UCW)#CrPa`TGL__SBSx1tPaza9Kl7s|~IT8;nRbNpB2J71jl1%1^mogA9X(L1i
zl4swxrkk|NlkU?z9>gq;i*R^qd@U=FM^3M*u(7Tc4@q_ONyUzgpqNNJC^Gz(U=^D)
z!WRCG&H5V~_8Xfk!Y28~rjD>FK@pp|4ef-mX{O7w#WL6(i*GE-#tL1uJ3_uVW^D~B
z%s8|L{6KV$(iFTh>Ki^zcr@JGcU*0mq_fDT*uNM2X<SX_o58=|_$B77)k-DEPqV>`
zzonkw#Hri<p_T&J7OMY(W*+i}+u>M^_ckHpm<d4%L)~PpBG{hu^`T~x*Y2%B>ub(`
z4trNuDt5>)^UJAt$$Y+1Vbaj%BPnw9h<VC?F0PifWp6@1?|d$fnQAjA-rgS5F-48x
zAH9d_@a~wpM-^}SKzQ#_PQ`E{mk-%a015)su<e9fIsR8b@omo~7Lk6bh?y9csW(3*
zvfTxo*yd7BCAph6H#>;th^>ay4~X!b?nrn+!UE;J>8~4=_-e6o$*M%TB8soj-g;N6
zG2SLKKlRJF;M4R4A8A0N4n?Qw8d<oYNP?xEA4Ro;9egvFW(%&A?Y{|Ufh$I|5|x)D
z`GE1RLPOFfBV&F6?;tSEIF8N%Iw&5FLFcCrh~TGZ`BC61ih4~oklKlTH#zlr`i}5<
z6qTN`x0!R323681dux(sb{0{v(>prqqb$|6LA==PX?dgTa3M2i<|Umhr#iwD*DV*V
z?VRTEiIYw1(si0k0rrBOC2Kj;JGF7krcWpJ8%(IQ?TX{hoe{L*(y19i3mt~1RoL<J
za$1p~lcwldI$v{idg=Jfy)&{;eEl$Uua?ylm61J57idnyM7jC0Yi4JS)x+tXrUeEw
zx_su|n%U8L?_O?`2dvf6bQqbwSM*Xov$gJCn@UZML=v%kT3_40cFagjczS<E&_bUX
z#W#O`GIM6*mM_zn1i$KNXp`^(L>hkw&m78mnm>IgX%TPc(8<qLGl#ZpnX#zlRm#kQ
z$(C7FUP)*0I7OKe=<vOki93g;Qg^k<EHba(&hVVSbY{i{YfOfwb?|;Y>zpo}?+lu2
zbyX3G4>E{vn9*qv7cp~2r}zX2VU=^NJUXU%^5P3;cqVb7Gd!r`nS0gWc&l~<Klbto
zGkWU1>7C*Ier$5af_+vGrj2#@(Q&OiCgO`Y7+$cJcJ@tKD~SBHw9q#<3qZ*4!Y{sR
z;0j_MCwKYD@i7Q`?xeAPmK#vNX3X8*s>luGPcQlQrN}anK($!2v4jgCgOWHGdn#s#
z$eugZVms`w@34Euo`5A;BIjC92M{u$P1AoH41|oB<NdDjTvQ=0U%7%&2m*~WS!9@n
zQDHRZ?oxFh2*LM~i!Yr9LKN??r^g=7TvXo!ke$BUHz;OiFCb{|3=uSzGQ%|7lRG1=
z|82uNuYv>;xYd?3DuV+K$Yp3ypuVqM-3mS}y9(BrGbi@5S<HBaSXsDcbTCwL*^5kl
z$gg(|VNdSSBSUQQwc<jr=Fk>+l%EC`$F3D?gKsO1Don!nvs#M>E1Fh#roVW|H*^j0
z?7LPR<<T5^-Kb&|`+?tcfaD$pyEU?kiUuo6S9nUy217krgf3;MooQiPdN})oQK48l
zmjG|NM;5mkc;2>AX1m#ZbSH*<9-kx_N^xb~@MJA?hHeYkY9U4YRBa^xrbz<zw7;Sk
zn72%x>&++Tx5-GAksa+*=3q1H6js+A_QJ+6mwoZ{=A%c894nrR6o4vflhKqKwQZ1B
zk%Yl}?ailQ%59>Up;w9EfDbqj8jjI%hh2e8DQ#yt-d!b}YEw=<<W_DoR8i*su8mco
z@)Du8jRmeXd?Y{PAHxQ4<I&pg9N;ck8K~pVc}NDoFtA&h9Y}uCCPTrKgerCc*pv67
zr^002Q#tB`lZ1!tY;rd&x9@E%sV)>#6-Em5M3efVYa8HRYx@)1?U(;>y6(I07H`<Y
zys@LW@8|C+>rTh5NW1^=`;_FTYHB}e{A_>X;*F>Kl6!I6?uTnoHpJ&WEPjRh@oUxH
zV$PRnsD#!r1~EkJN>`d>A|`x5HZ(dsoHbfdTx=L~Ib?pc@{h8;9PZsXhLH0Bi!*-d
zGZa3Ugbq-*fwpykg^`!MA(r`52X2Wxcu>2&g)36Dm_PLzQufNLPsER|5+1AJ>0sAR
zy%o6D@MI)RSC;PAh}xgxsj&<-VkT;-;t!$!SE+Jnv0NU@AfcB=ny!kb#;E?!qD@tE
z&1-nlY?8npd@1BKc&_{^UDE!5Q|LM0hJ%h2tN^TvZvLZK2Bs=}aC38cETdSk)O!A>
zPOfO2|M)}seEEIRamSc)dug%%CtfE}ROx{+{wfu~AvZ8agVp1b?UV8;$mBAkC0uFl
z$q9<cQZ8N{jaMkvwQCxpqi+M_;7ykqBnSn&c0uc6_6UwZSuc7088mpk#Izm%do7&=
zwJ4UP^M>pfPh7SzQGSi@LIugHqQlMGHHRl9Tyr+&wDdmTZ-UdWT+HX`)UK88n3OAz
zZ*Ax4<gI-R-;h}b5;0Kb5Vf=3ee2E&c<`B?M#2zr>-odKS!ne`KmG6=<3z!`Qj2o>
z5)<-u&BG4A8r&0xUE#P<@%5EhUGN7>x>s^}35)TmxNP5Fqw!`o)-e~+WSk-)J~z*C
zw02c7>Y1Q;IP9-c1J*kmuLrV|@qC}3iiy!nD$o5CdG9h#5j*t=Fve>aqg*NY;Xor1
zzWnpl`l+eMFD}N9=1q7+PW9u9KTm!BOS|@!tKp%h6%|Czf)i-R`?l$MYWUx6V+<YR
z7zEAKyc!S+{f|euB2;PCu`rEExyGZsv?FT7JdESE%4N~`D?^XZNnVQPWnGRu)P9*O
z8sR_o(u`w}NqN!M-`mh?1~+>VYD5e0YQvAc2!Ap}7)NR3$}9sMR5SuFjLw4j#?WJi
zKqTj!lG=yji2}~X2225X!wYUF=YrJ!ES`vk;`>cgr7>AF%K&)0m4M6V_{c!q@i_QS
z+9De?RbvbExKSWdpwGxyARM7~VS0hQKa>g?1i%|7qa&=1N5i=yQSXy}Q!{BpOEj!J
zBema;Cz8-_CrW;cNa1muI~faXFtATK5f~IreX8&Pc3{YgSHEZVDZ|S#YwLrfWn_Qa
zyh-^ayG;`HHA2ZQQEdM`tCvQSm1A_H!5fx*!tehY5#xwK8^tji_O8kQ-o{jOXl0@;
z2&_HU$BwS}+M(P%zJh9T%OE1+2;t}DOKcozx|{P?PFlrO?8(K~@MxI$z#k%hil*W{
zV=v4DsbKws!|_dyLg90hU(Ga#Sd8YrmbqDyuL{=u9N?8&TdmkXRN1F-Z0LI%24wyF
zA=gV;ZyH*ra@)GOA~8Siz|@}%7HRQT#=K}ROxR%DzA2SkG=5q=PsRR2ZSY*8WJlPb
zTHOy{rBk7o-+u?p8djUw^i?_`{&gioBid_D@Zf?w^S(;QTGfvv%qJ32k@v3#0Vt1~
zw<l<T2+*pr{#r#aC26?b)?n}_$66GVTCYXh@$yi#B$q4de~hxU((ILH%buBP5Mg`>
zT5QGz?=;viTJqH@fk!fd0~Qc@jOCr2C5#3Nnl&MbWk{eb6DW=$!KBkBjL>hB%T9gy
z&@3O1V%LAQ`UgWZJ^NLv;E`5Gd)dg{7Z5oZ6Q4_2uLY*A_;i_RF)`h-SYaaZiOzc6
zA|U_|aH4OH+TH|(;5dwrG@CTrMs6974jm(nB|AjTvF2n7To;M9|Fv-0#>2O_o_;k;
zjG@;Y{c-*R+mZti{8S!Rm}+!0XyNO`j61JCW4!QQ&o@7f{vb1(Qf!kMo7)Zsg~wnY
zU&^ok8;y<NOuSCieqs0&>Y)%mzgrS>>a4P=@YE^zEpHn=POMQDzNI84s;l$MgWBpP
z=7Hy28(^EuRwk3Sas8JUm~;oqmTZA#-wP?S4D|*Lvvxi&`SXD1Q)0n^zjP&+jGhql
zuoWW`do;Q)s4^o*K(h*j{?ZfiuFmI9+A%u27v`9rKQ(Ud&oQ?mS>6n)HC@m|yRY>}
zce%nFhyN-P9O=|FH=ziOov<5w1LHHadOB++E-x63VNGb{5m7?Q=g;qS$hAdbf9aAx
z{a6Q$MSPXTjn5DLwZmWbdBAw^UKSc?ws~T#h0o*FuI%J!@51jH$rS~lyC}~-4`e>A
zeVg>1wMn_a=S$dMS>(Q7?xC%~TY}*Q<MQ-cwx&5Lp2Tj=q>JRZ-bI2xIpz$ELK#>%
z&LLTuzP<XZQp0nOOS>|t9m4-<N>&inSc3aOsitm9r^p?vS=QI}L=#t{lim|~=9(Uu
zw-MIV?{d)Rxnp{1upz(x$4C!clvmu^2fP)V)P{QbaQDRZJyAA}Frgf?CYmZ|lw;<8
zYKTzsA6+T<(B0VCGXCDitcEvobt<v+E>|>RV*Sh^;A=!wTGpz(rKRzr1;*B6M?Aqo
z*698AIiMZIT=xIY28(Sm?J`?H%yY!dar-sO5-a$qv%E8wk<K!mSAKcoA{DB*{D-Y7
zhpry2_%&)5+GgtShCmSS&C9NbXb{Oh!%MGO*YG-7%dU^lC6d#@w}Iy!d3<nu=^P>n
z<5)Ge1=N=z?ZH#3OSHRw2fH#7_UY@F;E>MG2ERs`qtWAwubb|TGRM$HYj!OJwZeMa
z%QLE0tL2p!%MiI@etonj$^xydxZLNbDgu(-TE9hEIHD5WHEqzeQ25=74_-|Kk}gYO
zd|s0`lpWOklE<Tsawxi>HQ)4y^d_wo6>x9Zc~hX6z<y&Kqs39MS5-$i@m>5%+JW;#
z6v~r&Fu$zt)M1A_=VvYN_8vWXukE4Yh^B2n&W*ToN{Bn8n^(qrH=x%%EX!HhL3q2#
z+Jn^o?2=fK)(q{|CE3UZg6y3>o&Kz8aP!t9FUh?_M<Zhx3CEkInQh^fqgmHn`0hWZ
zj)dHu>V5$;@03<K_>HF-`eZ-1C?YY~cvCmu&u%xHYB!bPUtF}=NNl+~)ym)<7uvdu
zZTywI91jQnuX$-&J*l+w2jdrCJ!GCx7_-f8D2}OTdZ2LpUNx@w@^W!RlhKc;cljea
zMH63he-Xd%QT##NcQ)8<%-I4;$)S=Y!ds3HTfuK5r@_VthBo_DH`rZ>LKk}m?Y7I6
zd`vSS?Rz}3!typw-wV8f)uG8P#^jc37LsP4tHZKTUNAl@pUM&M&1T%ZmF0I=9&wFX
z+{y5?canv!hsCDMk39R=*V+HnkCuA0JfvN7nIdd<r5<wXyi<L4fMs_f#+>xFE8!@I
z`1n~*=cU|K6#Zt}L#inhFif~QeChjc8`$OH6m{R@*W{F2UUj1Jk>$BQn$gjgM|_#r
z3c?>Q$6#N-u{@gWV8m#ZjP5h4mMSwX$1Yg*G8ZY9XWIzY>=fr+Dx*G>F76VSu^e|n
z65cOms6yR@O5(%uY=@FjTO*soVBzI`{k8aKgL|$`b$!m*LHoHtejE3UkG}a)Qt0q;
z(#&myNK&BnkCEZL{m0fD8iv5c=W#-EJG$3CAN5tOE~rydz2ZwFDzck!q5-B>T49ft
z)l9rq>U<vPAH3~FP2njj0?u|r1@WG?n$`kmN`$piP3%YglbuFexwoHnf2l^4Slm({
z-A#yJdq*O8#tWcpMRupz4T-T4UK!}Uifg1(*(02??E;KTs|hVWi@dF?YMsV?d?SIO
z<_U$K=|<;4_wjm7oht&nZ#-Pe8PjCb47;if_z#q|%kB$IljEjtwxdUC$3=TbQL6&I
z8gZgOK8ak;Ewsj-y`?8o`sS()Y01J{?O+96bm&S3dAmuq(tyDaWi0xL&Q)GTy%Md+
z+S|DWCVhbLV;lk=)3j_d<{y!T6u(i|b}(Y(?k*<L@tT4*x_2s9c{80m^>W8n`UGjO
z;)cQ3{1I7q!QsX;UauTaE98?SOffc|q|~l}+c}@77(2MP@%SHhq2DNjUVN55{Rj(p
zw4;@>UFW5y-lK;HT4mk!RZt)$Voyx<g=4{gWw{zP9-`U&qll8!h}MttCC0BC?Z=OB
zr8nE*UE7}GgSsE%L`~&aru0lP!y0F-A1L28@FM5jQT~qZ>Gz3=)A`N@<Asj>2XuH$
z#hk6*4?D``%{s$9HJ}D){gbS!BXiI9yyS^36|p|Qd}Lgb?nU3%Rkz_l*1t9`1{JPV
zXUc0Hm{8E%jPJxds4?u9LT6P`T6*^QOK^w5*YERbW8-|aSBF7m<1Y;k24yfWLN%<B
zIvrR3svwXs1gPYvVW<k91EIWB1IXk~zn7|QQu%L+Bw0nw>3HGslHn;W1`&MB=n-h-
zP}4s++x*A_Wcd2me7~uQ1L1le1zD2N>?<d&3Y6T#nYUYyiBl<<CkN9>N++6oj%%yl
zli%F+stfRKUnkggXUaS#cI>~ntCjbbN9y}(Slpfee7EPd>zh89<+-*7FA|uf)(#cs
zC3+HB>Altjvj*NoYo$e49nVRek@cF&;2kB#f8Vh3taSKsl=g~{La~eX&5|4Txg-p`
z`0rye4FQ)P+{m>tjUoGfb}Gx<sV!US;4*ah4yG*MHUK7i%a)4^BLBF$47I%Mqa-}V
zWW^D2E9b(_O#{y2%pFC6TB7`^bF{nqx^~X;T%+Cg28E39fqujECzR0LuBrCULkBl$
zAN6uBcv9kLkw$i^u;rO}zAP+vS2WO997}caDl7dncY=S6<74!wU>tkC{L#ZsSEA>x
z=f?^@;pJnOQ}12l<6n5BI+aC#-d<EVIeKR##l>YTUtx(0Z1>hp&AK4dDNAX+7-Zho
zCY&0MNi=Mo$nVGOE_q&V?^|Xa%+D$4cX_Lo&vzb5&>eovcajcQ?<8m0=7xWL#}v07
zeLm{!dlG$eEcBX|KX;;4^azVR^*F?=%dI-7;FANZ)!^=nR-s=W!*|qK%KR+$H}<#?
zMU7w^ixp3UJKZBb^0G8Jewj~%p$z(gfD~t&!^XIxBL#=BFWs@_M_llE8@tOL%Gj2!
zeq>3$f*%r!m7Ph|)Nq*?;yQWw^X}@f>rE^A9P-YTDOT(^u{rx#Y*tyd`CTEE6yxX1
zb4sNylca@@6^NnV`4_e9eZ_YOV%%oxSY>u(PJuYa&8jTjeZ=+kWpdPR=P5r%acgJM
zgz2+@%Qg<FctN*sOx1-bpZMa@-ebzA?Pp_dwnmc3=x)|A;?1_DU(%n1jD7ite|!Os
z^bvgEWVgv!r@hGbMP!G>&_DunS?j|Emr^V8YL|@X_lx=~c7G_E2<Et7_V%Q1cj*6k
zB2Pf^r0;CcO*&qj>-c@xl<?X9u2bYgf<!Dz=a0uBnMGqSf5`hpxQc!IeQ03_+da}R
z-#xda@7?Ryp4W)xLjyQMPkfca?VfvoZKEmSoxThot}uBU(JJX~VI&-Mjvh}+)w8On
zZHrbOOrMhfQ5&4SCAC;vlX+lwtHfT*R44OE8^(}V-E2~ZUc897w%2*6)1oNoPx}Dc
zgiwEBpjh!26J@Z=xuSxn{P|^(@WFl2gJ%xnn5=wB?Te2=b<WQlCeL8>7Fnz1bBx<e
zk}XF~pJSt`Hgl~XuQu)BP>RoN!#e-hr2TE={+|Ra#SO0y_DpMA@KK4`_+1qBfM6N3
zN7?`1L;CaySdq+k35;sGHC{ItI%y0(bh96}N;7Mb{07}($|K)rN=n?@UT$KWpURwq
zb*7-aDfl}D%~k<zIfOPiQK)o$1e5b&LJQpa5jGfv_wIo+{__~{KXv-g69V3SR|#_x
z-=VAyQvUxm`VZUxc?<e=7x)~hF<8`v`Ph`VZJ1=RzT*iDpMYtP;^}|<&u5YUMTs8t
zN{5C>N4vB3<PjfZbWI@4_~|cc4DrC6^u62-2TSHi{;D~<zHyO<PF%yGyGtk)YUzo;
zSmMO<Oe}qW#);>fr2L|Rb6n)HlzFel><7xdoENcvn{Y1<2CK6UaxdN-m|Og;rhk3o
zVh@M72K&33l#OcXgkR7&leh-QHS;}=$6eoGJjY{4oYAjtKTrnLTyK>AfHR&~{Dbdl
zuG=Dy)65MuWj|3i<m`|0Gsf+=L#Y)f)>!Xz`<~*V=9*Bt3l}iIc$e=&?x%$w3z_k8
zex^9hn`!fkFW03095auSq$c^!cQe;wp~q$>v&LE<mur_<^Y*)YH%q_AIWG2C&3s-H
zx{~rdr$4sA7}tNWL7laqTYuAKPH|z4^SYw%Jj~+?54tU+jH<a_E!~c@o(DcWVH3`J
z{^(JrVU74FieZj(9N!q{Y*#p!Wy>u{wprkTiHk}owZKKpE4J`m!p-`TvL>gwM!bx2
zo_V)MtVOw-Qx+S%*u$7v8>hVvN4VLxAn<-o>&6&0iqHJfg-nZ@w*Y2lMa`0*C>1&4
zSnVx1@j<?Nx-)n9rp-bRuehj`(z!UsLJxK3m6|0#Qm*7A#%del5)W#tn;+(`xw&(0
zAf?7^edt^*1Dpx-QBC3xlt(#@vD%w)jR!N-%@1+!-YlPE;>C5lQ9jRvSX1_M!2B+e
z8tYoA87_N%v6-(n_uY3M+RXAA{qH>7nPD}FD=1+(BXQaWxDh+cIp$tmiyL9{0{^TD
z{dr_w*J3r+)$z?-ujQ1ygWj<Xrnqf6j_Q(>8tWsUR#UF3vF?;E#+fem&|((XRBym}
z+Evaqx8qhMhiNqF;n;RjbIeb2BX3O18wD8JeOgS}tj4-tYK}WTzu4Rt#eF!hSko87
zeYDU6!}N*GFu^fyOsEH5sS)dqXm%Zr<2w#72u!PaVW%<2+?~7N#?pDCW^vjFr?%jN
z=Z&6Zp5P8F^4K!8jytfhYaR1t&59o=FLM}k%`x08JsmZVhc!#q>n!TxtC`;lS%q6X
zFL2cmj=OSE7mm4$yK<q&+M(~b-9J!%%+ZT;--6S#vz<%c$32kzPMz$;?Xe?j6yLA0
zcC=VSF`pm!%g`!r+QP0?%z50j#U5%yC%7)(b)8@a)f6qK1m*O`x$EP4?F{CS-MAZX
zQ0Lrp<$A4)`H^C#CfP7#UsJS#l77%Y&GjI6V+!^AE_XG__93I1qGc4<g9dZSUfhkz
zk+GfYaJo!-O~7&rJ%^-5w&Qx~XR39bi_7@UVg<!m%{(<^4Gz1w>lfxwO~4AuP|l86
zqb;}{2YuAYN4V!wn$!X-YZ^CXF6mktmvLlj4bDzYvSw&4H*8VYTIP$Ik)J3pazwG6
z#yHVIo;ul<J8*NO8rhZmlO0AQkXTdgP%($HL5&<6vK}X!AGm&K19$0nT^pF@v6h=~
z*c&DbMsL&@Z}e2_vQ#7g6|xx@KR<BuP)3c;j}&ve^ts_q+_Yp9jnUgR#s;2qJ)YMT
zt@B*yaWu}|u3{0TSB-ov#0+OJFVO6<7UiZIPv29$Yjd3Y-ino!7BzC(xG}fsyDs+}
zer%L0w=KC?WAsT)kpX*7SCkq#E<_K<n-{1zw2}LKVb?}xV~zFCxC}e;9M{9#@*C78
z9zk(Y86ieE{ds{#Lp!;;D=7gvopDB+ah-PIb0q)NjI2ANR(z{QKY4UsacRxS&+Pg4
zj&sA3M;Dk>){Jaqt9z`D>)czRMR~49P7guh`sW3rhVb0_#a(!&dX4iB6!jd9xWY|1
z4Li-bu6Ep|$y9ZZvvE=J<6CirMO~+vdNs~JQuK0c<E}5KWarez78>Ge58jL`+=!#+
z)W$^}<|f_Dnp0d+lex}%p~sRqOS{NLl=E?x`y<y-?y7~~9mjm})VRHTe@kEmeVyIU
zMvFJB+kJ1|e(N88{CQEzk4fME^tayTSIL*>(U0!Bxco=@hOF41x1FA|EpxZ`yC+a%
z2<J#^SY_oOlX5Dp+crx$9OD!AD7-wcGOu7@6Vo|(FlkNH_d^AiA+-tCNg+W?*+Jfp
z>)4j7{n-nXcAnb0>iY$kU(S3PL+yi4?_Cx@{-nKBIpRFW(~TVH#ChC#drz$-Z~X{d
zy~_?u&pvT?$C+BH{OCcY+kc&%z2blWa{oKu<CUSBH2j_`!~t3E%j#9pB<h(e3guGt
zTjPfRp~HV)@Qy>cQQWCzT3X#?1#3d4?{3uVEPb)lu`}tvxxT6Yzbw8($CsW^{`H2f
zPo)+qZoJQMA2p^86zG;{B?ih5{gL~G5zt8%7Y51p(iCpF5tr3kFCHoC;{8T`#jDg|
z$a=~NUe?{)0?@u?YAD6Ux1N?-XELJ{RK13cAr`c3F2B>^p4DbsMVsuVX(Y;P2lrK1
zF4-D-K2HBwwgO$X!?v1Xo3;sd%5r|YNNE1Q==Z<senowKz=ez{csFzxD)e!$p@kht
zv6GLv!L;1V8MptBw<OS(tY7aCyV+>GM3InNF~xwLZ*NJIJlR*_x7Nb<$!`^FmS%3>
zsmE*$8Qi`mW8u(+-63}p8WTdwbSmDzJGZCe$x_di-X$B@WlKF>yi3-zLzjB)^e)l!
z)QLB#e75_>Xk@%e{IlI4XW~uro~5s2CoW~{zZ>|i;!?ax`m-0w#l?HmJKL=ex-uR#
zc>8<hRMH<b`1#x9Gz@&`-!XA4r%>?0^MXG<r?TTg1NO_=gRGhdmG9ft4u)Uf>sr(P
z=Rwwo2S(@p*XQ{4eOR%*d@GYZ{9(n;^6!{tVT0FJxi25OyDMaWqVbiGBRUm-yz@#5
z>CmZYNUT;Hy1P5Xb(Q<tp}UqLZxffS_goxra>jpQPG#c*qtpI&IetSQQh%8^l;hX`
z!PD1&b514ufzjD7&Ieha9#q!1GY_)fJunLJU!CK}|B$+^d<(N5H^@|aCWefxttd=1
zjt?2pskrzq&9-9cQqKr)qjjFP@x^~WTajFRbFXW2`=Nv3@q1nA?ezy)9S;iq{a57h
zdp<aCD>r27?+S5FEV>fnsZ(*`or`V7y``R^-n}=9Gxlovd@(!7Vn3*S*S_W;>-B@e
z)BZ<t_(LCBe<@$d6ki;?u-aXFDAF>dEU|j!(A2IF)|x0CrZ{x4ct`nCCL8c=n~2Qe
z^FDZDzbrWzesyp7<!9y_JfZl}1Kz#Kfw6nFu>PJo+Jhfj&B}F|OD+x$uZ~*AToN`I
zxV_wl$?pHqYCdr;N4w_(+uvV3M|=2#+181bIrbrgf!oU0GnWJpu36Lh-O$C|A&Cjq
zD~7IEhLG2Et{OV9D<m;7;Li{}or;a`cJ8k@y43TycgA`)d#UFR?+iV*^-|AZZ})ZV
z^YO)hKO?VaS1)A;yer>Vv2CfRy|?>%_KEo7)MsQp&%pT6FmHD~&y>BaPwhJonm0Z0
z^Y(Yo(H49tGb`6&9>EQMTHUETw9z7DByl7*<mTFnrSHP_RnV7u+Im~AXD^R0zWFSC
z9os2>^#5z`+~b*i|Hn_1kVAwJLQ<5yJ2>RDnxb@AB^0p^O3I-$=h+nHlv652%uqv)
zCEkQlPSu+^M!aVWnI&vCw%NVizk7WizsK+M{p0uN@Ansv2bb%*Uf1h-UC--vUDs>(
z?%h+oYGX**A7AmV+AG~G&0)BGM7k(vzSn5;m>OgL?o5N$m;&Rv6`JyBE)~5`r(wQh
z`C!8ZMK7hRQ3e$M_zGfmQ~EqMz9Or-DI+k|VR&rB{;1_JVfLy&swjuvyJWt6s_5%%
zFU8LvUX-)YyR@$s-oN|y%!;;+1Vh~#E%itz0iC?1;a-O#qM==pvh}Krp_gNPU{!UP
zK1C&d-t21pR?6A<z=UdtjKCKTmV+aQi##Fgv}`sobZ^f*)U?^cSUiCKl%jJFZMvml
zV@K-YhNp^@qgS2uz1})lei`|Y5%|<0tgf27m2xwFUiYe#Aw?@bu%?=8K=Fv5_rBV>
zm0}$q_^A47MqrbJ<+qV-MPsyHBTXAchFQo=ho+4#!@?RpnUWiW&e_r++i~h}L$@O3
z@Ks}dih6wD<Lb<ez&8$--$!;H<>otBwvUt?t?MS_-2A=2D5{H)bNx5EXl%asq~)@G
zQPc?G19?RAXcm=_bNTm)qOl*n-TOn;`|T!ryZ44#^v|JZu4_lZ`{#mZ<}E`N`{zPu
zrZ?MYFqW;*cT;lX(NQ`L5gk2F4bh4e%vFu86l{Fpy=wW4`7`l>gzDt<`MvRh8P&-d
z^Dz!}BO^vfxz8Qy+D2X-4eKR%-u%6{DC%E==k?#gMaS>VJku6P^xOUDwY&6NuE=Jp
zxBRbAqkf&x88@w*M`))l4L(=h^(mQ(6qBp&hF+5Kf$yttrOy{T)OC!!KN|KA!SmK{
z>mr-^-tv8+cKx}xXTE8FkYt>)Mr%K!B%s&oG^BI{A{r2il<ik74ZSYM2fnNJOs`0A
zsB0f7Kk7b67`yp9_Gs2;LR9Zaz)|;q2xHfOI~)zGci^U1k7dlu#Rq<<Rx<Ru6F-0X
zYS>n<F2dO5--busKN6zaMskn3_Y=naew!72fYNKf1B*<5_Rd*^D)oCo>7Gzn|FzJW
zWvvfN3}+j(;1MMaeQisFu){tHeNCsqDa9@Z?QVmXc@({Y@#O$IO*2ZF@de7KL~mi3
zSfSIjbMB+nbQ(5Y#UE^NR-~wQ=pq`vC{pyVLguK)&sSADrB@_5gtd(rXH=9raEq#)
zGAgni!UjjK9(AV>Y_9*lQ<MzF2-;C=7~`KW&7QhlBl*AM0r64u2;7DkEgAxkH|5WQ
z5v)AF>X&}xiVsR!BX5Eh%sxF_n%fvsN4oao^|k+wB>u-CH5ue|ba=v9&2M3O_8HNQ
zzK-mxtdaDSZ$P}O>gWHqcWEy$XW#XVF!N5qrGH{we=lyNw@u&9)FLP(O07i?-dJH5
z8MjX1WaG@hahu8_&ZJ@w?9;+a{9gLc_s2!l18IjSk(^&+@M^lUG4)l*tYgE(#ZkJV
zx}UjPEZLpJ=4*D-qbxGN+XL(<&fwFlDozT^$BkbN9dQ=CJeQ$f$?7B_{hG-L6qeIZ
zVhR4a;lKSZR@<Gz^C+W-`HhBN9=?@5L=R)ZiEYhNk&0T+!lU1tXyCBptO)Zvdvn;C
zB6AGkyoD7B*w{lB%s))k@{rYY7{xXUuh(}ifAJrEgXFV=MA~Df$<-HN6F^eOAWrB@
zhP|oReJeaN>|pVZ`dj0>cmEwbAZOInhB~DApOCEJqc(UAF-c0CW&5Ah=D$h-8|x1a
zWe=ISmP>-Iq+df5svmMbR(PkzxNCR3`FXDEk!kYW_i*b`+YiMr$Z8=yFjGaX(WWZ{
zD>o`+70dQrY?riC5h!Wtp7=13_UTQ^Iji5{=blV{hTUKB?MtO|r-h{9Q+}P3LmNz0
zLN8_=KCiUnQtI*kC5cGU##G|~t6Vor!#TFgz?i*N>iKEO2vJ7J{dwHY-2CF|cC#ya
zcfaFWtq<+l2Wtdi*&5z~%Tet|YKKYDxiq<}$vNy>bv~am&XX%?dKc(rEBN~H<Q%Nk
zrcf-d7Nzt;RC9O)3u{1CuFzMOR9@@t)(o}Ppj5i2^h3YpD45^Mkm;w?S=hobi)FR4
zWZJ!S`j<f^y9R4Fd(XgFlrkK#^J-;70`}J;cz>z+%?XnC3hdYL@f_hZXa-j5D!EU8
z{IG%C`l2l-zwZl3HWB%V;B~wH+tL3|7%X;P92{{-<R2*lTMeA9rYM<i6(#;XLb3v>
zFR4f9pnJ+=5M}NxBJqLb9<Xvnh7E!=E}z?p6VVqz`D7dppp$ljq$(a%v}o%1e~FWm
z-h339?b}+RDf)okjIwy-``=55wb1!Nv-p3kDi$f;PP37lc&*F**pwQ!qcY1U_i`#Z
zVj(8NvhE-EW0}owF8mu~+F#q9?wYW$&u5ukI#yHSMjflUd@*OE_xSCUz;~HVnCZ4T
zQ^kk~#$Bhm=&`R(dA_w2e5>i9{Ke%`j}*)z<`X=-$K4oM^GWY0eR4gimznm8J*<q)
z_@VTgZN8o~!b~Hw&1Fe#%$*F(?vF5YK$U?B_z2qv=;O)jF+(PYt1hzRrJ7BC==A~_
zF+_#G5p3i-+klp**>Ejpjbx@dZWql@s-hoYi7P$W#%uB{Xj<L)4dJ6Px6GlhKp$9l
zk;r#pV9ZCcv*ys3oDVFI<@0^l<keCgyW!f*8li=ss6K``S9gI;maz>W?aqelK&7=e
zMGv4-ZvHe1QiUDc51xgZMjd6ti0mOhLBKHZLR?)nO@^!?>15-KXnq2_0{&e|=qU-r
zX_Nxg=)-={L)>3Ee^?6YPq&-25z@STQ`9Z)56LcJV73I1gxNS#aobXUomfh;o1_X!
z=?(xNAXN+b(^Pp#RoX3)5NecFz*iERu9^-01+~%X2b{!0RnzcO^h&~9*kLwa8ZyV&
z9Q1=awkhS4#nOAa@k)@6PIE9qTuR`>#HGi&ahgy^dHsO9SjUrTk|HF8yd}y(H?IpI
z`R)e;#3OcNYlx-qW`ky8D=Ya6Vk`Z+L1n11cQ248ZhWL0+$7HS17vabS~sWyWqWRj
zhSAO214!?(!QD{frYnK8y}87>u%1ULVx4cUv&9Uvr(MMzd9gLcnzggZVpZdVm}&8V
zOZmIR8h3a5o}}OETaNN%e-}5k$tLTHrG_x6VikGQcg54dHOC!;R0$5U>%~Ix*<|rl
z+V^Af#6s26Y_Sk>KOUA_d2(#Qr5gpgkkEbrBZ8{KyxCc6p=z=@YAa-GG=YC#-0|^l
z4LJx4%CGshShENFh*+~_HcZ^Kc?h!yPo7G{`$>8Cs;adOtOI)Jl?NgBT!?PAn(&hn
z(b)Rp(mwj}t&m?L?NKVM8cEzT-*h8Vo2h|^J%HSlv;w#$5EY84|F~Jx7}9N<?wQ1f
z_hZk(cbFxM(*@eiw#?<s1}%>Rf6~Yc5r5JZ_qG4YyB+zH-aKa{PA^0^@0~a%`0Q_w
zGJ@0{zRu;BCO{-V(ckFj)#59<U3FMBLNgZMs%>ET>reJ@3;vn{atvnq0$ezWC-$TI
zE`C}#PG?l^2+#$6=_P&B8GX}<ebX2ErqA?EAH#8NjYe$^M{V^-t?WjvY)7rEN3G08
zt#*xCnT%TP7_~AUwK5uw7Lmtg3Ms?_N_@c*8&|8B_D#tvHryS4MxIrJ|A)?2kjguC
z_!aiJU``Tg?ELmIxz5pcj%X^tc(x5-&ub9;HJE6FZEyG(87ObjL$@)=TYfjp!;oT#
z8qXWQ)8nOWn_7HS@z5=X=&i;<Z2p-9BA)t%zHrD^i1iQvZRln#o%pUEd$=j>)BL+=
z4Ax?TArh<r!UQ5cj7Wyb@u~!aUiP5Ggr6XV$ybv^Y7|Tz#UmYUg`)Xo{`&-Cr)3Ad
zZXIT1>A-io-eFriaHl;<frSQLqOra$1B&N*`e*-<)C(0do=zJk5J|A;Sd2Z5ao8EU
zQ$ijBUKw;7W|*f-@}98~kHug~VcxuLU=q5G(Q+el3`uPnceJ&GM@tE;aw|`Dww{Ga
z|2)UA^}3N6S&*g8;s8sB%P+MIJlIxZ!!$@B4#(#uY&rrpptQ!Xu`dJnuqE0C$d=;2
z(EC|2{Rzf%h4Fm_yP%mjiI&=-$K<Rl<5)H9o%qb(xv%Gltq^0^Q?A2A7nGYV@n@Bh
zD`6oo$is(hp*OkhaSkm5vo30j{2XN@91O+>z3l1ii+I`pqOwjukAp02B-d>SkHopE
zafAx2DS^w1=$kHN;2QyEIEKhYh2)aM9BczXYkR5`<XM4C{x}44(bWsT5E~u|EMY{a
z+A^u}{UH@HkOQI&qjB=#))KDMB6TK*Tfz|rKszfn?bif*Kp8n!`GJgdvJHR>71^2)
zM55^}vOKSf+9`pD7Aso+IKyN3s~F!f3o8N5#fs?fwLEDC8y!=!{T2B~|2&Q(vNn6E
zGz;$p4Y^JLAC0lx4Q27Z9cbK<vG}FRWYJ>*Y!vRb<Jo6*<O2NG$B2g0CYF#e^w_By
zp<XKE!0DQh-W#)Jec!$p+R;;%Uz(2I9sHB8F0^xMG~0|H5V`&mc-l@dxGrt<S%W+*
z{7AG&eLtyyij$4TIoMLXsnl%9UzM(5nl-ageY5Y%$d*pFcBD7a&8pe(K2hOAGWA~g
zC~lC$pTB`U!o@X_xd>Ydu8~ZAFpWZkDbb?9{kVcL>O7lk03q|lQy;BZj^a*m`0>!-
zx%PPKy%pGK^F9n#1G2)#vy+f7N?f#7`6=5rz#h)n4oQ)bu-@DaysG6Pd4J*=5J5(P
zE#8MA+hhzHQ#(KoZ%Ju~8jHgv=oOJ3K-08xXvIeCwR%rT@zWZdm42m<aPd&!J4Cj$
zPv2UXVrdIf_WnBO;p?Ba^7i{<-#}M5x8`ASk&>pS&>EUiG=XJ<y>m;kuix|mF{yeS
z>4G&{)B#qqw^L<e2OSNRIee@*VylB<Sh@{5P2T-7``25~K3)zMyOV;`&r3~1gF{<b
zXiT|)7<vOZ2}e~bg&-z<t(z@{&>(p(T$C5&AH>>uQZMiMJc^4FZbYV4-Xkj=gvffL
z!T6404i61xC4^gx2Crcr8s=fK@)TSF>wq1Wf=d;z>ro!yv%mQ@<~|vD2-@l^B89Rk
zB*t>2&`%N?!G=Ztg9PHFpw*saP5U&RRk*aG!Yp}Vj)dd>Ar;^{CXo$bh&r;fP8&pV
z7Fzl4L}4su?`x4>fL?7g*7mhPYCNwNyt{`2?_It;%Y~h{4WPbLhgQ_Z6I|mOJB6vt
zAP?In`?Fw%KzjwKqD#T!*c|Swy=`dR;jsbPM_)D%2vviS0{ly`OQ;rYFN`jkP)CwU
zZSY{6qCGrSggtj8nJB3I!sTwBUnmyNEI65`?Nr?5u?10M^}=X|uOt*I4$XGn06E+!
zzY}*tGyB-EQQWq+O~xv_dkj5Z_MYHi9@Qd)@Tk~4WFMR4UI{Pcn^T%GC+-CHP52bF
zOL7mhZ>{hxJ2v^^c6*TWxoN<jpBD}%-)+>L!|S42pHH9*+ZkjBs-94^v@(B_BkU98
z=;~P<nl<H!Jgi?^O$HVV{RE69q58~9{^YyhJ?)ZC$?sC0$-I><59(!gO5>@i;gO<&
zkh~3A)c)mx7kfMVc+c|iiV~6PERLWradTw>OW)33Cx*Rlf<d1>2!{3X(rQWGmjDSC
zXJtUr0&kF)M^en^%cUrZ>lcEQkpg4kT2Vqrd`&b*gSQXb<wGP++3&{|2!`eJ*Y>hc
zMvAN@UT>aYEL-=y-J}KYBU|1{NFWL`Q&A-e9Y~I-bdnQzcv3qOH2uw1P)2sT>+9g}
zcj$3MWs@#i`g!x9vkv@zhXxw7#ugcC>GiTQ=i!0^fsGw02ZQ~q0XHx?P&u|Gd3u;5
zqKwmxp*11Wv2K>?#xeK|UaIR1UzH-##iQb<J2|}06~M7=fR%!6uF>R8?aC(3S@uO@
z9V$r=_AKdzM@2@P)j|70S<Q534R~J71&pgB;z{EZ4B)QA386L?>wtqRU9hEyGH^w>
zHukMi`<;81@ZnJ_{P-)sP%I#O9xNdhf$aj~oB%-e!zcOsn(W7A>7Vl8m>bY`sn<CO
zPR{uW^1#Z!;rWw9CFVJ^WTFrim`r4k*{UO<M_pZMfdAl|+ldO)kzCYoy?PRXuP+pq
z^zWg7y~~^xw_y>quiBDcQBkUpGX`l52-O0RlP<2E&*w=uq9TQF0{2kxeamQ}`%+!_
z3P0=t`!dVD5RKUYZ4T7B)U=4hj;Z9$iFx>bQOUIv5%ztHoAfd>CT$9S{y6-Vog4Q}
z=>|Ap^xAg#Mucrx0bgeh6#|^Yae(YvT<r5jjK!BOmR;XsO~KFV5J&QYALxC&6Gd1q
z<aW;Q8S+bbCNsFcyOO~z6jT=O4aS_Rv8CLIKxq3+@k(z*oHFlSQ4fGe<1Re<)(I__
zKB4?gR0C*prL=HkxuRo@wc49r{s4KH9UBidsJIcbtzf7m;aO*t-Y?P(u-B#2ser0C
zheu<4qS4WPv-G6ri&lj{tKr6mow)9Uoyas~r{1z-C$bW!LprcwNsqJQuj`_7zZqJP
zf&ngd-`-$g<n|yqz#br{A-lR*cfR&5Aq7r4dIvV=>ItL&)pF5|R#_4DPR=U3=%n9>
zsF~~)F_ws(GM0t2$&2k*zc_438O>VO3%K%SUy7UW^sW^wv<48mdIY{klL)=$yT%RC
zVd#FJR%}XmLz9^gbN2*e>6MHGoWNIY!lLzKP|8SdrA-1=oT&Ehm7bifqAOXSK@sSg
zkcIMtn$WR<GA_Ob9l)sEnLH^LhaFNNFuEafgrj86dnbiQVy({rd)o$tv+{o{XOsFS
zho#~^icbyIdYBUwV`TcKK+AiD|M}?+krTI)O*J9#^>n~rR3}%+>&ttB-lT?G+kYch
zRydK}cUIzIZH0V|T+|G&`#N+E4wKM;k9^wzKhv8Olrrs(#ul)tqg(UxaB8`vhtL^i
zjVs@mje~lfteY1H2a_-Xfv=gX#{lZ?L1EqSX*%Ss+7wa`PCF4IkO%)adD^`u8jZQG
z0`2d!qG;&M7TGXZQc3WFPGYChyI$Z?4?INl?-nR9o29ea(1{Y1kF`(whGGCnxSrR;
z@CNX5Bu1R)7IqS$_=t>zlUVqVUw1`BDQFFr&!*or$UGBX=mN@K8L!iRU7Fs-U3%=e
zvmR0KJ>_!>;)TP+N9{W)ncDziM@7fZ1BfdNQaU+t2Zsx<4ZW6a(KwGLTyU;UKac&+
z?mn`dUd$csQ2$Iz6GYzmI(Qs0(VO<w!^l@IabU>%mQjmawnue<?M#rBMR9=1?*;!K
zgUhnFr$Uya2kf7$t<CW+cR+kg|C`hoqT^8SU=T4}l=>O^6pWza_huy^*X~)U^F3kn
z7%%bE8qs)jgC~7cl{}Fcda7GfMQ5)i<FT~BF3dL=Vf(wz@#lNlW0#a%y9UfP{Xb5L
zD331*E`Ep4J(Hl<N1d$HWoaT1PfpHlToW}r`y#U4cSGXu<VuFxePMY8mE^u=%Yp#!
zMR97mqf?1#K(6n(%E?xbR;B%oy$FO*rLB6dXe)A(WrStb_~qkkqVc=AOURgI9w#<d
z=#noCMPuu6dwH4o#;XTSX5QFxT4J`*s0)@+mu!LPuz}22=`F(oIBw4lX;HhphSITn
zLR7|Fr#|bp{av=6ZuW-Gx{!W_L>7~O=c~HW_86QGD@(=U_QinUm&Z=Tgm!6|SnZM)
zy^P4y(N&^4EMF;iENY2RIyh+>iR)v@w7X96vV%>6F(*vb4m2Bj<l=9H)D{e7_@zx(
zasaf*)e|Z%k{`_*r{3&5NB`{zZA+<0&I;}Hpa>0~yjrT7aqLJcImu0?QqkJJ0bDaJ
z89l|Tz7e8aI3#=FAry51Az<w$78-cNe$!FNvZO$FI^)taCh37^GA8k_^M%k^!YUE;
zu5A7p^5D^BlVG6RyT;BA?sd=bUD6g**dfPM7{=K#Rmm%6G^;i(6;HW8&E>3QZ*s|f
ze{W{xH5K{k`7hq#H!k7c&@PK{bWFv0CG_BR@u^DQ@!#MxTpNqm)<J#0F4-kD<3>rp
zoQZV>e8VPtG(b_9;U2F{L+ly4td%^S#bGb4gxS?VA0lbLQYz){cqElnmI#HQ&DJ8;
zb+rT7JIW2sGfO3GBsYKg)iC(-`LCJ7Zyd&C%JIDmPIU6T6CR4uD|@323_Fe8T{0$}
za8ENPafL%0wPQOv(b&FI!&wI>uSVjAmyE7Mkuu&|6tG8&)IYbhGA#$~6xAhQ478Cn
zh(2lUZ+<l?uY;-+zv6hz5q?%WdrBL0Gn%A6y5Gv9K6I}f6FfMPx6h}@Qt8cU>|$5=
zbITJ{dz{bu=|eirH!Qy3@r}d5Pb|ra<i)w-a3(dPtcNlVOipp(|Ek`fqfhtjAI-t5
z&0f5Mmis5u{-223H8By$PZlRTi&|_Qr!>twa>Cy4h`^k%{pYI3Dcjs9a`-w{=D@M>
z#$N~NNs}&@Nw;v=phin7gId~oI7l=cEG$kO2dY!I?CZ<1Tq;FjA6o`#2M=gxKECwf
zp&B)3+a=JUB04Zw1%tI*>Ynlm8aJ<NeX^++ul4?lvkKr<)N|aWiI4hjseS7B!^vMY
zKKz<<&t;m<(_8(H-QIG<J~<~3dJHv%i{wtnCd<(AFXRM4Y&L9PQ-rrOko0{V!=S&U
zUpH<I{dCLidFGn2lh`}cFMX`W2avwr>1#xxv+}!-uBEU{>R`-ioXpKro}2FrFOIkb
zW>{9*jD)rs1nK6||D8E9j;V8=EKgQxj9_M4YDBO<X?OxvJ2cU(y<e|LcIGUMG_;Rn
zxWjv>X3NtbqHr(j2XpWi#g>6DEa6*lSH8X7W;MV4?l4UCFQu0rOR?9+ZL6J#wWf{y
z89<ll-u8*5(7f_WZ5&tzUR%0_v%jDE9Fp0@f9p=9<dDCP!?qDyuolmDl1!vUQt@@=
z&WqE6%HOD;-LX*@aqM5xRg`AiDr;H)SCo)%;q2}`KLgKa{`OKLI+n4f*<)uTE4kB!
z$CSq3d$&Z;{~5njXt@C6jI^Zeq%BlcjBXDS0sji4EMI-3hPmUS-dW;ze=DV_2aTgH
zpReA%X1ZO*B6L*c@pwaPp=V<R@NXbI=-9fbnZl<^5wnsxc++}2O^(c@bC3p;k5{kw
zK=G8BS@v(5E4i)n<ij0KXpp@ZK^Ql;lgVAoFboT4Gp`tR&NHVw6HzBdev~6Oji4{b
zTf*mias7tln23-iqF!P=xts5nk~?l&Ki2GRqe@%oE%E=*xRkm_J7-~Wy6@PF1<F&o
zv7l(X2zM2K6mBBx!`aqT<mX{wduNtK&%^30Nu=f07att*ZNlAO*?sQSjUPN2)wuMe
zMCtwa968|o?z`NGS+&F=^||8`&FFUuf~JvF1K+PY%x}A=7fPbG%8Gi}ENz*_kj!^k
z*xN0hsL$s4qN|^8H`-9Coac4(Z=0~wos+G)#jZ1VBmp(AQ+8&JY(c<9=hC|Ibg=1(
z^oVG{l4$><eAr)i@r&xXbvyH8`Gcj?YuAywC)O!cKQ4LDC=WQ48@MABC2<Aj5o*CZ
zc=7tAW6tS`G`&E(viryMcuwb)GUB!<iZa|-yY!u6a8K0GTc?gPsR3#OD#4q03)PQX
z9yDqLh2;|-h;b=VRC&A^B6S_O+4RE2uBcYHI)6+P+{`q-5PR$S;TYV@rPIz`+n8x}
zy4z(BC<3Zw$12h%Tj70?R=cL8naH<E_hk=k1TxDn$vhvthf8{TSbxfgiG07Egg7M$
z?w?w?4!E?!DRS$SgSB`I@9v+7d#NbW{PxLHe?ba7F-s^;-`4{F>RhWFyq)Lkd88-q
z<yw)TeBwHyXC1iZP4SC#ZY<7hk-JZHfQF9;wy$^USqoxJBMx>&&`>deR0__Xr{R$q
z@SJlGmtiie7Oc<H@N6H7yC^L(a_fyrPi`d*I@fLtmgQw#NZx@kTMGu?VjbzaM#Hs4
z?l7GSW>!`u)ywiFc<vrY{*AjRDe{@py9SuHlD?Sy+U~QL=kD3M4pFfN)H0QI=o+G-
zZW#@)uU`kumKEGaRICLfZ|#LmSu=wUindLnltd|^cXa9{ft<2@ZGFr8xOY!?=}&EE
z2302=U0<&Wc$T-T>DR@8hu-W+OZRLgb(?e;PQ}u2U1lE*>+az`cwwCErA6`OMGE?L
zvAB5Ge-K^qtzd#{8=^~xM)g}8FUw!g3;TW~YU&hop*G2DeZ4#ol@4MjsS2W|Z&O}f
zb~LK*?rhn54M0%dZl%w?2cEg5Vm5_k>Q$+u;xL<lv<rtA2we&Akm=@=U7ao9->yDK
zyJBg`>c^iRV736rkwbHP*8=fnK6mu-65wT<E-&3R;6~Gki(Q{+xPG&n+tOmdVx0{z
zyfnDyLsy2aoM_VRc4K;H3+|(0QdVaxB=c|^G6vjfljxNv4J8p?_G?ANx%|ioIe>h=
zm4mQX5c!rLvDe2-f_Fo2H(}HPvge@#2zwdPfZLw!`gj>o-tBQ?I<XZjaD92KOQQvR
z{B%ETDw&4+t~i|qy9Yk<YCG1vLG;dznUe0?0w$@|=ucf>;@>@%jKi!2DwCK7X^1>2
z@RnO}OnT*gFl3`Q=S<gd3;6KqZ`jl<4L9IypuDKSBqlK@(h<$FqPnsI3B>FBV8ENr
zG3i0~K%I@=htGD^wSpC{TMl-GwSalKHCw4`K|yG>1Yeg2uX?;W4x<O?jeeG2lw#t1
zjCQZ*>+|5X_pikP>j8WM(;y3h-5^4ix5M?}lAv#Be=M*GpwC@dySR^u3*3EQK0+5j
zjkL>7(P?16+~~$dc_!|fk;{6%5sy^+ct;!{2T;$q+99wCqM*4VIlcl9cD~gfft436
zl*MmGcuRm>x5WqP)O(=Jha2|+T>w7Xt}>-W13x?WD=#`RLI1THvV2t@t~%3VicABC
z<SbMcHJIRajmzmIi)8IxWi&&5oD^=|EFt^!8lYd!QN=`x_tdNC&@rZO&Hc={vox~L
zS|iz~8-W*dR}@WDdGF3Ey@>m=K~(0(T1R*r1J7}-IaFLmBL^D4EB2?6FRwi$`&0)w
zP);)@1jm3X5OLSymo)OVwGOf&vb?)v$M%|N@Yo5=i7Ld;b)?+=hUavd^moZ8iyLXA
z!BYii_$_#<T(iorvrN==qoMUr^?<cymv#}%q;Q8!KRXt$p~1F&OdghVRR$iE=kF%S
z-6JKal^LD8%+zR~#a(9ObY+-UF`bgOinKctX;R@^m?XGje*63blQp6%28~@!r;oJa
z>Yx5=dTtLBb$M;He8>S_vS;f!!b?(=u6B6GxjW1(<sa?r2aw{T^{{N%IawxZ=f~uq
z@~$ettFo=ZgbHcU)oro*^s5%ssI#^DFB4|g#vkp=4@?w9Z{3uWPhV@ny<ZP&hMl{>
z%u;nbvnRxy_tmrYG2*EdZtX_zB2@7rt#U`%#Ff%DJk#&T`brIWrk<^f2-h_@wT<3W
zsNyfQN|TSt0(sZ9z))F!B%$;^sX^_L!8vng=Y>Pd2v-@<JT$mANeZW6v(wW{N|YVC
zx3*ML<YCZwH2bu9D{9QSN4->?SE=>`W~5wd!K+mL(LNa0pbmr_<{g)dYfuD+lOfC2
zyUGBT=Z{Gtyp%-RM|fYM8cBc^`uOjLjX+5G)EdG>D~fzd%RQtOm-%#;**QDru*MJA
zA?07&nbcin6Sqt4dD`a>xgsbVM4n|ncL`cCB!b$uorAk+K|V%!`5|SXZuA(vbR$nY
znRz7`L6H+}Hvo(j5a#P}E~W>(inr5(wtr0SksaCubeH>VAY|VoJ*Z0REt#f~x}AHJ
zOV{!|lbBhE^&#3k&qQX{q4h&5K%M8I9>n`KxLX@V!RrZuGB|BhhC}f;TF@<{sP#kZ
zfVr}**9fEcNloivSmSdx%rNC2uw3O*JD$zxXP{JyXLI4$HbjUtsAJF=o_9L8g?b@Q
zqg(ZtA~US|@yWPf8${C3dPf$U(H3s1DJh#s0u%_@p15CfqIm=0+Ga$E6i&%B@ksGJ
zZDHp}RI2_tB_{W6lFIraRiNoe_#QYR@*XK|JudO#>84hydmPEuq1c{A8Zf!J^&E=H
zRs8`QQ2up_$*p_rANNZ}BnerOe_GfIKOLu`u<51*Pv*jBD};hHc*z>X!@{?;OiKKh
zGq-?m?np#m$T}U{g3GE(+Evm@b7IB3=2e{zyQkMK^;*sAtV2uMgyhL;Bf`V`e@b?`
ziNgRRCt33izz*Hs#wQ1hf6(;&j8x^#*8qiO+pZ8C#e&&cX|m>We<TJE7Jq1klyraX
ziffShQ#5t3xR0iH)yP;r1jg(1IHrb3k%TA7oG`U`)o~y9@@d<yb1J+uw)s2ljRvil
z$g0QL544o9o0OirJ#s!N0d6x*bSO>~n>zjTCgS88sOh=wx~EUBgZ|kMyQO?n?oZ=j
zqrr2`!tjIaU<<-)@p!Vc-pZQm0Q<^({0Z|?e}w&1Z?5C{UifT`=#~ckP5nHJFNpQ}
zwbu^%|7rVJmM|{^UNo)uEI#n3=1BeE#XmJ~tq9ZiaQB`{n+;<A6fDXS)MNg1<F@|2
zGBnV?%15$1#9_kYl+%C01T&4BvSQOB{BlnpZzcWfY@u;e^G`uy?&+`pfixQzDFK+4
z7wHn*{wTZRgD95<O-w&K75j+0ad~;J*!9oYU+Eyq*MT0Unn#Px{}dSMBFfi_ht+=a
zfrpGp!L2|2^sHFx$+u0Xwf{`y#&ZOVKl3vcMX>nK93OGb5z7pCFB5B_(7`F`>~{wp
z6D5tyC4!hYt?>KrE^a2p117;j@}3>=CyOg?p+_AnNCK~PJ!jP&-I*WiO@gC85wA_H
z)PFxWwNe86+_iM~R&m!7T%)9GNv-ls#%wZnhv9HtlX8txIqFhgICdwLi$3C50Y;s0
ztO$C!vzUZr$98A7)EC=pLKmyKnK8c%PkSp-l)Ac>a>?uX6b^7w+Cf#V-kxD|D0+Ql
z^b2E97V5RXVulA@!QR;s`2;*kMpET|m3A$8Y3Bn0*{BL)zw2qyo&dcj&Z7Tm(!D%<
z;>FLe42ETTHcsIO=DIV7ItSP}jNza)Puc~0gQMvdGeT+Ts`R<{&yp^}xtUvWdDF%@
zUGb`ignJ`nwm-h1*kI3CKq>Wo$zM_BtPCFyb$~`&eFrk*$AZt)O0OjWi1;#V^kQG@
z5|T_ky!^-|W0qWtm_rIIo2Gi9x01oW<7zHvqUBeF41!>%W_>f?S*^a=|6x9kFpN+1
zd7kzQ);o(*N|}YQW#FG=%zjvK<a42`5I0+$IfB>2@%Ew;Xcoq8p+9pPu~gXZ^eYA}
z51}C^s-B6KS`p5a+!bvl;g|8-Khkb3u-~naU>>AJKV89Jn?Y*E-_h;*l`?(<w$#fo
z(%+vOVM<Yapu3iCHSzN}cc<%ALYD8#mB9XuFdRt9bx946;LE(TzuWe;5KfvD7<$`_
z7HwbTaTcfX{IZW{U?_ME{bwPz8AE>7*@)rj=X}-SE>6Jh`Q5S^`r8)WwWCa=-GIfF
zlJF{xx6vVAzPjY``jm(&v;_~?zZ|s6h#El;zx-?C?|@MDzRyf9V1F|2m}Jzg`Ur9a
ze`Pkl(+)3(t9ubfVS9^~$0wxl+zz)+d<0mN1-HNY2-EtNuFF0JJ@(O77^{}l{QKu!
zr4w4vOHyh+rG6hQDq?=_riS(8&oDi_W?0A9S+fsCEKOJ?_ICX<-$u;52ltfK<j=cx
zp3sw*vWVlP*(dwFMVN~IyU>SIR|Xb@6OXdov7(RP-+4FPiyXp5LmzleBN3(!R0g&_
z@>I`bFOJ(}l?zI<hVgL0TlXel!4T~15x#djBynj=^Ugh*7Ze<d{551B-~0A-TgE+i
z^)o+Gw#GTEQ$O04?TBzZUY5M(f_GbbLc*k(qQl|sM-v&@4sPGvysXHfwfjPHuLQ7P
zrU;XV$t+vc<WHe_0O`erYb#?tIs7{)M&xBH_<Z55ah;w@tnk6NA3zN^AhPO-9*Ejk
z{t9SylA}8_B+%err@xSZ3{mUZ6^U+&uVcT16}r&sv3*O}u%1>oN%R{BOPvlI2Nz%U
z0gI%(f6q2k(**g%m#04EUBMm5z3;lfP5B9fSA}ABc|GiWn5Tn8UY=aQr4nPSqHcs3
z={%S|ner5^pSQ!#{a7WTid6o%=MyW|*Mwi5#_=vM3S)NK%o;D=g1!9PDns|v^s{ec
zd`j4fZt7=vG@Up$|9bK^J@dy0ekX1`<jP)QLO?t&?*y6Pfo;lGbeO$}GKYiX<+)&y
z3(M1qMMdwhfPeq%X-_LHTfv3l@)E=N!~p)qo7EwS$lkL+@b>5j3fi!qB6jc6fayEN
zx()jq_vCmVLXms@trb6fi$=q|lIDAMzen$Mi)Oj))`^>=>XrXQQg6?C?9Pq*1$*z&
zAQ9k_vIH=x0#-?6q~aTVPz4cR6@)u(7aj91sBU;5F&r~jc$cB~(mEV#uM=-LOrIV|
zv}ziuy-k9%Mt$Y^AlDXiP2VnIIT5ANzdJmiG1-n*RD2Y&>-DYE{*6t~u?|08d_23d
zj(Ty{!#QYjh!mC84=e7Wcsd7N39j-x0E!GPmv<45_i~0l|3sUgLX9^(#(u1BvT^Ho
z31@#RdCHN49=f&qvr1r<z$$@N0;>d839J%WC9q0hmB1>2RRXI7Rtc;USS7GZV3ois
zfmH&l1Xc;G5?Cd$N??`1DuGo3s{~dF{68c>1D9#(V*Lku!Qt(w|A#%Ts$M0qN??`1
vDuGo3s{~dFtP)ryuu5Q+z$$@N0;>d839J%WCGh`)K$V0UfRU4kv6B2>J$be<

literal 0
HcmV?d00001

diff --git a/tests/f_dirdata/name b/tests/f_dirdata/name
new file mode 100644
index 00000000..5abb9391
--- /dev/null
+++ b/tests/f_dirdata/name
@@ -0,0 +1 @@
+corrupted dirdata length
--
2.13.6 (Apple Git-96)

2017-11-14 07:04:57

by Artem Blagodarenko

[permalink] [raw]
Subject: [PATCH v2 5/7] ext2fs: add EXT4_FEATURE_INCOMPAT_64INODE support

Inodes count and free inodes count should be 64 bit long.
This patch also changes s_inodes_count* to 64 bit

Lustre-bug: https://jira.hpdd.intel.com/browse/LU-9309
Signed-off-by: Artem Blagodarenko <[email protected]>
---
debugfs/debugfs.c | 2 +-
debugfs/set_fields.c | 3 ++-
debugfs/util.c | 5 +++--
e2fsck/extents.c | 8 ++++----
e2fsck/journal.c | 2 +-
e2fsck/pass1.c | 16 ++++++++--------
e2fsck/pass1b.c | 2 +-
e2fsck/pass2.c | 4 ++--
e2fsck/pass4.c | 2 +-
e2fsck/pass5.c | 20 ++++++++++----------
e2fsck/quota.c | 2 +-
e2fsck/super.c | 18 ++++++++++--------
e2fsck/unix.c | 15 ++++++++-------
ext2ed/inode_com.c | 7 +++++--
ext2ed/super_com.c | 6 ++++--
lib/e2p/feature.c | 2 ++
lib/e2p/ls.c | 8 +++++---
lib/ext2fs/alloc.c | 8 ++++----
lib/ext2fs/alloc_stats.c | 6 ++++--
lib/ext2fs/bitmaps.c | 2 +-
lib/ext2fs/ext2_fs.h | 12 ++++++++++--
lib/ext2fs/ext2fs.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
lib/ext2fs/extent.c | 2 +-
lib/ext2fs/gen_bitmap64.c | 3 ++-
lib/ext2fs/get_num_dirs.c | 4 ++--
lib/ext2fs/icount.c | 7 ++++---
lib/ext2fs/initialize.c | 19 +++++++++++--------
lib/ext2fs/inline_data.c | 2 +-
lib/ext2fs/inode.c | 8 ++++----
lib/ext2fs/openfs.c | 4 ++--
lib/ext2fs/rw_bitmaps.c | 2 +-
lib/ext2fs/swapfs.c | 2 ++
lib/ext2fs/tst_bitmaps.c | 7 ++++---
lib/ext2fs/tst_iscan.c | 2 +-
lib/ext2fs/tst_super_size.c | 5 ++++-
misc/findsuper.c | 8 +++++---
misc/fuse2fs.c | 6 +++---
misc/mke2fs.c | 29 ++++++++++++++++++-----------
misc/tune2fs.c | 10 ++++++----
resize/main.c | 3 ++-
resize/resize2fs.c | 30 ++++++++++++++++--------------
tests/progs/test_icount.c | 4 ++--
42 files changed, 222 insertions(+), 129 deletions(-)

diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 4a533b53..a80cf668 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -829,7 +829,7 @@ void internal_dump_inode(FILE *out, const char *prefix,
else if (LINUX_S_ISFIFO(inode->i_mode)) i_type = "FIFO";
else if (LINUX_S_ISSOCK(inode->i_mode)) i_type = "socket";
else i_type = "bad type";
- fprintf(out, "%sInode: %u Type: %s ", prefix, inode_num, i_type);
+ fprintf(out, "%sInode: %lu Type: %s ", prefix, inode_num, i_type);
fprintf(out, "%sMode: 0%03o Flags: 0x%x\n",
prefix, inode->i_mode & 07777, inode->i_flags);
if (is_large_inode && large_inode->i_extra_isize >= 24) {
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
index 8dfbba9c..bfab7ff8 100644
--- a/debugfs/set_fields.c
+++ b/debugfs/set_fields.c
@@ -79,7 +79,8 @@ static errcode_t parse_mmp_clear(struct field_set_info *info, char *field,
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"

static struct field_set_info super_fields[] = {
- { "inodes_count", &set_sb.s_inodes_count, NULL, 4, parse_uint },
+ { "inodes_count", &set_sb.s_inodes_count, &set_sb.s_inodes_count_hi,
+ 4, parse_uint },
{ "blocks_count", &set_sb.s_blocks_count, &set_sb.s_blocks_count_hi,
4, parse_uint },
{ "r_blocks_count", &set_sb.s_r_blocks_count,
diff --git a/debugfs/util.c b/debugfs/util.c
index 452de749..3e4fcb5a 100644
--- a/debugfs/util.c
+++ b/debugfs/util.c
@@ -119,7 +119,8 @@ ext2_ino_t string_to_inode(char *str)
*/
if ((len > 2) && (str[0] == '<') && (str[len-1] == '>')) {
ino = strtoul(str+1, &end, 0);
- if (*end=='>' && (ino <= current_fs->super->s_inodes_count))
+ if (*end == '>' &&
+ (ino <= ext2fs_get_inodes_count(current_fs->super)))
return ino;
}

@@ -128,7 +129,7 @@ ext2_ino_t string_to_inode(char *str)
com_err(str, retval, 0);
return 0;
}
- if (ino > current_fs->super->s_inodes_count) {
+ if (ino > ext2fs_get_inodes_count(current_fs->super)) {
com_err(str, 0, "resolves to an illegal inode number: %u\n",
ino);
return 0;
diff --git a/e2fsck/extents.c b/e2fsck/extents.c
index ef3146d8..d6bfcfb1 100644
--- a/e2fsck/extents.c
+++ b/e2fsck/extents.c
@@ -381,7 +381,7 @@ static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header)
while (1) {
retval = ext2fs_find_first_set_inode_bitmap2(
ctx->inodes_to_rebuild, ino + 1,
- ctx->fs->super->s_inodes_count, &ino);
+ ext2fs_get_inodes_count(ctx->fs->super), &ino);
if (retval)
break;
pctx.ino = ino;
@@ -396,9 +396,9 @@ static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header)
}
if (ctx->progress && !ctx->progress_fd)
e2fsck_simple_progress(ctx, "Rebuilding extents",
- 100.0 * (float) ino /
- (float) ctx->fs->super->s_inodes_count,
- ino);
+ 100.0 * (float) ino /
+ (float) ext2fs_get_inodes_count(ctx->fs->super),
+ ino);
}
end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT);

diff --git a/e2fsck/journal.c b/e2fsck/journal.c
index c4f58f1b..9b107384 100644
--- a/e2fsck/journal.c
+++ b/e2fsck/journal.c
@@ -1132,7 +1132,7 @@ void e2fsck_move_ext3_journal(e2fsck_t ctx)
ext2fs_mark_ib_dirty(fs);
ext2fs_bg_free_inodes_count_set(fs, group, ext2fs_bg_free_inodes_count(fs, group) + 1);
ext2fs_group_desc_csum_set(fs, group);
- fs->super->s_free_inodes_count++;
+ ext2fs_inc_free_inodes_count(fs->super);
return;

err_out:
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 686c2019..24f8e215 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -341,7 +341,7 @@ static problem_t check_large_ea_inode(e2fsck_t ctx,

/* Check if inode is within valid range */
if ((entry->e_value_inum < EXT2_FIRST_INODE(ctx->fs->super)) ||
- (entry->e_value_inum > ctx->fs->super->s_inodes_count)) {
+ (entry->e_value_inum > ext2fs_get_inodes_count(ctx->fs->super))) {
pctx->num = entry->e_value_inum;
return PR_1_ATTR_VALUE_EA_INODE;
}
@@ -724,10 +724,10 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
de.inode = ext2fs_le32_to_cpu(de.inode);
de.rec_len = ext2fs_le16_to_cpu(de.rec_len);
ext2fs_get_rec_len(ctx->fs, &de, &rec_len2);
- if (dotdot >= ctx->fs->super->s_inodes_count ||
+ if (dotdot >= ext2fs_get_inodes_count(ctx->fs->super) ||
(dotdot < EXT2_FIRST_INO(ctx->fs->super) &&
dotdot != EXT2_ROOT_INO) ||
- de.inode >= ctx->fs->super->s_inodes_count ||
+ de.inode >= ext2fs_get_inodes_count(ctx->fs->super) ||
(de.inode < EXT2_FIRST_INO(ctx->fs->super) &&
de.inode != 0) ||
rec_len2 > EXT4_MIN_INLINE_DATA_SIZE -
@@ -1098,7 +1098,7 @@ out:
if (err) {
/* Error; disable itable readahead */
*group = ctx->fs->group_desc_count;
- *next_ino = ctx->fs->super->s_inodes_count;
+ *next_ino = ext2fs_get_inodes_count(ctx->fs->super);
} else {
/*
* Don't do more readahead until we've reached the first inode
@@ -1338,10 +1338,10 @@ void e2fsck_pass1(e2fsck_t ctx)
if (ctx->progress && ((ctx->progress)(ctx, 1, 0,
ctx->fs->group_desc_count)))
goto endit;
- if ((fs->super->s_wtime < fs->super->s_inodes_count) ||
- (fs->super->s_mtime < fs->super->s_inodes_count) ||
+ if ((fs->super->s_wtime < ext2fs_get_inodes_count(fs->super)) ||
+ (fs->super->s_mtime < ext2fs_get_inodes_count(fs->super)) ||
(fs->super->s_mkfs_time &&
- fs->super->s_mkfs_time < fs->super->s_inodes_count))
+ fs->super->s_mkfs_time < ext2fs_get_inodes_count(fs->super)))
low_dtime_check = 0;

if (ext2fs_has_feature_mmp(fs->super) &&
@@ -1444,7 +1444,7 @@ void e2fsck_pass1(e2fsck_t ctx)
* shouldn't be any bugs in the orphan list handling. :-)
*/
if (inode->i_dtime && low_dtime_check &&
- inode->i_dtime < ctx->fs->super->s_inodes_count) {
+ inode->i_dtime < ext2fs_get_inodes_count(ctx->fs->super)) {
if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
inode->i_dtime = inode->i_links_count ?
0 : ctx->now;
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index 392ff2c6..1607bfb0 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -470,7 +470,7 @@ static void pass1c(e2fsck_t ctx, char *block_buf)
*/
sd.count = dup_inode_count - dup_inode_founddir;
sd.first_inode = EXT2_FIRST_INODE(fs->super);
- sd.max_inode = fs->super->s_inodes_count;
+ sd.max_inode = ext2fs_get_inodes_count(fs->super);
ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
search_dirent_proc, &sd);
}
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 1a719b2f..08553003 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -829,7 +829,7 @@ static void salvage_directory(ext2_filsys fs,
if ((left < 0) &&
((int) rec_len + left > EXT2_DIR_ENTRY_HEADER_LEN) &&
((int) name_len + EXT2_DIR_ENTRY_HEADER_LEN <= (int) rec_len + left) &&
- dirent->inode <= fs->super->s_inodes_count &&
+ dirent->inode <= ext2fs_get_inodes_count(fs->super) &&
strnlen(dirent->name, name_len) == name_len) {
(void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent);
return;
@@ -1363,7 +1363,7 @@ skip_checksum:
name_len = ext2fs_dirent_name_len(dirent);
if (((dirent->inode != EXT2_ROOT_INO) &&
(dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
- (dirent->inode > fs->super->s_inodes_count)) {
+ (dirent->inode > ext2fs_get_inodes_count(fs->super))) {
problem = PR_2_BAD_INO;
} else if (ctx->inode_bb_map &&
(ext2fs_test_inode_bitmap2(ctx->inode_bb_map,
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index 9a491b13..7a76c472 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -177,7 +177,7 @@ void e2fsck_pass4(e2fsck_t ctx)
inode = e2fsck_allocate_memory(ctx, inode_size, "scratch inode");

/* Protect loop from wrap-around if s_inodes_count maxed */
- for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) {
+ for (i = 1; i <= ext2fs_get_inodes_count(fs->super) && i > 0; i++) {
int isdir;

if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
index 7803e8b8..746d8299 100644
--- a/e2fsck/pass5.c
+++ b/e2fsck/pass5.c
@@ -587,11 +587,11 @@ static void check_inode_bitmaps(e2fsck_t ctx)
fs->group_desc_count * sizeof(ext2_ino_t), "directory count array");

if ((1 < ext2fs_get_inode_bitmap_start2(ctx->inode_used_map)) ||
- (fs->super->s_inodes_count >
+ (ext2fs_get_inodes_count(fs->super) >
ext2fs_get_inode_bitmap_end2(ctx->inode_used_map))) {
pctx.num = 3;
pctx.blk = 1;
- pctx.blk2 = fs->super->s_inodes_count;
+ pctx.blk2 = ext2fs_get_inodes_count(fs->super);
pctx.ino = ext2fs_get_inode_bitmap_start2(ctx->inode_used_map);
pctx.ino2 = ext2fs_get_inode_bitmap_end2(ctx->inode_used_map);
fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
@@ -600,11 +600,11 @@ static void check_inode_bitmaps(e2fsck_t ctx)
goto errout;
}
if ((1 < ext2fs_get_inode_bitmap_start2(fs->inode_map)) ||
- (fs->super->s_inodes_count >
+ (ext2fs_get_inodes_count(fs->super) >
ext2fs_get_inode_bitmap_end2(fs->inode_map))) {
pctx.num = 4;
pctx.blk = 1;
- pctx.blk2 = fs->super->s_inodes_count;
+ pctx.blk2 = ext2fs_get_inodes_count(fs->super);
pctx.ino = ext2fs_get_inode_bitmap_start2(fs->inode_map);
pctx.ino2 = ext2fs_get_inode_bitmap_end2(fs->inode_map);
fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
@@ -623,7 +623,7 @@ redo_counts:
skip_group++;

/* Protect loop from wrap-around if inodes_count is maxed */
- for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
+ for (i = 1; i <= ext2fs_get_inodes_count(fs->super) && i > 0; i++) {
bitmap = 0;
if (skip_group &&
i % fs->super->s_inodes_per_group == 1) {
@@ -721,7 +721,7 @@ do_counts:
}

if ((inodes == fs->super->s_inodes_per_group) ||
- (i == fs->super->s_inodes_count)) {
+ (i == ext2fs_get_inodes_count(fs->super))) {
/*
* If the last inode is free, we can discard it as well.
*/
@@ -755,7 +755,7 @@ do_counts:
fs->group_desc_count*2))
goto errout;
if (csum_flag &&
- (i != fs->super->s_inodes_count) &&
+ (i != ext2fs_get_inodes_count(fs->super)) &&
(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)
))
skip_group++;
@@ -818,13 +818,13 @@ do_counts:
ext2fs_unmark_valid(fs);
}
}
- if (free_inodes != fs->super->s_free_inodes_count) {
+ if (free_inodes != ext2fs_get_free_inodes_count(fs->super)) {
pctx.group = -1;
- pctx.ino = fs->super->s_free_inodes_count;
+ pctx.ino = ext2fs_get_free_inodes_count(fs->super);
pctx.ino2 = free_inodes;

if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
- fs->super->s_free_inodes_count = free_inodes;
+ ext2fs_set_free_inodes_count(fs->super, free_inodes);
ext2fs_mark_super_dirty(fs);
}
}
diff --git a/e2fsck/quota.c b/e2fsck/quota.c
index b0f9af63..529e87ef 100644
--- a/e2fsck/quota.c
+++ b/e2fsck/quota.c
@@ -108,7 +108,7 @@ void e2fsck_validate_quota_inodes(e2fsck_t ctx)
(pctx.ino == EXT2_JOURNAL_INO) ||
(pctx.ino == EXT2_EXCLUDE_INO) ||
(pctx.ino == EXT4_REPLICA_INO) ||
- (pctx.ino > fs->super->s_inodes_count)) &&
+ (pctx.ino > ext2fs_get_inodes_count(fs->super))) &&
fix_problem(ctx, PR_0_INVALID_QUOTA_INO, &pctx)) {
*quota_sb_inump(sb, qtype) = 0;
ext2fs_mark_super_dirty(fs);
diff --git a/e2fsck/super.c b/e2fsck/super.c
index 47c89c56..7183755c 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -272,7 +272,7 @@ static int release_orphan_inodes(e2fsck_t ctx)
return 0;

if ((ino < EXT2_FIRST_INODE(fs->super)) ||
- (ino > fs->super->s_inodes_count)) {
+ (ino > ext2fs_get_inodes_count(fs->super))) {
clear_problem_context(&pctx);
pctx.ino = ino;
fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
@@ -296,7 +296,7 @@ static int release_orphan_inodes(e2fsck_t ctx)
next_ino = inode.i_dtime;
if (next_ino &&
((next_ino < EXT2_FIRST_INODE(fs->super)) ||
- (next_ino > fs->super->s_inodes_count))) {
+ (next_ino > ext2fs_get_inodes_count(fs->super)))) {
pctx.ino = next_ino;
fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
goto return_abort;
@@ -529,7 +529,7 @@ void check_super_block(e2fsck_t ctx)
/*
* Verify the super block constants...
*/
- check_super_value(ctx, "inodes_count", sb->s_inodes_count,
+ check_super_value(ctx, "inodes_count", ext2fs_get_inodes_count(sb),
MIN_CHECK, 1, 0);
check_super_value64(ctx, "blocks_count", ext2fs_blocks_count(sb),
MIN_CHECK | MAX_CHECK, 1, blks_max);
@@ -560,7 +560,8 @@ void check_super_block(e2fsck_t ctx)
if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
check_super_value(ctx, "first_ino", sb->s_first_ino,
MIN_CHECK | MAX_CHECK,
- EXT2_GOOD_OLD_FIRST_INO, sb->s_inodes_count);
+ EXT2_GOOD_OLD_FIRST_INO,
+ ext2fs_get_inodes_count(sb));
inode_size = EXT2_INODE_SIZE(sb);
check_super_value(ctx, "inode_size",
inode_size, MIN_CHECK | MAX_CHECK | LOG2_CHECK,
@@ -597,11 +598,11 @@ void check_super_block(e2fsck_t ctx)
should_be = (blk64_t)sb->s_inodes_per_group * fs->group_desc_count;
if (should_be > UINT_MAX)
should_be = UINT_MAX;
- if (sb->s_inodes_count != should_be) {
- pctx.ino = sb->s_inodes_count;
+ if (ext2fs_get_inodes_count(sb) != should_be) {
+ pctx.ino = ext2fs_get_inodes_count(sb);
pctx.ino2 = should_be;
if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
- sb->s_inodes_count = should_be;
+ ext2fs_set_inodes_count(sb, should_be);
ext2fs_mark_super_dirty(fs);
}
}
@@ -789,7 +790,7 @@ void check_super_block(e2fsck_t ctx)
ctx->free_inodes = free_inodes;

if ((ext2fs_free_blocks_count(sb) > ext2fs_blocks_count(sb)) ||
- (sb->s_free_inodes_count > sb->s_inodes_count))
+ (ext2fs_get_free_inodes_count(sb) > ext2fs_get_inodes_count(sb)))
ext2fs_unmark_valid(fs);


@@ -1046,6 +1047,7 @@ int check_backup_super_block(e2fsck_t ctx)
SUPER_DIFFERENT(s_blocks_count) ||
SUPER_DIFFERENT(s_blocks_count_hi) ||
SUPER_DIFFERENT(s_inodes_count) ||
+ SUPER_DIFFERENT(s_inodes_count_hi) ||
memcmp(fs->super->s_uuid, backup_sb->s_uuid,
sizeof(fs->super->s_uuid)))
ret = 1;
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index b46dcb2d..38bc63e5 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -112,9 +112,9 @@ static void show_stats(e2fsck_t ctx)
dir_links = 2 * ctx->fs_directory_count - 1;
num_files = ctx->fs_total_count - dir_links;
num_links = ctx->fs_links_count - dir_links;
- inodes = fs->super->s_inodes_count;
- inodes_used = (fs->super->s_inodes_count -
- fs->super->s_free_inodes_count);
+ inodes = ext2fs_get_inodes_count(fs->super);
+ inodes_used = (ext2fs_get_inodes_count(fs->super) -
+ ext2fs_get_free_inodes_count(fs->super));
blocks = ext2fs_blocks_count(fs->super);
blocks_used = (ext2fs_blocks_count(fs->super) -
ext2fs_free_blocks_count(fs->super));
@@ -412,12 +412,12 @@ static void check_if_skip(e2fsck_t ctx)
* using dumpe2fs. (This is for cosmetic reasons only.)
*/
clear_problem_context(&pctx);
- pctx.ino = fs->super->s_free_inodes_count;
+ pctx.ino = ext2fs_get_free_inodes_count(fs->super);
pctx.ino2 = ctx->free_inodes;
if ((pctx.ino != pctx.ino2) &&
!(ctx->options & E2F_OPT_READONLY) &&
fix_problem(ctx, PR_0_FREE_INODE_COUNT, &pctx)) {
- fs->super->s_free_inodes_count = ctx->free_inodes;
+ ext2fs_set_free_inodes_count(fs->super, ctx->free_inodes);
ext2fs_mark_super_dirty(fs);
}
clear_problem_context(&pctx);
@@ -433,8 +433,9 @@ static void check_if_skip(e2fsck_t ctx)
/* Print the summary message when we're skipping a full check */
log_out(ctx, _("%s: clean, %u/%u files, %llu/%llu blocks"),
ctx->device_name,
- fs->super->s_inodes_count - fs->super->s_free_inodes_count,
- fs->super->s_inodes_count,
+ ext2fs_get_free_inodes_count(fs->super) -
+ ext2fs_get_free_inodes_count(fs->super),
+ ext2fs_get_inodes_count(fs->super),
ext2fs_blocks_count(fs->super) -
ext2fs_free_blocks_count(fs->super),
ext2fs_blocks_count(fs->super));
diff --git a/ext2ed/inode_com.c b/ext2ed/inode_com.c
index 2d3dd6d6..279ce3c1 100644
--- a/ext2ed/inode_com.c
+++ b/ext2ed/inode_com.c
@@ -210,8 +210,11 @@ void type_ext2_inode___show (char *command_line)

wmove (show_win,1,0);

- wprintw (show_win,"Inode %ld of %ld. Entry %ld of %ld in group descriptor %ld.\n"
- ,inode_num,file_system_info.super_block.s_inodes_count,entry_num,last_entry,group_num);
+ wprintw (show_win,
+ "Inode %ld of %ld. Entry %ld of %ld in group descriptor %ld.\n",
+ inode_num,
+ ext2fs_get_inodes_count(&file_system_info.super_block),
+ entry_num, last_entry, group_num);

wprintw (show_win,"Inode type: ");

diff --git a/ext2ed/super_com.c b/ext2ed/super_com.c
index a998970e..98558c58 100644
--- a/ext2ed/super_com.c
+++ b/ext2ed/super_com.c
@@ -35,8 +35,10 @@ void type_ext2_super_block___show (char *command_line)
wmove (show_pad,3,40);wprintw (show_pad,"%2.2f%%",100*(float) ext2fs_free_blocks_count(super)/ (float) ext2fs_blocks_count(super));
}

- if (super->s_inodes_count != 0) {
- wmove (show_pad,4,40);wprintw (show_pad,"%2.2f%%",100*(float) super->s_free_inodes_count/ (float) super->s_inodes_count);
+ if (ext2fs_get_inodes_count(super) != 0) {
+ wmove(show_pad, 4, 40); wprintw(show_pad, "%2.2f%%",
+ 100*(float) ext2fs_get_free_inodes_count(super)/
+ (float) ext2fs_get_inodes_count(super);
}

wmove (show_pad,6,40);
diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c
index b7f6c1d2..fd77dedd 100644
--- a/lib/e2p/feature.c
+++ b/lib/e2p/feature.c
@@ -105,6 +105,8 @@ static struct feature feature_list[] = {
"inline_data"},
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT,
"encrypt"},
+ { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INODE64,
+ "inode64"},
{ 0, 0, 0 },
};

diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
index a7586e09..45437520 100644
--- a/lib/e2p/ls.c
+++ b/lib/e2p/ls.c
@@ -269,14 +269,16 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
str = e2p_os2string(sb->s_creator_os);
fprintf(f, "Filesystem OS type: %s\n", str);
free(str);
- fprintf(f, "Inode count: %u\n", sb->s_inodes_count);
+ fprintf(f, "Inode count: %u\n",
+ ext2fs_get_inodes_count(sb));
fprintf(f, "Block count: %llu\n", e2p_blocks_count(sb));
fprintf(f, "Reserved block count: %llu\n", e2p_r_blocks_count(sb));
if (sb->s_overhead_blocks)
fprintf(f, "Overhead blocks: %u\n",
sb->s_overhead_blocks);
- fprintf(f, "Free blocks: %llu\n", e2p_free_blocks_count(sb));
- fprintf(f, "Free inodes: %u\n", sb->s_free_inodes_count);
+ fprintf(f, "Free blocks: %llu\n",
+ e2p_free_blocks_count(sb));
+ fprintf(f, "Free inodes: %u\n", ext2fs_get_free_inodes_count(sb));
fprintf(f, "First block: %u\n", sb->s_first_data_block);
fprintf(f, "Block size: %u\n", EXT2_BLOCK_SIZE(sb));
if (ext2fs_has_feature_bigalloc(sb))
diff --git a/lib/ext2fs/alloc.c b/lib/ext2fs/alloc.c
index 3fd92167..e4ef9061 100644
--- a/lib/ext2fs/alloc.c
+++ b/lib/ext2fs/alloc.c
@@ -107,7 +107,7 @@ errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
}
if (start_inode < EXT2_FIRST_INODE(fs->super))
start_inode = EXT2_FIRST_INODE(fs->super);
- if (start_inode > fs->super->s_inodes_count)
+ if (start_inode > ext2fs_get_inodes_count(fs->super))
return EXT2_ET_INODE_ALLOC_FAIL;
i = start_inode;
do {
@@ -118,8 +118,8 @@ errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
upto = i + (EXT2_INODES_PER_GROUP(fs->super) - ino_in_group);
if (i < start_inode && upto >= start_inode)
upto = start_inode - 1;
- if (upto > fs->super->s_inodes_count)
- upto = fs->super->s_inodes_count;
+ if (upto > ext2fs_get_inodes_count(fs->super))
+ upto = ext2fs_get_inodes_count(fs->super);

retval = ext2fs_find_first_zero_inode_bitmap2(map, i, upto,
&first_zero);
@@ -130,7 +130,7 @@ errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
if (retval != ENOENT)
return EXT2_ET_INODE_ALLOC_FAIL;
i = upto + 1;
- if (i > fs->super->s_inodes_count)
+ if (i > ext2fs_get_inodes_count(fs->super))
i = EXT2_FIRST_INODE(fs->super);
} while (i != start_inode);

diff --git a/lib/ext2fs/alloc_stats.c b/lib/ext2fs/alloc_stats.c
index 3949f618..9a145b43 100644
--- a/lib/ext2fs/alloc_stats.c
+++ b/lib/ext2fs/alloc_stats.c
@@ -20,7 +20,7 @@ void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
{
int group = ext2fs_group_of_ino(fs, ino);

- if (ino > fs->super->s_inodes_count) {
+ if (ino > ext2fs_get_inodes_count(fs->super)) {
#ifndef OMIT_COM_ERR
com_err("ext2fs_inode_alloc_stats2", 0,
"Illegal inode number: %lu", (unsigned long) ino);
@@ -48,7 +48,9 @@ void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
ext2fs_group_desc_csum_set(fs, group);
}

- fs->super->s_free_inodes_count -= inuse;
+ ext2fs_set_free_inodes_count(fs->super,
+ ext2fs_get_free_inodes_count(fs->super) -
+ inuse);
ext2fs_mark_super_dirty(fs);
ext2fs_mark_ib_dirty(fs);
}
diff --git a/lib/ext2fs/bitmaps.c b/lib/ext2fs/bitmaps.c
index 84021917..bbfab1ae 100644
--- a/lib/ext2fs/bitmaps.c
+++ b/lib/ext2fs/bitmaps.c
@@ -61,7 +61,7 @@ errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
fs->write_bitmaps = ext2fs_write_bitmaps;

start = 1;
- end = fs->super->s_inodes_count;
+ end = ext2fs_get_inodes_count(fs->super);
real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count);

/* Are we permitted to use new-style bitmaps? */
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 90294ed0..cb0f59d4 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -737,7 +737,10 @@ struct ext2_super_block {
__le32 s_lpf_ino; /* Location of the lost+found inode */
__le32 s_prj_quota_inum; /* inode for tracking project quota */
__le32 s_checksum_seed; /* crc32c(orig_uuid) if csum_seed set */
- __le32 s_reserved[98]; /* Padding to the end of the block */
+ __le32 s_inodes_count_hi; /* higth part of inode count */
+ __le32 s_free_inodes_count_hi; /* Free inodes count */
+ __le32 s_prj_quota_inum_hi;
+ __le32 s_reserved[93]; /* Padding to the end of the block */
__u32 s_checksum; /* crc32c(superblock) */
};

@@ -827,6 +830,8 @@ struct ext2_super_block {
#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
+#define EXT4_FEATURE_INCOMPAT_INODE64 0x20000
+

#define EXT4_FEATURE_COMPAT_FUNCS(name, ver, flagname) \
static inline int ext2fs_has_feature_##name(struct ext2_super_block *sb) \
@@ -918,13 +923,16 @@ EXT4_FEATURE_INCOMPAT_FUNCS(csum_seed, 4, CSUM_SEED)
EXT4_FEATURE_INCOMPAT_FUNCS(largedir, 4, LARGEDIR)
EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, 4, INLINE_DATA)
EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, 4, ENCRYPT)
+EXT4_FEATURE_INCOMPAT_FUNCS(inode64, 4, INODE64)
+

#define EXT2_FEATURE_COMPAT_SUPP 0
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
EXT4_FEATURE_INCOMPAT_MMP| \
EXT4_FEATURE_INCOMPAT_LARGEDIR| \
EXT4_FEATURE_INCOMPAT_EA_INODE| \
- EXT4_FEATURE_INCOMPAT_DIRDATA)
+ EXT4_FEATURE_INCOMPAT_DIRDATA \
+ EXT4_FEATURE_INCOMPAT_INODE64)
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index b653012f..785042df 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -74,6 +74,7 @@ extern "C" {
#endif /* EXT2_FLAT_INCLUDES */

typedef __u32 __bitwise ext2_ino_t;
+typedef __u64 __bitwise ext2_ino64_t;
typedef __u32 __bitwise blk_t;
typedef __u64 __bitwise blk64_t;
typedef __u32 __bitwise dgrp_t;
@@ -601,6 +602,7 @@ typedef struct ext2_icount *ext2_icount_t;
EXT4_FEATURE_INCOMPAT_FLEX_BG|\
EXT4_FEATURE_INCOMPAT_EA_INODE|\
EXT4_FEATURE_INCOMPAT_DIRDATA|\
+ EXT4_FEATURE_INCOMPAT_INODE64|\
EXT4_LIB_INCOMPAT_MMP|\
EXT4_FEATURE_INCOMPAT_64BIT|\
EXT4_FEATURE_INCOMPAT_INLINE_DATA|\
@@ -2048,6 +2050,48 @@ ext2fs_const_inode(const struct ext2_inode_large * large_inode)
return (const struct ext2_inode *) large_inode;
}

+static inline ext2_ino64_t ext2fs_get_inodes_count(struct ext2_super_block *sb)
+{
+ ext2_ino64_t inodes_count = sb->s_inodes_count;
+
+ if (ext2fs_has_feature_inode64(sb))
+ inodes_count |= (ext2_ino64_t)sb->s_inodes_count_hi << 32;
+ return inodes_count;
+}
+
+static inline void ext2fs_set_inodes_count(struct ext2_super_block *sb,
+ ext2_ino64_t val)
+{
+ if (ext2fs_has_feature_inode64(sb))
+ sb->s_inodes_count_hi = val >> 32;
+ sb->s_inodes_count = val;
+}
+
+static inline ext2_ino64_t
+ext2fs_get_free_inodes_count(struct ext2_super_block *sb)
+{
+ ext2_ino64_t inodes_count = sb->s_free_inodes_count;
+
+ if (ext2fs_has_feature_inode64(sb))
+ inodes_count |= (ext2_ino64_t)sb->s_free_inodes_count_hi << 32;
+ return inodes_count;
+}
+
+static inline void ext2fs_set_free_inodes_count(struct ext2_super_block *sb,
+ ext2_ino64_t val)
+{
+ if (ext2fs_has_feature_inode64(sb))
+ sb->s_free_inodes_count_hi = (__u32)(val >> 32);
+ sb->s_free_inodes_count = val;
+}
+
+static inline void ext2fs_inc_free_inodes_count(struct ext2_super_block *sb)
+{
+ __u64 val = ext2fs_get_free_inodes_count(sb);
+
+ ext2fs_set_free_inodes_count(sb, ++val);
+}
+
#undef _INLINE_
#endif

diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
index a9cdae79..7d14da67 100644
--- a/lib/ext2fs/extent.c
+++ b/lib/ext2fs/extent.c
@@ -226,7 +226,7 @@ errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

if (!inode)
- if ((ino == 0) || (ino > fs->super->s_inodes_count))
+ if ((ino == 0) || (ino > ext2fs_get_inodes_count(fs->super)))
return EXT2_ET_BAD_INODE_NUM;

retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle);
diff --git a/lib/ext2fs/gen_bitmap64.c b/lib/ext2fs/gen_bitmap64.c
index 3fc73498..4c676f23 100644
--- a/lib/ext2fs/gen_bitmap64.c
+++ b/lib/ext2fs/gen_bitmap64.c
@@ -110,7 +110,8 @@ errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
break;
case EXT2FS_BMAP64_AUTODIR:
retval = ext2fs_get_num_dirs(fs, &num_dirs);
- if (retval || num_dirs > (fs->super->s_inodes_count / 320))
+ if (retval ||
+ num_dirs > (ext2fs_get_inodes_count(fs->super) / 320))
ops = &ext2fs_blkmap64_bitarray;
else
ops = &ext2fs_blkmap64_rbtree;
diff --git a/lib/ext2fs/get_num_dirs.c b/lib/ext2fs/get_num_dirs.c
index f5644f8e..552ac477 100644
--- a/lib/ext2fs/get_num_dirs.c
+++ b/lib/ext2fs/get_num_dirs.c
@@ -40,8 +40,8 @@ errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
else
num_dirs += ext2fs_bg_used_dirs_count(fs, i);
}
- if (num_dirs > fs->super->s_inodes_count)
- num_dirs = fs->super->s_inodes_count;
+ if (num_dirs > ext2fs_get_inodes_count(fs->super))
+ num_dirs = ext2fs_get_inodes_count(fs->super);

*ret_num_dirs = num_dirs;

diff --git a/lib/ext2fs/icount.c b/lib/ext2fs/icount.c
index d7de19fe..e652a0ad 100644
--- a/lib/ext2fs/icount.c
+++ b/lib/ext2fs/icount.c
@@ -112,7 +112,7 @@ static errcode_t alloc_icount(ext2_filsys fs, int flags, ext2_icount_t *ret)
return retval;
memset(icount, 0, sizeof(struct ext2_icount));
icount->magic = EXT2_ET_MAGIC_ICOUNT;
- icount->num_inodes = fs->super->s_inodes_count;
+ icount->num_inodes = ext2fs_get_inodes_count(fs->super);

if ((flags & EXT2_ICOUNT_OPT_FULLMAP) &&
(flags & EXT2_ICOUNT_OPT_INCREMENT)) {
@@ -235,7 +235,8 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs EXT2FS_NO_TDB_UNUSED,
* which case the number of inodes in use approaches the ideal
* value.
*/
- num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count;
+ num_inodes = ext2fs_get_inodes_count(fs->super) -
+ ext2fs_get_free_inodes_count(fs->super);

icount->tdb = tdb_open(fn, num_inodes, TDB_NOLOCK | TDB_NOSYNC,
O_RDWR | O_CREAT | O_TRUNC, 0600);
@@ -286,7 +287,7 @@ errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
retval = ext2fs_get_num_dirs(fs, &icount->size);
if (retval)
goto errout;
- icount->size += fs->super->s_inodes_count / 50;
+ icount->size += ext2fs_get_inodes_count(fs->super) / 50;
}

bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
index 32f43210..2554b2dd 100644
--- a/lib/ext2fs/initialize.c
+++ b/lib/ext2fs/initialize.c
@@ -285,16 +285,18 @@ retry:

if (ext2fs_has_feature_64bit(super) &&
(ext2fs_blocks_count(super) / i) > (1ULL << 32))
- set_field(s_inodes_count, ~0U);
+ ext2fs_set_inodes_count(super, ~0U);
else
- set_field(s_inodes_count, ext2fs_blocks_count(super) / i);
+ ext2fs_set_inodes_count(super, ext2fs_get_inodes_count(param) ?
+ ext2fs_get_inodes_count(param) :
+ ext2fs_blocks_count(super) / i);

/*
* Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
* that we have enough inodes for the filesystem(!)
*/
- if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
- super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
+ if (ext2fs_get_inodes_count(super) < EXT2_FIRST_INODE(super)+1)
+ ext2fs_set_inodes_count(super, EXT2_FIRST_INODE(super)+1);

/*
* There should be at least as many inodes as the user
@@ -302,7 +304,8 @@ retry:
* should be. But make sure that we don't allocate more than
* one bitmap's worth of inodes each group.
*/
- ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count);
+ ipg = ext2fs_div_ceil(ext2fs_get_inodes_count(super),
+ fs->group_desc_count);
if (ipg > fs->blocksize * 8) {
if (!bigalloc_flag && super->s_blocks_per_group >= 256) {
/* Try again with slightly different parameters */
@@ -355,9 +358,9 @@ ipg_retry:
ipg--;
goto ipg_retry;
}
- super->s_inodes_count = super->s_inodes_per_group *
- fs->group_desc_count;
- super->s_free_inodes_count = super->s_inodes_count;
+ ext2fs_set_inodes_count(super, (ext2_ino64_t)super->s_inodes_per_group *
+ fs->group_desc_count);
+ ext2fs_set_free_inodes_count(super, ext2fs_get_inodes_count(super));

/*
* check the number of reserved group descriptor table blocks
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 2ce2f6f7..4517afdd 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -784,7 +784,7 @@ int main(int argc, char *argv[])

memset(&param, 0, sizeof(param));
ext2fs_blocks_count_set(&param, 32768);
- param.s_inodes_count = 100;
+ ext2fs_set_inodes_count(&param, 100);

param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_INLINE_DATA;
param.s_rev_level = EXT2_DYNAMIC_REV;
diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
index ad01a9fc..182e9819 100644
--- a/lib/ext2fs/inode.c
+++ b/lib/ext2fs/inode.c
@@ -752,7 +752,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
return retval;
}
- if ((ino == 0) || (ino > fs->super->s_inodes_count))
+ if ((ino == 0) || (ino > ext2fs_get_inodes_count(fs->super)))
return EXT2_ET_BAD_INODE_NUM;
/* Create inode cache if not present */
if (!fs->icache) {
@@ -867,7 +867,7 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
return retval;
}

- if ((ino == 0) || (ino > fs->super->s_inodes_count))
+ if ((ino == 0) || (ino > ext2fs_get_inodes_count(fs->super)))
return EXT2_ET_BAD_INODE_NUM;

/* Prepare our shadow buffer for read/modify/byteswap/write */
@@ -1022,7 +1022,7 @@ errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)

EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

- if (ino > fs->super->s_inodes_count)
+ if (ino > ext2fs_get_inodes_count(fs->super))
return EXT2_ET_BAD_INODE_NUM;

if (fs->get_blocks) {
@@ -1044,7 +1044,7 @@ errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)

EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

- if (ino > fs->super->s_inodes_count)
+ if (ino > ext2fs_get_inodes_count(fs->super))
return EXT2_ET_BAD_INODE_NUM;

if (fs->check_directory) {
diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c
index f74cd245..2e9464cf 100644
--- a/lib/ext2fs/openfs.c
+++ b/lib/ext2fs/openfs.c
@@ -5,7 +5,7 @@
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Library
- * General Public License, version 2.
+* General Public License, version 2.
* %End-Header%
*/

@@ -381,7 +381,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
}
fs->group_desc_count = groups_cnt;
if (fs->group_desc_count * EXT2_INODES_PER_GROUP(fs->super) !=
- fs->super->s_inodes_count) {
+ ext2fs_get_inodes_count(fs->super)) {
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
goto cleanup;
}
diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c
index ae593d49..66c8ee69 100644
--- a/lib/ext2fs/rw_bitmaps.c
+++ b/lib/ext2fs/rw_bitmaps.c
@@ -252,7 +252,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)

if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
blk = (fs->image_header->offset_inodemap / fs->blocksize);
- ino_cnt = fs->super->s_inodes_count;
+ ino_cnt = ext2fs_get_inodes_count(fs->super);
while (inode_nbytes > 0) {
retval = io_channel_read_blk64(fs->image_io, blk++,
1, inode_bitmap);
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index b9d8f557..b7c01005 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -26,10 +26,12 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
{
int i;
sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count);
+ sb->s_inodes_count_hi = ext2fs_swab32(sb->s_inodes_count_hi);
sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count);
sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count);
sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count);
sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count);
+ sb->s_free_inodes_count_hi = ext2fs_swab32(sb->s_free_inodes_count_hi);
sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block);
sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size);
sb->s_log_cluster_size = ext2fs_swab32(sb->s_log_cluster_size);
diff --git a/lib/ext2fs/tst_bitmaps.c b/lib/ext2fs/tst_bitmaps.c
index 574fb7a7..5ca4c680 100644
--- a/lib/ext2fs/tst_bitmaps.c
+++ b/lib/ext2fs/tst_bitmaps.c
@@ -158,7 +158,7 @@ static void setup_filesystem(const char *name,

memset(&param, 0, sizeof(param));
ext2fs_blocks_count_set(&param, blocks);
- param.s_inodes_count = inodes;
+ ext2fs_set_inodes_count(&param, inodes);

retval = ext2fs_initialize("test fs", flags, &param,
test_io_manager, &test_fs);
@@ -275,9 +275,10 @@ void dump_inode_bitmap_cmd(int argc, char **argv)
return;

printf("inode bitmap: ");
- dump_bitmap(test_fs->inode_map, 1, test_fs->super->s_inodes_count);
+ dump_bitmap(test_fs->inode_map, 1,
+ ext2fs_get_inodes_count(test_fs->super));
}
-
+
void dump_block_bitmap_cmd(int argc, char **argv)
{
if (check_fs_open(argv[0]))
diff --git a/lib/ext2fs/tst_iscan.c b/lib/ext2fs/tst_iscan.c
index 70bfbecc..6c9ceaf6 100644
--- a/lib/ext2fs/tst_iscan.c
+++ b/lib/ext2fs/tst_iscan.c
@@ -200,7 +200,7 @@ static void check_map(void)
}
}
printf("Bad inodes: ");
- for (i=1; i <= test_fs->super->s_inodes_count; i++) {
+ for (i = 1; i <= ext2fs_get_inodes_count(test_fs->super); i++) {
if (ext2fs_test_inode_bitmap2(bad_inode_map, i)) {
if (first)
first = 0;
diff --git a/lib/ext2fs/tst_super_size.c b/lib/ext2fs/tst_super_size.c
index 0adac411..e3dc608a 100644
--- a/lib/ext2fs/tst_super_size.c
+++ b/lib/ext2fs/tst_super_size.c
@@ -142,7 +142,10 @@ int main(int argc, char **argv)
check_field(s_lpf_ino, 4);
check_field(s_prj_quota_inum, 4);
check_field(s_checksum_seed, 4);
- check_field(s_reserved, 98 * 4);
+ check_field(s_inodes_count_hi, 4);
+ check_field(s_free_inodes_count_hi, 4);
+ check_field(s_prj_quota_inum_hi, 4);
+ check_field(s_reserved, 93 * 4);
check_field(s_checksum, 4);
do_field("Superblock end", 0, 0, cur_offset, 1024);
#endif
diff --git a/misc/findsuper.c b/misc/findsuper.c
index ff20b988..e73e92a5 100644
--- a/misc/findsuper.c
+++ b/misc/findsuper.c
@@ -226,9 +226,11 @@ int main(int argc, char *argv[])
WHY("free_blocks_count > blocks_count\n (%u > %u)\n",
ext2fs_free_blocks_count(&ext2),
ext2fs_blocks_count(&ext2));
- if (ext2.s_free_inodes_count > ext2.s_inodes_count)
- WHY("free_inodes_count > inodes_count (%u > %u)\n",
- ext2.s_free_inodes_count, ext2.s_inodes_count);
+ if (ext2fs_get_free_inodes_count(&ext2) >
+ ext2fs_get_inodes_count(&ext2))
+ WHY("free_inodes_count > inodes_count (%lu > %lu)\n",
+ ext2fs_get_free_inodes_count(&ext2),
+ ext2fs_get_inodes_count(&ext);

if (ext2.s_mkfs_time != 0)
tm = ext2.s_mkfs_time;
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 9feafd72..75e87536 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -2368,9 +2368,9 @@ static int op_statfs(const char *path EXT2FS_ATTR((unused)),
buf->f_bavail = 0;
else
buf->f_bavail = free - reserved;
- buf->f_files = fs->super->s_inodes_count;
- buf->f_ffree = fs->super->s_free_inodes_count;
- buf->f_favail = fs->super->s_free_inodes_count;
+ buf->f_files = ext2fs_get_inodes_count(fs->super);
+ buf->f_ffree = ext2fs_get_inodes_count(fs->super);
+ buf->f_favail = ext2fs_get_free_inodes_count(fs->super);
f = (uint64_t *)fs->super->s_uuid;
fsid = *f;
f++;
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 1edc0cd1..64102b79 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -654,9 +654,9 @@ static void show_stats(ext2_filsys fs)

if (!verbose) {
printf(_("Creating filesystem with %llu %dk blocks and "
- "%u inodes\n"),
+ "%lu inodes\n"),
ext2fs_blocks_count(s), fs->blocksize >> 10,
- s->s_inodes_count);
+ ext2fs_get_inodes_count(s));
goto skip_details;
}

@@ -682,7 +682,7 @@ static void show_stats(ext2_filsys fs)
s->s_log_cluster_size);
printf(_("Stride=%u blocks, Stripe width=%u blocks\n"),
s->s_raid_stride, s->s_raid_stripe_width);
- printf(_("%u inodes, %llu blocks\n"), s->s_inodes_count,
+ printf(_("%lu inodes, %llu blocks\n"), ext2fs_get_inodes_count(s),
ext2fs_blocks_count(s));
printf(_("%llu blocks (%2.2f%%) reserved for the super user\n"),
ext2fs_r_blocks_count(s),
@@ -1089,7 +1089,8 @@ static __u32 ok_features[3] = {
EXT4_FEATURE_INCOMPAT_INLINE_DATA|
EXT4_FEATURE_INCOMPAT_ENCRYPT |
EXT4_FEATURE_INCOMPAT_CSUM_SEED |
- EXT4_FEATURE_INCOMPAT_LARGEDIR,
+ EXT4_FEATURE_INCOMPAT_LARGEDIR|
+ EXT4_FEATURE_INCOMPAT_INODE64,
/* R/O compat */
EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -2457,13 +2458,15 @@ profile_error:
if (num_inodes == 0) {
unsigned long long n;
n = ext2fs_blocks_count(&fs_param) * blocksize / inode_ratio;
- if (n > MAX_32_NUM) {
- if (ext2fs_has_feature_64bit(&fs_param))
+ if (n > MAX_32_NUM && !(fs_param.s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_INODE64)) {
+ if (fs_param.s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_64BIT)
num_inodes = MAX_32_NUM;
else {
com_err(program_name, 0,
_("too many inodes (%llu), raise "
- "inode ratio?"), n);
+ "inode ratio?"), num_inodes);
exit(1);
}
}
@@ -2476,10 +2479,14 @@ profile_error:
/*
* Calculate number of inodes based on the inode ratio
*/
- fs_param.s_inodes_count = num_inodes ? num_inodes :
- (ext2fs_blocks_count(&fs_param) * blocksize) / inode_ratio;
+ if (num_inodes == 0)
+ num_inodes = (ext2fs_blocks_count(&fs_param) * blocksize) /
+ inode_ratio;

- if ((((unsigned long long)fs_param.s_inodes_count) *
+ ext2fs_set_inodes_count(&fs_param, num_inodes);
+
+
+ if ((ext2fs_get_inodes_count(&fs_param) *
(inode_size ? inode_size : EXT2_GOOD_OLD_INODE_SIZE)) >=
((ext2fs_blocks_count(&fs_param)) *
EXT2_BLOCK_SIZE(&fs_param))) {
@@ -2489,7 +2496,7 @@ profile_error:
"specify higher inode_ratio (-i)\n\t"
"or lower inode count (-N).\n"),
inode_size ? inode_size : EXT2_GOOD_OLD_INODE_SIZE,
- fs_param.s_inodes_count,
+ ext2fs_get_inodes_count(&fs_param),
(unsigned long long) ext2fs_blocks_count(&fs_param));
exit(1);
}
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 44dd41a5..3538ab9c 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -161,7 +161,8 @@ static __u32 ok_features[3] = {
EXT4_FEATURE_INCOMPAT_64BIT |
EXT4_FEATURE_INCOMPAT_ENCRYPT |
EXT4_FEATURE_INCOMPAT_CSUM_SEED |
- EXT4_FEATURE_INCOMPAT_LARGEDIR,
+ EXT4_FEATURE_INCOMPAT_LARGEDIR |
+ EXT4_FEATURE_INCOMPAT_INODE64,
/* R/O compat */
EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -2614,21 +2615,22 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
group = 0;

/* Protect loop from wrap-around if s_inodes_count maxed */
- for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
+ for (ino = 1;
+ ino <= ext2fs_get_inodes_count(fs->super) && ino > 0; ino++) {
if (!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
group_free++;
total_free++;
}
count++;
if ((count == fs->super->s_inodes_per_group) ||
- (ino == fs->super->s_inodes_count)) {
+ (ino == ext2fs_get_inodes_count(fs->super))) {
ext2fs_bg_free_inodes_count_set(fs, group++,
group_free);
count = 0;
group_free = 0;
}
}
- fs->super->s_free_inodes_count = total_free;
+ ext2fs_set_free_inodes_count(fs->super, total_free);
ext2fs_mark_super_dirty(fs);
return 0;
}
diff --git a/resize/main.c b/resize/main.c
index ba6bb6b1..79523803 100644
--- a/resize/main.c
+++ b/resize/main.c
@@ -441,7 +441,8 @@ int main (int argc, char ** argv)
checkit = 1;

if ((fs->super->s_free_blocks_count > fs->super->s_blocks_count) ||
- (fs->super->s_free_inodes_count > fs->super->s_inodes_count))
+ (ext2fs_get_free_inodes_count(fs->super) >
+ ext2fs_get_inodes_count(fs->super)))
checkit = 1;

if (checkit) {
diff --git a/resize/resize2fs.c b/resize/resize2fs.c
index 0bd325ba..ec13436c 100644
--- a/resize/resize2fs.c
+++ b/resize/resize2fs.c
@@ -760,8 +760,8 @@ retry:
new_inodes, ~0U);
return EXT2_ET_TOO_MANY_INODES;
}
- fs->super->s_inodes_count = fs->super->s_inodes_per_group *
- fs->group_desc_count;
+ ext2fs_set_inodes_count(fs->super, fs->super->s_inodes_per_group *
+ fs->group_desc_count);

/*
* Adjust the number of free blocks
@@ -788,8 +788,8 @@ retry:
/*
* Adjust the bitmaps for size
*/
- retval = ext2fs_resize_inode_bitmap2(fs->super->s_inodes_count,
- fs->super->s_inodes_count,
+ retval = ext2fs_resize_inode_bitmap2(ext2fs_get_inodes_count(fs->super),
+ ext2fs_get_inodes_count(fs->super),
fs->inode_map);
if (retval) goto errout;

@@ -987,8 +987,9 @@ retry:
numblocks -= adjblocks;
ext2fs_free_blocks_count_set(fs->super,
ext2fs_free_blocks_count(fs->super) - adjblocks);
- fs->super->s_free_inodes_count +=
- fs->super->s_inodes_per_group;
+ ext2fs_set_free_inodes_count(fs->super,
+ ext2fs_get_free_inodes_count(fs->super) +
+ fs->super->s_inodes_per_group);
ext2fs_bg_free_blocks_count_set(fs, i, numblocks);
ext2fs_bg_free_inodes_count_set(fs, i,
fs->super->s_inodes_per_group);
@@ -1046,9 +1047,9 @@ static errcode_t adjust_superblock(ext2_resize_t rfs, blk64_t new_size)
/*
* Check to make sure there are enough inodes
*/
- if ((rfs->old_fs->super->s_inodes_count -
- rfs->old_fs->super->s_free_inodes_count) >
- rfs->new_fs->super->s_inodes_count) {
+ if ((ext2fs_get_inodes_count(rfs->old_fs->super) -
+ ext2fs_get_free_inodes_count(rfs->old_fs->super)) >
+ ext2fs_get_inodes_count(rfs->new_fs->super)) {
retval = ENOSPC;
goto errout;
}
@@ -2866,7 +2867,8 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)

/* Protect loop from wrap-around if s_inodes_count maxed */
uninit = ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT);
- for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
+ for (ino = 1;
+ ino <= ext2fs_get_inodes_count(fs->super) && ino > 0; ino++) {
if (uninit ||
!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
group_free++;
@@ -2874,7 +2876,7 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
}
count++;
if ((count == fs->super->s_inodes_per_group) ||
- (ino == fs->super->s_inodes_count)) {
+ (ino == ext2fs_get_inodes_count(fs->super))) {
ext2fs_bg_free_inodes_count_set(fs, group, group_free);
ext2fs_group_desc_csum_set(fs, group);
group++;
@@ -2885,7 +2887,7 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
uninit = ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT);
}
}
- fs->super->s_free_inodes_count = total_inodes_free;
+ ext2fs_set_free_inodes_count(fs->super, total_inodes_free);
ext2fs_mark_super_dirty(fs);
return 0;
}
@@ -2955,8 +2957,8 @@ blk64_t calculate_minimum_resize_size(ext2_filsys fs, int flags)
* first figure out how many group descriptors we need to
* handle the number of inodes we have
*/
- inode_count = fs->super->s_inodes_count -
- fs->super->s_free_inodes_count;
+ inode_count = ext2fs_get_inodes_count(fs->super) -
+ ext2fs_get_free_inodes_count(fs->super);
blks_needed = ext2fs_div_ceil(inode_count,
fs->super->s_inodes_per_group) *
(blk64_t) EXT2_BLOCKS_PER_GROUP(fs->super);
diff --git a/tests/progs/test_icount.c b/tests/progs/test_icount.c
index d028a601..b4dd013b 100644
--- a/tests/progs/test_icount.c
+++ b/tests/progs/test_icount.c
@@ -208,7 +208,7 @@ void do_dump(int argc, char **argv)

if (check_icount(argv[0]))
return;
- for (i=1; i <= test_fs->super->s_inodes_count; i++) {
+ for (i = 1; i <= ext2fs_get_inodes_count(test_fs->super); i++) {
retval = ext2fs_icount_fetch(test_icount, i, &count);
if (retval) {
com_err(argv[0], retval,
@@ -312,7 +312,7 @@ int main(int argc, char **argv)
*/
memset(&param, 0, sizeof(struct ext2_super_block));
ext2fs_blocks_count_set(&param, 80000);
- param.s_inodes_count = 20000;
+ ext2fs_set_inodes_count(&param, 20000);
retval = ext2fs_initialize("/dev/null", 0, &param,
unix_io_manager, &test_fs);
if (retval) {
--
2.13.6 (Apple Git-96)

2017-11-14 07:04:59

by Artem Blagodarenko

[permalink] [raw]
Subject: [PATCH v2 7/7] quota: quota 64bit inode number cleanup

Quota stores inodes numbers and beed to be fixed
to store 64bit inodes.

This patch makes quota 64bit inode ready.

Lustre-bug: https://jira.hpdd.intel.com/browse/LU-9309
Signed-off-by: Artem Blagodarenko <[email protected]>
---
e2fsck/pass1.c | 2 +-
e2fsck/quota.c | 8 ++++----
e2fsck/unix.c | 2 +-
lib/e2p/ls.c | 4 ++--
lib/ext2fs/swapfs.c | 1 +
lib/support/mkquota.c | 10 +++-------
lib/support/quotaio.c | 2 +-
lib/support/quotaio.h | 39 +++++++++++++++++++++++++++++++--------
misc/tune2fs.c | 4 ++--
9 files changed, 46 insertions(+), 26 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 24f8e215..702dd1bf 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -1130,7 +1130,7 @@ static int quota_inum_is_super(struct ext2_super_block *sb, ext2_ino_t ino)
enum quota_type qtype;

for (qtype = 0; qtype < MAXQUOTAS; qtype++)
- if (*quota_sb_inump(sb, qtype) == ino)
+ if (quota_sb_inum(sb, qtype) == ino)
return 1;

return 0;
diff --git a/e2fsck/quota.c b/e2fsck/quota.c
index 529e87ef..130240a4 100644
--- a/e2fsck/quota.c
+++ b/e2fsck/quota.c
@@ -72,13 +72,13 @@ void e2fsck_hide_quota(e2fsck_t ctx)

for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
pctx.dir = 2; /* This is a guess, but it's a good one */
- pctx.ino = *quota_sb_inump(sb, qtype);
+ pctx.ino = quota_sb_inum(sb, qtype);
pctx.num = qtype;
quota_ino = quota_type2inum(qtype, fs->super);
if (pctx.ino && (pctx.ino != quota_ino) &&
fix_problem(ctx, PR_0_HIDE_QUOTA, &pctx)) {
move_quota_inode(fs, pctx.ino, quota_ino, qtype);
- *quota_sb_inump(sb, qtype) = quota_ino;
+ quota_set_sb_inump(sb, qtype, quota_ino);
ext2fs_mark_super_dirty(fs);
}
}
@@ -97,7 +97,7 @@ void e2fsck_validate_quota_inodes(e2fsck_t ctx)
clear_problem_context(&pctx);

for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
- pctx.ino = *quota_sb_inump(sb, qtype);
+ pctx.ino = quota_sb_inum(sb, qtype);
pctx.num = qtype;
if (pctx.ino &&
((pctx.ino == EXT2_BAD_INO) ||
@@ -110,7 +110,7 @@ void e2fsck_validate_quota_inodes(e2fsck_t ctx)
(pctx.ino == EXT4_REPLICA_INO) ||
(pctx.ino > ext2fs_get_inodes_count(fs->super))) &&
fix_problem(ctx, PR_0_INVALID_QUOTA_INO, &pctx)) {
- *quota_sb_inump(sb, qtype) = 0;
+ quota_set_sb_inump(sb, qtype, 0);
ext2fs_mark_super_dirty(fs);
}
}
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index 38bc63e5..0d1a450c 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -1862,7 +1862,7 @@ no_journal:
int needs_writeout;

for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
- if (*quota_sb_inump(sb, qtype) == 0)
+ if (quota_sb_inum(sb, qtype) != 0)
continue;
needs_writeout = 0;
pctx.num = qtype;
diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
index 45437520..416f382c 100644
--- a/lib/e2p/ls.c
+++ b/lib/e2p/ls.c
@@ -453,10 +453,10 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
sb->s_mmp_update_interval);
}
for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
- if (*quota_sb_inump(sb, qtype) != 0)
+ if (quota_sb_inum(sb, qtype) != 0)
fprintf(f, "%-26s%u\n",
quota_type2prefix(qtype),
- *quota_sb_inump(sb, qtype));
+ quota_sb_inum(sb, qtype));
}

if (ext2fs_has_feature_metadata_csum(sb)) {
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 60cdf124..22cd50ec 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -82,6 +82,7 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
ext2fs_swab64(sb->s_snapshot_r_blocks_count);
sb->s_snapshot_list = ext2fs_swab32(sb->s_snapshot_list);
sb->s_prj_quota_inum = ext2fs_swab32(sb->s_prj_quota_inum);
+ sb->s_prj_quota_inum_hi = ext2fs_swab32(sb->s_prj_quota_inum_hi);
sb->s_usr_quota_inum = ext2fs_swab32(sb->s_usr_quota_inum);
sb->s_grp_quota_inum = ext2fs_swab32(sb->s_grp_quota_inum);
sb->s_overhead_blocks = ext2fs_swab32(sb->s_overhead_blocks);
diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c
index e65c95b7..791fae05 100644
--- a/lib/support/mkquota.c
+++ b/lib/support/mkquota.c
@@ -93,13 +93,9 @@ int quota_file_exists(ext2_filsys fs, enum quota_type qtype)
*/
void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, enum quota_type qtype)
{
- ext2_ino_t *inump;
-
- inump = quota_sb_inump(fs->super, qtype);
-
log_debug("setting quota ino in superblock: ino=%u, type=%d", ino,
qtype);
- *inump = ino;
+ quota_set_sb_inump(fs->super, qtype, ino);
ext2fs_mark_super_dirty(fs);
}

@@ -113,8 +109,8 @@ errcode_t quota_remove_inode(ext2_filsys fs, enum quota_type qtype)
log_debug("Couldn't read bitmaps: %s", error_message(retval));
return retval;
}
+ qf_ino = quota_sb_inum(fs->super, qtype);

- qf_ino = *quota_sb_inump(fs->super, qtype);
if (qf_ino == 0)
return 0;
retval = quota_inode_truncate(fs, qf_ino);
@@ -308,7 +304,7 @@ errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs,
if (((1 << qtype) & qtype_bits) == 0)
continue;
} else {
- if (*quota_sb_inump(fs->super, qtype) == 0)
+ if (quota_sb_inum(fs->super, qtype) == 0)
continue;
}
err = ext2fs_get_mem(sizeof(dict_t), &dict);
diff --git a/lib/support/quotaio.c b/lib/support/quotaio.c
index 2daf1785..a26576b5 100644
--- a/lib/support/quotaio.c
+++ b/lib/support/quotaio.c
@@ -230,7 +230,7 @@ errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h,
return err;

if (qf_ino == 0)
- qf_ino = *quota_sb_inump(fs->super, qtype);
+ qf_ino = quota_sb_inum(fs->super, qtype);

log_debug("Opening quota ino=%u, type=%d", qf_ino, qtype);
err = ext2fs_file_open(fs, qf_ino, flags, &e2_file);
diff --git a/lib/support/quotaio.h b/lib/support/quotaio.h
index 60689700..7c65673e 100644
--- a/lib/support/quotaio.h
+++ b/lib/support/quotaio.h
@@ -245,21 +245,44 @@ int parse_quota_types(const char *in_str, unsigned int *qtype_bits,
* This allows the caller to get or set the quota inode by type without the
* need for the quota array to be contiguous in the superblock.
*/
-static inline ext2_ino_t *quota_sb_inump(struct ext2_super_block *sb,
- enum quota_type qtype)
+static inline ext2_ino_t quota_sb_inum(struct ext2_super_block *sb,
+ enum quota_type qtype)
{
+ ext2_ino_t quota_inum = 0;
+
switch (qtype) {
case USRQUOTA:
- return &sb->s_usr_quota_inum;
+ quota_inum = sb->s_usr_quota_inum;
+ break;
case GRPQUOTA:
- return &sb->s_grp_quota_inum;
+ quota_inum = sb->s_grp_quota_inum;
+ break;
case PRJQUOTA:
- return &sb->s_prj_quota_inum;
- default:
- return NULL;
+ quota_inum = sb->s_prj_quota_inum;
+ if (ext2fs_has_feature_inode64(sb))
+ quota_inum |= (__u64)sb->s_prj_quota_inum_hi << 32;
+ break;
}

- return NULL;
+ return quota_inum;
+}
+
+static inline void quota_set_sb_inump(struct ext2_super_block *sb,
+ enum quota_type qtype, ext2_ino64_t ino)
+{
+ switch (qtype) {
+ case USRQUOTA:
+ sb->s_usr_quota_inum = ino;
+ break;
+ case GRPQUOTA:
+ sb->s_grp_quota_inum = ino;
+ break;
+ case PRJQUOTA:
+ if (ext2fs_has_feature_inode64(sb))
+ sb->s_prj_quota_inum_hi = (__u32)(ino >> 32);
+ sb->s_prj_quota_inum = ino;
+ break;
+ }
}

#endif /* GUARD_QUOTAIO_H */
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 3538ab9c..0368340b 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -1640,7 +1640,7 @@ static void handle_quota_options(ext2_filsys fs)

for (qtype = 0 ; qtype < MAXQUOTAS; qtype++) {
if (quota_enable[qtype] == QOPT_ENABLE &&
- *quota_sb_inump(fs->super, qtype) == 0) {
+ quota_sb_inum(fs->super, qtype) == 0) {
if ((qf_ino = quota_file_exists(fs, qtype)) > 0) {
retval = quota_update_limits(qctx, qf_ino,
qtype);
@@ -1687,7 +1687,7 @@ static void handle_quota_options(ext2_filsys fs)
/* Clear Quota feature if all quota types disabled. */
if (!qtype_bits) {
for (qtype = 0 ; qtype < MAXQUOTAS; qtype++)
- if (*quota_sb_inump(fs->super, qtype))
+ if (quota_sb_inum(fs->super, qtype))
break;
if (qtype == MAXQUOTAS) {
ext2fs_clear_feature_quota(fs->super);
--
2.13.6 (Apple Git-96)

2017-11-14 20:49:01

by Darrick J. Wong

[permalink] [raw]
Subject: Re: [PATCH v2 1/7] e2fsck: add support for dirdata feature

On Tue, Nov 14, 2017 at 10:04:34AM +0300, Artem Blagodarenko wrote:
> From: Andreas Dilger <[email protected]>
>
> Add support for the INCOMPAT_DIRDATA feature, which allows
> storing extra data in the directory entry beyond the name.
> This allows the Lustre File IDentifier to be accessed in
> an efficient manner, and would be useful for expanding a
> filesystem to allow more than 2^32 inodes in the future.
>
> Include this patches:
>
> e2fsck: e2fsck -D does not change dirdata content
>
> Fix dir optimization to preserve dirdata content for dot
> and dotdot entries.
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-1774
> Signed-off-by: Bobi Jam <[email protected]>
> Change-Id: Iae190794da75a2080a8e5cc5b95a49e0c894f72f
>
> e2fsprogs: Consider DIRENT_LUFID flag in link_proc().
>
> While adding the new file entry in directory block, link_proc()
> calculates minimum record length of the existing directory entry
> without considering the dirent data size and which leads to
> corruption. Changed the code to use EXT2_DIR_REC_LEN() which will
> return correct record length including dirent data size.
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-2462
> Signed-off-by: Manisha Salve <[email protected]>
> Change-Id: Ic593c558c47a78183143ec8e99d8385ac94d06f7
>
> libext2fs, e2fsck: don't use ext2_dir_entry_2
>
> Due to endian issues, do not use ext2_dir_entry_2 because it will
> have the wrong byte order on directory entries that are swabbed.
> Instead, use the standard practice of mask-and-shift to access the
> file_type and dirdata flags.
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-4677
> Signed-off-by: Pravin Shelar <[email protected]>
> Signed-off-by: Andreas Dilger <[email protected]>
>
> Signed-off-by: Artem Blagodarenko <[email protected]>
> ---
> debugfs/htree.c | 2 +-
> debugfs/ls.c | 44 +++++++++++++++-
> e2fsck/pass1.c | 4 +-
> e2fsck/pass2.c | 133 +++++++++++++++++++++++++++++++++++++++--------
> e2fsck/pass3.c | 8 +++
> e2fsck/problem.c | 5 ++
> e2fsck/problem.h | 3 ++
> e2fsck/rehash.c | 78 ++++++++++++++++-----------
> lib/ext2fs/dirblock.c | 34 ++++++++++++
> lib/ext2fs/ext2_fs.h | 16 +++++-
> lib/ext2fs/ext2fs.h | 22 +++++++-
> lib/ext2fs/inline_data.c | 14 ++---
> lib/ext2fs/lfsck.h | 42 +++++++++++++++
> lib/ext2fs/link.c | 10 ++--
> lib/ext2fs/newdir.c | 4 +-
> misc/mke2fs.c | 1 +
> misc/tune2fs.c | 2 +
> 17 files changed, 349 insertions(+), 73 deletions(-)

Kind of a long patch here... (says the guy who habitually dumps out
huge patch series :P)

> diff --git a/debugfs/htree.c b/debugfs/htree.c
> index cf7d78aa..b7f1add0 100644
> --- a/debugfs/htree.c
> +++ b/debugfs/htree.c
> @@ -278,7 +278,7 @@ void do_htree_dump(int argc, char *argv[])
> goto errout;
> }
>
> - rootnode = (struct ext2_dx_root_info *) (buf + 24);
> + rootnode = get_ext2_dx_root_info(current_fs, buf);
>
> fprintf(pager, "Root node dump:\n");
> fprintf(pager, "\t Reserved zero: %u\n", rootnode->reserved_zero);
> diff --git a/debugfs/ls.c b/debugfs/ls.c
> index 61b63196..5655933e 100644
> --- a/debugfs/ls.c
> +++ b/debugfs/ls.c
> @@ -24,6 +24,7 @@ extern char *optarg;
> #endif
>
> #include "debugfs.h"
> +#include "ext2fs/lfsck.h"
>
> /*
> * list directory
> @@ -32,6 +33,7 @@ extern char *optarg;
> #define LONG_OPT 0x0001
> #define PARSE_OPT 0x0002
> #define RAW_OPT 0x0004
> +#define DIRDATA_OPT 0x0008
> #define ENCRYPT_OPT 0x8000
>
> struct list_dir_struct {
> @@ -44,6 +46,41 @@ struct list_dir_struct {
> static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
> "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
>
> +static void list_dirdata(struct list_dir_struct *ls,
> + struct ext2_dir_entry *dirent)
> +{
> + unsigned char *data;
> + int dlen;
> + __u8 dirdata_mask;
> + __u8 file_type = dirent->name_len >> 8;
> +
> + data = (unsigned char *)dirent->name +
> + (dirent->name_len & EXT2_NAME_LEN) + 1;
> +
> + for (dirdata_mask = EXT2_FT_MASK + 1;
> + dirdata_mask != 0; dirdata_mask <<= 1) {
> + if ((dirdata_mask & file_type) == 0)
> + continue;
> +
> + dlen = data[0];
> +
> + if (dirdata_mask == EXT2_DIRENT_LUFID) {
> + struct lu_fid *fid = (struct lu_fid *)(data + 1);
> +
> + fid_be_to_cpu(fid, fid);
> + fprintf(ls->f, DFID, PFID(fid));

/me wonders if this could just be a fprintf_lufid() helper in lfsck.h...

> + } else {
> + int i;
> +
> + for (i = 1; i < dlen; i++)
> + fprintf(ls->f, "%02x", data[i]);
> + }
> +
> + fprintf(ls->f, " ");
> + data += dlen;
> + }
> +}
> +
> static int print_filename(FILE *f, struct ext2_dir_entry *dirent, int options)
> {
> unsigned char ch;
> @@ -157,6 +194,8 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
> else
> fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode));
> fprintf(ls->f, " %s ", datestr);
> + if ((ls->options & DIRDATA_OPT) != 0)
> + list_dirdata(ls, dirent);
> print_filename(ls->f, dirent, options);
> fputc('\n', ls->f);
> } else {
> @@ -204,7 +243,7 @@ void do_list_dir(int argc, char *argv[])
> return;
>
> reset_getopt();
> - while ((c = getopt (argc, argv, "cdlpr")) != EOF) {
> + while ((c = getopt(argc, argv, "cdDlpr")) != EOF) {
> switch (c) {
> case 'c':
> flags |= DIRENT_FLAG_INCLUDE_CSUM;
> @@ -212,6 +251,9 @@ void do_list_dir(int argc, char *argv[])
> case 'l':
> ls.options |= LONG_OPT;
> break;
> + case 'D':
> + ls.options |= DIRDATA_OPT;
> + break;
> case 'd':
> flags |= DIRENT_FLAG_INCLUDE_REMOVED;
> break;
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index 5015d938..686c2019 100644
> --- a/e2fsck/pass1.c
> +++ b/e2fsck/pass1.c
> @@ -719,7 +719,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
> */
> memcpy(&dotdot, inode->i_block, sizeof(dotdot));
> memcpy(&de, ((char *)inode->i_block) + EXT4_INLINE_DATA_DOTDOT_SIZE,
> - EXT2_DIR_REC_LEN(0));
> + __EXT2_DIR_REC_LEN(0));
> dotdot = ext2fs_le32_to_cpu(dotdot);
> de.inode = ext2fs_le32_to_cpu(de.inode);
> de.rec_len = ext2fs_le16_to_cpu(de.rec_len);
> @@ -2646,7 +2646,7 @@ static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
> return 1;
>
> /* XXX should check that beginning matches a directory */
> - root = (struct ext2_dx_root_info *) (block_buf + 24);
> + root = get_ext2_dx_root_info(fs, block_buf);
>
> if ((root->reserved_zero || root->info_length < 8) &&
> fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
> diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
> index 1b0504c8..1a719b2f 100644
> --- a/e2fsck/pass2.c
> +++ b/e2fsck/pass2.c
> @@ -366,13 +366,88 @@ static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
> return (int) (db_a->blockcnt - db_b->blockcnt);
> }
>
> +void ext2_fix_dirent_dirdata(struct ext2_dir_entry *de)
> +{
> + __u16 file_type = de->name_len & (EXT2_FT_MASK << 8);
> + __u8 de_flags = (de->name_len >> 8) & ~EXT2_FT_MASK;
> + __u8 name_len = de->name_len & EXT2_NAME_LEN;
> + __u8 new_flag = 0;
> + int i;
> +
> + for (i = 0; i < 4; i++) {
> + __u8 flags = new_flag | (1 << i) << 4;
> +
> + /* new_flag is accumulating flags that are set in de_flags
> + * and still fit inside rec_len. ext2_get_dirent_dirdata_size()
> + * returns the size of all the dirdata entries in flags, and
> + * chops off any that are beyond rec_len.
> + */
> + if ((de_flags & flags) == flags) {
> + int dirdatalen = ext2_get_dirent_dirdata_size(de,
> + flags);
> + int rlen = __EXT2_DIR_REC_LEN(name_len + dirdatalen);
> +
> + if (rlen > de->rec_len)
> + break;
> +
> + new_flag |= flags;
> + }
> + }
> +
> + de->name_len = name_len | file_type | (new_flag << 8);
> +}
> +
> +/*
> + * check for dirent data in ext3 dirent.
> + * return 0 if dirent data is ok.
> + * return 1 if dirent data does not exist.
> + * return 2 if dirent was modified due to error.
> + */
> +int e2fsck_check_dirent_data(e2fsck_t ctx, struct ext2_dir_entry *de,
> + unsigned int offset, struct problem_context *pctx)
> +{
> + if (!(ctx->fs->super->s_feature_incompat &
> + EXT4_FEATURE_INCOMPAT_DIRDATA)) {

if (!ext2fs_has_feature_dirdata(...))


> + if ((de->name_len >> 8) & ~EXT2_FT_MASK) {
> + /* clear dirent extra data flags. */
> + if (fix_problem(ctx, PR_2_CLEAR_DIRDATA, pctx)) {
> + de->name_len &= (EXT2_FT_MASK << 8) |
> + EXT2_NAME_LEN;
> + return 2;
> + }
> + }
> + return 1;
> + }
> + if ((de->name_len >> 8) & ~EXT2_FT_MASK) {
> + if (de->rec_len >= EXT2_DIR_REC_LEN(de) ||
> + de->rec_len + offset == EXT2_BLOCK_SIZE(ctx->fs->super)) {
> + if (ext2_get_dirent_dirdata_size(de,
> + EXT2_DIRENT_LUFID) %
> + EXT2_DIRENT_LUFID_SIZE == 1 /*size*/ + 1 /*NULL*/)
> + return 0;
> + }
> + /* just clear dirent data flags for now, we should fix FID data
> + * in lustre specific pass.
> + */
> + if (fix_problem(ctx, PR_2_CLEAR_DIRDATA, pctx)) {
> + ext2_fix_dirent_dirdata(de);
> + if (ext2_get_dirent_dirdata_size(de,
> + EXT2_DIRENT_LUFID) !=
> + EXT2_DIRENT_LUFID_SIZE)
> + de->name_len &= ~(EXT2_DIRENT_LUFID << 8);
> +
> + return 2;
> + }
> + }
> + return 1;
> +}
>
> /*
> * Make sure the first entry in the directory is '.', and that the
> * directory entry is sane.
> */
> static int check_dot(e2fsck_t ctx,
> - struct ext2_dir_entry *dirent,
> + struct ext2_dir_entry *dirent, unsigned int offset,
> ext2_ino_t ino, struct problem_context *pctx)
> {
> struct ext2_dir_entry *nextdir;
> @@ -380,6 +455,7 @@ static int check_dot(e2fsck_t ctx,
> int status = 0;
> int created = 0;
> problem_t problem = 0;
> + int dir_data_error;
>
> if (!dirent->inode)
> problem = PR_2_MISSING_DOT;
> @@ -389,10 +465,12 @@ static int check_dot(e2fsck_t ctx,
> else if (dirent->name[1] != '\0')
> problem = PR_2_DOT_NULL_TERM;
>
> + dir_data_error = e2fsck_check_dirent_data(ctx, dirent, offset, pctx);
> +
> (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
> if (problem) {
> if (fix_problem(ctx, problem, pctx)) {
> - if (rec_len < 12)
> + if (rec_len < 12 && dir_data_error)
> rec_len = dirent->rec_len = 12;
> dirent->inode = ino;
> ext2fs_dirent_set_name_len(dirent, 1);
> @@ -411,7 +489,7 @@ static int check_dot(e2fsck_t ctx,
> }
> if (rec_len > 12) {
> new_len = rec_len - 12;
> - if (new_len > 12) {
> + if (new_len > 12 && dir_data_error) {
> if (created ||
> fix_problem(ctx, PR_2_SPLIT_DOT, pctx)) {
> nextdir = (struct ext2_dir_entry *)
> @@ -436,11 +514,12 @@ static int check_dot(e2fsck_t ctx,
> * here; this gets done in pass 3.
> */
> static int check_dotdot(e2fsck_t ctx,
> - struct ext2_dir_entry *dirent,
> + struct ext2_dir_entry *dirent, unsigned int offset,
> ext2_ino_t ino, struct problem_context *pctx)
> {
> problem_t problem = 0;
> unsigned int rec_len;
> + int dir_data_error;
>
> if (!dirent->inode)
> problem = PR_2_MISSING_DOT_DOT;
> @@ -451,10 +530,12 @@ static int check_dotdot(e2fsck_t ctx,
> else if (dirent->name[2] != '\0')
> problem = PR_2_DOT_DOT_NULL_TERM;
>
> + dir_data_error = e2fsck_check_dirent_data(ctx, dirent, offset, pctx);
> +
> (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
> if (problem) {
> if (fix_problem(ctx, problem, pctx)) {
> - if (rec_len < 12)
> + if (rec_len < 12 && dir_data_error)
> dirent->rec_len = 12;
> /*
> * Note: we don't have the parent inode just
> @@ -528,6 +609,13 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
> int filetype = ext2fs_dirent_file_type(dirent);
> int should_be = EXT2_FT_UNKNOWN;
> struct ext2_inode inode;
> + __u8 dirdata = 0;
> +
> + if (ctx->fs->super->s_feature_incompat &
> + EXT4_FEATURE_INCOMPAT_DIRDATA) {
> + dirdata = filetype & ~EXT2_FT_MASK;
> + filetype = filetype & EXT2_FT_MASK;
> + }
>
> if (!ext2fs_has_feature_filetype(ctx->fs->super)) {
> if (filetype == 0 ||
> @@ -559,7 +647,7 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
> pctx) == 0)
> return 0;
>
> - ext2fs_dirent_set_file_type(dirent, should_be);
> + ext2fs_dirent_set_file_type(dirent, should_be | dirdata);
> return 1;
> }
>
> @@ -581,7 +669,7 @@ static void parse_int_node(ext2_filsys fs,
> int csum_size = 0;
>
> if (db->blockcnt == 0) {
> - root = (struct ext2_dx_root_info *) (block_buf + 24);
> + root = get_ext2_dx_root_info(fs, block_buf);
>
> #ifdef DX_DEBUG
> printf("Root node dump:\n");
> @@ -591,8 +679,8 @@ static void parse_int_node(ext2_filsys fs,
> printf("\t Indirect levels: %d\n", root->indirect_levels);
> printf("\t Flags: %d\n", root->unused_flags);
> #endif
> -
> - ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
> + ent = (struct ext2_dx_entry *)((char *)root +
> + root->info_length);
>
> if (failed_csum &&
> (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
> @@ -600,7 +688,7 @@ static void parse_int_node(ext2_filsys fs,
> &cd->pctx)))
> goto clear_and_exit;
> } else {
> - ent = (struct ext2_dx_entry *) (block_buf+8);
> + ent = (struct ext2_dx_entry *)(block_buf + 8);
>
> if (failed_csum &&
> (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
> @@ -608,8 +696,7 @@ static void parse_int_node(ext2_filsys fs,
> &cd->pctx)))
> goto clear_and_exit;
> }
> -
> - limit = (struct ext2_dx_countlimit *) ent;
> + limit = (struct ext2_dx_countlimit *)ent;
>
> #ifdef DX_DEBUG
> printf("Number of entries (count): %d\n",
> @@ -794,7 +881,7 @@ static errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf)
> d = NEXT_DIRENT(d);
>
> if (d != top) {
> - unsigned int min_size = EXT2_DIR_REC_LEN(
> + unsigned int min_size = __EXT2_DIR_REC_LEN(
> ext2fs_dirent_name_len(dirbuf));
> if (min_size > (char *)top - (char *)d)
> return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
> @@ -828,7 +915,7 @@ static errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino,
> */
> if (old_size > EXT4_MIN_INLINE_DATA_SIZE &&
> old_size < EXT4_MIN_INLINE_DATA_SIZE +
> - EXT2_DIR_REC_LEN(1)) {
> + __EXT2_DIR_REC_LEN(1)) {
> old_size = EXT4_MIN_INLINE_DATA_SIZE;
> new_size = old_size;
> } else
> @@ -1035,7 +1122,7 @@ inline_read_fail:
> if (((inline_data_size & 3) ||
> (inline_data_size > EXT4_MIN_INLINE_DATA_SIZE &&
> inline_data_size < EXT4_MIN_INLINE_DATA_SIZE +
> - EXT2_DIR_REC_LEN(1))) &&
> + __EXT2_DIR_REC_LEN(1))) &&
> fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) {
> errcode_t err = fix_inline_dir_size(ctx, ino,
> &inline_data_size, &pctx,
> @@ -1085,7 +1172,7 @@ inline_read_fail:
> (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
> limit = (struct ext2_dx_countlimit *) (buf+8);
> if (db->blockcnt == 0) {
> - root = (struct ext2_dx_root_info *) (buf + 24);
> + root = get_ext2_dx_root_info(fs, buf);
> dx_db->type = DX_DIRBLOCK_ROOT;
> dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
> if ((root->reserved_zero ||
> @@ -1165,7 +1252,7 @@ skip_checksum:
> * force salvaging this dir.
> */
> if (max_block_size - offset < EXT2_DIR_ENTRY_HEADER_LEN)
> - rec_len = EXT2_DIR_REC_LEN(1);
> + rec_len = __EXT2_DIR_REC_LEN(1);
> else
> (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
> cd->pctx.dirent = dirent;
> @@ -1227,7 +1314,7 @@ skip_checksum:
> memset(&dot, 0, sizeof(dot));
> dirent = &dot;
> dirent->inode = ino;
> - dirent->rec_len = EXT2_DIR_REC_LEN(1);
> + dirent->rec_len = __EXT2_DIR_REC_LEN(1);
> dirent->name_len = 1 | filetype;
> dirent->name[0] = '.';
> } else if (dot_state == 1) {
> @@ -1235,7 +1322,7 @@ skip_checksum:
> dirent = &dotdot;
> dirent->inode =
> ((struct ext2_dir_entry *)buf)->inode;
> - dirent->rec_len = EXT2_DIR_REC_LEN(2);
> + dirent->rec_len = __EXT2_DIR_REC_LEN(2);
> dirent->name_len = 2 | filetype;
> dirent->name[0] = '.';
> dirent->name[1] = '.';
> @@ -1247,10 +1334,10 @@ skip_checksum:
> }
>
> if (dot_state == 0) {
> - if (check_dot(ctx, dirent, ino, &cd->pctx))
> + if (check_dot(ctx, dirent, offset, ino, &cd->pctx))
> dir_modified++;
> } else if (dot_state == 1) {
> - ret = check_dotdot(ctx, dirent, ino, &cd->pctx);
> + ret = check_dotdot(ctx, dirent, offset, ino, &cd->pctx);
> if (ret < 0)
> goto abort_free_dict;
> if (ret)
> @@ -1266,6 +1353,10 @@ skip_checksum:
> if (!dirent->inode)
> goto next;
>
> + ret = e2fsck_check_dirent_data(ctx, dirent, offset, &cd->pctx);
> + if (ret == 2)
> + dir_modified++;
> +
> /*
> * Make sure the inode listed is a legal one.
> */
> diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> index 6a975b36..8ed871ff 100644
> --- a/e2fsck/pass3.c
> +++ b/e2fsck/pass3.c
> @@ -698,6 +698,7 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
> struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) priv_data;
> errcode_t retval;
> struct problem_context pctx;
> + __u16 dirdata = 0;
>
> if (ext2fs_dirent_name_len(dirent) != 2)
> return 0;
> @@ -717,11 +718,18 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
> fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
> }
> dirent->inode = fp->parent;
> +
> + dirdata = dirent->name_len & (~EXT2_FT_MASK << 8);
> +
> if (ext2fs_has_feature_filetype(fp->ctx->fs->super))
> ext2fs_dirent_set_file_type(dirent, EXT2_FT_DIR);
> else
> ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
>
> + if (fp->ctx->fs->super->s_feature_incompat &
> + EXT4_FEATURE_INCOMPAT_DIRDATA)

if (ext2fs_has_feature_dirdata(...)) ?

> + dirent->name_len |= dirdata;
> +
> fp->done++;
> return DIRENT_ABORT | DIRENT_CHANGED;
> }
> diff --git a/e2fsck/problem.c b/e2fsck/problem.c
> index edc9d51f..2a86d528 100644
> --- a/e2fsck/problem.c
> +++ b/e2fsck/problem.c
> @@ -1671,6 +1671,11 @@ static struct e2fsck_problem problem_table[] = {
> N_("Encrypted @E is too short.\n"),
> PROMPT_CLEAR, 0 },
>
> + /* Directory entry dirdata length set incorrectly */
> + { PR_2_CLEAR_DIRDATA,
> + N_("@E dirdata length set incorrectly.\n"),
> + PROMPT_CLEAR, PR_PREEN_OK },
> +
> /* Pass 3 errors */
>
> /* Pass 3: Checking directory connectivity */
> diff --git a/e2fsck/problem.h b/e2fsck/problem.h
> index 482d111a..05214840 100644
> --- a/e2fsck/problem.h
> +++ b/e2fsck/problem.h
> @@ -1004,6 +1004,9 @@ struct problem_context {
> /* Encrypted directory entry is too short */
> #define PR_2_BAD_ENCRYPTED_NAME 0x020050
>
> +/* Entry dirdata length set incorrectly */
> +#define PR_2_CLEAR_DIRDATA 0x020051
> +
> /*
> * Pass 3 errors
> */
> diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
> index 486e1f21..8656c417 100644
> --- a/e2fsck/rehash.c
> +++ b/e2fsck/rehash.c
> @@ -85,6 +85,8 @@ struct fill_dir_struct {
> int compress;
> ino_t parent;
> ext2_ino_t dir;
> + struct ext2_dir_entry *dot_de;
> + struct ext2_dir_entry *dotdot_de;
> };
>
> struct hash_entry {
> @@ -160,11 +162,14 @@ static int fill_dir_block(ext2_filsys fs,
> if (dirent->inode == 0)
> continue;
> if (!fd->compress && (name_len == 1) &&
> - (dirent->name[0] == '.'))
> + (dirent->name[0] == '.')) {
> + fd->dot_de = dirent;
> continue;
> + }
> if (!fd->compress && (name_len == 2) &&
> (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
> fd->parent = dirent->inode;
> + fd->dotdot_de = dirent;
> continue;
> }
> if (fd->num_array >= fd->max_array) {
> @@ -179,7 +184,7 @@ static int fill_dir_block(ext2_filsys fs,
> }
> ent = fd->harray + fd->num_array++;
> ent->dir = dirent;
> - fd->dir_size += EXT2_DIR_REC_LEN(name_len);
> + fd->dir_size += EXT2_DIR_REC_LEN(dirent);
> ent->ino = dirent->inode;
> if (fd->compress)
> ent->hash = ent->minor_hash = 0;
> @@ -475,7 +480,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
> ent = fd->harray + i;
> if (ent->dir->inode == 0)
> continue;
> - rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(ent->dir));
> + rec_len = EXT2_DIR_REC_LEN(ent->dir);
> if (rec_len > left) {
> if (left) {
> left += prev_rec_len;
> @@ -510,8 +515,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
> if (retval)
> return retval;
> prev_rec_len = rec_len;
> - memcpy(dirent->name, ent->dir->name,
> - ext2fs_dirent_name_len(dirent));
> + memcpy(dirent->name, ent->dir->name, rec_len);
> offset += rec_len;
> left -= rec_len;
> if (left < slack) {
> @@ -536,45 +540,54 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
>
>
> static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
> - ext2_ino_t ino, ext2_ino_t parent)
> + ext2_ino_t ino, ext2_ino_t parent,
> + struct ext2_dir_entry *dot_de,
> + struct ext2_dir_entry *dotdot_de)
> {
> - struct ext2_dir_entry *dir;
> - struct ext2_dx_root_info *root;
> + struct ext2_dir_entry *dir;
> + struct ext2_dx_root_info *root;
> struct ext2_dx_countlimit *limits;
> - int filetype = 0;
> int csum_size = 0;
> -
> - if (ext2fs_has_feature_filetype(fs->super))
> - filetype = EXT2_FT_DIR;
> + int offset;
> + int rec_len;
>
> memset(buf, 0, fs->blocksize);
> dir = (struct ext2_dir_entry *) buf;
> dir->inode = ino;
> - dir->name[0] = '.';
> - ext2fs_dirent_set_name_len(dir, 1);
> - ext2fs_dirent_set_file_type(dir, filetype);
> - dir->rec_len = 12;
> - dir = (struct ext2_dir_entry *) (buf + 12);
> +
> + ext2fs_dirent_set_name_len(dir, dot_de->name_len);
> + dir->rec_len = dot_de->rec_len;
> + rec_len = EXT2_DIR_REC_LEN(dot_de);
> + memcpy(dir->name, dot_de->name, rec_len);
> + offset = rec_len;
> +
> + dir = (struct ext2_dir_entry *) (buf + offset);
> + /* set to jump over the index block */
> +
> dir->inode = parent;
> - dir->name[0] = '.';
> - dir->name[1] = '.';
> - ext2fs_dirent_set_name_len(dir, 2);
> - ext2fs_dirent_set_file_type(dir, filetype);
> - dir->rec_len = fs->blocksize - 12;
>
> - root = (struct ext2_dx_root_info *) (buf+24);
> + ext2fs_dirent_set_name_len(dir, dotdot_de->name_len);
> + dir->rec_len = fs->blocksize - rec_len;
> + rec_len = EXT2_DIR_REC_LEN(dotdot_de);
> + memcpy(dir->name, dotdot_de->name, rec_len);
> + offset += rec_len;
> +
> + root = (struct ext2_dx_root_info *) (buf + offset);
> +
> root->reserved_zero = 0;
> root->hash_version = fs->super->s_def_hash_version;
> - root->info_length = 8;
> + root->info_length = sizeof(struct ext2_dx_root_info);
> root->indirect_levels = 0;
> root->unused_flags = 0;
> + offset += sizeof(struct ext2_dx_root_info);
>
> if (ext2fs_has_feature_metadata_csum(fs->super))
> csum_size = sizeof(struct ext2_dx_tail);
>
> - limits = (struct ext2_dx_countlimit *) (buf+32);
> - limits->limit = (fs->blocksize - (32 + csum_size)) /
> + limits->limit = (fs->blocksize - (offset + csum_size)) /
> sizeof(struct ext2_dx_entry);
> + limits = (struct ext2_dx_countlimit *) (buf + offset);
> +
> limits->count = 0;
>
> return root;
> @@ -647,7 +660,9 @@ static int alloc_blocks(ext2_filsys fs,
> static errcode_t calculate_tree(ext2_filsys fs,
> struct out_dir *outdir,
> ext2_ino_t ino,
> - ext2_ino_t parent)
> + ext2_ino_t parent,
> + struct ext2_dir_entry *dot_de,
> + struct ext2_dir_entry *dotdot_de)
> {
> struct ext2_dx_root_info *root_info;
> struct ext2_dx_entry *root, *int_ent, *dx_ent = 0;
> @@ -657,7 +672,9 @@ static errcode_t calculate_tree(ext2_filsys fs,
> int i, c1, c2, c3, nblks;
> int limit_offset, int_offset, root_offset;
>
> - root_info = set_root_node(fs, outdir->buf, ino, parent);
> + root_info = set_root_node(fs, outdir->buf, ino, parent, dot_de,
> + dotdot_de);
> +
> root_offset = limit_offset = ((char *) root_info - outdir->buf) +
> root_info->info_length;
> root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
> @@ -944,11 +961,10 @@ resort:
> if (retval)
> goto errout;
>
> - free(dir_buf); dir_buf = 0;
> -
> if (!fd.compress) {
> /* Calculate the interior nodes */
> - retval = calculate_tree(fs, &outdir, ino, fd.parent);
> + retval = calculate_tree(fs, &outdir, ino, fd.parent,
> + fd.dot_de, fd.dotdot_de);
> if (retval)
> goto errout;
> }
> diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
> index 54b27772..e524139b 100644
> --- a/lib/ext2fs/dirblock.c
> +++ b/lib/ext2fs/dirblock.c
> @@ -50,6 +50,40 @@ errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
> return ext2fs_read_dir_block4(fs, block, buf, flags, 0);
> }
>
> +/*
> + * Compute the total directory entry data length.
> + * This includes the filename and an implicit NUL terminator (always present),
> + * and optional extensions. Each extension has a bit set in the high 4 bits of
> + * de->file_type, and the extension length is the first byte in each entry.
> + */
> +int ext2_get_dirent_dirdata_size(struct ext2_dir_entry *de,
> + char dirdata_flags)
> +{
> + char *len = de->name + (de->name_len & EXT2_NAME_LEN) + 1 /* NUL */;
> + __u8 extra_data_flags = (de->name_len & ~(EXT2_FT_MASK << 8)) >> 12;
> + int dlen = 0;
> +
> + dirdata_flags >>= 4;
> + while ((extra_data_flags & dirdata_flags) != 0) {
> + if (extra_data_flags & 1) {
> + if (dirdata_flags & 1)
> + dlen += *len;
> +
> + len += *len;
> + }
> + extra_data_flags >>= 1;
> + dirdata_flags >>= 1;
> + }
> +
> + /* add NUL terminator byte to dirdata length */
> + return dlen + (dlen != 0);
> +}
> +
> +int ext2_get_dirent_size(struct ext2_dir_entry *de)
> +{
> + return ext2_get_dirent_dirdata_size(de, ~EXT2_FT_MASK);
> +}
> +
> errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
> void *buf, int flags EXT2FS_ATTR((unused)))
> {
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 2496d16d..f0cab391 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -923,7 +923,8 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, 4, ENCRYPT)
> #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
> EXT4_FEATURE_INCOMPAT_MMP| \
> EXT4_FEATURE_INCOMPAT_LARGEDIR| \
> - EXT4_FEATURE_INCOMPAT_EA_INODE)
> + EXT4_FEATURE_INCOMPAT_EA_INODE| \
> + EXT4_FEATURE_INCOMPAT_DIRDATA)
> #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
> EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
> EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
> @@ -1011,6 +1012,7 @@ struct ext2_dir_entry_tail {
> #define EXT2_FT_SYMLINK 7
>
> #define EXT2_FT_MAX 8
> +#define EXT2_FT_MASK 0x0f
>
> /*
> * Annoyingly, e2fsprogs always swab16s ext2_dir_entry.name_len, so we
> @@ -1028,11 +1030,18 @@ struct ext2_dir_entry_tail {
> #define EXT2_DIR_ENTRY_HEADER_LEN 8
> #define EXT2_DIR_PAD 4
> #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
> -#define EXT2_DIR_REC_LEN(name_len) (((name_len) + \
> +#define __EXT2_DIR_REC_LEN(name_len) (((name_len) + \
> EXT2_DIR_ENTRY_HEADER_LEN + \
> EXT2_DIR_ROUND) & \
> ~EXT2_DIR_ROUND)
>
> +#define EXT2_DIR_REC_LEN(de) (__EXT2_DIR_REC_LEN(((de)->name_len & \
> + EXT2_NAME_LEN) + \
> + ext2_get_dirent_size(de)))

Still need a comment explaining the difference between the two.

> +/* lu_fid size and NUL char */
> +#define EXT2_DIRENT_LUFID_SIZE 16
> +#define EXT2_DIRENT_LUFID 0x10
> +
> /*
> * Constants for ext4's extended time encoding
> */
> @@ -1091,6 +1100,9 @@ struct mmp_struct {
> */
> #define EXT4_MMP_MIN_CHECK_INTERVAL 5
>
> +int ext2_get_dirent_dirdata_size(struct ext2_dir_entry *de, char dirdata_flags);
> +int ext2_get_dirent_size(struct ext2_dir_entry *de);
> +
> /*
> * Minimum size of inline data.
> */
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index 6774e32c..b653012f 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -600,6 +600,7 @@ typedef struct ext2_icount *ext2_icount_t;
> EXT3_FEATURE_INCOMPAT_EXTENTS|\
> EXT4_FEATURE_INCOMPAT_FLEX_BG|\
> EXT4_FEATURE_INCOMPAT_EA_INODE|\
> + EXT4_FEATURE_INCOMPAT_DIRDATA|\
> EXT4_LIB_INCOMPAT_MMP|\
> EXT4_FEATURE_INCOMPAT_64BIT|\
> EXT4_FEATURE_INCOMPAT_INLINE_DATA|\
> @@ -1978,6 +1979,25 @@ _INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks)
> return blocks * ((fs->blocksize - 8) / sizeof(struct ext2_dx_entry));
> }
>
> +_INLINE_ struct ext2_dx_root_info *get_ext2_dx_root_info(ext2_filsys fs,
> + char *buf)
> +{
> + struct ext2_dir_entry *de = (struct ext2_dir_entry *)buf;
> +
> + if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA))
> + return (struct ext2_dx_root_info *)(buf +
> + __EXT2_DIR_REC_LEN(1) +
> + __EXT2_DIR_REC_LEN(2));
> +
> + /* get dotdot first */
> + de = (struct ext2_dir_entry *)((char *)de + de->rec_len);
> +
> + /* dx root info is after dotdot entry */
> + de = (struct ext2_dir_entry *)((char *)de + EXT2_DIR_REC_LEN(de));
> +
> + return (struct ext2_dx_root_info *)de;
> +}
> +
> /*
> * This is an efficient, overflow safe way of calculating ceil((1.0 * a) / b)
> */
> @@ -1997,7 +2017,7 @@ _INLINE_ __u64 ext2fs_div64_ceil(__u64 a, __u64 b)
>
> _INLINE_ int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry)
> {
> - return entry->name_len & 0xff;
> + return entry->name_len & EXT2_NAME_LEN;
> }
>
> _INLINE_ void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len)
> diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
> index 7215c517..2ce2f6f7 100644
> --- a/lib/ext2fs/inline_data.c
> +++ b/lib/ext2fs/inline_data.c
> @@ -149,7 +149,7 @@ int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,
> /* we first check '.' and '..' dir */
> dirent.inode = ino;
> dirent.name_len = 1;
> - ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
> + ext2fs_set_rec_len(fs, __EXT2_DIR_REC_LEN(2), &dirent);
> dirent.name[0] = '.';
> dirent.name[1] = '\0';
> ctx->buf = (char *)&dirent;
> @@ -160,7 +160,7 @@ int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,
>
> dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]);
> dirent.name_len = 2;
> - ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
> + ext2fs_set_rec_len(fs, __EXT2_DIR_REC_LEN(3), &dirent);
> dirent.name[0] = '.';
> dirent.name[1] = '.';
> dirent.name[2] = '\0';
> @@ -296,14 +296,14 @@ static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
> ext2fs_dirent_set_name_len(dir, 1);
> ext2fs_dirent_set_file_type(dir, filetype);
> dir->name[0] = '.';
> - rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
> - dir->rec_len = EXT2_DIR_REC_LEN(1);
> + rec_len = (fs->blocksize - csum_size) - __EXT2_DIR_REC_LEN(1);
> + dir->rec_len = __EXT2_DIR_REC_LEN(1);
>
> /*
> * Set up entry for '..'
> */
> dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len);
> - dir->rec_len = EXT2_DIR_REC_LEN(2);
> + dir->rec_len = __EXT2_DIR_REC_LEN(2);
> dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]);
> ext2fs_dirent_set_name_len(dir, 2);
> ext2fs_dirent_set_file_type(dir, filetype);
> @@ -313,11 +313,11 @@ static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
> /*
> * Adjust the last rec_len
> */
> - offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2);
> + offset = __EXT2_DIR_REC_LEN(1) + __EXT2_DIR_REC_LEN(2);
> dir = (struct ext2_dir_entry *) (bbuf + offset);
> memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE,
> size - EXT4_INLINE_DATA_DOTDOT_SIZE);
> - size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) -
> + size += __EXT2_DIR_REC_LEN(1) + __EXT2_DIR_REC_LEN(2) -
> EXT4_INLINE_DATA_DOTDOT_SIZE;
>
> do {
> diff --git a/lib/ext2fs/lfsck.h b/lib/ext2fs/lfsck.h
> new file mode 100644
> index 00000000..9401cd0c
> --- /dev/null
> +++ b/lib/ext2fs/lfsck.h
> @@ -0,0 +1,42 @@
> +#ifndef LFSCK_H
> +#define LFSCK_H
> +
> +/* This is unfortunately needed for older lustre_user.h to be usable */
> +#define LASSERT(cond) do { } while (0)
> +
> +#ifdef HAVE_LUSTRE_LUSTREAPI_H
> +#include <lustre/lustreapi.h>
> +#elif HAVE_LUSTRE_LIBLUSTREAPI_H
> +#include <lustre/liblustreapi.h>
> +#endif
> +
> +#ifndef DFID
> +#define DFID "[%#llx:0x%x:0x%x]"
> +#define PFID(fid) ((unsigned long long)fid_seq(fid),\
> + fid_oid(fid), fid_ver(fid))
> +struct lu_fid {
> + __u64 f_seq;
> + __u32 f_oid;
> + __u32 f_ver;
> +};
> +#endif /* !DFID */
> +
> +/* Unfortunately, neither the 1.8 or 2.x lustre_idl.h file is suitable
> + * for inclusion by userspace programs because of external dependencies.
> + * Define the minimum set of replacement functions here until that is fixed.
> + */
> +#ifndef HAVE_LUSTRE_LUSTRE_IDL_H
> +#define fid_seq(fid) ((fid)->f_seq)
> +#define fid_oid(fid) ((fid)->f_oid)
> +#define fid_ver(fid) ((fid)->f_ver)
> +
> +static inline void fid_be_to_cpu(struct lu_fid *dst, struct lu_fid *src)
> +{
> + dst->f_seq = ext2fs_be64_to_cpu(src->f_seq);
> + dst->f_oid = ext2fs_be32_to_cpu(src->f_oid);
> + dst->f_ver = ext2fs_be32_to_cpu(src->f_ver);
> +}
> +#endif
> +
> +#endif /* LFSCK_H */
> +
> diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
> index 65dc8877..5bb1581f 100644
> --- a/lib/ext2fs/link.c
> +++ b/lib/ext2fs/link.c
> @@ -47,7 +47,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
> if (ls->done)
> return DIRENT_ABORT;
>
> - rec_len = EXT2_DIR_REC_LEN(ls->namelen);
> + rec_len = __EXT2_DIR_REC_LEN(ls->namelen);
>
> ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len);
> if (ls->err)
> @@ -92,8 +92,8 @@ static int link_proc(struct ext2_dir_entry *dirent,
>
> /* De-convert a dx_root block */
> if (csum_size &&
> - curr_rec_len == ls->fs->blocksize - EXT2_DIR_REC_LEN(1) &&
> - offset == EXT2_DIR_REC_LEN(1) &&
> + curr_rec_len == ls->fs->blocksize - __EXT2_DIR_REC_LEN(1) &&
> + offset == __EXT2_DIR_REC_LEN(1) &&
> dirent->name[0] == '.' && dirent->name[1] == '.') {
> curr_rec_len -= csum_size;
> ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
> @@ -110,7 +110,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
> * truncate it and return.
> */
> if (dirent->inode) {
> - min_rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(dirent));
> + min_rec_len = EXT2_DIR_REC_LEN(dirent);
> if (curr_rec_len < (min_rec_len + rec_len))
> return ret;
> rec_len = curr_rec_len - min_rec_len;
> @@ -138,7 +138,7 @@ static int link_proc(struct ext2_dir_entry *dirent,
> ext2fs_dirent_set_name_len(dirent, ls->namelen);
> strncpy(dirent->name, ls->name, ls->namelen);
> if (ext2fs_has_feature_filetype(ls->sb))
> - ext2fs_dirent_set_file_type(dirent, ls->flags & 0x7);
> + ext2fs_dirent_set_file_type(dirent, ls->flags & EXT2_FT_MASK);
>
> ls->done++;
> return DIRENT_ABORT|DIRENT_CHANGED;
> diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
> index 7f472850..aa88f3e4 100644
> --- a/lib/ext2fs/newdir.c
> +++ b/lib/ext2fs/newdir.c
> @@ -64,8 +64,8 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
> ext2fs_dirent_set_name_len(dir, 1);
> ext2fs_dirent_set_file_type(dir, filetype);
> dir->name[0] = '.';
> - rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
> - dir->rec_len = EXT2_DIR_REC_LEN(1);
> + rec_len = (fs->blocksize - csum_size) - __EXT2_DIR_REC_LEN(1);
> + dir->rec_len = __EXT2_DIR_REC_LEN(1);
>
> /*
> * Set up entry for '..'
> diff --git a/misc/mke2fs.c b/misc/mke2fs.c
> index cfb10bc4..1edc0cd1 100644
> --- a/misc/mke2fs.c
> +++ b/misc/mke2fs.c
> @@ -1084,6 +1084,7 @@ static __u32 ok_features[3] = {
> EXT4_FEATURE_INCOMPAT_FLEX_BG|
> EXT4_FEATURE_INCOMPAT_EA_INODE|
> EXT4_FEATURE_INCOMPAT_MMP |
> + EXT4_FEATURE_INCOMPAT_DIRDATA|
> EXT4_FEATURE_INCOMPAT_64BIT|
> EXT4_FEATURE_INCOMPAT_INLINE_DATA|
> EXT4_FEATURE_INCOMPAT_ENCRYPT |
> diff --git a/misc/tune2fs.c b/misc/tune2fs.c
> index d0a18a18..44dd41a5 100644
> --- a/misc/tune2fs.c
> +++ b/misc/tune2fs.c
> @@ -157,6 +157,7 @@ static __u32 ok_features[3] = {
> EXT4_FEATURE_INCOMPAT_FLEX_BG |
> EXT4_FEATURE_INCOMPAT_EA_INODE|
> EXT4_FEATURE_INCOMPAT_MMP |
> + EXT4_FEATURE_INCOMPAT_DIRDATA |
> EXT4_FEATURE_INCOMPAT_64BIT |
> EXT4_FEATURE_INCOMPAT_ENCRYPT |
> EXT4_FEATURE_INCOMPAT_CSUM_SEED |
> @@ -183,6 +184,7 @@ static __u32 clear_ok_features[3] = {
> EXT2_FEATURE_INCOMPAT_FILETYPE |
> EXT4_FEATURE_INCOMPAT_FLEX_BG |
> EXT4_FEATURE_INCOMPAT_MMP |
> + EXT4_FEATURE_INCOMPAT_DIRDATA |
> EXT4_FEATURE_INCOMPAT_64BIT |
> EXT4_FEATURE_INCOMPAT_CSUM_SEED,
> /* R/O compat */
> --
> 2.13.6 (Apple Git-96)
>

2017-11-14 20:59:06

by Darrick J. Wong

[permalink] [raw]
Subject: Re: [PATCH v2 7/7] quota: quota 64bit inode number cleanup

On Tue, Nov 14, 2017 at 10:04:40AM +0300, Artem Blagodarenko wrote:
> Quota stores inodes numbers and beed to be fixed
> to store 64bit inodes.
>
> This patch makes quota 64bit inode ready.
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-9309
> Signed-off-by: Artem Blagodarenko <[email protected]>
> ---
> e2fsck/pass1.c | 2 +-
> e2fsck/quota.c | 8 ++++----
> e2fsck/unix.c | 2 +-
> lib/e2p/ls.c | 4 ++--
> lib/ext2fs/swapfs.c | 1 +
> lib/support/mkquota.c | 10 +++-------
> lib/support/quotaio.c | 2 +-
> lib/support/quotaio.h | 39 +++++++++++++++++++++++++++++++--------
> misc/tune2fs.c | 4 ++--
> 9 files changed, 46 insertions(+), 26 deletions(-)
>
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index 24f8e215..702dd1bf 100644
> --- a/e2fsck/pass1.c
> +++ b/e2fsck/pass1.c
> @@ -1130,7 +1130,7 @@ static int quota_inum_is_super(struct ext2_super_block *sb, ext2_ino_t ino)
> enum quota_type qtype;
>
> for (qtype = 0; qtype < MAXQUOTAS; qtype++)
> - if (*quota_sb_inump(sb, qtype) == ino)
> + if (quota_sb_inum(sb, qtype) == ino)
> return 1;
>
> return 0;
> diff --git a/e2fsck/quota.c b/e2fsck/quota.c
> index 529e87ef..130240a4 100644
> --- a/e2fsck/quota.c
> +++ b/e2fsck/quota.c
> @@ -72,13 +72,13 @@ void e2fsck_hide_quota(e2fsck_t ctx)
>
> for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
> pctx.dir = 2; /* This is a guess, but it's a good one */
> - pctx.ino = *quota_sb_inump(sb, qtype);
> + pctx.ino = quota_sb_inum(sb, qtype);
> pctx.num = qtype;
> quota_ino = quota_type2inum(qtype, fs->super);
> if (pctx.ino && (pctx.ino != quota_ino) &&
> fix_problem(ctx, PR_0_HIDE_QUOTA, &pctx)) {
> move_quota_inode(fs, pctx.ino, quota_ino, qtype);
> - *quota_sb_inump(sb, qtype) = quota_ino;
> + quota_set_sb_inump(sb, qtype, quota_ino);
> ext2fs_mark_super_dirty(fs);
> }
> }
> @@ -97,7 +97,7 @@ void e2fsck_validate_quota_inodes(e2fsck_t ctx)
> clear_problem_context(&pctx);
>
> for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
> - pctx.ino = *quota_sb_inump(sb, qtype);
> + pctx.ino = quota_sb_inum(sb, qtype);
> pctx.num = qtype;
> if (pctx.ino &&
> ((pctx.ino == EXT2_BAD_INO) ||
> @@ -110,7 +110,7 @@ void e2fsck_validate_quota_inodes(e2fsck_t ctx)
> (pctx.ino == EXT4_REPLICA_INO) ||
> (pctx.ino > ext2fs_get_inodes_count(fs->super))) &&
> fix_problem(ctx, PR_0_INVALID_QUOTA_INO, &pctx)) {
> - *quota_sb_inump(sb, qtype) = 0;
> + quota_set_sb_inump(sb, qtype, 0);
> ext2fs_mark_super_dirty(fs);
> }
> }
> diff --git a/e2fsck/unix.c b/e2fsck/unix.c
> index 38bc63e5..0d1a450c 100644
> --- a/e2fsck/unix.c
> +++ b/e2fsck/unix.c
> @@ -1862,7 +1862,7 @@ no_journal:
> int needs_writeout;
>
> for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
> - if (*quota_sb_inump(sb, qtype) == 0)
> + if (quota_sb_inum(sb, qtype) != 0)
> continue;
> needs_writeout = 0;
> pctx.num = qtype;
> diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
> index 45437520..416f382c 100644
> --- a/lib/e2p/ls.c
> +++ b/lib/e2p/ls.c
> @@ -453,10 +453,10 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
> sb->s_mmp_update_interval);
> }
> for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
> - if (*quota_sb_inump(sb, qtype) != 0)
> + if (quota_sb_inum(sb, qtype) != 0)
> fprintf(f, "%-26s%u\n",
> quota_type2prefix(qtype),
> - *quota_sb_inump(sb, qtype));
> + quota_sb_inum(sb, qtype));
> }
>
> if (ext2fs_has_feature_metadata_csum(sb)) {
> diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
> index 60cdf124..22cd50ec 100644
> --- a/lib/ext2fs/swapfs.c
> +++ b/lib/ext2fs/swapfs.c
> @@ -82,6 +82,7 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
> ext2fs_swab64(sb->s_snapshot_r_blocks_count);
> sb->s_snapshot_list = ext2fs_swab32(sb->s_snapshot_list);
> sb->s_prj_quota_inum = ext2fs_swab32(sb->s_prj_quota_inum);
> + sb->s_prj_quota_inum_hi = ext2fs_swab32(sb->s_prj_quota_inum_hi);

Wasn't this in the last patch?

> sb->s_usr_quota_inum = ext2fs_swab32(sb->s_usr_quota_inum);
> sb->s_grp_quota_inum = ext2fs_swab32(sb->s_grp_quota_inum);
> sb->s_overhead_blocks = ext2fs_swab32(sb->s_overhead_blocks);
> diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c
> index e65c95b7..791fae05 100644
> --- a/lib/support/mkquota.c
> +++ b/lib/support/mkquota.c
> @@ -93,13 +93,9 @@ int quota_file_exists(ext2_filsys fs, enum quota_type qtype)
> */
> void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, enum quota_type qtype)
> {
> - ext2_ino_t *inump;
> -
> - inump = quota_sb_inump(fs->super, qtype);
> -
> log_debug("setting quota ino in superblock: ino=%u, type=%d", ino,
> qtype);
> - *inump = ino;
> + quota_set_sb_inump(fs->super, qtype, ino);
> ext2fs_mark_super_dirty(fs);
> }
>
> @@ -113,8 +109,8 @@ errcode_t quota_remove_inode(ext2_filsys fs, enum quota_type qtype)
> log_debug("Couldn't read bitmaps: %s", error_message(retval));
> return retval;
> }
> + qf_ino = quota_sb_inum(fs->super, qtype);
>
> - qf_ino = *quota_sb_inump(fs->super, qtype);
> if (qf_ino == 0)
> return 0;
> retval = quota_inode_truncate(fs, qf_ino);
> @@ -308,7 +304,7 @@ errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs,
> if (((1 << qtype) & qtype_bits) == 0)
> continue;
> } else {
> - if (*quota_sb_inump(fs->super, qtype) == 0)
> + if (quota_sb_inum(fs->super, qtype) == 0)
> continue;
> }
> err = ext2fs_get_mem(sizeof(dict_t), &dict);
> diff --git a/lib/support/quotaio.c b/lib/support/quotaio.c
> index 2daf1785..a26576b5 100644
> --- a/lib/support/quotaio.c
> +++ b/lib/support/quotaio.c
> @@ -230,7 +230,7 @@ errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h,
> return err;
>
> if (qf_ino == 0)
> - qf_ino = *quota_sb_inump(fs->super, qtype);
> + qf_ino = quota_sb_inum(fs->super, qtype);
>
> log_debug("Opening quota ino=%u, type=%d", qf_ino, qtype);
> err = ext2fs_file_open(fs, qf_ino, flags, &e2_file);
> diff --git a/lib/support/quotaio.h b/lib/support/quotaio.h
> index 60689700..7c65673e 100644
> --- a/lib/support/quotaio.h
> +++ b/lib/support/quotaio.h
> @@ -245,21 +245,44 @@ int parse_quota_types(const char *in_str, unsigned int *qtype_bits,
> * This allows the caller to get or set the quota inode by type without the
> * need for the quota array to be contiguous in the superblock.
> */
> -static inline ext2_ino_t *quota_sb_inump(struct ext2_super_block *sb,
> - enum quota_type qtype)
> +static inline ext2_ino_t quota_sb_inum(struct ext2_super_block *sb,
> + enum quota_type qtype)
> {
> + ext2_ino_t quota_inum = 0;
> +
> switch (qtype) {
> case USRQUOTA:
> - return &sb->s_usr_quota_inum;
> + quota_inum = sb->s_usr_quota_inum;
> + break;
> case GRPQUOTA:
> - return &sb->s_grp_quota_inum;
> + quota_inum = sb->s_grp_quota_inum;

It seems kinda strange that the user/group quota inode number has to be
below 2^32 yet the project quota inode doesn't have this restriction?

Oh, right, the user/group quota are supposed to be inum 3 and 4 whereas
the project inode number can float. Never mind.

> + break;
> case PRJQUOTA:
> - return &sb->s_prj_quota_inum;
> - default:
> - return NULL;
> + quota_inum = sb->s_prj_quota_inum;
> + if (ext2fs_has_feature_inode64(sb))
> + quota_inum |= (__u64)sb->s_prj_quota_inum_hi << 32;
> + break;
> }
>
> - return NULL;
> + return quota_inum;
> +}
> +
> +static inline void quota_set_sb_inump(struct ext2_super_block *sb,
> + enum quota_type qtype, ext2_ino64_t ino)

quota_set_sb_inum and quota_sb_inum?

How about quota_{get,set}_sb_inum since they're a pair?

--D

> +{
> + switch (qtype) {
> + case USRQUOTA:
> + sb->s_usr_quota_inum = ino;
> + break;
> + case GRPQUOTA:
> + sb->s_grp_quota_inum = ino;
> + break;
> + case PRJQUOTA:
> + if (ext2fs_has_feature_inode64(sb))
> + sb->s_prj_quota_inum_hi = (__u32)(ino >> 32);
> + sb->s_prj_quota_inum = ino;
> + break;
> + }
> }
>
> #endif /* GUARD_QUOTAIO_H */
> diff --git a/misc/tune2fs.c b/misc/tune2fs.c
> index 3538ab9c..0368340b 100644
> --- a/misc/tune2fs.c
> +++ b/misc/tune2fs.c
> @@ -1640,7 +1640,7 @@ static void handle_quota_options(ext2_filsys fs)
>
> for (qtype = 0 ; qtype < MAXQUOTAS; qtype++) {
> if (quota_enable[qtype] == QOPT_ENABLE &&
> - *quota_sb_inump(fs->super, qtype) == 0) {
> + quota_sb_inum(fs->super, qtype) == 0) {
> if ((qf_ino = quota_file_exists(fs, qtype)) > 0) {
> retval = quota_update_limits(qctx, qf_ino,
> qtype);
> @@ -1687,7 +1687,7 @@ static void handle_quota_options(ext2_filsys fs)
> /* Clear Quota feature if all quota types disabled. */
> if (!qtype_bits) {
> for (qtype = 0 ; qtype < MAXQUOTAS; qtype++)
> - if (*quota_sb_inump(fs->super, qtype))
> + if (quota_sb_inum(fs->super, qtype))
> break;
> if (qtype == MAXQUOTAS) {
> ext2fs_clear_feature_quota(fs->super);
> --
> 2.13.6 (Apple Git-96)
>

2017-11-14 21:05:29

by Darrick J. Wong

[permalink] [raw]
Subject: Re: [PATCH v2 5/7] ext2fs: add EXT4_FEATURE_INCOMPAT_64INODE support

On Tue, Nov 14, 2017 at 10:04:38AM +0300, Artem Blagodarenko wrote:
> Inodes count and free inodes count should be 64 bit long.
> This patch also changes s_inodes_count* to 64 bit
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-9309
> Signed-off-by: Artem Blagodarenko <[email protected]>
> ---
> debugfs/debugfs.c | 2 +-
> debugfs/set_fields.c | 3 ++-
> debugfs/util.c | 5 +++--
> e2fsck/extents.c | 8 ++++----
> e2fsck/journal.c | 2 +-
> e2fsck/pass1.c | 16 ++++++++--------
> e2fsck/pass1b.c | 2 +-
> e2fsck/pass2.c | 4 ++--
> e2fsck/pass4.c | 2 +-
> e2fsck/pass5.c | 20 ++++++++++----------
> e2fsck/quota.c | 2 +-
> e2fsck/super.c | 18 ++++++++++--------
> e2fsck/unix.c | 15 ++++++++-------
> ext2ed/inode_com.c | 7 +++++--
> ext2ed/super_com.c | 6 ++++--
> lib/e2p/feature.c | 2 ++
> lib/e2p/ls.c | 8 +++++---
> lib/ext2fs/alloc.c | 8 ++++----
> lib/ext2fs/alloc_stats.c | 6 ++++--
> lib/ext2fs/bitmaps.c | 2 +-
> lib/ext2fs/ext2_fs.h | 12 ++++++++++--
> lib/ext2fs/ext2fs.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
> lib/ext2fs/extent.c | 2 +-
> lib/ext2fs/gen_bitmap64.c | 3 ++-
> lib/ext2fs/get_num_dirs.c | 4 ++--
> lib/ext2fs/icount.c | 7 ++++---
> lib/ext2fs/initialize.c | 19 +++++++++++--------
> lib/ext2fs/inline_data.c | 2 +-
> lib/ext2fs/inode.c | 8 ++++----
> lib/ext2fs/openfs.c | 4 ++--
> lib/ext2fs/rw_bitmaps.c | 2 +-
> lib/ext2fs/swapfs.c | 2 ++
> lib/ext2fs/tst_bitmaps.c | 7 ++++---
> lib/ext2fs/tst_iscan.c | 2 +-
> lib/ext2fs/tst_super_size.c | 5 ++++-
> misc/findsuper.c | 8 +++++---
> misc/fuse2fs.c | 6 +++---
> misc/mke2fs.c | 29 ++++++++++++++++++-----------
> misc/tune2fs.c | 10 ++++++----
> resize/main.c | 3 ++-
> resize/resize2fs.c | 30 ++++++++++++++++--------------
> tests/progs/test_icount.c | 4 ++--
> 42 files changed, 222 insertions(+), 129 deletions(-)
>
> diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
> index 4a533b53..a80cf668 100644
> --- a/debugfs/debugfs.c
> +++ b/debugfs/debugfs.c
> @@ -829,7 +829,7 @@ void internal_dump_inode(FILE *out, const char *prefix,
> else if (LINUX_S_ISFIFO(inode->i_mode)) i_type = "FIFO";
> else if (LINUX_S_ISSOCK(inode->i_mode)) i_type = "socket";
> else i_type = "bad type";
> - fprintf(out, "%sInode: %u Type: %s ", prefix, inode_num, i_type);
> + fprintf(out, "%sInode: %lu Type: %s ", prefix, inode_num, i_type);
> fprintf(out, "%sMode: 0%03o Flags: 0x%x\n",
> prefix, inode->i_mode & 07777, inode->i_flags);
> if (is_large_inode && large_inode->i_extra_isize >= 24) {
> diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
> index 8dfbba9c..bfab7ff8 100644
> --- a/debugfs/set_fields.c
> +++ b/debugfs/set_fields.c
> @@ -79,7 +79,8 @@ static errcode_t parse_mmp_clear(struct field_set_info *info, char *field,
> #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
>
> static struct field_set_info super_fields[] = {
> - { "inodes_count", &set_sb.s_inodes_count, NULL, 4, parse_uint },
> + { "inodes_count", &set_sb.s_inodes_count, &set_sb.s_inodes_count_hi,
> + 4, parse_uint },
> { "blocks_count", &set_sb.s_blocks_count, &set_sb.s_blocks_count_hi,
> 4, parse_uint },
> { "r_blocks_count", &set_sb.s_r_blocks_count,
> diff --git a/debugfs/util.c b/debugfs/util.c
> index 452de749..3e4fcb5a 100644
> --- a/debugfs/util.c
> +++ b/debugfs/util.c
> @@ -119,7 +119,8 @@ ext2_ino_t string_to_inode(char *str)
> */
> if ((len > 2) && (str[0] == '<') && (str[len-1] == '>')) {
> ino = strtoul(str+1, &end, 0);
> - if (*end=='>' && (ino <= current_fs->super->s_inodes_count))
> + if (*end == '>' &&
> + (ino <= ext2fs_get_inodes_count(current_fs->super)))
> return ino;
> }
>
> @@ -128,7 +129,7 @@ ext2_ino_t string_to_inode(char *str)
> com_err(str, retval, 0);
> return 0;
> }
> - if (ino > current_fs->super->s_inodes_count) {
> + if (ino > ext2fs_get_inodes_count(current_fs->super)) {
> com_err(str, 0, "resolves to an illegal inode number: %u\n",
> ino);
> return 0;
> diff --git a/e2fsck/extents.c b/e2fsck/extents.c
> index ef3146d8..d6bfcfb1 100644
> --- a/e2fsck/extents.c
> +++ b/e2fsck/extents.c
> @@ -381,7 +381,7 @@ static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header)
> while (1) {
> retval = ext2fs_find_first_set_inode_bitmap2(
> ctx->inodes_to_rebuild, ino + 1,
> - ctx->fs->super->s_inodes_count, &ino);
> + ext2fs_get_inodes_count(ctx->fs->super), &ino);
> if (retval)
> break;
> pctx.ino = ino;
> @@ -396,9 +396,9 @@ static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header)
> }
> if (ctx->progress && !ctx->progress_fd)
> e2fsck_simple_progress(ctx, "Rebuilding extents",
> - 100.0 * (float) ino /
> - (float) ctx->fs->super->s_inodes_count,
> - ino);
> + 100.0 * (float) ino /
> + (float) ext2fs_get_inodes_count(ctx->fs->super),
> + ino);
> }
> end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT);
>
> diff --git a/e2fsck/journal.c b/e2fsck/journal.c
> index c4f58f1b..9b107384 100644
> --- a/e2fsck/journal.c
> +++ b/e2fsck/journal.c
> @@ -1132,7 +1132,7 @@ void e2fsck_move_ext3_journal(e2fsck_t ctx)
> ext2fs_mark_ib_dirty(fs);
> ext2fs_bg_free_inodes_count_set(fs, group, ext2fs_bg_free_inodes_count(fs, group) + 1);
> ext2fs_group_desc_csum_set(fs, group);
> - fs->super->s_free_inodes_count++;
> + ext2fs_inc_free_inodes_count(fs->super);
> return;
>
> err_out:
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index 686c2019..24f8e215 100644
> --- a/e2fsck/pass1.c
> +++ b/e2fsck/pass1.c
> @@ -341,7 +341,7 @@ static problem_t check_large_ea_inode(e2fsck_t ctx,
>
> /* Check if inode is within valid range */
> if ((entry->e_value_inum < EXT2_FIRST_INODE(ctx->fs->super)) ||
> - (entry->e_value_inum > ctx->fs->super->s_inodes_count)) {
> + (entry->e_value_inum > ext2fs_get_inodes_count(ctx->fs->super))) {
> pctx->num = entry->e_value_inum;
> return PR_1_ATTR_VALUE_EA_INODE;
> }
> @@ -724,10 +724,10 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
> de.inode = ext2fs_le32_to_cpu(de.inode);
> de.rec_len = ext2fs_le16_to_cpu(de.rec_len);
> ext2fs_get_rec_len(ctx->fs, &de, &rec_len2);
> - if (dotdot >= ctx->fs->super->s_inodes_count ||
> + if (dotdot >= ext2fs_get_inodes_count(ctx->fs->super) ||
> (dotdot < EXT2_FIRST_INO(ctx->fs->super) &&
> dotdot != EXT2_ROOT_INO) ||
> - de.inode >= ctx->fs->super->s_inodes_count ||
> + de.inode >= ext2fs_get_inodes_count(ctx->fs->super) ||
> (de.inode < EXT2_FIRST_INO(ctx->fs->super) &&
> de.inode != 0) ||
> rec_len2 > EXT4_MIN_INLINE_DATA_SIZE -
> @@ -1098,7 +1098,7 @@ out:
> if (err) {
> /* Error; disable itable readahead */
> *group = ctx->fs->group_desc_count;
> - *next_ino = ctx->fs->super->s_inodes_count;
> + *next_ino = ext2fs_get_inodes_count(ctx->fs->super);
> } else {
> /*
> * Don't do more readahead until we've reached the first inode
> @@ -1338,10 +1338,10 @@ void e2fsck_pass1(e2fsck_t ctx)
> if (ctx->progress && ((ctx->progress)(ctx, 1, 0,
> ctx->fs->group_desc_count)))
> goto endit;
> - if ((fs->super->s_wtime < fs->super->s_inodes_count) ||
> - (fs->super->s_mtime < fs->super->s_inodes_count) ||
> + if ((fs->super->s_wtime < ext2fs_get_inodes_count(fs->super)) ||
> + (fs->super->s_mtime < ext2fs_get_inodes_count(fs->super)) ||
> (fs->super->s_mkfs_time &&
> - fs->super->s_mkfs_time < fs->super->s_inodes_count))
> + fs->super->s_mkfs_time < ext2fs_get_inodes_count(fs->super)))
> low_dtime_check = 0;
>
> if (ext2fs_has_feature_mmp(fs->super) &&
> @@ -1444,7 +1444,7 @@ void e2fsck_pass1(e2fsck_t ctx)
> * shouldn't be any bugs in the orphan list handling. :-)
> */
> if (inode->i_dtime && low_dtime_check &&
> - inode->i_dtime < ctx->fs->super->s_inodes_count) {
> + inode->i_dtime < ext2fs_get_inodes_count(ctx->fs->super)) {
> if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
> inode->i_dtime = inode->i_links_count ?
> 0 : ctx->now;
> diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
> index 392ff2c6..1607bfb0 100644
> --- a/e2fsck/pass1b.c
> +++ b/e2fsck/pass1b.c
> @@ -470,7 +470,7 @@ static void pass1c(e2fsck_t ctx, char *block_buf)
> */
> sd.count = dup_inode_count - dup_inode_founddir;
> sd.first_inode = EXT2_FIRST_INODE(fs->super);
> - sd.max_inode = fs->super->s_inodes_count;
> + sd.max_inode = ext2fs_get_inodes_count(fs->super);
> ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
> search_dirent_proc, &sd);
> }
> diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
> index 1a719b2f..08553003 100644
> --- a/e2fsck/pass2.c
> +++ b/e2fsck/pass2.c
> @@ -829,7 +829,7 @@ static void salvage_directory(ext2_filsys fs,
> if ((left < 0) &&
> ((int) rec_len + left > EXT2_DIR_ENTRY_HEADER_LEN) &&
> ((int) name_len + EXT2_DIR_ENTRY_HEADER_LEN <= (int) rec_len + left) &&
> - dirent->inode <= fs->super->s_inodes_count &&
> + dirent->inode <= ext2fs_get_inodes_count(fs->super) &&
> strnlen(dirent->name, name_len) == name_len) {
> (void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent);
> return;
> @@ -1363,7 +1363,7 @@ skip_checksum:
> name_len = ext2fs_dirent_name_len(dirent);
> if (((dirent->inode != EXT2_ROOT_INO) &&
> (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
> - (dirent->inode > fs->super->s_inodes_count)) {
> + (dirent->inode > ext2fs_get_inodes_count(fs->super))) {
> problem = PR_2_BAD_INO;
> } else if (ctx->inode_bb_map &&
> (ext2fs_test_inode_bitmap2(ctx->inode_bb_map,
> diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
> index 9a491b13..7a76c472 100644
> --- a/e2fsck/pass4.c
> +++ b/e2fsck/pass4.c
> @@ -177,7 +177,7 @@ void e2fsck_pass4(e2fsck_t ctx)
> inode = e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
>
> /* Protect loop from wrap-around if s_inodes_count maxed */
> - for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) {
> + for (i = 1; i <= ext2fs_get_inodes_count(fs->super) && i > 0; i++) {
> int isdir;
>
> if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
> diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
> index 7803e8b8..746d8299 100644
> --- a/e2fsck/pass5.c
> +++ b/e2fsck/pass5.c
> @@ -587,11 +587,11 @@ static void check_inode_bitmaps(e2fsck_t ctx)
> fs->group_desc_count * sizeof(ext2_ino_t), "directory count array");
>
> if ((1 < ext2fs_get_inode_bitmap_start2(ctx->inode_used_map)) ||
> - (fs->super->s_inodes_count >
> + (ext2fs_get_inodes_count(fs->super) >
> ext2fs_get_inode_bitmap_end2(ctx->inode_used_map))) {
> pctx.num = 3;
> pctx.blk = 1;
> - pctx.blk2 = fs->super->s_inodes_count;
> + pctx.blk2 = ext2fs_get_inodes_count(fs->super);
> pctx.ino = ext2fs_get_inode_bitmap_start2(ctx->inode_used_map);
> pctx.ino2 = ext2fs_get_inode_bitmap_end2(ctx->inode_used_map);
> fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
> @@ -600,11 +600,11 @@ static void check_inode_bitmaps(e2fsck_t ctx)
> goto errout;
> }
> if ((1 < ext2fs_get_inode_bitmap_start2(fs->inode_map)) ||
> - (fs->super->s_inodes_count >
> + (ext2fs_get_inodes_count(fs->super) >
> ext2fs_get_inode_bitmap_end2(fs->inode_map))) {
> pctx.num = 4;
> pctx.blk = 1;
> - pctx.blk2 = fs->super->s_inodes_count;
> + pctx.blk2 = ext2fs_get_inodes_count(fs->super);
> pctx.ino = ext2fs_get_inode_bitmap_start2(fs->inode_map);
> pctx.ino2 = ext2fs_get_inode_bitmap_end2(fs->inode_map);
> fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
> @@ -623,7 +623,7 @@ redo_counts:
> skip_group++;
>
> /* Protect loop from wrap-around if inodes_count is maxed */
> - for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
> + for (i = 1; i <= ext2fs_get_inodes_count(fs->super) && i > 0; i++) {
> bitmap = 0;
> if (skip_group &&
> i % fs->super->s_inodes_per_group == 1) {
> @@ -721,7 +721,7 @@ do_counts:
> }
>
> if ((inodes == fs->super->s_inodes_per_group) ||
> - (i == fs->super->s_inodes_count)) {
> + (i == ext2fs_get_inodes_count(fs->super))) {
> /*
> * If the last inode is free, we can discard it as well.
> */
> @@ -755,7 +755,7 @@ do_counts:
> fs->group_desc_count*2))
> goto errout;
> if (csum_flag &&
> - (i != fs->super->s_inodes_count) &&
> + (i != ext2fs_get_inodes_count(fs->super)) &&
> (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)
> ))
> skip_group++;
> @@ -818,13 +818,13 @@ do_counts:
> ext2fs_unmark_valid(fs);
> }
> }
> - if (free_inodes != fs->super->s_free_inodes_count) {
> + if (free_inodes != ext2fs_get_free_inodes_count(fs->super)) {
> pctx.group = -1;
> - pctx.ino = fs->super->s_free_inodes_count;
> + pctx.ino = ext2fs_get_free_inodes_count(fs->super);
> pctx.ino2 = free_inodes;
>
> if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
> - fs->super->s_free_inodes_count = free_inodes;
> + ext2fs_set_free_inodes_count(fs->super, free_inodes);
> ext2fs_mark_super_dirty(fs);
> }
> }
> diff --git a/e2fsck/quota.c b/e2fsck/quota.c
> index b0f9af63..529e87ef 100644
> --- a/e2fsck/quota.c
> +++ b/e2fsck/quota.c
> @@ -108,7 +108,7 @@ void e2fsck_validate_quota_inodes(e2fsck_t ctx)
> (pctx.ino == EXT2_JOURNAL_INO) ||
> (pctx.ino == EXT2_EXCLUDE_INO) ||
> (pctx.ino == EXT4_REPLICA_INO) ||
> - (pctx.ino > fs->super->s_inodes_count)) &&
> + (pctx.ino > ext2fs_get_inodes_count(fs->super))) &&
> fix_problem(ctx, PR_0_INVALID_QUOTA_INO, &pctx)) {
> *quota_sb_inump(sb, qtype) = 0;
> ext2fs_mark_super_dirty(fs);
> diff --git a/e2fsck/super.c b/e2fsck/super.c
> index 47c89c56..7183755c 100644
> --- a/e2fsck/super.c
> +++ b/e2fsck/super.c
> @@ -272,7 +272,7 @@ static int release_orphan_inodes(e2fsck_t ctx)
> return 0;
>
> if ((ino < EXT2_FIRST_INODE(fs->super)) ||
> - (ino > fs->super->s_inodes_count)) {
> + (ino > ext2fs_get_inodes_count(fs->super))) {
> clear_problem_context(&pctx);
> pctx.ino = ino;
> fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
> @@ -296,7 +296,7 @@ static int release_orphan_inodes(e2fsck_t ctx)
> next_ino = inode.i_dtime;
> if (next_ino &&
> ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
> - (next_ino > fs->super->s_inodes_count))) {
> + (next_ino > ext2fs_get_inodes_count(fs->super)))) {
> pctx.ino = next_ino;
> fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
> goto return_abort;
> @@ -529,7 +529,7 @@ void check_super_block(e2fsck_t ctx)
> /*
> * Verify the super block constants...
> */
> - check_super_value(ctx, "inodes_count", sb->s_inodes_count,
> + check_super_value(ctx, "inodes_count", ext2fs_get_inodes_count(sb),
> MIN_CHECK, 1, 0);
> check_super_value64(ctx, "blocks_count", ext2fs_blocks_count(sb),
> MIN_CHECK | MAX_CHECK, 1, blks_max);
> @@ -560,7 +560,8 @@ void check_super_block(e2fsck_t ctx)
> if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
> check_super_value(ctx, "first_ino", sb->s_first_ino,
> MIN_CHECK | MAX_CHECK,
> - EXT2_GOOD_OLD_FIRST_INO, sb->s_inodes_count);
> + EXT2_GOOD_OLD_FIRST_INO,
> + ext2fs_get_inodes_count(sb));
> inode_size = EXT2_INODE_SIZE(sb);
> check_super_value(ctx, "inode_size",
> inode_size, MIN_CHECK | MAX_CHECK | LOG2_CHECK,
> @@ -597,11 +598,11 @@ void check_super_block(e2fsck_t ctx)
> should_be = (blk64_t)sb->s_inodes_per_group * fs->group_desc_count;
> if (should_be > UINT_MAX)
> should_be = UINT_MAX;
> - if (sb->s_inodes_count != should_be) {
> - pctx.ino = sb->s_inodes_count;
> + if (ext2fs_get_inodes_count(sb) != should_be) {
> + pctx.ino = ext2fs_get_inodes_count(sb);
> pctx.ino2 = should_be;
> if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
> - sb->s_inodes_count = should_be;
> + ext2fs_set_inodes_count(sb, should_be);
> ext2fs_mark_super_dirty(fs);
> }
> }
> @@ -789,7 +790,7 @@ void check_super_block(e2fsck_t ctx)
> ctx->free_inodes = free_inodes;
>
> if ((ext2fs_free_blocks_count(sb) > ext2fs_blocks_count(sb)) ||
> - (sb->s_free_inodes_count > sb->s_inodes_count))
> + (ext2fs_get_free_inodes_count(sb) > ext2fs_get_inodes_count(sb)))
> ext2fs_unmark_valid(fs);
>
>
> @@ -1046,6 +1047,7 @@ int check_backup_super_block(e2fsck_t ctx)
> SUPER_DIFFERENT(s_blocks_count) ||
> SUPER_DIFFERENT(s_blocks_count_hi) ||
> SUPER_DIFFERENT(s_inodes_count) ||
> + SUPER_DIFFERENT(s_inodes_count_hi) ||
> memcmp(fs->super->s_uuid, backup_sb->s_uuid,
> sizeof(fs->super->s_uuid)))
> ret = 1;
> diff --git a/e2fsck/unix.c b/e2fsck/unix.c
> index b46dcb2d..38bc63e5 100644
> --- a/e2fsck/unix.c
> +++ b/e2fsck/unix.c
> @@ -112,9 +112,9 @@ static void show_stats(e2fsck_t ctx)
> dir_links = 2 * ctx->fs_directory_count - 1;
> num_files = ctx->fs_total_count - dir_links;
> num_links = ctx->fs_links_count - dir_links;
> - inodes = fs->super->s_inodes_count;
> - inodes_used = (fs->super->s_inodes_count -
> - fs->super->s_free_inodes_count);
> + inodes = ext2fs_get_inodes_count(fs->super);
> + inodes_used = (ext2fs_get_inodes_count(fs->super) -
> + ext2fs_get_free_inodes_count(fs->super));
> blocks = ext2fs_blocks_count(fs->super);
> blocks_used = (ext2fs_blocks_count(fs->super) -
> ext2fs_free_blocks_count(fs->super));
> @@ -412,12 +412,12 @@ static void check_if_skip(e2fsck_t ctx)
> * using dumpe2fs. (This is for cosmetic reasons only.)
> */
> clear_problem_context(&pctx);
> - pctx.ino = fs->super->s_free_inodes_count;
> + pctx.ino = ext2fs_get_free_inodes_count(fs->super);
> pctx.ino2 = ctx->free_inodes;
> if ((pctx.ino != pctx.ino2) &&
> !(ctx->options & E2F_OPT_READONLY) &&
> fix_problem(ctx, PR_0_FREE_INODE_COUNT, &pctx)) {
> - fs->super->s_free_inodes_count = ctx->free_inodes;
> + ext2fs_set_free_inodes_count(fs->super, ctx->free_inodes);
> ext2fs_mark_super_dirty(fs);
> }
> clear_problem_context(&pctx);
> @@ -433,8 +433,9 @@ static void check_if_skip(e2fsck_t ctx)
> /* Print the summary message when we're skipping a full check */
> log_out(ctx, _("%s: clean, %u/%u files, %llu/%llu blocks"),
> ctx->device_name,
> - fs->super->s_inodes_count - fs->super->s_free_inodes_count,
> - fs->super->s_inodes_count,
> + ext2fs_get_free_inodes_count(fs->super) -
> + ext2fs_get_free_inodes_count(fs->super),
> + ext2fs_get_inodes_count(fs->super),
> ext2fs_blocks_count(fs->super) -
> ext2fs_free_blocks_count(fs->super),
> ext2fs_blocks_count(fs->super));
> diff --git a/ext2ed/inode_com.c b/ext2ed/inode_com.c
> index 2d3dd6d6..279ce3c1 100644
> --- a/ext2ed/inode_com.c
> +++ b/ext2ed/inode_com.c
> @@ -210,8 +210,11 @@ void type_ext2_inode___show (char *command_line)
>
> wmove (show_win,1,0);
>
> - wprintw (show_win,"Inode %ld of %ld. Entry %ld of %ld in group descriptor %ld.\n"
> - ,inode_num,file_system_info.super_block.s_inodes_count,entry_num,last_entry,group_num);
> + wprintw (show_win,
> + "Inode %ld of %ld. Entry %ld of %ld in group descriptor %ld.\n",
> + inode_num,
> + ext2fs_get_inodes_count(&file_system_info.super_block),
> + entry_num, last_entry, group_num);
>
> wprintw (show_win,"Inode type: ");
>
> diff --git a/ext2ed/super_com.c b/ext2ed/super_com.c
> index a998970e..98558c58 100644
> --- a/ext2ed/super_com.c
> +++ b/ext2ed/super_com.c
> @@ -35,8 +35,10 @@ void type_ext2_super_block___show (char *command_line)
> wmove (show_pad,3,40);wprintw (show_pad,"%2.2f%%",100*(float) ext2fs_free_blocks_count(super)/ (float) ext2fs_blocks_count(super));
> }
>
> - if (super->s_inodes_count != 0) {
> - wmove (show_pad,4,40);wprintw (show_pad,"%2.2f%%",100*(float) super->s_free_inodes_count/ (float) super->s_inodes_count);
> + if (ext2fs_get_inodes_count(super) != 0) {
> + wmove(show_pad, 4, 40); wprintw(show_pad, "%2.2f%%",
> + 100*(float) ext2fs_get_free_inodes_count(super)/
> + (float) ext2fs_get_inodes_count(super);
> }
>
> wmove (show_pad,6,40);
> diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c
> index b7f6c1d2..fd77dedd 100644
> --- a/lib/e2p/feature.c
> +++ b/lib/e2p/feature.c
> @@ -105,6 +105,8 @@ static struct feature feature_list[] = {
> "inline_data"},
> { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT,
> "encrypt"},

Huh. Are we missing an entry for EXT4_FEATURE_INCOMPAT_DIRDATA here?

> + { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INODE64,
> + "inode64"},
> { 0, 0, 0 },
> };
>
> diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
> index a7586e09..45437520 100644
> --- a/lib/e2p/ls.c
> +++ b/lib/e2p/ls.c
> @@ -269,14 +269,16 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
> str = e2p_os2string(sb->s_creator_os);
> fprintf(f, "Filesystem OS type: %s\n", str);
> free(str);
> - fprintf(f, "Inode count: %u\n", sb->s_inodes_count);
> + fprintf(f, "Inode count: %u\n",
> + ext2fs_get_inodes_count(sb));
> fprintf(f, "Block count: %llu\n", e2p_blocks_count(sb));
> fprintf(f, "Reserved block count: %llu\n", e2p_r_blocks_count(sb));
> if (sb->s_overhead_blocks)
> fprintf(f, "Overhead blocks: %u\n",
> sb->s_overhead_blocks);
> - fprintf(f, "Free blocks: %llu\n", e2p_free_blocks_count(sb));
> - fprintf(f, "Free inodes: %u\n", sb->s_free_inodes_count);
> + fprintf(f, "Free blocks: %llu\n",
> + e2p_free_blocks_count(sb));
> + fprintf(f, "Free inodes: %u\n", ext2fs_get_free_inodes_count(sb));
> fprintf(f, "First block: %u\n", sb->s_first_data_block);
> fprintf(f, "Block size: %u\n", EXT2_BLOCK_SIZE(sb));
> if (ext2fs_has_feature_bigalloc(sb))
> diff --git a/lib/ext2fs/alloc.c b/lib/ext2fs/alloc.c
> index 3fd92167..e4ef9061 100644
> --- a/lib/ext2fs/alloc.c
> +++ b/lib/ext2fs/alloc.c
> @@ -107,7 +107,7 @@ errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
> }
> if (start_inode < EXT2_FIRST_INODE(fs->super))
> start_inode = EXT2_FIRST_INODE(fs->super);
> - if (start_inode > fs->super->s_inodes_count)
> + if (start_inode > ext2fs_get_inodes_count(fs->super))
> return EXT2_ET_INODE_ALLOC_FAIL;
> i = start_inode;
> do {
> @@ -118,8 +118,8 @@ errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
> upto = i + (EXT2_INODES_PER_GROUP(fs->super) - ino_in_group);
> if (i < start_inode && upto >= start_inode)
> upto = start_inode - 1;
> - if (upto > fs->super->s_inodes_count)
> - upto = fs->super->s_inodes_count;
> + if (upto > ext2fs_get_inodes_count(fs->super))
> + upto = ext2fs_get_inodes_count(fs->super);
>
> retval = ext2fs_find_first_zero_inode_bitmap2(map, i, upto,
> &first_zero);
> @@ -130,7 +130,7 @@ errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
> if (retval != ENOENT)
> return EXT2_ET_INODE_ALLOC_FAIL;
> i = upto + 1;
> - if (i > fs->super->s_inodes_count)
> + if (i > ext2fs_get_inodes_count(fs->super))
> i = EXT2_FIRST_INODE(fs->super);
> } while (i != start_inode);
>
> diff --git a/lib/ext2fs/alloc_stats.c b/lib/ext2fs/alloc_stats.c
> index 3949f618..9a145b43 100644
> --- a/lib/ext2fs/alloc_stats.c
> +++ b/lib/ext2fs/alloc_stats.c
> @@ -20,7 +20,7 @@ void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
> {
> int group = ext2fs_group_of_ino(fs, ino);
>
> - if (ino > fs->super->s_inodes_count) {
> + if (ino > ext2fs_get_inodes_count(fs->super)) {
> #ifndef OMIT_COM_ERR
> com_err("ext2fs_inode_alloc_stats2", 0,
> "Illegal inode number: %lu", (unsigned long) ino);
> @@ -48,7 +48,9 @@ void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
> ext2fs_group_desc_csum_set(fs, group);
> }
>
> - fs->super->s_free_inodes_count -= inuse;
> + ext2fs_set_free_inodes_count(fs->super,
> + ext2fs_get_free_inodes_count(fs->super) -
> + inuse);
> ext2fs_mark_super_dirty(fs);
> ext2fs_mark_ib_dirty(fs);
> }
> diff --git a/lib/ext2fs/bitmaps.c b/lib/ext2fs/bitmaps.c
> index 84021917..bbfab1ae 100644
> --- a/lib/ext2fs/bitmaps.c
> +++ b/lib/ext2fs/bitmaps.c
> @@ -61,7 +61,7 @@ errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
> fs->write_bitmaps = ext2fs_write_bitmaps;
>
> start = 1;
> - end = fs->super->s_inodes_count;
> + end = ext2fs_get_inodes_count(fs->super);
> real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count);
>
> /* Are we permitted to use new-style bitmaps? */
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 90294ed0..cb0f59d4 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -737,7 +737,10 @@ struct ext2_super_block {
> __le32 s_lpf_ino; /* Location of the lost+found inode */
> __le32 s_prj_quota_inum; /* inode for tracking project quota */
> __le32 s_checksum_seed; /* crc32c(orig_uuid) if csum_seed set */
> - __le32 s_reserved[98]; /* Padding to the end of the block */
> + __le32 s_inodes_count_hi; /* higth part of inode count */

"high part of inode count"

> + __le32 s_free_inodes_count_hi; /* Free inodes count */
> + __le32 s_prj_quota_inum_hi;

"high part of project quota inode number"

> + __le32 s_reserved[93]; /* Padding to the end of the block */

This adds three __le32 fields but decreases s_reserved by 5???

> __u32 s_checksum; /* crc32c(superblock) */
> };
>
> @@ -827,6 +830,8 @@ struct ext2_super_block {
> #define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
> #define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
> #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
> +#define EXT4_FEATURE_INCOMPAT_INODE64 0x20000
> +
>
> #define EXT4_FEATURE_COMPAT_FUNCS(name, ver, flagname) \
> static inline int ext2fs_has_feature_##name(struct ext2_super_block *sb) \
> @@ -918,13 +923,16 @@ EXT4_FEATURE_INCOMPAT_FUNCS(csum_seed, 4, CSUM_SEED)
> EXT4_FEATURE_INCOMPAT_FUNCS(largedir, 4, LARGEDIR)
> EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, 4, INLINE_DATA)
> EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, 4, ENCRYPT)
> +EXT4_FEATURE_INCOMPAT_FUNCS(inode64, 4, INODE64)
> +
>
> #define EXT2_FEATURE_COMPAT_SUPP 0
> #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
> EXT4_FEATURE_INCOMPAT_MMP| \
> EXT4_FEATURE_INCOMPAT_LARGEDIR| \
> EXT4_FEATURE_INCOMPAT_EA_INODE| \
> - EXT4_FEATURE_INCOMPAT_DIRDATA)
> + EXT4_FEATURE_INCOMPAT_DIRDATA \
> + EXT4_FEATURE_INCOMPAT_INODE64)
> #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
> EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
> EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index b653012f..785042df 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -74,6 +74,7 @@ extern "C" {
> #endif /* EXT2_FLAT_INCLUDES */
>
> typedef __u32 __bitwise ext2_ino_t;
> +typedef __u64 __bitwise ext2_ino64_t;

Whitespace damage...

> typedef __u32 __bitwise blk_t;
> typedef __u64 __bitwise blk64_t;
> typedef __u32 __bitwise dgrp_t;
> @@ -601,6 +602,7 @@ typedef struct ext2_icount *ext2_icount_t;
> EXT4_FEATURE_INCOMPAT_FLEX_BG|\
> EXT4_FEATURE_INCOMPAT_EA_INODE|\
> EXT4_FEATURE_INCOMPAT_DIRDATA|\
> + EXT4_FEATURE_INCOMPAT_INODE64|\
> EXT4_LIB_INCOMPAT_MMP|\
> EXT4_FEATURE_INCOMPAT_64BIT|\
> EXT4_FEATURE_INCOMPAT_INLINE_DATA|\
> @@ -2048,6 +2050,48 @@ ext2fs_const_inode(const struct ext2_inode_large * large_inode)
> return (const struct ext2_inode *) large_inode;
> }
>
> +static inline ext2_ino64_t ext2fs_get_inodes_count(struct ext2_super_block *sb)
> +{
> + ext2_ino64_t inodes_count = sb->s_inodes_count;
> +
> + if (ext2fs_has_feature_inode64(sb))
> + inodes_count |= (ext2_ino64_t)sb->s_inodes_count_hi << 32;
> + return inodes_count;
> +}
> +
> +static inline void ext2fs_set_inodes_count(struct ext2_super_block *sb,
> + ext2_ino64_t val)
> +{
> + if (ext2fs_has_feature_inode64(sb))
> + sb->s_inodes_count_hi = val >> 32;
> + sb->s_inodes_count = val;
> +}
> +
> +static inline ext2_ino64_t
> +ext2fs_get_free_inodes_count(struct ext2_super_block *sb)
> +{
> + ext2_ino64_t inodes_count = sb->s_free_inodes_count;
> +
> + if (ext2fs_has_feature_inode64(sb))
> + inodes_count |= (ext2_ino64_t)sb->s_free_inodes_count_hi << 32;
> + return inodes_count;
> +}
> +
> +static inline void ext2fs_set_free_inodes_count(struct ext2_super_block *sb,
> + ext2_ino64_t val)
> +{
> + if (ext2fs_has_feature_inode64(sb))
> + sb->s_free_inodes_count_hi = (__u32)(val >> 32);
> + sb->s_free_inodes_count = val;
> +}
> +
> +static inline void ext2fs_inc_free_inodes_count(struct ext2_super_block *sb)
> +{
> + __u64 val = ext2fs_get_free_inodes_count(sb);
> +
> + ext2fs_set_free_inodes_count(sb, ++val);
> +}
> +
> #undef _INLINE_
> #endif
>
> diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
> index a9cdae79..7d14da67 100644
> --- a/lib/ext2fs/extent.c
> +++ b/lib/ext2fs/extent.c
> @@ -226,7 +226,7 @@ errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
> EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
>
> if (!inode)
> - if ((ino == 0) || (ino > fs->super->s_inodes_count))
> + if ((ino == 0) || (ino > ext2fs_get_inodes_count(fs->super)))
> return EXT2_ET_BAD_INODE_NUM;
>
> retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle);
> diff --git a/lib/ext2fs/gen_bitmap64.c b/lib/ext2fs/gen_bitmap64.c
> index 3fc73498..4c676f23 100644
> --- a/lib/ext2fs/gen_bitmap64.c
> +++ b/lib/ext2fs/gen_bitmap64.c
> @@ -110,7 +110,8 @@ errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
> break;
> case EXT2FS_BMAP64_AUTODIR:
> retval = ext2fs_get_num_dirs(fs, &num_dirs);
> - if (retval || num_dirs > (fs->super->s_inodes_count / 320))
> + if (retval ||
> + num_dirs > (ext2fs_get_inodes_count(fs->super) / 320))
> ops = &ext2fs_blkmap64_bitarray;
> else
> ops = &ext2fs_blkmap64_rbtree;
> diff --git a/lib/ext2fs/get_num_dirs.c b/lib/ext2fs/get_num_dirs.c
> index f5644f8e..552ac477 100644
> --- a/lib/ext2fs/get_num_dirs.c
> +++ b/lib/ext2fs/get_num_dirs.c
> @@ -40,8 +40,8 @@ errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
> else
> num_dirs += ext2fs_bg_used_dirs_count(fs, i);
> }
> - if (num_dirs > fs->super->s_inodes_count)
> - num_dirs = fs->super->s_inodes_count;
> + if (num_dirs > ext2fs_get_inodes_count(fs->super))
> + num_dirs = ext2fs_get_inodes_count(fs->super);
>
> *ret_num_dirs = num_dirs;
>
> diff --git a/lib/ext2fs/icount.c b/lib/ext2fs/icount.c
> index d7de19fe..e652a0ad 100644
> --- a/lib/ext2fs/icount.c
> +++ b/lib/ext2fs/icount.c
> @@ -112,7 +112,7 @@ static errcode_t alloc_icount(ext2_filsys fs, int flags, ext2_icount_t *ret)
> return retval;
> memset(icount, 0, sizeof(struct ext2_icount));
> icount->magic = EXT2_ET_MAGIC_ICOUNT;
> - icount->num_inodes = fs->super->s_inodes_count;
> + icount->num_inodes = ext2fs_get_inodes_count(fs->super);
>
> if ((flags & EXT2_ICOUNT_OPT_FULLMAP) &&
> (flags & EXT2_ICOUNT_OPT_INCREMENT)) {
> @@ -235,7 +235,8 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs EXT2FS_NO_TDB_UNUSED,
> * which case the number of inodes in use approaches the ideal
> * value.
> */
> - num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count;
> + num_inodes = ext2fs_get_inodes_count(fs->super) -
> + ext2fs_get_free_inodes_count(fs->super);
>
> icount->tdb = tdb_open(fn, num_inodes, TDB_NOLOCK | TDB_NOSYNC,
> O_RDWR | O_CREAT | O_TRUNC, 0600);
> @@ -286,7 +287,7 @@ errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
> retval = ext2fs_get_num_dirs(fs, &icount->size);
> if (retval)
> goto errout;
> - icount->size += fs->super->s_inodes_count / 50;
> + icount->size += ext2fs_get_inodes_count(fs->super) / 50;
> }
>
> bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
> diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
> index 32f43210..2554b2dd 100644
> --- a/lib/ext2fs/initialize.c
> +++ b/lib/ext2fs/initialize.c
> @@ -285,16 +285,18 @@ retry:
>
> if (ext2fs_has_feature_64bit(super) &&
> (ext2fs_blocks_count(super) / i) > (1ULL << 32))
> - set_field(s_inodes_count, ~0U);
> + ext2fs_set_inodes_count(super, ~0U);
> else
> - set_field(s_inodes_count, ext2fs_blocks_count(super) / i);
> + ext2fs_set_inodes_count(super, ext2fs_get_inodes_count(param) ?
> + ext2fs_get_inodes_count(param) :
> + ext2fs_blocks_count(super) / i);
>
> /*
> * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
> * that we have enough inodes for the filesystem(!)
> */
> - if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
> - super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
> + if (ext2fs_get_inodes_count(super) < EXT2_FIRST_INODE(super)+1)
> + ext2fs_set_inodes_count(super, EXT2_FIRST_INODE(super)+1);
>
> /*
> * There should be at least as many inodes as the user
> @@ -302,7 +304,8 @@ retry:
> * should be. But make sure that we don't allocate more than
> * one bitmap's worth of inodes each group.
> */
> - ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count);
> + ipg = ext2fs_div_ceil(ext2fs_get_inodes_count(super),
> + fs->group_desc_count);
> if (ipg > fs->blocksize * 8) {
> if (!bigalloc_flag && super->s_blocks_per_group >= 256) {
> /* Try again with slightly different parameters */
> @@ -355,9 +358,9 @@ ipg_retry:
> ipg--;
> goto ipg_retry;
> }
> - super->s_inodes_count = super->s_inodes_per_group *
> - fs->group_desc_count;
> - super->s_free_inodes_count = super->s_inodes_count;
> + ext2fs_set_inodes_count(super, (ext2_ino64_t)super->s_inodes_per_group *
> + fs->group_desc_count);
> + ext2fs_set_free_inodes_count(super, ext2fs_get_inodes_count(super));
>
> /*
> * check the number of reserved group descriptor table blocks
> diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
> index 2ce2f6f7..4517afdd 100644
> --- a/lib/ext2fs/inline_data.c
> +++ b/lib/ext2fs/inline_data.c
> @@ -784,7 +784,7 @@ int main(int argc, char *argv[])
>
> memset(&param, 0, sizeof(param));
> ext2fs_blocks_count_set(&param, 32768);
> - param.s_inodes_count = 100;
> + ext2fs_set_inodes_count(&param, 100);
>
> param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_INLINE_DATA;
> param.s_rev_level = EXT2_DYNAMIC_REV;
> diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
> index ad01a9fc..182e9819 100644
> --- a/lib/ext2fs/inode.c
> +++ b/lib/ext2fs/inode.c
> @@ -752,7 +752,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
> if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
> return retval;
> }
> - if ((ino == 0) || (ino > fs->super->s_inodes_count))
> + if ((ino == 0) || (ino > ext2fs_get_inodes_count(fs->super)))
> return EXT2_ET_BAD_INODE_NUM;
> /* Create inode cache if not present */
> if (!fs->icache) {
> @@ -867,7 +867,7 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
> return retval;
> }
>
> - if ((ino == 0) || (ino > fs->super->s_inodes_count))
> + if ((ino == 0) || (ino > ext2fs_get_inodes_count(fs->super)))
> return EXT2_ET_BAD_INODE_NUM;
>
> /* Prepare our shadow buffer for read/modify/byteswap/write */
> @@ -1022,7 +1022,7 @@ errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
>
> EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
>
> - if (ino > fs->super->s_inodes_count)
> + if (ino > ext2fs_get_inodes_count(fs->super))
> return EXT2_ET_BAD_INODE_NUM;
>
> if (fs->get_blocks) {
> @@ -1044,7 +1044,7 @@ errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
>
> EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
>
> - if (ino > fs->super->s_inodes_count)
> + if (ino > ext2fs_get_inodes_count(fs->super))
> return EXT2_ET_BAD_INODE_NUM;
>
> if (fs->check_directory) {
> diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c
> index f74cd245..2e9464cf 100644
> --- a/lib/ext2fs/openfs.c
> +++ b/lib/ext2fs/openfs.c
> @@ -5,7 +5,7 @@
> *
> * %Begin-Header%
> * This file may be redistributed under the terms of the GNU Library
> - * General Public License, version 2.
> +* General Public License, version 2.

Whitespace damage...

> * %End-Header%
> */
>
> @@ -381,7 +381,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
> }
> fs->group_desc_count = groups_cnt;
> if (fs->group_desc_count * EXT2_INODES_PER_GROUP(fs->super) !=
> - fs->super->s_inodes_count) {
> + ext2fs_get_inodes_count(fs->super)) {
> retval = EXT2_ET_CORRUPT_SUPERBLOCK;
> goto cleanup;
> }
> diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c
> index ae593d49..66c8ee69 100644
> --- a/lib/ext2fs/rw_bitmaps.c
> +++ b/lib/ext2fs/rw_bitmaps.c
> @@ -252,7 +252,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
>
> if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
> blk = (fs->image_header->offset_inodemap / fs->blocksize);
> - ino_cnt = fs->super->s_inodes_count;
> + ino_cnt = ext2fs_get_inodes_count(fs->super);
> while (inode_nbytes > 0) {
> retval = io_channel_read_blk64(fs->image_io, blk++,
> 1, inode_bitmap);
> diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
> index b9d8f557..b7c01005 100644
> --- a/lib/ext2fs/swapfs.c
> +++ b/lib/ext2fs/swapfs.c
> @@ -26,10 +26,12 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
> {
> int i;
> sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count);
> + sb->s_inodes_count_hi = ext2fs_swab32(sb->s_inodes_count_hi);
> sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count);
> sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count);
> sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count);
> sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count);
> + sb->s_free_inodes_count_hi = ext2fs_swab32(sb->s_free_inodes_count_hi);
> sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block);
> sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size);
> sb->s_log_cluster_size = ext2fs_swab32(sb->s_log_cluster_size);
> diff --git a/lib/ext2fs/tst_bitmaps.c b/lib/ext2fs/tst_bitmaps.c
> index 574fb7a7..5ca4c680 100644
> --- a/lib/ext2fs/tst_bitmaps.c
> +++ b/lib/ext2fs/tst_bitmaps.c
> @@ -158,7 +158,7 @@ static void setup_filesystem(const char *name,
>
> memset(&param, 0, sizeof(param));
> ext2fs_blocks_count_set(&param, blocks);
> - param.s_inodes_count = inodes;
> + ext2fs_set_inodes_count(&param, inodes);
>
> retval = ext2fs_initialize("test fs", flags, &param,
> test_io_manager, &test_fs);
> @@ -275,9 +275,10 @@ void dump_inode_bitmap_cmd(int argc, char **argv)
> return;
>
> printf("inode bitmap: ");
> - dump_bitmap(test_fs->inode_map, 1, test_fs->super->s_inodes_count);
> + dump_bitmap(test_fs->inode_map, 1,
> + ext2fs_get_inodes_count(test_fs->super));
> }
> -
> +
> void dump_block_bitmap_cmd(int argc, char **argv)
> {
> if (check_fs_open(argv[0]))
> diff --git a/lib/ext2fs/tst_iscan.c b/lib/ext2fs/tst_iscan.c
> index 70bfbecc..6c9ceaf6 100644
> --- a/lib/ext2fs/tst_iscan.c
> +++ b/lib/ext2fs/tst_iscan.c
> @@ -200,7 +200,7 @@ static void check_map(void)
> }
> }
> printf("Bad inodes: ");
> - for (i=1; i <= test_fs->super->s_inodes_count; i++) {
> + for (i = 1; i <= ext2fs_get_inodes_count(test_fs->super); i++) {
> if (ext2fs_test_inode_bitmap2(bad_inode_map, i)) {
> if (first)
> first = 0;
> diff --git a/lib/ext2fs/tst_super_size.c b/lib/ext2fs/tst_super_size.c
> index 0adac411..e3dc608a 100644
> --- a/lib/ext2fs/tst_super_size.c
> +++ b/lib/ext2fs/tst_super_size.c
> @@ -142,7 +142,10 @@ int main(int argc, char **argv)
> check_field(s_lpf_ino, 4);
> check_field(s_prj_quota_inum, 4);
> check_field(s_checksum_seed, 4);
> - check_field(s_reserved, 98 * 4);
> + check_field(s_inodes_count_hi, 4);
> + check_field(s_free_inodes_count_hi, 4);
> + check_field(s_prj_quota_inum_hi, 4);
> + check_field(s_reserved, 93 * 4);
> check_field(s_checksum, 4);
> do_field("Superblock end", 0, 0, cur_offset, 1024);
> #endif
> diff --git a/misc/findsuper.c b/misc/findsuper.c
> index ff20b988..e73e92a5 100644
> --- a/misc/findsuper.c
> +++ b/misc/findsuper.c
> @@ -226,9 +226,11 @@ int main(int argc, char *argv[])
> WHY("free_blocks_count > blocks_count\n (%u > %u)\n",
> ext2fs_free_blocks_count(&ext2),
> ext2fs_blocks_count(&ext2));
> - if (ext2.s_free_inodes_count > ext2.s_inodes_count)
> - WHY("free_inodes_count > inodes_count (%u > %u)\n",
> - ext2.s_free_inodes_count, ext2.s_inodes_count);
> + if (ext2fs_get_free_inodes_count(&ext2) >
> + ext2fs_get_inodes_count(&ext2))
> + WHY("free_inodes_count > inodes_count (%lu > %lu)\n",
> + ext2fs_get_free_inodes_count(&ext2),
> + ext2fs_get_inodes_count(&ext);
>
> if (ext2.s_mkfs_time != 0)
> tm = ext2.s_mkfs_time;
> diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
> index 9feafd72..75e87536 100644
> --- a/misc/fuse2fs.c
> +++ b/misc/fuse2fs.c
> @@ -2368,9 +2368,9 @@ static int op_statfs(const char *path EXT2FS_ATTR((unused)),
> buf->f_bavail = 0;
> else
> buf->f_bavail = free - reserved;
> - buf->f_files = fs->super->s_inodes_count;
> - buf->f_ffree = fs->super->s_free_inodes_count;
> - buf->f_favail = fs->super->s_free_inodes_count;
> + buf->f_files = ext2fs_get_inodes_count(fs->super);
> + buf->f_ffree = ext2fs_get_inodes_count(fs->super);
> + buf->f_favail = ext2fs_get_free_inodes_count(fs->super);
> f = (uint64_t *)fs->super->s_uuid;
> fsid = *f;
> f++;
> diff --git a/misc/mke2fs.c b/misc/mke2fs.c
> index 1edc0cd1..64102b79 100644
> --- a/misc/mke2fs.c
> +++ b/misc/mke2fs.c
> @@ -654,9 +654,9 @@ static void show_stats(ext2_filsys fs)
>
> if (!verbose) {
> printf(_("Creating filesystem with %llu %dk blocks and "
> - "%u inodes\n"),
> + "%lu inodes\n"),
> ext2fs_blocks_count(s), fs->blocksize >> 10,
> - s->s_inodes_count);
> + ext2fs_get_inodes_count(s));
> goto skip_details;
> }
>
> @@ -682,7 +682,7 @@ static void show_stats(ext2_filsys fs)
> s->s_log_cluster_size);
> printf(_("Stride=%u blocks, Stripe width=%u blocks\n"),
> s->s_raid_stride, s->s_raid_stripe_width);
> - printf(_("%u inodes, %llu blocks\n"), s->s_inodes_count,
> + printf(_("%lu inodes, %llu blocks\n"), ext2fs_get_inodes_count(s),
> ext2fs_blocks_count(s));
> printf(_("%llu blocks (%2.2f%%) reserved for the super user\n"),
> ext2fs_r_blocks_count(s),
> @@ -1089,7 +1089,8 @@ static __u32 ok_features[3] = {
> EXT4_FEATURE_INCOMPAT_INLINE_DATA|
> EXT4_FEATURE_INCOMPAT_ENCRYPT |
> EXT4_FEATURE_INCOMPAT_CSUM_SEED |
> - EXT4_FEATURE_INCOMPAT_LARGEDIR,
> + EXT4_FEATURE_INCOMPAT_LARGEDIR|
> + EXT4_FEATURE_INCOMPAT_INODE64,
> /* R/O compat */
> EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
> EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
> @@ -2457,13 +2458,15 @@ profile_error:
> if (num_inodes == 0) {
> unsigned long long n;
> n = ext2fs_blocks_count(&fs_param) * blocksize / inode_ratio;
> - if (n > MAX_32_NUM) {
> - if (ext2fs_has_feature_64bit(&fs_param))
> + if (n > MAX_32_NUM && !(fs_param.s_feature_incompat &
> + EXT4_FEATURE_INCOMPAT_INODE64)) {

Don't un-convert feature bit test functions.

--D

> + if (fs_param.s_feature_incompat &
> + EXT4_FEATURE_INCOMPAT_64BIT)
> num_inodes = MAX_32_NUM;
> else {
> com_err(program_name, 0,
> _("too many inodes (%llu), raise "
> - "inode ratio?"), n);
> + "inode ratio?"), num_inodes);
> exit(1);
> }
> }
> @@ -2476,10 +2479,14 @@ profile_error:
> /*
> * Calculate number of inodes based on the inode ratio
> */
> - fs_param.s_inodes_count = num_inodes ? num_inodes :
> - (ext2fs_blocks_count(&fs_param) * blocksize) / inode_ratio;
> + if (num_inodes == 0)
> + num_inodes = (ext2fs_blocks_count(&fs_param) * blocksize) /
> + inode_ratio;
>
> - if ((((unsigned long long)fs_param.s_inodes_count) *
> + ext2fs_set_inodes_count(&fs_param, num_inodes);
> +
> +
> + if ((ext2fs_get_inodes_count(&fs_param) *
> (inode_size ? inode_size : EXT2_GOOD_OLD_INODE_SIZE)) >=
> ((ext2fs_blocks_count(&fs_param)) *
> EXT2_BLOCK_SIZE(&fs_param))) {
> @@ -2489,7 +2496,7 @@ profile_error:
> "specify higher inode_ratio (-i)\n\t"
> "or lower inode count (-N).\n"),
> inode_size ? inode_size : EXT2_GOOD_OLD_INODE_SIZE,
> - fs_param.s_inodes_count,
> + ext2fs_get_inodes_count(&fs_param),
> (unsigned long long) ext2fs_blocks_count(&fs_param));
> exit(1);
> }
> diff --git a/misc/tune2fs.c b/misc/tune2fs.c
> index 44dd41a5..3538ab9c 100644
> --- a/misc/tune2fs.c
> +++ b/misc/tune2fs.c
> @@ -161,7 +161,8 @@ static __u32 ok_features[3] = {
> EXT4_FEATURE_INCOMPAT_64BIT |
> EXT4_FEATURE_INCOMPAT_ENCRYPT |
> EXT4_FEATURE_INCOMPAT_CSUM_SEED |
> - EXT4_FEATURE_INCOMPAT_LARGEDIR,
> + EXT4_FEATURE_INCOMPAT_LARGEDIR |
> + EXT4_FEATURE_INCOMPAT_INODE64,
> /* R/O compat */
> EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
> EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
> @@ -2614,21 +2615,22 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
> group = 0;
>
> /* Protect loop from wrap-around if s_inodes_count maxed */
> - for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
> + for (ino = 1;
> + ino <= ext2fs_get_inodes_count(fs->super) && ino > 0; ino++) {
> if (!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
> group_free++;
> total_free++;
> }
> count++;
> if ((count == fs->super->s_inodes_per_group) ||
> - (ino == fs->super->s_inodes_count)) {
> + (ino == ext2fs_get_inodes_count(fs->super))) {
> ext2fs_bg_free_inodes_count_set(fs, group++,
> group_free);
> count = 0;
> group_free = 0;
> }
> }
> - fs->super->s_free_inodes_count = total_free;
> + ext2fs_set_free_inodes_count(fs->super, total_free);
> ext2fs_mark_super_dirty(fs);
> return 0;
> }
> diff --git a/resize/main.c b/resize/main.c
> index ba6bb6b1..79523803 100644
> --- a/resize/main.c
> +++ b/resize/main.c
> @@ -441,7 +441,8 @@ int main (int argc, char ** argv)
> checkit = 1;
>
> if ((fs->super->s_free_blocks_count > fs->super->s_blocks_count) ||
> - (fs->super->s_free_inodes_count > fs->super->s_inodes_count))
> + (ext2fs_get_free_inodes_count(fs->super) >
> + ext2fs_get_inodes_count(fs->super)))
> checkit = 1;
>
> if (checkit) {
> diff --git a/resize/resize2fs.c b/resize/resize2fs.c
> index 0bd325ba..ec13436c 100644
> --- a/resize/resize2fs.c
> +++ b/resize/resize2fs.c
> @@ -760,8 +760,8 @@ retry:
> new_inodes, ~0U);
> return EXT2_ET_TOO_MANY_INODES;
> }
> - fs->super->s_inodes_count = fs->super->s_inodes_per_group *
> - fs->group_desc_count;
> + ext2fs_set_inodes_count(fs->super, fs->super->s_inodes_per_group *
> + fs->group_desc_count);
>
> /*
> * Adjust the number of free blocks
> @@ -788,8 +788,8 @@ retry:
> /*
> * Adjust the bitmaps for size
> */
> - retval = ext2fs_resize_inode_bitmap2(fs->super->s_inodes_count,
> - fs->super->s_inodes_count,
> + retval = ext2fs_resize_inode_bitmap2(ext2fs_get_inodes_count(fs->super),
> + ext2fs_get_inodes_count(fs->super),
> fs->inode_map);
> if (retval) goto errout;
>
> @@ -987,8 +987,9 @@ retry:
> numblocks -= adjblocks;
> ext2fs_free_blocks_count_set(fs->super,
> ext2fs_free_blocks_count(fs->super) - adjblocks);
> - fs->super->s_free_inodes_count +=
> - fs->super->s_inodes_per_group;
> + ext2fs_set_free_inodes_count(fs->super,
> + ext2fs_get_free_inodes_count(fs->super) +
> + fs->super->s_inodes_per_group);
> ext2fs_bg_free_blocks_count_set(fs, i, numblocks);
> ext2fs_bg_free_inodes_count_set(fs, i,
> fs->super->s_inodes_per_group);
> @@ -1046,9 +1047,9 @@ static errcode_t adjust_superblock(ext2_resize_t rfs, blk64_t new_size)
> /*
> * Check to make sure there are enough inodes
> */
> - if ((rfs->old_fs->super->s_inodes_count -
> - rfs->old_fs->super->s_free_inodes_count) >
> - rfs->new_fs->super->s_inodes_count) {
> + if ((ext2fs_get_inodes_count(rfs->old_fs->super) -
> + ext2fs_get_free_inodes_count(rfs->old_fs->super)) >
> + ext2fs_get_inodes_count(rfs->new_fs->super)) {
> retval = ENOSPC;
> goto errout;
> }
> @@ -2866,7 +2867,8 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
>
> /* Protect loop from wrap-around if s_inodes_count maxed */
> uninit = ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT);
> - for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
> + for (ino = 1;
> + ino <= ext2fs_get_inodes_count(fs->super) && ino > 0; ino++) {
> if (uninit ||
> !ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
> group_free++;
> @@ -2874,7 +2876,7 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
> }
> count++;
> if ((count == fs->super->s_inodes_per_group) ||
> - (ino == fs->super->s_inodes_count)) {
> + (ino == ext2fs_get_inodes_count(fs->super))) {
> ext2fs_bg_free_inodes_count_set(fs, group, group_free);
> ext2fs_group_desc_csum_set(fs, group);
> group++;
> @@ -2885,7 +2887,7 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
> uninit = ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT);
> }
> }
> - fs->super->s_free_inodes_count = total_inodes_free;
> + ext2fs_set_free_inodes_count(fs->super, total_inodes_free);
> ext2fs_mark_super_dirty(fs);
> return 0;
> }
> @@ -2955,8 +2957,8 @@ blk64_t calculate_minimum_resize_size(ext2_filsys fs, int flags)
> * first figure out how many group descriptors we need to
> * handle the number of inodes we have
> */
> - inode_count = fs->super->s_inodes_count -
> - fs->super->s_free_inodes_count;
> + inode_count = ext2fs_get_inodes_count(fs->super) -
> + ext2fs_get_free_inodes_count(fs->super);
> blks_needed = ext2fs_div_ceil(inode_count,
> fs->super->s_inodes_per_group) *
> (blk64_t) EXT2_BLOCKS_PER_GROUP(fs->super);
> diff --git a/tests/progs/test_icount.c b/tests/progs/test_icount.c
> index d028a601..b4dd013b 100644
> --- a/tests/progs/test_icount.c
> +++ b/tests/progs/test_icount.c
> @@ -208,7 +208,7 @@ void do_dump(int argc, char **argv)
>
> if (check_icount(argv[0]))
> return;
> - for (i=1; i <= test_fs->super->s_inodes_count; i++) {
> + for (i = 1; i <= ext2fs_get_inodes_count(test_fs->super); i++) {
> retval = ext2fs_icount_fetch(test_icount, i, &count);
> if (retval) {
> com_err(argv[0], retval,
> @@ -312,7 +312,7 @@ int main(int argc, char **argv)
> */
> memset(&param, 0, sizeof(struct ext2_super_block));
> ext2fs_blocks_count_set(&param, 80000);
> - param.s_inodes_count = 20000;
> + ext2fs_set_inodes_count(&param, 20000);
> retval = ext2fs_initialize("/dev/null", 0, &param,
> unix_io_manager, &test_fs);
> if (retval) {
> --
> 2.13.6 (Apple Git-96)
>

2017-11-16 17:56:42

by Theodore Ts'o

[permalink] [raw]
Subject: Re: [PATCH v2 0/7] 64bit inode e2fsprogs support

Patch 3/7 is missing; it's not in my inbox, and it's not also visible
in the ext4 patchwork queue. From Andreas's description, it sounds
like it's a test case. Can you resend it directly to me?

Thanks!!

- Ted

2017-11-20 20:22:54

by Andreas Dilger

[permalink] [raw]
Subject: Re: [PATCH v2 4/7] debugfs: 64bit inode support

On Nov 14, 2017, at 12:04 AM, Artem Blagodarenko <[email protected]> wrote:
>
> New dirdata type EXT2_DIRENT_INODE is added.
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-9309
> Signed-off-by: Artem Blagodarenko <[email protected]>
> ---
> debugfs/ls.c | 6 ++++--
> lib/ext2fs/ext2_fs.h | 1 +
> 2 files changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/debugfs/ls.c b/debugfs/ls.c
> index 5655933e..b67c0800 100644
> --- a/debugfs/ls.c
> +++ b/debugfs/ls.c
> @@ -64,11 +64,13 @@ static void list_dirdata(struct list_dir_struct *ls,
>
> dlen = data[0];
>
> - if (dirdata_mask == EXT2_DIRENT_LUFID) {
> + if (dirdata_mask == EXT2_DIRENT_INODE)
> + fprintf(ls->f, "ino64:%04\n", *(__u32 *)(data + 1));
> + else if (dirdata_mask == EXT2_DIRENT_LUFID) {

(style) add {} around first part of if/else if needed on any part.

Looks fine otherwise. You could add my:

Reviewed-by: Andreas Dilger <[email protected]>

Cheers, Andreas






Attachments:
signature.asc (195.00 B)
Message signed with OpenPGP

2017-11-20 21:26:04

by Andreas Dilger

[permalink] [raw]
Subject: Re: [PATCH v2 6/7] quota: swapping s_prj_quota_inum superblock field

On Nov 14, 2017, at 12:04 AM, Artem Blagodarenko <[email protected]> wrote:
>
> ext2fs_swap_super() swaps s_usr_quota_inum and
> s_grp_quota_inum fields but not s_prj_quota_inum.
>
> This patch adds s_prj_quota_inum swapping.
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-9309
> Signed-off-by: Artem Blagodarenko <[email protected]>

You can add my:

Reviewed-by: Andreas Dilger <[email protected]>

I would suggest this patch just be submitted separately, since it is a
bug fix that could go into the "maint" branch along with other project
quota functionality, and doesn't really relate to the inode64 feature.

> ---
> lib/ext2fs/swapfs.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
> index b7c01005..60cdf124 100644
> --- a/lib/ext2fs/swapfs.c
> +++ b/lib/ext2fs/swapfs.c
> @@ -81,6 +81,7 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
> sb->s_snapshot_r_blocks_count =
> ext2fs_swab64(sb->s_snapshot_r_blocks_count);
> sb->s_snapshot_list = ext2fs_swab32(sb->s_snapshot_list);
> + sb->s_prj_quota_inum = ext2fs_swab32(sb->s_prj_quota_inum);
> sb->s_usr_quota_inum = ext2fs_swab32(sb->s_usr_quota_inum);
> sb->s_grp_quota_inum = ext2fs_swab32(sb->s_grp_quota_inum);
> sb->s_overhead_blocks = ext2fs_swab32(sb->s_overhead_blocks);


Cheers, Andreas






Attachments:
signature.asc (195.00 B)
Message signed with OpenPGP

2017-11-20 22:59:02

by Andreas Dilger

[permalink] [raw]
Subject: Re: [PATCH v2 1/7] e2fsck: add support for dirdata feature

On Nov 14, 2017, at 12:04 AM, Artem Blagodarenko <[email protected]> wrote:
>
> From: Andreas Dilger <[email protected]>
>
> Add support for the INCOMPAT_DIRDATA feature, which allows
> storing extra data in the directory entry beyond the name.
> This allows the Lustre File IDentifier to be accessed in
> an efficient manner, and would be useful for expanding a
> filesystem to allow more than 2^32 inodes in the future.
>
> Include this patches:
>
> e2fsck: e2fsck -D does not change dirdata content
>
> Fix dir optimization to preserve dirdata content for dot
> and dotdot entries.
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-1774
> Signed-off-by: Bobi Jam <[email protected]>
> Change-Id: Iae190794da75a2080a8e5cc5b95a49e0c894f72f
>
> e2fsprogs: Consider DIRENT_LUFID flag in link_proc().
>
> While adding the new file entry in directory block, link_proc()
> calculates minimum record length of the existing directory entry
> without considering the dirent data size and which leads to
> corruption. Changed the code to use EXT2_DIR_REC_LEN() which will
> return correct record length including dirent data size.
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-2462
> Signed-off-by: Manisha Salve <[email protected]>
> Change-Id: Ic593c558c47a78183143ec8e99d8385ac94d06f7
>
> libext2fs, e2fsck: don't use ext2_dir_entry_2
>
> Due to endian issues, do not use ext2_dir_entry_2 because it will
> have the wrong byte order on directory entries that are swabbed.
> Instead, use the standard practice of mask-and-shift to access the
> file_type and dirdata flags.
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-4677
> Signed-off-by: Pravin Shelar <[email protected]>
> Signed-off-by: Andreas Dilger <[email protected]>
>
> Signed-off-by: Artem Blagodarenko <[email protected]>
> ---
>
> diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
> index 1b0504c8..1a719b2f 100644
> --- a/e2fsck/pass2.c
> +++ b/e2fsck/pass2.c
> +/*
> + * check for dirent data in ext3 dirent.
> + * return 0 if dirent data is ok.
> + * return 1 if dirent data does not exist.
> + * return 2 if dirent was modified due to error.
> + */
> +int e2fsck_check_dirent_data(e2fsck_t ctx, struct ext2_dir_entry *de,
> + unsigned int offset, struct problem_context *pctx)
> +{
> + if (!(ctx->fs->super->s_feature_incompat &
> + EXT4_FEATURE_INCOMPAT_DIRDATA)) {
> + if ((de->name_len >> 8) & ~EXT2_FT_MASK) {
> + /* clear dirent extra data flags. */
> + if (fix_problem(ctx, PR_2_CLEAR_DIRDATA, pctx)) {
> + de->name_len &= (EXT2_FT_MASK << 8) |
> + EXT2_NAME_LEN;
> + return 2;
> + }
> + }
> + return 1;
> + }

This part is OK for LUFID, since we can reconstruct the FID from the inode
xattr. However, for 64-bit inodes it would not be safe to drop the extra
dirdata fields. It makes sense that e2fsck would force INCOMPAT_DIRDATA
to be set if INCOMPAT_INODE64 is set (and set INODE64 for > 2^32 inodes),
and tune2fs would not allow DIRDATA to be cleared in this case.

That isn't something to add in this patch, but please check it is done in
the inode64 patches.

> + if ((de->name_len >> 8) & ~EXT2_FT_MASK) {
> + if (de->rec_len >= EXT2_DIR_REC_LEN(de) ||
> + de->rec_len + offset == EXT2_BLOCK_SIZE(ctx->fs->super)) {
> + if (ext2_get_dirent_dirdata_size(de,
> + EXT2_DIRENT_LUFID) %
> + EXT2_DIRENT_LUFID_SIZE == 1 /*size*/ + 1 /*NULL*/)
> + return 0;
> + }

See comments below about ext2_get_dirent_dirdata_size() NOT returning the NUL
byte, since that makes this code less clear, but it would need to be added
into the next check.

> + /* just clear dirent data flags for now, we should fix FID data
> + * in lustre specific pass.
> + */
> + if (fix_problem(ctx, PR_2_CLEAR_DIRDATA, pctx)) {
> + ext2_fix_dirent_dirdata(de);
> + if (ext2_get_dirent_dirdata_size(de,
> + EXT2_DIRENT_LUFID) !=
> + EXT2_DIRENT_LUFID_SIZE)
> + de->name_len &= ~(EXT2_DIRENT_LUFID << 8);
> +
> + return 2;
> + }

This will need to be smarter for INODE64. It should preferably keep the
INO64 field over LUFID, since it is both smaller, and more important.
It would need to verify the field size is valid (== 5), otherwise e2fsck
will have to fix this itself. It would probably need to look for 64-bit
inodes in lost+found to match up with any entries that are pointing at
incorrect inodes, but that is for a later patch.

> @@ -528,6 +609,13 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
> int filetype = ext2fs_dirent_file_type(dirent);
> int should_be = EXT2_FT_UNKNOWN;
> struct ext2_inode inode;
> + __u8 dirdata = 0;
> +
> + if (ctx->fs->super->s_feature_incompat &
> + EXT4_FEATURE_INCOMPAT_DIRDATA) {

(style) align continued line after '(' on previous line. Actually, this
should be using the ext2fs_has_feature_inode64() helper...

> @@ -1035,7 +1122,7 @@ inline_read_fail:
> if (((inline_data_size & 3) ||
> (inline_data_size > EXT4_MIN_INLINE_DATA_SIZE &&
> inline_data_size < EXT4_MIN_INLINE_DATA_SIZE +
> - EXT2_DIR_REC_LEN(1))) &&
> + __EXT2_DIR_REC_LEN(1))) &&
> fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) {
> errcode_t err = fix_inline_dir_size(ctx, ino,
> &inline_data_size, &pctx,

This reminds me - I heard that dirdata doesn't play nicely with inline_data
for very small directories? We don't use inline_data together with Lustre,
but it might be something to check out in the future. For now it probably
makes sense to disallow setting dirdata + inline_data at the same time until
this has been tested/fixed.

> diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> index 6a975b36..8ed871ff 100644
> --- a/e2fsck/pass3.c
> +++ b/e2fsck/pass3.c
> @@ -717,11 +718,18 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
> fix_problem(fp->ctx, PR_3_ADJUST_INODE, &pctx);
> }
> dirent->inode = fp->parent;
> +
> + dirdata = dirent->name_len & (~EXT2_FT_MASK << 8);
> +
> if (ext2fs_has_feature_filetype(fp->ctx->fs->super))
> ext2fs_dirent_set_file_type(dirent, EXT2_FT_DIR);
> else
> ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
>
> + if (fp->ctx->fs->super->s_feature_incompat &
> + EXT4_FEATURE_INCOMPAT_DIRDATA)

Should use ext2fs_has_feature_dirdata() helper function.

> diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
> index 486e1f21..8656c417 100644
> --- a/e2fsck/rehash.c
> +++ b/e2fsck/rehash.c
>
> static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
> - ext2_ino_t ino, ext2_ino_t parent)
> + ext2_ino_t ino, ext2_ino_t parent,
> + struct ext2_dir_entry *dot_de,
> + struct ext2_dir_entry *dotdot_de)
> {
> - struct ext2_dir_entry *dir;
> - struct ext2_dx_root_info *root;
> + struct ext2_dir_entry *dir;

(style) This would be better named as "dirent"

> + struct ext2_dx_root_info *root;
> struct ext2_dx_countlimit *limits;
> - int filetype = 0;
> int csum_size = 0;
> -
> - if (ext2fs_has_feature_filetype(fs->super))
> - filetype = EXT2_FT_DIR;
> + int offset;
> + int rec_len;
>
> memset(buf, 0, fs->blocksize);
> dir = (struct ext2_dir_entry *) buf;
> dir->inode = ino;
> - dir->name[0] = '.';
> - ext2fs_dirent_set_name_len(dir, 1);
> - ext2fs_dirent_set_file_type(dir, filetype);
> - dir->rec_len = 12;
> - dir = (struct ext2_dir_entry *) (buf + 12);
> +
> + ext2fs_dirent_set_name_len(dir, dot_de->name_len);
> + dir->rec_len = dot_de->rec_len;
> + rec_len = EXT2_DIR_REC_LEN(dot_de);
> + memcpy(dir->name, dot_de->name, rec_len);
> + offset = rec_len;
> +
> + dir = (struct ext2_dir_entry *) (buf + offset);

There is a macro NEXT_DIRENT() in pass2.c that could be used here:

dir = NEXT_DIRENT(dir);

> + /* set to jump over the index block */
> +
> dir->inode = parent;
> - dir->name[0] = '.';
> - dir->name[1] = '.';
> - ext2fs_dirent_set_name_len(dir, 2);
> - ext2fs_dirent_set_file_type(dir, filetype);
> - dir->rec_len = fs->blocksize - 12;
>
> - root = (struct ext2_dx_root_info *) (buf+24);
> + ext2fs_dirent_set_name_len(dir, dotdot_de->name_len);
> + dir->rec_len = fs->blocksize - rec_len;
> + rec_len = EXT2_DIR_REC_LEN(dotdot_de);
> + memcpy(dir->name, dotdot_de->name, rec_len);
> + offset += rec_len;
> +
> + root = (struct ext2_dx_root_info *) (buf + offset);
> +
> root->reserved_zero = 0;
> root->hash_version = fs->super->s_def_hash_version;
> - root->info_length = 8;
> + root->info_length = sizeof(struct ext2_dx_root_info);

(style) sizeof(*root)

> root->indirect_levels = 0;
> root->unused_flags = 0;
> + offset += sizeof(struct ext2_dx_root_info);

offset += root->info_length;

> if (ext2fs_has_feature_metadata_csum(fs->super))
> csum_size = sizeof(struct ext2_dx_tail);
>
> - limits = (struct ext2_dx_countlimit *) (buf+32);
> - limits->limit = (fs->blocksize - (32 + csum_size)) /
> + limits->limit = (fs->blocksize - (offset + csum_size)) /
> sizeof(struct ext2_dx_entry);
> + limits = (struct ext2_dx_countlimit *) (buf + offset);

(defect) "limits" needs to be initialized before "limits->limit" is set?

> limits->count = 0;
>
> return root;
> @@ -647,7 +660,9 @@ static int alloc_blocks(ext2_filsys fs,
> static errcode_t calculate_tree(ext2_filsys fs,
> struct out_dir *outdir,
> ext2_ino_t ino,
> - ext2_ino_t parent)
> + ext2_ino_t parent,
> + struct ext2_dir_entry *dot_de,
> + struct ext2_dir_entry *dotdot_de)
> {
> struct ext2_dx_root_info *root_info;
> struct ext2_dx_entry *root, *int_ent, *dx_ent = 0;
> @@ -657,7 +672,9 @@ static errcode_t calculate_tree(ext2_filsys fs,
> int i, c1, c2, c3, nblks;
> int limit_offset, int_offset, root_offset;
>
> - root_info = set_root_node(fs, outdir->buf, ino, parent);
> + root_info = set_root_node(fs, outdir->buf, ino, parent, dot_de,
> + dotdot_de);
> +
> root_offset = limit_offset = ((char *) root_info - outdir->buf) +
> root_info->info_length;
> root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
> @@ -944,11 +961,10 @@ resort:
> if (retval)
> goto errout;
>
> - free(dir_buf); dir_buf = 0;

(defect) this looks like it is leaking memory now?

It would be better to use e2fsck_allocate_memory() instead of malloc(), so that
it would catch such leaks, but that is something to fix in a different patch.

> diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
> index 54b27772..e524139b 100644
> --- a/lib/ext2fs/dirblock.c
> +++ b/lib/ext2fs/dirblock.c
> @@ -50,6 +50,40 @@ errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
> return ext2fs_read_dir_block4(fs, block, buf, flags, 0);
> }
>
> +/*
> + * Compute the total directory entry data length.
> + * This includes the filename and an implicit NUL terminator (always present),

This part of the comment is incorrect (likely my fault for historical reasons).
The returned size does not include the filename length.

> + * and optional extensions. Each extension has a bit set in the high 4 bits of
> + * de->file_type, and the extension length is the first byte in each entry.
> + */
> +int ext2_get_dirent_dirdata_size(struct ext2_dir_entry *de,
> + char dirdata_flags)
> +{
> + char *len = de->name + (de->name_len & EXT2_NAME_LEN) + 1 /* NUL */;

This should probably be renamed "lenp" since it is a pointer to the field
length, not the length itself.

> + __u8 extra_data_flags = (de->name_len & ~(EXT2_FT_MASK << 8)) >> 12;
> + int dlen = 0;
> +
> + dirdata_flags >>= 4;
> + while ((extra_data_flags & dirdata_flags) != 0) {
> + if (extra_data_flags & 1) {
> + if (dirdata_flags & 1)
> + dlen += *len;
> +
> + len += *len;
> + }
> + extra_data_flags >>= 1;
> + dirdata_flags >>= 1;
> + }
> +
> + /* add NUL terminator byte to dirdata length */
> + return dlen + (dlen != 0);

I think this NUL byte should be added to ext2_get_dirent_size() below,
but not into the return value of ext2_get_dirent_dirdata_size(), since
that adds complexity to the caller (e.g. e2fsck_check_dirent_data())
and makes it harder to understand what is being returned.

> +}
> +
> +int ext2_get_dirent_size(struct ext2_dir_entry *de)

This is a bit of a confusing name, since it doesn't return the dirent size,
but the dirdata size. I suspect, based on the comment above, that this
_used_ to return the full dirent size, but it no longer does. It would be
better to rename this function "ext2_get_dirdata_size()" and the previous
function "ext2_get_dirdata_field_size()" or similar?

> +{
> + return ext2_get_dirent_dirdata_size(de, ~EXT2_FT_MASK);
> +}
> +
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index 6774e32c..b653012f 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
>
> +_INLINE_ struct ext2_dx_root_info *get_ext2_dx_root_info(ext2_filsys fs,
> + char *buf)
> +{
> + struct ext2_dir_entry *de = (struct ext2_dir_entry *)buf;
> +
> + if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA))
> + return (struct ext2_dx_root_info *)(buf +
> + __EXT2_DIR_REC_LEN(1) +
> + __EXT2_DIR_REC_LEN(2));
> +
> + /* get dotdot first */
> + de = (struct ext2_dir_entry *)((char *)de + de->rec_len);
> +
> + /* dx root info is after dotdot entry */
> + de = (struct ext2_dir_entry *)((char *)de + EXT2_DIR_REC_LEN(de));

These would also benefit from the "NEXT_ENTRY()" macro, possibly renamed
to EXT2_DIRENTRY_NEXT() or similar for public use?

> + return (struct ext2_dx_root_info *)de;
> +}
> +
> diff --git a/lib/ext2fs/lfsck.h b/lib/ext2fs/lfsck.h
> new file mode 100644
> index 00000000..9401cd0c
> --- /dev/null
> +++ b/lib/ext2fs/lfsck.h
> @@ -0,0 +1,42 @@
> +#ifndef LFSCK_H
> +#define LFSCK_H
> +
> +/* This is unfortunately needed for older lustre_user.h to be usable */
> +#define LASSERT(cond) do { } while (0)
> +
> +#ifdef HAVE_LUSTRE_LUSTREAPI_H
> +#include <lustre/lustreapi.h>
> +#elif HAVE_LUSTRE_LIBLUSTREAPI_H
> +#include <lustre/liblustreapi.h>
> +#endif

I don't think there is much value in including the Lustre headers here.
That was done long ago when the Lustre fsck was implemented as part of
e2fsck, but that is now gone. Better to just #define the few fields
needed below as they are now.

> +#ifndef DFID
> +#define DFID "[%#llx:0x%x:0x%x]"
> +#define PFID(fid) ((unsigned long long)fid_seq(fid),\
> + fid_oid(fid), fid_ver(fid))
> +struct lu_fid {
> + __u64 f_seq;
> + __u32 f_oid;
> + __u32 f_ver;
> +};
> +#endif /* !DFID */
> +
> +/* Unfortunately, neither the 1.8 or 2.x lustre_idl.h file is suitable
> + * for inclusion by userspace programs because of external dependencies.
> + * Define the minimum set of replacement functions here until that is fixed.
> + */
> +#ifndef HAVE_LUSTRE_LUSTRE_IDL_H
> +#define fid_seq(fid) ((fid)->f_seq)
> +#define fid_oid(fid) ((fid)->f_oid)
> +#define fid_ver(fid) ((fid)->f_ver)
> +
> +static inline void fid_be_to_cpu(struct lu_fid *dst, struct lu_fid *src)
> +{
> + dst->f_seq = ext2fs_be64_to_cpu(src->f_seq);
> + dst->f_oid = ext2fs_be32_to_cpu(src->f_oid);
> + dst->f_ver = ext2fs_be32_to_cpu(src->f_ver);
> +}
> +#endif
> +
> +#endif /* LFSCK_H */


Cheers, Andreas






Attachments:
signature.asc (195.00 B)
Message signed with OpenPGP

2017-11-20 23:09:11

by Andreas Dilger

[permalink] [raw]
Subject: Re: [PATCH v2 5/7] ext2fs: add EXT4_FEATURE_INCOMPAT_64INODE support

Note "Subject:" line needs to list "INODE64" instead of "64INODE"

On Nov 14, 2017, at 12:04 AM, Artem Blagodarenko <[email protected]> wrote:
>
> Inodes count and free inodes count should be 64 bit long.
> This patch also changes s_inodes_count* to 64 bit
>
> Lustre-bug: https://jira.hpdd.intel.com/browse/LU-9309
> Signed-off-by: Artem Blagodarenko <[email protected]>
> ---

At a high level this patch is good.

I think it would be a lot easier to review this patch if there was
one patch that just added the ext2fs_{get,set}_inodes_count() and
ext2fs_{get,set}_free_inodes_count() helper routines (that only
use the low word) and "%lu" format, and then the second patch added
the INODE64 functionality.

This would allow about 90% of this patch to be trivially reviewed,
and even landed, and then the second patch contains the important
64-bit inode related changes that needs more thorough review.

> diff --git a/debugfs/util.c b/debugfs/util.c
> index 452de749..3e4fcb5a 100644
> --- a/debugfs/util.c
> +++ b/debugfs/util.c
> @@ -119,7 +119,8 @@ ext2_ino_t string_to_inode(char *str)
> */
> if ((len > 2) && (str[0] == '<') && (str[len-1] == '>')) {
> ino = strtoul(str+1, &end, 0);
> - if (*end=='>' && (ino <= current_fs->super->s_inodes_count))
> + if (*end == '>' &&
> + (ino <= ext2fs_get_inodes_count(current_fs->super)))

(style) align after '(' on previous line.
(style) No need for () around <= comparison.

> diff --git a/e2fsck/extents.c b/e2fsck/extents.c
> index ef3146d8..d6bfcfb1 100644
> --- a/e2fsck/extents.c
> +++ b/e2fsck/extents.c
> @@ -396,9 +396,9 @@ static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header)
> }
> if (ctx->progress && !ctx->progress_fd)
> e2fsck_simple_progress(ctx, "Rebuilding extents",
> - 100.0 * (float) ino /
> - (float) ctx->fs->super->s_inodes_count,
> - ino);
> + 100.0 * (float) ino /
> + (float) ext2fs_get_inodes_count(ctx->fs->super),

(style) no space after typecast.

> diff --git a/lib/ext2fs/alloc_stats.c b/lib/ext2fs/alloc_stats.c
> index 3949f618..9a145b43 100644
> --- a/lib/ext2fs/alloc_stats.c
> +++ b/lib/ext2fs/alloc_stats.c
> @@ -48,7 +48,9 @@ void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
> ext2fs_group_desc_csum_set(fs, group);
> }
>
> - fs->super->s_free_inodes_count -= inuse;
> + ext2fs_set_free_inodes_count(fs->super,
> + ext2fs_get_free_inodes_count(fs->super) -
> + inuse);

This looks like "inuse" is an argument to ext2_get_free_inodes_count().
It should be indented one tab from ext2fs_get_free_inodes_count() so it is
clear this is a continued line.

> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 90294ed0..cb0f59d4 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -737,7 +737,10 @@ struct ext2_super_block {
> __le32 s_lpf_ino; /* Location of the lost+found inode */
> __le32 s_prj_quota_inum; /* inode for tracking project quota */
> __le32 s_checksum_seed; /* crc32c(orig_uuid) if csum_seed set */
> - __le32 s_reserved[98]; /* Padding to the end of the block */
> + __le32 s_inodes_count_hi; /* higth part of inode count */
> + __le32 s_free_inodes_count_hi; /* Free inodes count */
> + __le32 s_prj_quota_inum_hi;
> + __le32 s_reserved[93]; /* Padding to the end of the block */

98 - 3 = 95?

> __u32 s_checksum; /* crc32c(superblock) */
> };

This misalignment of the s_checksum field should cause test failures in the
checksum patches, and hopefully also some other checks to fail. We should
definitely have a "sizeof(ext2_super_block) == 1024" check somewhere.
Did you run "make check" on these patches?

> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index b653012f..785042df 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> +static inline void ext2fs_set_inodes_count(struct ext2_super_block *sb,
> + ext2_ino64_t val)
> +{
> + if (ext2fs_has_feature_inode64(sb))
> + sb->s_inodes_count_hi = val >> 32;

(style) two spaces before "val" here

> +static inline void ext2fs_set_free_inodes_count(struct ext2_super_block *sb,
> + ext2_ino64_t val)
> +{
> + if (ext2fs_has_feature_inode64(sb))
> + sb->s_free_inodes_count_hi = (__u32)(val >> 32);

(style) two spaces before "(__u32)" here

> diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
> index 32f43210..2554b2dd 100644
> --- a/lib/ext2fs/initialize.c
> +++ b/lib/ext2fs/initialize.c
> @@ -285,16 +285,18 @@ retry:
>
> if (ext2fs_has_feature_64bit(super) &&
> (ext2fs_blocks_count(super) / i) > (1ULL << 32))
> - set_field(s_inodes_count, ~0U);
> + ext2fs_set_inodes_count(super, ~0U);
> else
> - set_field(s_inodes_count, ext2fs_blocks_count(super) / i);
> + ext2fs_set_inodes_count(super, ext2fs_get_inodes_count(param) ?
> + ext2fs_get_inodes_count(param) :
> + ext2fs_blocks_count(super) / i);
>
> /*
> * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
> * that we have enough inodes for the filesystem(!)
> */
> - if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
> - super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
> + if (ext2fs_get_inodes_count(super) < EXT2_FIRST_INODE(super)+1)
> + ext2fs_set_inodes_count(super, EXT2_FIRST_INODE(super)+1);

(style) space around those '+'

> @@ -355,9 +358,9 @@ ipg_retry:
> ipg--;
> goto ipg_retry;
> }
> - super->s_inodes_count = super->s_inodes_per_group *
> - fs->group_desc_count;
> - super->s_free_inodes_count = super->s_inodes_count;
> + ext2fs_set_inodes_count(super, (ext2_ino64_t)super->s_inodes_per_group *
> + fs->group_desc_count);

(style) align continued line after '(' on previous line

> diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
> index b9d8f557..b7c01005 100644
> --- a/lib/ext2fs/swapfs.c
> +++ b/lib/ext2fs/swapfs.c
> @@ -26,10 +26,12 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
> {
> int i;
> sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count);
> + sb->s_inodes_count_hi = ext2fs_swab32(sb->s_inodes_count_hi);
> sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count);
> sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count);
> sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count);
> sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count);
> + sb->s_free_inodes_count_hi = ext2fs_swab32(sb->s_free_inodes_count_hi);
> sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block);
> sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size);
> sb->s_log_cluster_size = ext2fs_swab32(sb->s_log_cluster_size);

(style) this should be consistent with the rest of the function, and swab
these new fields in ext2_super_block offset order (i.e. at the end)

> diff --git a/lib/ext2fs/tst_super_size.c b/lib/ext2fs/tst_super_size.c
> index 0adac411..e3dc608a 100644
> --- a/lib/ext2fs/tst_super_size.c
> +++ b/lib/ext2fs/tst_super_size.c
> @@ -142,7 +142,10 @@ int main(int argc, char **argv)
> check_field(s_lpf_ino, 4);
> check_field(s_prj_quota_inum, 4);
> check_field(s_checksum_seed, 4);
> - check_field(s_reserved, 98 * 4);
> + check_field(s_inodes_count_hi, 4);
> + check_field(s_free_inodes_count_hi, 4);
> + check_field(s_prj_quota_inum_hi, 4);
> + check_field(s_reserved, 93 * 4);

> check_field(s_checksum, 4);
> do_field("Superblock end", 0, 0, cur_offset, 1024);

This test should have failed, since 98 - 3 = 95, and the superblock
size was no longer 1024 bytes. You should run "make check" after
every patch in your series to catch problems like this.

> diff --git a/misc/mke2fs.c b/misc/mke2fs.c
> index 1edc0cd1..64102b79 100644
> --- a/misc/mke2fs.c
> +++ b/misc/mke2fs.c
> @@ -2476,10 +2479,14 @@ profile_error:
> /*
> * Calculate number of inodes based on the inode ratio
> */
> - fs_param.s_inodes_count = num_inodes ? num_inodes :
> - (ext2fs_blocks_count(&fs_param) * blocksize) / inode_ratio;
> + if (num_inodes == 0)
> + num_inodes = (ext2fs_blocks_count(&fs_param) * blocksize) /
> + inode_ratio;
>
> - if ((((unsigned long long)fs_param.s_inodes_count) *
> + ext2fs_set_inodes_count(&fs_param, num_inodes);
> +
> +

(style) two empty lines here

Should this set FEATURE_INCOMPAT_INODE64 if num_inodes >= 2^32, or is
that handled internally if more than 2^32 inodes are created? Same
for setting the DIRDATA feature.


I know for block count that we rounded the block count down to 2^32-1
if it was only a little bit higher (e.g. less than 1M inodes over), so
that we didn't introduce an incompatible feature if it wasn't needed.

> diff --git a/misc/tune2fs.c b/misc/tune2fs.c
> index 44dd41a5..3538ab9c 100644
> --- a/misc/tune2fs.c
> +++ b/misc/tune2fs.c
> @@ -2614,21 +2615,22 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
> group = 0;
>
> /* Protect loop from wrap-around if s_inodes_count maxed */
> - for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
> + for (ino = 1;
> + ino <= ext2fs_get_inodes_count(fs->super) && ino > 0; ino++) {
> if (!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
> group_free++;
> total_free++;
> }
> count++;
> if ((count == fs->super->s_inodes_per_group) ||
> - (ino == fs->super->s_inodes_count)) {
> + (ino == ext2fs_get_inodes_count(fs->super))) {
> ext2fs_bg_free_inodes_count_set(fs, group++,
> group_free);
> count = 0;
> group_free = 0;
> }
> }
> - fs->super->s_free_inodes_count = total_free;
> + ext2fs_set_free_inodes_count(fs->super, total_free);
> ext2fs_mark_super_dirty(fs);
> return 0;
> }

The tune2fs code should check and prevent the INODE64 and DIRDATA features
from being cleared if the filesystem has more than 2^32 inodes.


This patch adds support for tools to accept the INODE64 feature, but I don't
see anywhere in this patch that adds the 64-bit inode numbers to the dirent
using EXT2_DIRENT_INODE64. That means if these patches landed without the
dirent support then e2fsck would probably corrupt the filesystem. That
means that EXT2_FEATURE_INCOMPAT_INODE64 shouldn't be added to the list of
supported features until the rest of the functionality is complete.

Cheers, Andreas






Attachments:
signature.asc (195.00 B)
Message signed with OpenPGP