Patch "xfs: rework the inline directory verifiers" has been added to the 4.9-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
xfs: rework the inline directory verifiers
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
xfs-rework-the-inline-directory-verifiers.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
78420281a9d74014af7616958806c3aba056319eMon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <[email protected]>
Date: Mon, 3 Apr 2017 12:22:20 -0700
Subject: xfs: rework the inline directory verifiers
From: Darrick J. Wong <[email protected]>
commit 78420281a9d74014af7616958806c3aba056319e upstream.
The inline directory verifiers should be called on the inode fork data, which means after iformat_local on the read side, and prior to ifork_flush on the write side. This makes the fork verifier more consistent with the way buffer verifiers work -- i.e. they will operate on the memory buffer that the code will be reading and writing directly.
Furthermore, revise the verifier function to return -EFSCORRUPTED so that we don't flood the logs with corruption messages and assert notices. This has been a particular problem with xfs/348, which triggers the XFS_WANT_CORRUPTED_RETURN assertions, which halts the kernel when CONFIG_XFS_DEBUG=y. Disk corruption isn't supposed to do that, at least not in a verifier.
--- fs/xfs/libxfs/xfs_dir2_priv.h | 3 - fs/xfs/libxfs/xfs_dir2_sf.c | 63 ++++++++++++++++++++++++++--------------- fs/xfs/libxfs/xfs_inode_fork.c | 35 ++++++++-------------- fs/xfs/libxfs/xfs_inode_fork.h | 2 - fs/xfs/xfs_inode.c | 19 ++++++------ 5 files changed, 66 insertions(+), 56 deletions(-)
fs/xfs/libxfs/xfs_dir2_priv.h +1 -2
@@ -126,8 +126,7 @@ extern int xfs_dir2_sf_create(struct xfsextern 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_mount *mp,struct xfs_dir2_sf_hdr *sfp, -int size); +extern int xfs_dir2_sf_verify (struct xfs_inode *ip);/* xfs_dir2_readdir.c */ extern int xfs_readdir(struct xfs_inode *dp, struct dir_context *ctx,
fs/xfs/libxfs/xfs_dir2_sf.c +41 -22
122 lines not on this page · raw message
fs/xfs/libxfs/xfs_inode_fork.c +13 -22
@@ -212,6 +212,16 @@ xfs_iformat_fork(if (error)return error; +/* Check inline dir contents. */ +if (S_ISDIR (VFS_I (ip)->i_mode) && + dip->di_format ==XFS_DINODE_FMT_LOCAL ) { + error =xfs_dir2_sf_verify (ip); +if (error) { +xfs_idestroy_fork (ip,XFS_DATA_FORK ); +return error; + } + } +if (xfs_is_reflink_inode (ip)) {ASSERT (ip->i_cowfp ==NULL );xfs_ifork_init_cow (ip);
@@ -322,8 +332,6 @@ xfs_iformat_local(int whichfork, int size) { -int error; -/* * If the size is unreasonable, then something * is wrong and we just bail out rather than crash in
@@ -339,14 +347,6 @@ xfs_iformat_local(return -EFSCORRUPTED ; } -if (S_ISDIR (VFS_I (ip)->i_mode) && whichfork ==XFS_DATA_FORK ) { - error =xfs_dir2_sf_verify (ip->i_mount, - (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR (dip), - size); -if (error) -return error; - } -xfs_init_local_fork (ip, whichfork,XFS_DFORK_PTR (dip, whichfork), size);return 0 ; }
@@ -867,7 +867,7 @@ xfs_iextents_copy(* In these cases, the format always takes precedence, because the * format indicates the current state of the fork. */ -int +void xfs_iflush_fork( xfs_inode_t *ip, xfs_dinode_t *dip,
@@ -877,7 +877,6 @@ xfs_iflush_fork(char *cp;xfs_ifork_t *ifp;xfs_mount_t *mp; -int error;static const short brootflag[2 ] = {XFS_ILOG_DBROOT ,XFS_ILOG_ABROOT }; static const short dataflag[2] =
@@ -886,7 +885,7 @@ xfs_iflush_fork( { XFS_ILOG_DEXT, XFS_ILOG_AEXT };if (!iip) -return 0 ; +return ; ifp =XFS_IFORK_PTR (ip, whichfork);/* * This can happen if we gave up in iformat in an error path,
@@ -894,19 +893,12 @@ xfs_iflush_fork(*/ if (!ifp) {ASSERT (whichfork ==XFS_ATTR_FORK ); -return 0 ; +return ; } cp =XFS_DFORK_PTR (dip, whichfork); mp = ip->i_mount;switch (XFS_IFORK_FORMAT (ip, whichfork)) {case XFS_DINODE_FMT_LOCAL : -if (S_ISDIR (VFS_I (ip)->i_mode) && whichfork ==XFS_DATA_FORK ) { - error =xfs_dir2_sf_verify (mp, - (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data, - ifp->if_bytes); -if (error) -return error; - }if ((iip->ili_fields & dataflag[whichfork]) && (ifp->if_bytes >0 )) {ASSERT (ifp->if_u1.if_data !=NULL );
@@ -959,7 +951,6 @@ xfs_iflush_fork(ASSERT (0 );break ; } -return 0 ; }/*
fs/xfs/libxfs/xfs_inode_fork.h +1 -1
@@ -140,7 +140,7 @@ typedef struct xfs_ifork {struct xfs_ifork *xfs_iext_state_to_fork (struct xfs_inode *ip,int state);int xfs_iformat_fork (struct xfs_inode *,struct xfs_dinode *); -int xfs_iflush_fork (struct xfs_inode *,struct xfs_dinode *, +void xfs_iflush_fork (struct xfs_inode *,struct xfs_dinode *,struct xfs_inode_log_item *,int );void xfs_idestroy_fork (struct xfs_inode *,int );void xfs_idata_realloc (struct xfs_inode *,int ,int );
fs/xfs/xfs_inode.c +10 -9
@@ -50,6 +50,7 @@#include "xfs_log.h" #include "xfs_bmap_btree.h" #include "xfs_reflink.h" +#include "xfs_dir2_priv.h" kmem_zone_t *xfs_inode_zone;
@@ -3491,7 +3492,6 @@ xfs_iflush_int(struct xfs_inode_log_item *iip = ip->i_itemp;struct xfs_dinode *dip;struct xfs_mount *mp = ip->i_mount; -int error;ASSERT (xfs_isilocked (ip,XFS_ILOCK_EXCL |XFS_ILOCK_SHARED ));ASSERT (xfs_isiflocked (ip));
@@ -3563,6 +3563,12 @@ xfs_iflush_int(if (ip->i_d.di_version <3 ) ip->i_d.di_flushiter++; +/* 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)) + goto corrupt_out; +/* * Copy the dirty parts of the inode into the on-disk inode. We always * copy out the core of the inode, because if the inode is dirty at all
@@ -3574,14 +3580,9 @@ xfs_iflush_int(if (ip->i_d.di_flushiter ==DI_MAX_FLUSH ) ip->i_d.di_flushiter =0 ; - error =xfs_iflush_fork (ip, dip, iip,XFS_DATA_FORK ); -if (error) -return error; -if (XFS_IFORK_Q (ip)) { - error =xfs_iflush_fork (ip, dip, iip,XFS_ATTR_FORK ); -if (error) -return error; - } +xfs_iflush_fork (ip, dip, iip,XFS_DATA_FORK ); +if (XFS_IFORK_Q (ip)) +xfs_iflush_fork (ip, dip, iip,XFS_ATTR_FORK );xfs_inobp_check (mp, bp);/*
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/xfs-fix-missed-holes-in-seek_hole-implementation.patch queue-4.9/xfs-fix-off-by-one-on-max-nr_pages-in-xfs_find_get_desired_pgoff.patch queue-4.9/xfs-use-dedicated-log-worker-wq-to-avoid-deadlock-with-cil-wq.patch queue-4.9/xfs-rework-the-inline-directory-verifiers.patch queue-4.9/xfs-use-b_state-to-fix-buffer-i-o-accounting-release-race.patch queue-4.9/xfs-verify-inline-directory-data-forks.patch queue-4.9/xfs-fix-kernel-memory-exposure-problems.patch