Commit e744cef2 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: zap broken inode forks



Determine if inode fork damage is responsible for the inode being unable
to pass the ifork verifiers in xfs_iget and zap the fork contents if
this is true.  Once this is done the fork will be empty but we'll be
able to construct an in-core inode, and a subsequent call to the inode
fork repair ioctl will search the rmapbt to rebuild the records that
were in the fork.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 2d295fe6
Loading
Loading
Loading
Loading
+3 −10
Original line number Diff line number Diff line
@@ -1040,23 +1040,16 @@ xfs_attr_shortform_allfit(
	return xfs_attr_shortform_bytesfit(dp, bytes);
}

/* Verify the consistency of an inline attribute fork. */
/* Verify the consistency of a raw inline attribute fork. */
xfs_failaddr_t
xfs_attr_shortform_verify(
	struct xfs_inode		*ip)
	struct xfs_attr_shortform	*sfp,
	size_t				size)
{
	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;
	int64_t				size;

	ASSERT(ip->i_af.if_format == 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.
+2 −1
Original line number Diff line number Diff line
@@ -56,7 +56,8 @@ int xfs_attr_sf_findname(struct xfs_da_args *args,
			     unsigned int *basep);
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);
xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_attr_shortform *sfp,
		size_t size);
void	xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp);

/*
+16 −6
Original line number Diff line number Diff line
@@ -6168,19 +6168,18 @@ xfs_bmap_finish_one(
	return error;
}

/* Check that an inode's extent does not have invalid flags or bad ranges. */
/* Check that an extent does not have invalid flags or bad ranges. */
xfs_failaddr_t
xfs_bmap_validate_extent(
	struct xfs_inode	*ip,
xfs_bmap_validate_extent_raw(
	struct xfs_mount	*mp,
	bool			rtfile,
	int			whichfork,
	struct xfs_bmbt_irec	*irec)
{
	struct xfs_mount	*mp = ip->i_mount;

	if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount))
		return __this_address;

	if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) {
	if (rtfile && whichfork == XFS_DATA_FORK) {
		if (!xfs_verify_rtbext(mp, irec->br_startblock,
					   irec->br_blockcount))
			return __this_address;
@@ -6210,3 +6209,14 @@ xfs_bmap_intent_destroy_cache(void)
	kmem_cache_destroy(xfs_bmap_intent_cache);
	xfs_bmap_intent_cache = NULL;
}

/* Check that an inode's extent does not have invalid flags or bad ranges. */
xfs_failaddr_t
xfs_bmap_validate_extent(
	struct xfs_inode	*ip,
	int			whichfork,
	struct xfs_bmbt_irec	*irec)
{
	return xfs_bmap_validate_extent_raw(ip->i_mount,
			XFS_IS_REALTIME_INODE(ip), whichfork, irec);
}
+2 −0
Original line number Diff line number Diff line
@@ -263,6 +263,8 @@ static inline uint32_t xfs_bmap_fork_to_state(int whichfork)
	}
}

xfs_failaddr_t xfs_bmap_validate_extent_raw(struct xfs_mount *mp, bool rtfile,
		int whichfork, struct xfs_bmbt_irec *irec);
xfs_failaddr_t xfs_bmap_validate_extent(struct xfs_inode *ip, int whichfork,
		struct xfs_bmbt_irec *irec);
int xfs_bmap_complain_bad_rec(struct xfs_inode *ip, int whichfork,
+2 −1
Original line number Diff line number Diff line
@@ -175,7 +175,8 @@ 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 xfs_failaddr_t xfs_dir2_sf_verify(struct xfs_inode *ip);
xfs_failaddr_t xfs_dir2_sf_verify(struct xfs_mount *mp,
		struct xfs_dir2_sf_hdr *sfp, int64_t size);
int xfs_dir2_sf_entsize(struct xfs_mount *mp,
		struct xfs_dir2_sf_hdr *hdr, int len);
void xfs_dir2_sf_put_ino(struct xfs_mount *mp, struct xfs_dir2_sf_hdr *hdr,
Loading