mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
xfs: rework the inline directory verifiers
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. Reviewed-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- v2: get the inode d_ops the proper way v3: describe the bug that this patch fixes; no code changes
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user