Hello community, here is the log from the commit of package xfsprogs for openSUSE:Leap:15.2 checked in at 2020-02-27 06:41:31 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/xfsprogs (Old) and /work/SRC/openSUSE:Leap:15.2/.xfsprogs.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "xfsprogs" Thu Feb 27 06:41:31 2020 rev:35 rq:779123 version:4.15.0 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/xfsprogs/xfsprogs.changes 2020-01-15 16:30:40.772829703 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.xfsprogs.new.26092/xfsprogs.changes 2020-02-27 06:41:32.565614533 +0100 @@ -1,0 +2,28 @@ +Tue Jan 28 14:22:35 UTC 2020 - Anthony Iliopoulos <ailiopou...@suse.com> + +- mkfs.xfs: validate extent size hint parameters (bsc#1158509) + * Add xfsprogs-mkfs-validate-extent-size-hint-parameters.patch + * Add xfsprogs-xfs-move-inode-extent-size-hint-validation-to-libxfs.patch + * Add xfsprogs-xfs_repair-use-libxfs-extsize-cowextsize-validation-.patch + +------------------------------------------------------------------- +Sun Jan 5 16:24:49 UTC 2020 - Anthony Iliopoulos <ailiopou...@suse.com> + +- xfs_repair: don't fail recovery of orphaned shortform directories + (bsc#1158504) + * Add xfsprogs-xfs-create-structure-verifier-function-for-short-for.patch + * Add xfsprogs-xfs-create-structure-verifier-function-for-shortform.patch + * Add xfsprogs-xfs-provide-a-centralized-method-for-verifying-inlin.patch + * Add xfsprogs-xfs-refactor-short-form-directory-structure-verifier.patch + * Add xfsprogs-xfs_repair-don-t-fail-directory-repairs-when-grabbin.patch + * Add xfsprogs-xfs_repair-implement-custom-ifork-verifiers.patch + * Add xfsprogs-xfs_repair-use-custom-ifork-verifier-in-mv_orphanage.patch + +------------------------------------------------------------------- +Sun Jan 5 12:38:16 UTC 2020 - Anthony Iliopoulos <ailiopou...@suse.com> + +- xfs_quota: fix false error reporting of project inheritance flag is + not set (bsc#1158758) + * Add xfsprogs-xfs_quota-fix-false-error-reporting-of-project-inher.patch + +------------------------------------------------------------------- New: ---- xfsprogs-mkfs-validate-extent-size-hint-parameters.patch xfsprogs-xfs-create-structure-verifier-function-for-short-for.patch xfsprogs-xfs-create-structure-verifier-function-for-shortform.patch xfsprogs-xfs-move-inode-extent-size-hint-validation-to-libxfs.patch xfsprogs-xfs-provide-a-centralized-method-for-verifying-inlin.patch xfsprogs-xfs-refactor-short-form-directory-structure-verifier.patch xfsprogs-xfs_quota-fix-false-error-reporting-of-project-inher.patch xfsprogs-xfs_repair-don-t-fail-directory-repairs-when-grabbin.patch xfsprogs-xfs_repair-implement-custom-ifork-verifiers.patch xfsprogs-xfs_repair-use-custom-ifork-verifier-in-mv_orphanage.patch xfsprogs-xfs_repair-use-libxfs-extsize-cowextsize-validation-.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ xfsprogs.spec ++++++ --- /var/tmp/diff_new_pack.yDFEc9/_old 2020-02-27 06:41:33.145615740 +0100 +++ /var/tmp/diff_new_pack.yDFEc9/_new 2020-02-27 06:41:33.149615749 +0100 @@ -46,6 +46,18 @@ Patch13: xfsprogs-mkfs-use-geometry-generation-helper-functions.patch Patch14: xfsprogs-xfs_info-call-xfs_db-for-offline-filesystems.patch Patch15: xfsprogs-xfs_info-use-findmnt-to-handle-mounted-block-devices.patch +Patch16: xfsprogs-xfs_quota-fix-false-error-reporting-of-project-inher.patch +Patch17: xfsprogs-xfs-create-structure-verifier-function-for-shortform.patch +Patch18: xfsprogs-xfs-create-structure-verifier-function-for-short-for.patch +Patch19: xfsprogs-xfs-refactor-short-form-directory-structure-verifier.patch +Patch20: xfsprogs-xfs-provide-a-centralized-method-for-verifying-inlin.patch +Patch21: xfsprogs-xfs_repair-don-t-fail-directory-repairs-when-grabbin.patch +Patch22: xfsprogs-xfs_repair-implement-custom-ifork-verifiers.patch +Patch23: xfsprogs-xfs_repair-use-custom-ifork-verifier-in-mv_orphanage.patch +Patch24: xfsprogs-xfs-move-inode-extent-size-hint-validation-to-libxfs.patch +Patch25: xfsprogs-xfs_repair-use-libxfs-extsize-cowextsize-validation-.patch +Patch26: xfsprogs-mkfs-validate-extent-size-hint-parameters.patch + BuildRequires: autoconf BuildRequires: automake BuildRequires: libblkid-devel @@ -109,6 +121,17 @@ %patch13 -p1 %patch14 -p1 %patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 %endif %build ++++++ xfsprogs-mkfs-validate-extent-size-hint-parameters.patch ++++++ >From 5786ad73fc1640239c7f08c8f705be48ea3aa04b Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.w...@oracle.com> Date: Thu, 18 Apr 2019 13:19:39 -0500 Subject: [PATCH] mkfs: validate extent size hint parameters Git-commit: 9cfe71bae43451bf5cc6b6688b94c88336e1ea00 Patch-mainline: v5.0.0-rc1 References: bsc#1158509 Validate extent and cow extent size hints that are passed to mkfs so that we avoid formatting a filesystem that will never mount. Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com> Reviewed-by: Eric Sandeen <sand...@redhat.com> [sandeen: use DIFLAG macros for now to be consistent, fixed later] Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- mkfs/xfs_mkfs.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 050381f4..b2bfec26 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -2208,6 +2208,85 @@ validate_rtextsize( ASSERT(cfg->rtextblocks); } +/* Validate the incoming extsize hint. */ +static void +validate_extsize_hint( + struct xfs_mount *mp, + struct cli_params *cli) +{ + xfs_failaddr_t fa; + uint16_t flags = 0; + + /* + * First we validate the extent size inherit hint on a directory so + * that we know that we'll be propagating a correct hint and flag to + * new files on the data device. + */ + if (cli->fsx.fsx_xflags & XFS_DIFLAG_EXTSZINHERIT) + flags |= XFS_DIFLAG_EXTSZINHERIT; + + fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFDIR, + flags); + if (fa) { + fprintf(stderr, +_("illegal extent size hint %lld, must be less than %u.\n"), + (long long)cli->fsx.fsx_extsize, + min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2)); + usage(); + } + + /* + * Now we do it again with a realtime file so that we know the hint and + * flag that get passed on to realtime files will be correct. + */ + if (mp->m_sb.sb_rextsize == 0) + return; + + flags = XFS_DIFLAG_REALTIME; + if (cli->fsx.fsx_xflags & XFS_DIFLAG_EXTSIZE) + flags |= XFS_DIFLAG_EXTSIZE; + + fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFREG, + flags); + + if (fa) { + fprintf(stderr, +_("illegal extent size hint %lld, must be less than %u and a multiple of %u.\n"), + (long long)cli->fsx.fsx_extsize, + min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2), + mp->m_sb.sb_rextsize); + usage(); + } +} + +/* Validate the incoming CoW extsize hint. */ +static void +validate_cowextsize_hint( + struct xfs_mount *mp, + struct cli_params *cli) +{ + xfs_failaddr_t fa; + uint64_t flags2 = 0; + + /* + * Validate the copy on write extent size inherit hint on a directory + * so that we know that we'll be propagating a correct hint and flag to + * new files on the data device. + */ + if (cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) + flags2 |= XFS_DIFLAG2_COWEXTSIZE; + + fa = libxfs_inode_validate_cowextsize(mp, cli->fsx.fsx_cowextsize, + S_IFDIR, 0, flags2); + if (fa) { + fprintf(stderr, +_("illegal CoW extent size hint %lld, must be less than %u.\n"), + (long long)cli->fsx.fsx_cowextsize, + min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2)); + usage(); + } +} + /* * Validate the configured stripe geometry, or is none is specified, pull * the configuration from the underlying device. @@ -3944,6 +4023,10 @@ main( finish_superblock_setup(&cfg, mp, sbp); + /* Validate the extent size hints now that @mp is fully set up. */ + validate_extsize_hint(mp, &cli); + validate_cowextsize_hint(mp, &cli); + /* Print the intended geometry of the fs. */ if (!quiet || dry_run) { struct xfs_fsop_geom geo; -- 2.16.4 ++++++ xfsprogs-xfs-create-structure-verifier-function-for-short-for.patch ++++++ >From 31337a6ef7d39381f0407620cbcc0b82ea6ac6be Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.w...@oracle.com> Date: Mon, 26 Feb 2018 22:43:17 -0600 Subject: [PATCH] xfs: create structure verifier function for short form symlinks Git-commit: 6db3a8007a2493d6887cf45a5edfaa6a770b8492 Patch-mainline: v4.16.0-rc1 References: bsc#1158504 Source kernel commit: 0795e004fd4f2723f3dbf09a195cd7ccf3c74c58 Create a function to check the structure of short form symlink targets. Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com> Reviewed-by: Dave Chinner <dchin...@redhat.com> Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- libxfs/xfs_shared.h | 1 + libxfs/xfs_symlink_remote.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/libxfs/xfs_shared.h b/libxfs/xfs_shared.h index c6f4eb4..67ccb1a 100644 --- a/libxfs/xfs_shared.h +++ b/libxfs/xfs_shared.h @@ -143,5 +143,6 @@ bool xfs_symlink_hdr_ok(xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp); void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *ip, struct xfs_ifork *ifp); +xfs_failaddr_t xfs_symlink_shortform_verify(struct xfs_inode *ip); #endif /* __XFS_SHARED_H__ */ diff --git a/libxfs/xfs_symlink_remote.c b/libxfs/xfs_symlink_remote.c index d638530..5a7afd3 100644 --- a/libxfs/xfs_symlink_remote.c +++ b/libxfs/xfs_symlink_remote.c @@ -203,3 +203,37 @@ xfs_symlink_local_to_remote( xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) + ifp->if_bytes - 1); } + +/* Verify the consistency of an inline symlink. */ +xfs_failaddr_t +xfs_symlink_shortform_verify( + struct xfs_inode *ip) +{ + char *sfp; + char *endp; + struct xfs_ifork *ifp; + int size; + + ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL); + ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); + sfp = (char *)ifp->if_u1.if_data; + size = ifp->if_bytes; + endp = sfp + size; + + /* Zero length symlinks can exist while we're deleting a remote one. */ + if (size == 0) + return NULL; + + /* No negative sizes or overly long symlink targets. */ + if (size < 0 || size > XFS_SYMLINK_MAXLEN) + return __this_address; + + /* No NULLs in the target either. */ + if (memchr(sfp, 0, size - 1)) + return __this_address; + + /* We /did/ null-terminate the buffer, right? */ + if (*endp != 0) + return __this_address; + return NULL; +} -- 2.16.4 ++++++ xfsprogs-xfs-create-structure-verifier-function-for-shortform.patch ++++++ >From 7b605756fd25385061e2e6c1d8f722e1d4f39aa8 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.w...@oracle.com> Date: Mon, 26 Feb 2018 22:43:17 -0600 Subject: [PATCH] xfs: create structure verifier function for shortform xattrs Git-commit: c7a710b7beeb21c5d84ab5e3c6a6aa9c96631fcc Patch-mainline: v4.16.0-rc1 References: bsc#1158504 Source kernel commit: 1e1bbd8e7ee0624034e9bf1e91ac11a7aaa2f8a6 Create a function to perform structure verification for short form extended attributes. Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com> Reviewed-by: Dave Chinner <dchin...@redhat.com> Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- libxfs/libxfs_priv.h | 1 + libxfs/util.c | 7 +++++ libxfs/xfs_attr_leaf.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_attr_leaf.h | 1 + 4 files changed, 83 insertions(+) diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 82ae2e9..082963b 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -525,5 +525,6 @@ bool xfs_log_check_lsn(struct xfs_mount *, xfs_lsn_t); #define XFS_STATS_ADD_OFF(mp, off, val) typedef unsigned char u8; +unsigned int hweight8(unsigned int w); #endif /* __LIBXFS_INTERNAL_XFS_H__ */ diff --git a/libxfs/util.c b/libxfs/util.c index 5f49b82..7e42fb1 100644 --- a/libxfs/util.c +++ b/libxfs/util.c @@ -812,3 +812,10 @@ libxfs_zero_extent( return libxfs_device_zero(xfs_find_bdev_for_inode(ip), sector, size); } +unsigned int +hweight8(unsigned int w) +{ + unsigned int res = w - ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res + (res >> 4)) & 0x0F; +} diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c index 2f24567..62cb035 100644 --- a/libxfs/xfs_attr_leaf.c +++ b/libxfs/xfs_attr_leaf.c @@ -865,6 +865,80 @@ xfs_attr_shortform_allfit( return xfs_attr_shortform_bytesfit(dp, bytes); } +/* Verify the consistency of an inline attribute fork. */ +xfs_failaddr_t +xfs_attr_shortform_verify( + struct xfs_inode *ip) +{ + struct xfs_attr_shortform *sfp; + struct xfs_attr_sf_entry *sfep; + struct xfs_attr_sf_entry *next_sfep; + char *endp; + struct xfs_ifork *ifp; + int i; + int size; + + ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL); + ifp = XFS_IFORK_PTR(ip, XFS_ATTR_FORK); + sfp = (struct xfs_attr_shortform *)ifp->if_u1.if_data; + size = ifp->if_bytes; + + /* + * Give up if the attribute is way too short. + */ + if (size < sizeof(struct xfs_attr_sf_hdr)) + return __this_address; + + endp = (char *)sfp + size; + + /* Check all reported entries */ + sfep = &sfp->list[0]; + for (i = 0; i < sfp->hdr.count; i++) { + /* + * struct xfs_attr_sf_entry has a variable length. + * Check the fixed-offset parts of the structure are + * within the data buffer. + */ + if (((char *)sfep + sizeof(*sfep)) >= endp) + return __this_address; + + /* Don't allow names with known bad length. */ + if (sfep->namelen == 0) + return __this_address; + + /* + * Check that the variable-length part of the structure is + * within the data buffer. The next entry starts after the + * name component, so nextentry is an acceptable test. + */ + next_sfep = XFS_ATTR_SF_NEXTENTRY(sfep); + if ((char *)next_sfep > endp) + return __this_address; + + /* + * Check for unknown flags. Short form doesn't support + * the incomplete or local bits, so we can use the namespace + * mask here. + */ + if (sfep->flags & ~XFS_ATTR_NSP_ONDISK_MASK) + return __this_address; + + /* + * Check for invalid namespace combinations. We only allow + * one namespace flag per xattr, so we can just count the + * bits (i.e. hweight) here. + */ + if (hweight8(sfep->flags & XFS_ATTR_NSP_ONDISK_MASK) > 1) + return __this_address; + + sfep = next_sfep; + } + if ((void *)sfep != (void *)endp) + return __this_address; + + return NULL; +} + /* * Convert a leaf attribute list to shortform attribute list */ diff --git a/libxfs/xfs_attr_leaf.h b/libxfs/xfs_attr_leaf.h index 894124e..4da08af 100644 --- a/libxfs/xfs_attr_leaf.h +++ b/libxfs/xfs_attr_leaf.h @@ -53,6 +53,7 @@ int xfs_attr_shortform_to_leaf(struct xfs_da_args *args, int xfs_attr_shortform_remove(struct xfs_da_args *args); int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes); +xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip); void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp); /* -- 2.16.4 ++++++ xfsprogs-xfs-move-inode-extent-size-hint-validation-to-libxfs.patch ++++++ >From 5365dcd5e7aacda2dac9d28cb9e3762789f77e03 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.w...@oracle.com> Date: Wed, 18 Apr 2018 14:46:07 -0500 Subject: [PATCH] xfs: move inode extent size hint validation to libxfs Git-commit: fd0c360d19c8c1e7235e3d3aa09b600553ddf6a1 Patch-mainline: v4.17.0-rc1 References: bsc#1158509 Source kernel commit: 8bb82bc12a9e75dd47047d9a2e53135cc5e5787b Extent size hint validation is used by scrub to decide if there's an error, and it will be used by repair to decide to remove the hint. Since these use the same validation functions, move them to libxfs. Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com> Reviewed-by: Brian Foster <bfos...@redhat.com> Signed-off-by: Eric Sandeen <sand...@redhat.com> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- libxfs/xfs_inode_buf.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_inode_buf.h | 5 +++ 2 files changed, 110 insertions(+) diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c index a3a5239b..8d3a818f 100644 --- a/libxfs/xfs_inode_buf.c +++ b/libxfs/xfs_inode_buf.c @@ -576,3 +576,108 @@ xfs_iread( xfs_trans_brelse(tp, bp); return error; } + +/* + * Validate di_extsize hint. + * + * The rules are documented at xfs_ioctl_setattr_check_extsize(). + * These functions must be kept in sync with each other. + */ +xfs_failaddr_t +xfs_inode_validate_extsize( + struct xfs_mount *mp, + uint32_t extsize, + uint16_t mode, + uint16_t flags) +{ + bool rt_flag; + bool hint_flag; + bool inherit_flag; + uint32_t extsize_bytes; + uint32_t blocksize_bytes; + + rt_flag = (flags & XFS_DIFLAG_REALTIME); + hint_flag = (flags & XFS_DIFLAG_EXTSIZE); + inherit_flag = (flags & XFS_DIFLAG_EXTSZINHERIT); + extsize_bytes = XFS_FSB_TO_B(mp, extsize); + + if (rt_flag) + blocksize_bytes = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog; + else + blocksize_bytes = mp->m_sb.sb_blocksize; + + if ((hint_flag || inherit_flag) && !(S_ISDIR(mode) || S_ISREG(mode))) + return __this_address; + + if (hint_flag && !S_ISREG(mode)) + return __this_address; + + if (inherit_flag && !S_ISDIR(mode)) + return __this_address; + + if ((hint_flag || inherit_flag) && extsize == 0) + return __this_address; + + if (!(hint_flag || inherit_flag) && extsize != 0) + return __this_address; + + if (extsize_bytes % blocksize_bytes) + return __this_address; + + if (extsize > MAXEXTLEN) + return __this_address; + + if (!rt_flag && extsize > mp->m_sb.sb_agblocks / 2) + return __this_address; + + return NULL; +} + +/* + * Validate di_cowextsize hint. + * + * The rules are documented at xfs_ioctl_setattr_check_cowextsize(). + * These functions must be kept in sync with each other. + */ +xfs_failaddr_t +xfs_inode_validate_cowextsize( + struct xfs_mount *mp, + uint32_t cowextsize, + uint16_t mode, + uint16_t flags, + uint64_t flags2) +{ + bool rt_flag; + bool hint_flag; + uint32_t cowextsize_bytes; + + rt_flag = (flags & XFS_DIFLAG_REALTIME); + hint_flag = (flags2 & XFS_DIFLAG2_COWEXTSIZE); + cowextsize_bytes = XFS_FSB_TO_B(mp, cowextsize); + + if (hint_flag && !xfs_sb_version_hasreflink(&mp->m_sb)) + return __this_address; + + if (hint_flag && !(S_ISDIR(mode) || S_ISREG(mode))) + return __this_address; + + if (hint_flag && cowextsize == 0) + return __this_address; + + if (!hint_flag && cowextsize != 0) + return __this_address; + + if (hint_flag && rt_flag) + return __this_address; + + if (cowextsize_bytes % mp->m_sb.sb_blocksize) + return __this_address; + + if (cowextsize > MAXEXTLEN) + return __this_address; + + if (cowextsize > mp->m_sb.sb_agblocks / 2) + return __this_address; + + return NULL; +} diff --git a/libxfs/xfs_inode_buf.h b/libxfs/xfs_inode_buf.h index a9c97a35..35161515 100644 --- a/libxfs/xfs_inode_buf.h +++ b/libxfs/xfs_inode_buf.h @@ -84,5 +84,10 @@ void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); bool xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino, struct xfs_dinode *dip); +xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp, + uint32_t extsize, uint16_t mode, uint16_t flags); +xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp, + uint32_t cowextsize, uint16_t mode, uint16_t flags, + uint64_t flags2); #endif /* __XFS_INODE_BUF_H__ */ -- 2.16.4 ++++++ xfsprogs-xfs-provide-a-centralized-method-for-verifying-inlin.patch ++++++ >From 08da938ab771dc644e48909dcba04b0223871546 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.w...@oracle.com> Date: Mon, 26 Feb 2018 22:43:17 -0600 Subject: [PATCH] xfs: provide a centralized method for verifying inline fork data Git-commit: 20e882d4fe6a7fdd0efbb61b3f10fb5b8ee8316a Patch-mainline: v4.16.0-rc1 References: bsc#1158504 Source kernel commit: 9cfb9b47479e237d217dbcfafe034cbf98f45909 Replace the current haphazard dir2 shortform verifier callsites with a centralized verifier function that can be called either with the default verifier functions or with a custom set. This helps us strengthen integrity checking while providing us with flexibility for repair tools. xfs_repair wants this to be able to supply its own verifier functions when trying to fix possibly corrupt metadata. Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com> Reviewed-by: Dave Chinner <dchin...@redhat.com> Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- include/xfs_inode.h | 1 + libxfs/rdwr.c | 33 +++++++++++++++++++++++++ libxfs/util.c | 6 ++--- libxfs/xfs_inode_fork.c | 64 +++++++++++++++++++++++++++++++++---------------- libxfs/xfs_inode_fork.h | 14 +++++++++++ 5 files changed, 94 insertions(+), 24 deletions(-) diff --git a/include/xfs_inode.h b/include/xfs_inode.h index 11a549e..92829a2 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -162,6 +162,7 @@ extern void libxfs_trans_ichgtime(struct xfs_trans *, extern int libxfs_iflush_int (struct xfs_inode *, struct xfs_buf *); /* Inode Cache Interfaces */ +extern bool libxfs_inode_verify_forks(struct xfs_inode *ip); extern int libxfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, uint, struct xfs_inode **); extern void libxfs_iput(struct xfs_inode *); diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c index 474e5eb..14afece 100644 --- a/libxfs/rdwr.c +++ b/libxfs/rdwr.c @@ -1336,6 +1336,34 @@ struct cache_operations libxfs_bcache_operations = { extern kmem_zone_t *xfs_ili_zone; extern kmem_zone_t *xfs_inode_zone; +/* + * If there are inline format data / attr forks attached to this inode, + * make sure they're not corrupt. + */ +bool +libxfs_inode_verify_forks( + struct xfs_inode *ip) +{ + xfs_failaddr_t fa; + + fa = xfs_ifork_verify_data(ip, &xfs_default_ifork_ops); + if (fa) { + xfs_alert(ip->i_mount, + "%s: bad inode %Lu inline data fork at %pF", + __func__, ip->i_ino, fa); + return false; + } + + fa = xfs_ifork_verify_attr(ip, &xfs_default_ifork_ops); + if (fa) { + xfs_alert(ip->i_mount, + "%s: bad inode %Lu inline attr fork at %pF", + __func__, ip->i_ino, fa); + return false; + } + return true; +} + int libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags, xfs_inode_t **ipp) @@ -1356,6 +1384,11 @@ libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags, return error; } + if (!libxfs_inode_verify_forks(ip)) { + libxfs_iput(ip); + return -EFSCORRUPTED; + } + /* * set up the inode ops structure that the libxfs code relies on */ diff --git a/libxfs/util.c b/libxfs/util.c index 7e42fb1..2dcce57 100644 --- a/libxfs/util.c +++ b/libxfs/util.c @@ -493,10 +493,8 @@ libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp) if (ip->i_d.di_version == 3) VFS_I(ip)->i_version++; - /* Check the inline directory data. */ - if (S_ISDIR(VFS_I(ip)->i_mode) && - ip->i_d.di_format == XFS_DINODE_FMT_LOCAL && - xfs_dir2_sf_verify(ip)) + /* Check the inline fork data before we write out. */ + if (!libxfs_inode_verify_forks(ip)) return -EFSCORRUPTED; /* diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c index b2bd8c7..063dab6 100644 --- a/libxfs/xfs_inode_fork.c +++ b/libxfs/xfs_inode_fork.c @@ -31,6 +31,8 @@ #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_dir2_priv.h" +#include "xfs_attr_leaf.h" +#include "xfs_shared.h" kmem_zone_t *xfs_ifork_zone; @@ -180,14 +182,6 @@ xfs_iformat_fork( if (error) return error; - /* Check inline dir contents. */ - if (S_ISDIR(inode->i_mode) && dip->di_format == XFS_DINODE_FMT_LOCAL) { - if (xfs_dir2_sf_verify(ip)) { - xfs_idestroy_fork(ip, XFS_DATA_FORK); - return -EFSCORRUPTED; - } - } - if (xfs_is_reflink_inode(ip)) { ASSERT(ip->i_cowfp == NULL); xfs_ifork_init_cow(ip); @@ -204,18 +198,6 @@ xfs_iformat_fork( atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); size = be16_to_cpu(atp->hdr.totsize); - if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) { - xfs_warn(ip->i_mount, - "corrupt inode %Lu (bad attr fork size %Ld).", - (unsigned long long) ip->i_ino, - (long long) size); - XFS_CORRUPTION_ERROR("xfs_iformat(8)", - XFS_ERRLEVEL_LOW, - ip->i_mount, dip); - error = -EFSCORRUPTED; - break; - } - error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); break; case XFS_DINODE_FMT_EXTENTS: @@ -823,3 +805,45 @@ xfs_ifork_init_cow( ip->i_cformat = XFS_DINODE_FMT_EXTENTS; ip->i_cnextents = 0; } + +/* Default fork content verifiers. */ +struct xfs_ifork_ops xfs_default_ifork_ops = { + .verify_attr = xfs_attr_shortform_verify, + .verify_dir = xfs_dir2_sf_verify, + .verify_symlink = xfs_symlink_shortform_verify, +}; + +/* Verify the inline contents of the data fork of an inode. */ +xfs_failaddr_t +xfs_ifork_verify_data( + struct xfs_inode *ip, + struct xfs_ifork_ops *ops) +{ + /* Non-local data fork, we're done. */ + if (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) + return NULL; + + /* Check the inline data fork if there is one. */ + switch (VFS_I(ip)->i_mode & S_IFMT) { + case S_IFDIR: + return ops->verify_dir(ip); + case S_IFLNK: + return ops->verify_symlink(ip); + default: + return NULL; + } +} + +/* Verify the inline contents of the attr fork of an inode. */ +xfs_failaddr_t +xfs_ifork_verify_attr( + struct xfs_inode *ip, + struct xfs_ifork_ops *ops) +{ + /* There has to be an attr fork allocated if aformat is local. */ + if (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) + return NULL; + if (!XFS_IFORK_PTR(ip, XFS_ATTR_FORK)) + return __this_address; + return ops->verify_attr(ip); +} diff --git a/libxfs/xfs_inode_fork.h b/libxfs/xfs_inode_fork.h index b9f0098..dd8aba0 100644 --- a/libxfs/xfs_inode_fork.h +++ b/libxfs/xfs_inode_fork.h @@ -186,4 +186,18 @@ extern struct kmem_zone *xfs_ifork_zone; extern void xfs_ifork_init_cow(struct xfs_inode *ip); +typedef xfs_failaddr_t (*xfs_ifork_verifier_t)(struct xfs_inode *); + +struct xfs_ifork_ops { + xfs_ifork_verifier_t verify_symlink; + xfs_ifork_verifier_t verify_dir; + xfs_ifork_verifier_t verify_attr; +}; +extern struct xfs_ifork_ops xfs_default_ifork_ops; + +xfs_failaddr_t xfs_ifork_verify_data(struct xfs_inode *ip, + struct xfs_ifork_ops *ops); +xfs_failaddr_t xfs_ifork_verify_attr(struct xfs_inode *ip, + struct xfs_ifork_ops *ops); + #endif /* __XFS_INODE_FORK_H__ */ -- 2.16.4 ++++++ xfsprogs-xfs-refactor-short-form-directory-structure-verifier.patch ++++++ >From 590ec7c1de3f8fa708fef15d23c0787f0125e93d Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.w...@oracle.com> Date: Mon, 26 Feb 2018 22:43:17 -0600 Subject: [PATCH] xfs: refactor short form directory structure verifier function Git-commit: 1f98251ffd56f2d78fff582568e984dec952d89c Patch-mainline: v4.16.0-rc1 References: bsc#1158504 Source kernel commit: dc042c2d8ff629dd411e9a60bce9c379e2f8aaf8 Change the short form directory structure verifier function to return the instruction pointer of a failing check or NULL if everything's ok. Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com> Reviewed-by: Dave Chinner <dchin...@redhat.com> Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- libxfs/xfs_dir2_priv.h | 2 +- libxfs/xfs_dir2_sf.c | 26 +++++++++++++------------- libxfs/xfs_inode_fork.c | 5 ++--- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/libxfs/xfs_dir2_priv.h b/libxfs/xfs_dir2_priv.h index 4badd26..1fca1c2 100644 --- a/libxfs/xfs_dir2_priv.h +++ b/libxfs/xfs_dir2_priv.h @@ -127,7 +127,7 @@ extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); extern int xfs_dir2_sf_lookup(struct xfs_da_args *args); extern int xfs_dir2_sf_removename(struct xfs_da_args *args); extern int xfs_dir2_sf_replace(struct xfs_da_args *args); -extern int xfs_dir2_sf_verify(struct xfs_inode *ip); +extern xfs_failaddr_t xfs_dir2_sf_verify(struct xfs_inode *ip); /* xfs_dir2_readdir.c */ extern int xfs_readdir(struct xfs_trans *tp, struct xfs_inode *dp, diff --git a/libxfs/xfs_dir2_sf.c b/libxfs/xfs_dir2_sf.c index 0c45398..cf352b6 100644 --- a/libxfs/xfs_dir2_sf.c +++ b/libxfs/xfs_dir2_sf.c @@ -628,7 +628,7 @@ xfs_dir2_sf_check( #endif /* DEBUG */ /* Verify the consistency of an inline directory. */ -int +xfs_failaddr_t xfs_dir2_sf_verify( struct xfs_inode *ip) { @@ -663,7 +663,7 @@ xfs_dir2_sf_verify( */ if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) || size < xfs_dir2_sf_hdr_size(sfp->i8count)) - return -EFSCORRUPTED; + return __this_address; endp = (char *)sfp + size; @@ -672,7 +672,7 @@ xfs_dir2_sf_verify( i8count = ino > XFS_DIR2_MAX_SHORT_INUM; error = xfs_dir_ino_validate(mp, ino); if (error) - return error; + return __this_address; offset = dops->data_first_offset; /* Check all reported entries */ @@ -684,11 +684,11 @@ xfs_dir2_sf_verify( * within the data buffer. */ if (((char *)sfep + sizeof(*sfep)) >= endp) - return -EFSCORRUPTED; + return __this_address; /* Don't allow names with known bad length. */ if (sfep->namelen == 0) - return -EFSCORRUPTED; + return __this_address; /* * Check that the variable-length part of the structure is @@ -697,23 +697,23 @@ xfs_dir2_sf_verify( */ next_sfep = dops->sf_nextentry(sfp, sfep); if (endp < (char *)next_sfep) - return -EFSCORRUPTED; + return __this_address; /* Check that the offsets always increase. */ if (xfs_dir2_sf_get_offset(sfep) < offset) - return -EFSCORRUPTED; + return __this_address; /* Check the inode number. */ ino = dops->sf_get_ino(sfp, sfep); i8count += ino > XFS_DIR2_MAX_SHORT_INUM; error = xfs_dir_ino_validate(mp, ino); if (error) - return error; + return __this_address; /* Check the file type. */ filetype = dops->sf_get_ftype(sfep); if (filetype >= XFS_DIR3_FT_MAX) - return -EFSCORRUPTED; + return __this_address; offset = xfs_dir2_sf_get_offset(sfep) + dops->data_entsize(sfep->namelen); @@ -721,16 +721,16 @@ xfs_dir2_sf_verify( sfep = next_sfep; } if (i8count != sfp->i8count) - return -EFSCORRUPTED; + return __this_address; if ((void *)sfep != (void *)endp) - return -EFSCORRUPTED; + return __this_address; /* Make sure this whole thing ought to be in local format. */ if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + (uint)sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) - return -EFSCORRUPTED; + return __this_address; - return 0; + return NULL; } /* diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c index 3c0be58..b2bd8c7 100644 --- a/libxfs/xfs_inode_fork.c +++ b/libxfs/xfs_inode_fork.c @@ -182,10 +182,9 @@ xfs_iformat_fork( /* Check inline dir contents. */ if (S_ISDIR(inode->i_mode) && dip->di_format == XFS_DINODE_FMT_LOCAL) { - error = xfs_dir2_sf_verify(ip); - if (error) { + if (xfs_dir2_sf_verify(ip)) { xfs_idestroy_fork(ip, XFS_DATA_FORK); - return error; + return -EFSCORRUPTED; } } -- 2.16.4 ++++++ xfsprogs-xfs_quota-fix-false-error-reporting-of-project-inher.patch ++++++ >From b136f48b19a5b8e788aceb4b80e97d6ae9edd0ea Mon Sep 17 00:00:00 2001 From: Achilles Gaikwad <agaik...@redhat.com> Date: Mon, 28 Jan 2019 13:03:08 -0600 Subject: [PATCH] xfs_quota: fix false error reporting of project inheritance flag is not set Git-commit: b136f48b19a5b8e788aceb4b80e97d6ae9edd0ea Patch-mainline: v4.20.0-rc1 References: bsc#1158758 After kernel commit: 9336e3a7 "xfs: project id inheritance is a directory only flag" xfs stopped setting the project inheritance flag on regular files, but userspace quota code still checks for it and will now issue the error: "project inheritance flag is not set" for every regular file during quotacheck. Fix this by only checking for the flag on directories. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1663502 Reported-by: Steven Gardner <sgard...@redhat.com> Signed-off-by: Achilles Gaikwad <agaik...@redhat.com> Reviewed-by: Darrick J. Wong <darrick.w...@oracle.com> Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- quota/project.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quota/project.c b/quota/project.c index 78ede9e5..7c22947c 100644 --- a/quota/project.c +++ b/quota/project.c @@ -114,7 +114,7 @@ check_project( printf(_("%s - project identifier is not set" " (inode=%u, tree=%u)\n"), path, fsx.fsx_projid, (unsigned int)prid); - if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)) + if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) && S_ISDIR(stat->st_mode)) printf(_("%s - project inheritance flag is not set\n"), path); } -- 2.16.4 ++++++ xfsprogs-xfs_repair-don-t-fail-directory-repairs-when-grabbin.patch ++++++ >From b825809fdccde5f441858f05e0c3cf128f21b57a Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.w...@oracle.com> Date: Thu, 8 Mar 2018 20:35:23 -0600 Subject: [PATCH] xfs_repair: don't fail directory repairs when grabbing inodes Git-commit: 12ac6e048a0fbf987820ee613465eecf884a8528 Patch-mainline: v4.16.0-rc1 References: bsc#1158504 There are a few places where xfs_repair needs to be able to load a damaged directory inode to perform repairs. Since inline data fork verifiers can now be customized, refactor libxfs_iget to enable repair to get at this so that we don't crash in phase 6. Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com> Reviewed-by: Eric Sandeen <sand...@redhat.com> Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- db/attrset.c | 6 ++++-- include/xfs_inode.h | 6 ++++-- libxfs/rdwr.c | 25 +++++++++++++++++-------- libxfs/trans.c | 6 ++++-- libxfs/util.c | 2 +- repair/phase6.c | 16 +++++++++++----- 6 files changed, 41 insertions(+), 20 deletions(-) diff --git a/db/attrset.c b/db/attrset.c index ad3c8f3..457317a 100644 --- a/db/attrset.c +++ b/db/attrset.c @@ -151,7 +151,8 @@ attr_set_f( value = NULL; } - if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &ip)) { + if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &ip, + &xfs_default_ifork_ops)) { dbprintf(_("failed to iget inode %llu\n"), (unsigned long long)iocur_top->ino); goto out; @@ -226,7 +227,8 @@ attr_remove_f( name = argv[optind]; - if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &ip)) { + if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &ip, + &xfs_default_ifork_ops)) { dbprintf(_("failed to iget inode %llu\n"), (unsigned long long)iocur_top->ino); goto out; diff --git a/include/xfs_inode.h b/include/xfs_inode.h index 92829a2..f29f0f0 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -162,9 +162,11 @@ extern void libxfs_trans_ichgtime(struct xfs_trans *, extern int libxfs_iflush_int (struct xfs_inode *, struct xfs_buf *); /* Inode Cache Interfaces */ -extern bool libxfs_inode_verify_forks(struct xfs_inode *ip); +extern bool libxfs_inode_verify_forks(struct xfs_inode *ip, + struct xfs_ifork_ops *); extern int libxfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, - uint, struct xfs_inode **); + uint, struct xfs_inode **, + struct xfs_ifork_ops *); extern void libxfs_iput(struct xfs_inode *); #define IRELE(ip) libxfs_iput(ip) diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c index 14afece..04ddd74 100644 --- a/libxfs/rdwr.c +++ b/libxfs/rdwr.c @@ -1342,11 +1342,15 @@ extern kmem_zone_t *xfs_inode_zone; */ bool libxfs_inode_verify_forks( - struct xfs_inode *ip) + struct xfs_inode *ip, + struct xfs_ifork_ops *ops) { xfs_failaddr_t fa; - fa = xfs_ifork_verify_data(ip, &xfs_default_ifork_ops); + if (!ops) + return true; + + fa = xfs_ifork_verify_data(ip, ops); if (fa) { xfs_alert(ip->i_mount, "%s: bad inode %Lu inline data fork at %pF", @@ -1354,7 +1358,7 @@ libxfs_inode_verify_forks( return false; } - fa = xfs_ifork_verify_attr(ip, &xfs_default_ifork_ops); + fa = xfs_ifork_verify_attr(ip, ops); if (fa) { xfs_alert(ip->i_mount, "%s: bad inode %Lu inline attr fork at %pF", @@ -1365,11 +1369,16 @@ libxfs_inode_verify_forks( } int -libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags, - xfs_inode_t **ipp) +libxfs_iget( + struct xfs_mount *mp, + struct xfs_trans *tp, + xfs_ino_t ino, + uint lock_flags, + struct xfs_inode **ipp, + struct xfs_ifork_ops *ifork_ops) { - xfs_inode_t *ip; - int error = 0; + struct xfs_inode *ip; + int error = 0; ip = kmem_zone_zalloc(xfs_inode_zone, 0); if (!ip) @@ -1384,7 +1393,7 @@ libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags, return error; } - if (!libxfs_inode_verify_forks(ip)) { + if (!libxfs_inode_verify_forks(ip, ifork_ops)) { libxfs_iput(ip); return -EFSCORRUPTED; } diff --git a/libxfs/trans.c b/libxfs/trans.c index f330d4b..af568ba 100644 --- a/libxfs/trans.c +++ b/libxfs/trans.c @@ -243,9 +243,11 @@ libxfs_trans_iget( xfs_inode_log_item_t *iip; if (tp == NULL) - return libxfs_iget(mp, tp, ino, lock_flags, ipp); + return libxfs_iget(mp, tp, ino, lock_flags, ipp, + &xfs_default_ifork_ops); - error = libxfs_iget(mp, tp, ino, lock_flags, &ip); + error = libxfs_iget(mp, tp, ino, lock_flags, &ip, + &xfs_default_ifork_ops); if (error) return error; ASSERT(ip != NULL); diff --git a/libxfs/util.c b/libxfs/util.c index 2dcce57..16db612 100644 --- a/libxfs/util.c +++ b/libxfs/util.c @@ -494,7 +494,7 @@ libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp) VFS_I(ip)->i_version++; /* Check the inline fork data before we write out. */ - if (!libxfs_inode_verify_forks(ip)) + if (!libxfs_inode_verify_forks(ip, &xfs_default_ifork_ops)) return -EFSCORRUPTED; /* diff --git a/repair/phase6.c b/repair/phase6.c index 1a398aa..aff83bc 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -927,7 +927,9 @@ mk_orphanage(xfs_mount_t *mp) * would have been cleared in phase3 and phase4. */ - if ((i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip))) + i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, + &xfs_default_ifork_ops); + if (i) do_error(_("%d - couldn't iget root inode to obtain %s\n"), i, ORPHANAGE); @@ -951,7 +953,9 @@ mk_orphanage(xfs_mount_t *mp) * use iget/ijoin instead of trans_iget because the ialloc * wrapper can commit the transaction and start a new one */ -/* if ((i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip))) +/* i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, + &xfs_default_ifork_ops); + if (i) do_error(_("%d - couldn't iget root inode to make %s\n"), i, ORPHANAGE);*/ @@ -1066,7 +1070,8 @@ mv_orphanage( xname.len = snprintf((char *)fname, sizeof(fname), "%llu", (unsigned long long)ino); - err = -libxfs_iget(mp, NULL, orphanage_ino, 0, &orphanage_ip); + err = -libxfs_iget(mp, NULL, orphanage_ino, 0, &orphanage_ip, + &xfs_default_ifork_ops); if (err) do_error(_("%d - couldn't iget orphanage inode\n"), err); /* @@ -1078,7 +1083,8 @@ mv_orphanage( xname.len = snprintf((char *)fname, sizeof(fname), "%llu.%d", (unsigned long long)ino, ++incr); - if ((err = -libxfs_iget(mp, NULL, ino, 0, &ino_p))) + err = -libxfs_iget(mp, NULL, ino, 0, &ino_p, &xfs_default_ifork_ops); + if (err) do_error(_("%d - couldn't iget disconnected inode\n"), err); xname.type = libxfs_mode_to_ftype(VFS_I(ino_p)->i_mode); @@ -2827,7 +2833,7 @@ process_dir_inode( ASSERT(!is_inode_refchecked(irec, ino_offset) || dotdot_update); - error = -libxfs_iget(mp, NULL, ino, 0, &ip); + error = -libxfs_iget(mp, NULL, ino, 0, &ip, NULL); if (error) { if (!no_modify) do_error( -- 2.16.4 ++++++ xfsprogs-xfs_repair-implement-custom-ifork-verifiers.patch ++++++ >From 78ccf903dc85056d1e47c732337a2f1387a69cad Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.w...@oracle.com> Date: Mon, 26 Mar 2018 21:27:28 -0500 Subject: [PATCH] xfs_repair: implement custom ifork verifiers Git-commit: 3452f451b2ecd91ca2c6609c150779e32a8a1442 Patch-mainline: v4.16.0-rc1 References: bsc#1158504 There are a few cases where an early stage of xfs_repair will write an invalid inode fork buffer to signal to a later stage that it needs to correct the value. This happens in phase 4 when we detect an inline format directory with an invalid .. pointer. To avoid triggering the ifork verifiers on this, inject a custom verifier for phase 6 that lets this pass for now. Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com> Reviewed-by: Eric Sandeen <sand...@redhat.com> Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- libxfs/libxfs_api_defs.h | 2 ++ repair/phase6.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 709632f..8b8f007 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -151,5 +151,7 @@ #define xfs_refc_block libxfs_refc_block #define xfs_rmap_compare libxfs_rmap_compare #define xfs_fs_geometry libxfs_fs_geometry +#define xfs_dir_get_ops libxfs_dir_get_ops +#define xfs_default_ifork_ops libxfs_default_ifork_ops #endif /* __LIBXFS_API_DEFS_H__ */ diff --git a/repair/phase6.c b/repair/phase6.c index aff83bc..ed005e8 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -38,6 +38,61 @@ static struct xfs_name xfs_name_dot = {(unsigned char *)".", 1, XFS_DIR3_FT_DIR}; +/* + * When we're checking directory inodes, we're allowed to set a directory's + * dotdot entry to zero to signal that the parent needs to be reconnected + * during phase 6. If we're handling a shortform directory the ifork + * verifiers will fail, so temporarily patch out this canary so that we can + * verify the rest of the fork and move on to fixing the dir. + */ +static xfs_failaddr_t +phase6_verify_dir( + struct xfs_inode *ip) +{ + struct xfs_mount *mp = ip->i_mount; + const struct xfs_dir_ops *dops; + struct xfs_ifork *ifp; + struct xfs_dir2_sf_hdr *sfp; + xfs_failaddr_t fa; + xfs_ino_t old_parent; + bool parent_bypass = false; + int size; + + dops = libxfs_dir_get_ops(mp, NULL); + + ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); + sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data; + size = ifp->if_bytes; + + /* + * If this is a shortform directory, phase4 may have set the parent + * inode to zero to indicate that it must be fixed. Temporarily + * set a valid parent so that the directory verifier will pass. + */ + if (size > offsetof(struct xfs_dir2_sf_hdr, parent) && + size >= xfs_dir2_sf_hdr_size(sfp->i8count)) { + old_parent = dops->sf_get_parent_ino(sfp); + if (old_parent == 0) { + dops->sf_put_parent_ino(sfp, mp->m_sb.sb_rootino); + parent_bypass = true; + } + } + + fa = libxfs_default_ifork_ops.verify_dir(ip); + + /* Put it back. */ + if (parent_bypass) + dops->sf_put_parent_ino(sfp, old_parent); + + return fa; +} + +static struct xfs_ifork_ops phase6_ifork_ops = { + .verify_attr = xfs_attr_shortform_verify, + .verify_dir = phase6_verify_dir, + .verify_symlink = xfs_symlink_shortform_verify, +}; + /* * Data structures used to keep track of directories where the ".." * entries are updated. These must be rebuilt after the initial pass @@ -2833,7 +2888,7 @@ process_dir_inode( ASSERT(!is_inode_refchecked(irec, ino_offset) || dotdot_update); - error = -libxfs_iget(mp, NULL, ino, 0, &ip, NULL); + error = -libxfs_iget(mp, NULL, ino, 0, &ip, &phase6_ifork_ops); if (error) { if (!no_modify) do_error( -- 2.16.4 ++++++ xfsprogs-xfs_repair-use-custom-ifork-verifier-in-mv_orphanage.patch ++++++ >From 24212da4f9362ab2fc02ee498953f7cd6e6032a9 Mon Sep 17 00:00:00 2001 From: Eric Sandeen <sand...@redhat.com> Date: Mon, 26 Mar 2018 21:27:28 -0500 Subject: [PATCH] xfs_repair: use custom ifork verifier in mv_orphanage Git-commit: f8cd7da8eec39dddbdeebac8617b64f2a1a2deb0 Patch-mainline: v4.16.0-rc1 References: bsc#1158504 Now that we have a custom verifier which can ignore parent inode numbers, use it in mv_orphanage() as well; orphan inodes may have invalid parents, and we're about to reconnect them anyway, so override that test when we get them off disk. Signed-off-by: Eric Sandeen <sand...@redhat.com> Reviewed-by: Darrick J. Wong <darrick.w...@oracle.com> Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- repair/phase6.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/repair/phase6.c b/repair/phase6.c index ed005e8..498a3b5 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -1138,7 +1138,8 @@ mv_orphanage( xname.len = snprintf((char *)fname, sizeof(fname), "%llu.%d", (unsigned long long)ino, ++incr); - err = -libxfs_iget(mp, NULL, ino, 0, &ino_p, &xfs_default_ifork_ops); + /* Orphans may not have a proper parent, so use custom ops here */ + err = -libxfs_iget(mp, NULL, ino, 0, &ino_p, &phase6_ifork_ops); if (err) do_error(_("%d - couldn't iget disconnected inode\n"), err); -- 2.16.4 ++++++ xfsprogs-xfs_repair-use-libxfs-extsize-cowextsize-validation-.patch ++++++ >From e45ab8b8e5921fa3fa763a5e9729d90d342dcbcc Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.w...@oracle.com> Date: Wed, 1 Aug 2018 17:06:44 -0500 Subject: [PATCH] xfs_repair: use libxfs extsize/cowextsize validation helpers Git-commit: db3d080b40ecce86ec6755a04544bbc59aa344da Patch-mainline: v4.18.0-rc1 References: bsc#1158509 Now that we've ported the extent size hint verifiers to libxfs, call them from xfs_repair instead of open-coding the checks. Tweak the repair message slightly to reflect the fact that we zero the field and clear the inode flag if the hint is garbage or is inconsistent with the inode flags. Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com> Reviewed-by: Eric Sandeen <sand...@redhat.com> Signed-off-by: Eric Sandeen <sand...@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopou...@suse.com> --- libxfs/libxfs_api_defs.h | 2 ++ repair/dinode.c | 75 +++++++++++++++++------------------------------- 2 files changed, 28 insertions(+), 49 deletions(-) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 8b8f0071..ab2b7c42 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -106,6 +106,8 @@ #define xfs_dinode_calc_crc libxfs_dinode_calc_crc #define xfs_idata_realloc libxfs_idata_realloc #define xfs_idestroy_fork libxfs_idestroy_fork +#define xfs_inode_validate_extsize libxfs_inode_validate_extsize +#define xfs_inode_validate_cowextsize libxfs_inode_validate_cowextsize #define xfs_rmap_ag_owner libxfs_rmap_ag_owner #define xfs_rmap_alloc libxfs_rmap_alloc diff --git a/repair/dinode.c b/repair/dinode.c index af4d740d..0f7bf354 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -2829,24 +2829,21 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"), * only regular files with REALTIME or EXTSIZE flags set can have * extsize set, or directories with EXTSZINHERIT. */ - if (be32_to_cpu(dino->di_extsize) != 0) { - if ((type == XR_INO_RTDATA) || - (type == XR_INO_DIR && (be16_to_cpu(dino->di_flags) & - XFS_DIFLAG_EXTSZINHERIT)) || - (type == XR_INO_DATA && (be16_to_cpu(dino->di_flags) & - XFS_DIFLAG_EXTSIZE))) { - /* s'okay */ ; - } else { - do_warn( -_("bad non-zero extent size %u for non-realtime/extsize inode %" PRIu64 ", "), - be32_to_cpu(dino->di_extsize), lino); - if (!no_modify) { - do_warn(_("resetting to zero\n")); - dino->di_extsize = 0; - *dirty = 1; - } else - do_warn(_("would reset to zero\n")); - } + if (libxfs_inode_validate_extsize(mp, + be32_to_cpu(dino->di_extsize), + be16_to_cpu(dino->di_mode), + be16_to_cpu(dino->di_flags)) != NULL) { + do_warn( +_("Bad extent size %u on inode %" PRIu64 ", "), + be32_to_cpu(dino->di_extsize), lino); + if (!no_modify) { + do_warn(_("resetting to zero\n")); + dino->di_extsize = 0; + dino->di_flags &= ~cpu_to_be16(XFS_DIFLAG_EXTSIZE | + XFS_DIFLAG_EXTSZINHERIT); + *dirty = 1; + } else + do_warn(_("would reset to zero\n")); } /* @@ -2854,41 +2851,21 @@ _("bad non-zero extent size %u for non-realtime/extsize inode %" PRIu64 ", "), * set can have extsize set. */ if (dino->di_version >= 3 && - be32_to_cpu(dino->di_cowextsize) != 0) { - if ((type == XR_INO_DIR || type == XR_INO_DATA) && - (be64_to_cpu(dino->di_flags2) & - XFS_DIFLAG2_COWEXTSIZE)) { - /* s'okay */ ; - } else { - do_warn( -_("Cannot have non-zero CoW extent size %u on non-cowextsize inode %" PRIu64 ", "), - be32_to_cpu(dino->di_cowextsize), lino); - if (!no_modify) { - do_warn(_("resetting to zero\n")); - dino->di_flags2 &= ~cpu_to_be64(XFS_DIFLAG2_COWEXTSIZE); - dino->di_cowextsize = 0; - *dirty = 1; - } else - do_warn(_("would reset to zero\n")); - } - } - - /* - * Can't have the COWEXTSIZE flag set with no hint. - */ - if (dino->di_version >= 3 && - be32_to_cpu(dino->di_cowextsize) == 0 && - (be64_to_cpu(dino->di_flags2) & XFS_DIFLAG2_COWEXTSIZE)) { + libxfs_inode_validate_cowextsize(mp, + be32_to_cpu(dino->di_cowextsize), + be16_to_cpu(dino->di_mode), + be16_to_cpu(dino->di_flags), + be64_to_cpu(dino->di_flags2)) != NULL) { do_warn( -_("Cannot have CoW extent size of zero on cowextsize inode %" PRIu64 ", "), - lino); +_("Bad CoW extent size %u on inode %" PRIu64 ", "), + be32_to_cpu(dino->di_cowextsize), lino); if (!no_modify) { - do_warn(_("clearing cowextsize flag\n")); + do_warn(_("resetting to zero\n")); dino->di_flags2 &= ~cpu_to_be64(XFS_DIFLAG2_COWEXTSIZE); + dino->di_cowextsize = 0; *dirty = 1; - } else { - do_warn(_("would clear cowextsize flag\n")); - } + } else + do_warn(_("would reset to zero\n")); } /* -- 2.16.4