mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-30 06:25:03 +08:00
xfs: distinguish between corrupt inode and invalid inum in xfs_scrub_get_inode
In xfs_scrub_get_inode, we don't do a good enough job distinguishing EINVAL returns from xfs_iget w/ IGET_UNTRUSTED -- this can happen if the passed in inode number is invalid (past eofs, inobt says it isn't an inode) or if the inum is actually valid but the inode buffer fails verifier. In the first case we still want to return ENOENT, but in the second case we want to capture the corruption error. Therefore, if xfs_iget returns EINVAL, try the raw imap lookup. If that succeeds, we conclude it's a corruption error, otherwise we just bounce out to userspace. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
This commit is contained in:
parent
1ad1205e71
commit
d658e72b4a
@ -503,6 +503,7 @@ xfs_scrub_get_inode(
|
|||||||
struct xfs_scrub_context *sc,
|
struct xfs_scrub_context *sc,
|
||||||
struct xfs_inode *ip_in)
|
struct xfs_inode *ip_in)
|
||||||
{
|
{
|
||||||
|
struct xfs_imap imap;
|
||||||
struct xfs_mount *mp = sc->mp;
|
struct xfs_mount *mp = sc->mp;
|
||||||
struct xfs_inode *ip = NULL;
|
struct xfs_inode *ip = NULL;
|
||||||
int error;
|
int error;
|
||||||
@ -518,10 +519,33 @@ xfs_scrub_get_inode(
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
error = xfs_iget(mp, NULL, sc->sm->sm_ino,
|
error = xfs_iget(mp, NULL, sc->sm->sm_ino,
|
||||||
XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE, 0, &ip);
|
XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE, 0, &ip);
|
||||||
if (error == -ENOENT || error == -EINVAL) {
|
switch (error) {
|
||||||
/* inode doesn't exist... */
|
case -ENOENT:
|
||||||
|
/* Inode doesn't exist, just bail out. */
|
||||||
|
return error;
|
||||||
|
case 0:
|
||||||
|
/* Got an inode, continue. */
|
||||||
|
break;
|
||||||
|
case -EINVAL:
|
||||||
|
/*
|
||||||
|
* -EINVAL with IGET_UNTRUSTED could mean one of several
|
||||||
|
* things: userspace gave us an inode number that doesn't
|
||||||
|
* correspond to fs space, or doesn't have an inobt entry;
|
||||||
|
* or it could simply mean that the inode buffer failed the
|
||||||
|
* read verifiers.
|
||||||
|
*
|
||||||
|
* Try just the inode mapping lookup -- if it succeeds, then
|
||||||
|
* the inode buffer verifier failed and something needs fixing.
|
||||||
|
* Otherwise, we really couldn't find it so tell userspace
|
||||||
|
* that it no longer exists.
|
||||||
|
*/
|
||||||
|
error = xfs_imap(sc->mp, sc->tp, sc->sm->sm_ino, &imap,
|
||||||
|
XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE);
|
||||||
|
if (error)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
} else if (error) {
|
error = -EFSCORRUPTED;
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
trace_xfs_scrub_op_error(sc,
|
trace_xfs_scrub_op_error(sc,
|
||||||
XFS_INO_TO_AGNO(mp, sc->sm->sm_ino),
|
XFS_INO_TO_AGNO(mp, sc->sm->sm_ino),
|
||||||
XFS_INO_TO_AGBNO(mp, sc->sm->sm_ino),
|
XFS_INO_TO_AGBNO(mp, sc->sm->sm_ino),
|
||||||
|
Loading…
Reference in New Issue
Block a user