Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.2
xfsprogs
xfsprogs-xfs-provide-a-centralized-method-for-v...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File xfsprogs-xfs-provide-a-centralized-method-for-verifying-inlin.patch of Package xfsprogs
From 08da938ab771dc644e48909dcba04b0223871546 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" <darrick.wong@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.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Eric Sandeen <sandeen@sandeen.net> Acked-by: Anthony Iliopoulos <ailiopoulos@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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor