From 7e84359f60250be357ed15a1fa626b2e9e2e2dfd Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 7 Jan 2021 15:59:17 -0500 Subject: [PATCH 1/8] xfs: refactor data device extent validation Source kernel commit: 67457eb0d225521a0e81327aef808cd0f9075880 Refactor all the open-coded validation of non-static data device extents into a single helper. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Eric Sandeen Signed-off-by: Ferry Meng --- libxfs/xfs_bmap.c | 8 ++------ libxfs/xfs_types.c | 23 +++++++++++++++++++++++ libxfs/xfs_types.h | 2 ++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c index e0ca8b05..b25e32d4 100644 --- a/libxfs/xfs_bmap.c +++ b/libxfs/xfs_bmap.c @@ -6230,12 +6230,8 @@ xfs_bmap_validate_extent( if (!xfs_verify_rtbno(mp, endfsb)) return __this_address; } else { - if (!xfs_verify_fsbno(mp, irec->br_startblock)) - return __this_address; - if (!xfs_verify_fsbno(mp, endfsb)) - return __this_address; - if (XFS_FSB_TO_AGNO(mp, irec->br_startblock) != - XFS_FSB_TO_AGNO(mp, endfsb)) + if (!xfs_verify_fsbext(mp, irec->br_startblock, + irec->br_blockcount)) return __this_address; } if (irec->br_state != XFS_EXT_NORM && whichfork != XFS_DATA_FORK) diff --git a/libxfs/xfs_types.c b/libxfs/xfs_types.c index fa113727..3e6921e0 100644 --- a/libxfs/xfs_types.c +++ b/libxfs/xfs_types.c @@ -61,6 +61,29 @@ xfs_verify_fsbno( return xfs_verify_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno)); } +/* + * Verify that a data device extent is fully contained inside the filesystem, + * does not cross an AG boundary, and does not point at static metadata. + */ +bool +xfs_verify_fsbext( + struct xfs_mount *mp, + xfs_fsblock_t fsbno, + xfs_fsblock_t len) +{ + if (fsbno + len <= fsbno) + return false; + + if (!xfs_verify_fsbno(mp, fsbno)) + return false; + + if (!xfs_verify_fsbno(mp, fsbno + len - 1)) + return false; + + return XFS_FSB_TO_AGNO(mp, fsbno) == + XFS_FSB_TO_AGNO(mp, fsbno + len - 1); +} + /* Calculate the first and last possible inode number in an AG. */ void xfs_agino_range( diff --git a/libxfs/xfs_types.h b/libxfs/xfs_types.h index 397d9477..7feaaac2 100644 --- a/libxfs/xfs_types.h +++ b/libxfs/xfs_types.h @@ -184,6 +184,8 @@ xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno); bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno); bool xfs_verify_fsbno(struct xfs_mount *mp, xfs_fsblock_t fsbno); +bool xfs_verify_fsbext(struct xfs_mount *mp, xfs_fsblock_t fsbno, + xfs_fsblock_t len); void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t *first, xfs_agino_t *last); -- Gitee From 5e779a76d0a627b4e8e7c897d8ee31d7699b2ce7 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 4 Apr 2022 11:29:34 -0700 Subject: [PATCH 2/8] mkfs: fix missing validation of -l size against maximum internal log size If a sysadmin specifies a log size explicitly, we don't actually check that against the maximum internal log size that we compute for the default log size computation. We're going to add more validation soon, so refactor the max internal log blocks into a common variable and add a check. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Ferry Meng Reviewed-by: Joseph Qi --- mkfs/xfs_mkfs.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 0581843f..8c94bdf8 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3246,6 +3246,7 @@ calculate_log_size( { struct xfs_sb *sbp = &mp->m_sb; int min_logblocks; + int max_logblocks; /* absolute max for this AG */ struct xfs_mount mount; /* we need a temporary mount to calculate the minimum log size. */ @@ -3285,6 +3286,18 @@ _("external log device size %lld blocks too small, must be at least %lld blocks\ return; } + /* + * Make sure the log fits wholly within an AG + * + * XXX: If agf->freeblks ends up as 0 because the log uses all + * the free space, it causes the kernel all sorts of problems + * with per-ag reservations. Right now just back it off one + * block, but there's a whole can of worms here that needs to be + * opened to decide what is the valid maximum size of a log in + * an AG. + */ + max_logblocks = libxfs_alloc_ag_max_usable(mp) - 1; + /* internal log - if no size specified, calculate automatically */ if (!cfg->logblocks) { if (cfg->dblocks < GIGABYTES(1, cfg->blocklog)) { @@ -3310,21 +3323,9 @@ _("external log device size %lld blocks too small, must be at least %lld blocks\ cfg->logblocks = cfg->logblocks >> cfg->blocklog; } - /* Ensure the chosen size meets minimum log size requirements */ + /* Ensure the chosen size fits within log size requirements */ cfg->logblocks = max(min_logblocks, cfg->logblocks); - - /* - * Make sure the log fits wholly within an AG - * - * XXX: If agf->freeblks ends up as 0 because the log uses all - * the free space, it causes the kernel all sorts of problems - * with per-ag reservations. Right now just back it off one - * block, but there's a whole can of worms here that needs to be - * opened to decide what is the valid maximum size of a log in - * an AG. - */ - cfg->logblocks = min(cfg->logblocks, - libxfs_alloc_ag_max_usable(mp) - 1); + cfg->logblocks = min(cfg->logblocks, max_logblocks); /* and now clamp the size to the maximum supported size */ cfg->logblocks = min(cfg->logblocks, XFS_MAX_LOG_BLOCKS); @@ -3332,6 +3333,13 @@ _("external log device size %lld blocks too small, must be at least %lld blocks\ cfg->logblocks = XFS_MAX_LOG_BYTES >> cfg->blocklog; validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); + } else if (cfg->logblocks > max_logblocks) { + /* check specified log size */ + fprintf(stderr, +_("internal log size %lld too large, must be less than %d\n"), + (long long)cfg->logblocks, + max_logblocks); + usage(); } if (cfg->logblocks > sbp->sb_agblocks - libxfs_prealloc_blocks(mp)) { -- Gitee From 4f977d3a3480dc301b72cf8c44861e4a3a5bd118 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 4 Apr 2022 10:10:24 -0700 Subject: [PATCH 3/8] mkfs: reduce internal log size when log stripe units are in play Currently, one can feed mkfs a combination of options like this: $ truncate -s 6366g /tmp/a ; mkfs.xfs -f /tmp/a -d agcount=3200 -d su=256k,sw=4 meta-data=/tmp/a isize=512 agcount=3200, agsize=521536 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=1, sparse=1, rmapbt=0 = reflink=1 bigtime=0 inobtcount=0 data = bsize=4096 blocks=1668808704, imaxpct=5 = sunit=64 swidth=256 blks naming =version 2 bsize=4096 ascii-ci=0, ftype=1 log =internal log bsize=4096 blocks=521536, version=2 = sectsz=512 sunit=64 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 Metadata corruption detected at 0x55e88052c6b6, xfs_agf block 0x1/0x200 libxfs_bwrite: write verifier failed on xfs_agf bno 0x1/0x1 mkfs.xfs: writing AG headers failed, err=117 The format fails because the internal log size sizing algorithm specifies a log size of 521492 blocks to avoid taking all the space in the AG, but align_log_size sees the stripe unit and rounds that up to the next stripe unit, which is 521536 blocks. Fix this problem by rounding the log size down if rounding up would result in a log that consumes more space in the AG than we allow. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Ferry Meng --- mkfs/xfs_mkfs.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 8c94bdf8..64a19490 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3151,9 +3151,10 @@ sb_set_features( static void align_log_size( struct mkfs_params *cfg, - int sunit) + int sunit, + int max_logblocks) { - uint64_t tmp_logblocks; + uint64_t tmp_logblocks; /* nothing to do if it's already aligned. */ if ((cfg->logblocks % sunit) == 0) @@ -3170,7 +3171,8 @@ _("log size %lld is not a multiple of the log stripe unit %d\n"), /* If the log is too large, round down instead of round up */ if ((tmp_logblocks > XFS_MAX_LOG_BLOCKS) || - ((tmp_logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES)) { + ((tmp_logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES) || + tmp_logblocks > max_logblocks) { tmp_logblocks = (cfg->logblocks / sunit) * sunit; } cfg->logblocks = tmp_logblocks; @@ -3184,7 +3186,8 @@ static void align_internal_log( struct mkfs_params *cfg, struct xfs_mount *mp, - int sunit) + int sunit, + int max_logblocks) { uint64_t logend; @@ -3202,7 +3205,7 @@ _("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n" } /* round up/down the log size now */ - align_log_size(cfg, sunit); + align_log_size(cfg, sunit, max_logblocks); /* check the aligned log still starts and ends in the same AG. */ logend = cfg->logstart + cfg->logblocks - 1; @@ -3280,7 +3283,7 @@ _("external log device size %lld blocks too small, must be at least %lld blocks\ cfg->logstart = 0; cfg->logagno = 0; if (cfg->lsunit) - align_log_size(cfg, cfg->lsunit); + align_log_size(cfg, cfg->lsunit, XFS_MAX_LOG_BLOCKS); validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); return; @@ -3368,9 +3371,9 @@ _("log ag number %lld too large, must be less than %lld\n"), * Align the logstart at stripe unit boundary. */ if (cfg->lsunit) { - align_internal_log(cfg, mp, cfg->lsunit); + align_internal_log(cfg, mp, cfg->lsunit, max_logblocks); } else if (cfg->dsunit) { - align_internal_log(cfg, mp, cfg->dsunit); + align_internal_log(cfg, mp, cfg->dsunit, max_logblocks); } validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); } -- Gitee From fd421160515ed875f8221e52dfebebf06c1c4659 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 11 Mar 2022 17:32:02 -0800 Subject: [PATCH 4/8] mkfs: don't let internal logs bump the root dir inode chunk to AG 1 Currently, we don't let an internal log consume every last block in an AG. According to the comment, we're doing this to avoid tripping AGF verifiers if freeblks==0, but on a modern filesystem this isn't sufficient to avoid problems because we need to have enough space in the AG to allocate an aligned root inode chunk, if it should be the case that the log also ends up in AG 0: $ truncate -s 6366g /tmp/a ; mkfs.xfs -f /tmp/a -d agcount=3200 -l agnum=0 meta-data=/tmp/a isize=512 agcount=3200, agsize=521503 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=1, sparse=1, rmapbt=0 = reflink=1 bigtime=0 inobtcount=0 data = bsize=4096 blocks=1668808704, imaxpct=5 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0, ftype=1 log =internal log bsize=4096 blocks=521492, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 mkfs.xfs: root inode created in AG 1, not AG 0 Therefore, modify the maximum internal log size calculation to constrain the maximum internal log size so that the aligned inode chunk allocation will always succeed. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Ferry Meng Reviewed-by: Joseph Qi --- mkfs/xfs_mkfs.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 64a19490..3c5b6f3c 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3241,6 +3241,49 @@ validate_log_size(uint64_t logblocks, int blocklog, int min_logblocks) } } +static void +adjust_ag0_internal_logblocks( + struct mkfs_params *cfg, + struct xfs_mount *mp, + int min_logblocks, + int *max_logblocks) +{ + int backoff = 0; + int ichunk_blocks; + + /* + * mkfs will trip over the write verifiers if the log is allocated in + * AG 0 and consumes enough space that we cannot allocate a non-sparse + * inode chunk for the root directory. The inode allocator requires + * that the AG have enough free space for the chunk itself plus enough + * to fix up the freelist with aligned blocks if we need to fill the + * allocation from the AGFL. + */ + ichunk_blocks = XFS_INODES_PER_CHUNK * cfg->inodesize >> cfg->blocklog; + backoff = ichunk_blocks * 4; + + /* + * We try to align inode allocations to the data device stripe unit, + * so ensure there's enough space to perform an aligned allocation. + * The inode geometry structure isn't set up yet, so compute this by + * hand. + */ + backoff = max(backoff, cfg->dsunit * 2); + + *max_logblocks -= backoff; + + /* If the specified log size is too big, complain. */ + if (cli_opt_set(&lopts, L_SIZE) && cfg->logblocks > *max_logblocks) { + fprintf(stderr, +_("internal log size %lld too large, must be less than %d\n"), + (long long)cfg->logblocks, + *max_logblocks); + usage(); + } + + cfg->logblocks = min(cfg->logblocks, *max_logblocks); +} + static void calculate_log_size( struct mkfs_params *cfg, @@ -3364,6 +3407,10 @@ _("log ag number %lld too large, must be less than %lld\n"), } else cfg->logagno = (xfs_agnumber_t)(sbp->sb_agcount / 2); + if (cfg->logagno == 0) + adjust_ag0_internal_logblocks(cfg, mp, min_logblocks, + &max_logblocks); + cfg->logstart = XFS_AGB_TO_FSB(mp, cfg->logagno, libxfs_prealloc_blocks(mp)); -- Gitee From 7374106f0474657636ab061dd68cd6bacfdd2baf Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 14 Apr 2022 13:29:37 -0700 Subject: [PATCH 5/8] mkfs: improve log extent validation Use the standard libxfs fsblock verifiers to check the start and end of the internal log. The current code does not catch the case of a (segmented) fsblock that is beyond agf_blocks but not so large to change the agno part of the segmented fsblock. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Ferry Meng --- libxfs/libxfs_api_defs.h | 1 + mkfs/xfs_mkfs.c | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 9492955d..a0cb756a 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -195,6 +195,7 @@ #define xfs_verify_agino libxfs_verify_agino #define xfs_verify_cksum libxfs_verify_cksum #define xfs_verify_dir_ino libxfs_verify_dir_ino +#define xfs_verify_fsbext libxfs_verify_fsbext #define xfs_verify_fsbno libxfs_verify_fsbno #define xfs_verify_ino libxfs_verify_ino #define xfs_verify_rtbno libxfs_verify_rtbno diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 3c5b6f3c..370c0dcb 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3189,15 +3189,13 @@ align_internal_log( int sunit, int max_logblocks) { - uint64_t logend; - /* round up log start if necessary */ if ((cfg->logstart % sunit) != 0) cfg->logstart = ((cfg->logstart + (sunit - 1)) / sunit) * sunit; /* If our log start overlaps the next AG's metadata, fail. */ - if (XFS_FSB_TO_AGBNO(mp, cfg->logstart) <= XFS_AGFL_BLOCK(mp)) { - fprintf(stderr, + if (!libxfs_verify_fsbno(mp, cfg->logstart)) { + fprintf(stderr, _("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n" "within an allocation group.\n"), (long long) cfg->logstart); @@ -3208,8 +3206,7 @@ _("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n" align_log_size(cfg, sunit, max_logblocks); /* check the aligned log still starts and ends in the same AG. */ - logend = cfg->logstart + cfg->logblocks - 1; - if (XFS_FSB_TO_AGNO(mp, cfg->logstart) != XFS_FSB_TO_AGNO(mp, logend)) { + if (!libxfs_verify_fsbext(mp, cfg->logstart, cfg->logblocks)) { fprintf(stderr, _("Due to stripe alignment, the internal log size (%lld) is too large.\n" "Must fit within an allocation group.\n"), @@ -3447,6 +3444,7 @@ start_superblock_setup( sbp->sb_agblocks = (xfs_agblock_t)cfg->agsize; sbp->sb_agblklog = (uint8_t)log2_roundup(cfg->agsize); sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount; + sbp->sb_dblocks = (xfs_rfsblock_t)cfg->dblocks; sbp->sb_inodesize = (uint16_t)cfg->inodesize; sbp->sb_inodelog = (uint8_t)cfg->inodelog; -- Gitee From 75421026425013a5601c899d2aca89d180853111 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 14 Apr 2022 13:32:32 -0700 Subject: [PATCH 6/8] mkfs: round log size down if rounding log start up causes overflow If rounding the log start up to the next stripe unit would cause the log to overrun the end of the AG, round the log size down by a stripe unit. We already ensured that logblocks was small enough to fit inside the AG, so the minor adjustment should suffice. This can be reproduced with: mkfs.xfs -dsu=44k,sw=1,size=300m,file,name=fsfile -m rmapbt=0 and: mkfs.xfs -dsu=48k,sw=1,size=512m,file,name=fsfile -m rmapbt=0 Reported-by: Eric Sandeen Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Ferry Meng --- mkfs/xfs_mkfs.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 370c0dcb..beeb70f3 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3205,6 +3205,15 @@ _("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n" /* round up/down the log size now */ align_log_size(cfg, sunit, max_logblocks); + /* + * If the end of the log has been rounded past the end of the AG, + * reduce logblocks by a stripe unit to try to get it back under EOAG. + */ + if (!libxfs_verify_fsbext(mp, cfg->logstart, cfg->logblocks) && + cfg->logblocks > sunit) { + cfg->logblocks -= sunit; + } + /* check the aligned log still starts and ends in the same AG. */ if (!libxfs_verify_fsbext(mp, cfg->logstart, cfg->logblocks)) { fprintf(stderr, -- Gitee From 4d6cd5c34b713465463ecb36455864d158a362ac Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 13 Jul 2022 20:58:28 -0500 Subject: [PATCH 7/8] mkfs: terminate getsubopt arrays properly Having not drank any (or maybe too much) coffee this morning, I typed: $ mkfs.xfs -d agcount=3 -d nrext64=0 Segmentation fault I traced this down to getsubopt walking off the end of the dopts.subopts array. The manpage says you're supposed to terminate the suboptions string array with a NULL entry, but the structure definition uses MAX_SUBOPTS/D_MAX_OPTS directly, which means there is no terminator. Explicitly terminate each suboption array with a NULL entry after making room for it. Signed-off-by: Darrick J. Wong [sandeen: explicitly add NULL terminators & clarify comment] Reviewed-by: Eric Sandeen Signed-off-by: Eric Sandeen Signed-off-by: Ferry Meng Reviewed-by: Joseph Qi --- mkfs/xfs_mkfs.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index beeb70f3..ecd13fca 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -130,8 +130,11 @@ enum { M_MAX_OPTS, }; -/* Just define the max options array size manually right now */ -#define MAX_SUBOPTS D_MAX_OPTS +/* + * Just define the max options array size manually to the largest + * enum right now, leaving room for a NULL terminator at the end + */ +#define MAX_SUBOPTS (D_MAX_OPTS + 1) #define SUBOPT_NEEDS_VAL (-1LL) #define MAX_CONFLICTS 8 @@ -241,6 +244,7 @@ static struct opt_params bopts = { .ini_section = "block", .subopts = { [B_SIZE] = "size", + [B_MAX_OPTS] = NULL, }, .subopt_params = { { .index = B_SIZE, @@ -267,6 +271,7 @@ static struct opt_params copts = { .name = 'c', .subopts = { [C_OPTFILE] = "options", + [C_MAX_OPTS] = NULL, }, .subopt_params = { { .index = C_OPTFILE, @@ -296,6 +301,7 @@ static struct opt_params dopts = { [D_EXTSZINHERIT] = "extszinherit", [D_COWEXTSIZE] = "cowextsize", [D_DAXINHERIT] = "daxinherit", + [D_MAX_OPTS] = NULL, }, .subopt_params = { { .index = D_AGCOUNT, @@ -432,6 +438,7 @@ static struct opt_params iopts = { [I_ATTR] = "attr", [I_PROJID32BIT] = "projid32bit", [I_SPINODES] = "sparse", + [I_MAX_OPTS] = NULL, }, .subopt_params = { { .index = I_ALIGN, @@ -498,6 +505,7 @@ static struct opt_params lopts = { [L_FILE] = "file", [L_NAME] = "name", [L_LAZYSBCNTR] = "lazy-count", + [L_MAX_OPTS] = NULL, }, .subopt_params = { { .index = L_AGNUM, @@ -590,6 +598,7 @@ static struct opt_params nopts = { [N_SIZE] = "size", [N_VERSION] = "version", [N_FTYPE] = "ftype", + [N_MAX_OPTS] = NULL, }, .subopt_params = { { .index = N_SIZE, @@ -625,6 +634,7 @@ static struct opt_params ropts = { [R_FILE] = "file", [R_NAME] = "name", [R_NOALIGN] = "noalign", + [R_MAX_OPTS] = NULL, }, .subopt_params = { { .index = R_EXTSIZE, @@ -672,6 +682,7 @@ static struct opt_params sopts = { .subopts = { [S_SIZE] = "size", [S_SECTSIZE] = "sectsize", + [S_MAX_OPTS] = NULL, }, .subopt_params = { { .index = S_SIZE, @@ -708,6 +719,7 @@ static struct opt_params mopts = { [M_REFLINK] = "reflink", [M_INOBTCNT] = "inobtcount", [M_BIGTIME] = "bigtime", + [M_MAX_OPTS] = NULL, }, .subopt_params = { { .index = M_CRC, -- Gitee From 768a8c511e1f2e43a5da7fe9e3ccf75aec836178 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 13 Jul 2022 20:58:25 -0500 Subject: [PATCH 8/8] xfs_repair: ignore empty xattr leaf blocks As detailed in the commit: 5e572d1a xfs: empty xattr leaf header blocks are not corruption empty xattr leaf blocks can be the benign byproduct of the system going down during the multi-step process of adding a large xattr to a file that has no xattrs. If we find one at attr fork offset 0, we should clear it, but this isn't a corruption. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Signed-off-by: Eric Sandeen Signed-off-by: Ferry Meng Reviewed-by: Joseph Qi --- repair/attr_repair.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/repair/attr_repair.c b/repair/attr_repair.c index ba39c2b5..090b5cae 100644 --- a/repair/attr_repair.c +++ b/repair/attr_repair.c @@ -579,6 +579,26 @@ process_leaf_attr_block( firstb = mp->m_sb.sb_blocksize; stop = xfs_attr3_leaf_hdr_size(leaf); + /* + * Empty leaf blocks at offset zero can occur as a race between + * setxattr and the system going down, so we only take action if we're + * running in modify mode. See xfs_attr3_leaf_verify for details of + * how we've screwed this up many times. + */ + if (!leafhdr.count && da_bno == 0) { + if (no_modify) { + do_log( + _("would clear empty leaf attr block 0, inode %" PRIu64 "\n"), + ino); + return 0; + } + + do_warn( + _("will clear empty leaf attr block 0, inode %" PRIu64 "\n"), + ino); + return 1; + } + /* does the count look sorta valid? */ if (!leafhdr.count || leafhdr.count * sizeof(xfs_attr_leaf_entry_t) + stop > -- Gitee