Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba372674 authored by Dave Chinner's avatar Dave Chinner Committed by Dave Chinner
Browse files

xfs: check xfs_buf_read_uncached returns correctly



xfs_buf_read_uncached() has two failure modes. If can either return
NULL or bp->b_error != 0 depending on the type of failure, and not
all callers check for both. Fix it so that xfs_buf_read_uncached()
always returns the error status, and the buffer is returned as a
function parameter. The buffer will only be returned on success.

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 595bff75
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -688,29 +688,39 @@ xfs_buf_readahead_map(
 * Read an uncached buffer from disk. Allocates and returns a locked
 * buffer containing the disk contents or nothing.
 */
struct xfs_buf *
int
xfs_buf_read_uncached(
	struct xfs_buftarg	*target,
	xfs_daddr_t		daddr,
	size_t			numblks,
	int			flags,
	struct xfs_buf		**bpp,
	const struct xfs_buf_ops *ops)
{
	struct xfs_buf		*bp;

	*bpp = NULL;

	bp = xfs_buf_get_uncached(target, numblks, flags);
	if (!bp)
		return NULL;
		return -ENOMEM;

	/* set up the buffer for a read IO */
	ASSERT(bp->b_map_count == 1);
	bp->b_bn = daddr;
	bp->b_bn = XFS_BUF_DADDR_NULL;  /* always null for uncached buffers */
	bp->b_maps[0].bm_bn = daddr;
	bp->b_flags |= XBF_READ;
	bp->b_ops = ops;

	xfs_buf_submit_wait(bp);
	return bp;
	if (bp->b_error) {
		int	error = bp->b_error;
		xfs_buf_relse(bp);
		return error;
	}

	*bpp = bp;
	return 0;
}

/*
+3 −3
Original line number Diff line number Diff line
@@ -269,8 +269,8 @@ int xfs_buf_associate_memory(struct xfs_buf *bp, void *mem, size_t length);

struct xfs_buf *xfs_buf_get_uncached(struct xfs_buftarg *target, size_t numblks,
				int flags);
struct xfs_buf *xfs_buf_read_uncached(struct xfs_buftarg *target,
				xfs_daddr_t daddr, size_t numblks, int flags,
int xfs_buf_read_uncached(struct xfs_buftarg *target, xfs_daddr_t daddr,
			  size_t numblks, int flags, struct xfs_buf **bpp,
			  const struct xfs_buf_ops *ops);
void xfs_buf_hold(struct xfs_buf *bp);

+3 −8
Original line number Diff line number Diff line
@@ -172,16 +172,11 @@ xfs_growfs_data_private(
	if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
		return error;
	dpct = pct - mp->m_sb.sb_imax_pct;
	bp = xfs_buf_read_uncached(mp->m_ddev_targp,
	error = xfs_buf_read_uncached(mp->m_ddev_targp,
				XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
				XFS_FSS_TO_BB(mp, 1), 0, NULL);
	if (!bp)
		return -EIO;
	if (bp->b_error) {
		error = bp->b_error;
		xfs_buf_relse(bp);
				XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
	if (error)
		return error;
	}
	xfs_buf_relse(bp);

	new = nb;	/* use new as a temporary here */
+26 −29
Original line number Diff line number Diff line
@@ -302,21 +302,15 @@ xfs_readsb(
	 * access to the superblock.
	 */
reread:
	bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
				   BTOBB(sector_size), 0, buf_ops);
	if (!bp) {
		if (loud)
			xfs_warn(mp, "SB buffer read failed");
		return -EIO;
	}
	if (bp->b_error) {
		error = bp->b_error;
	error = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
				   BTOBB(sector_size), 0, &bp, buf_ops);
	if (error) {
		if (loud)
			xfs_warn(mp, "SB validate failed with error %d.", error);
		/* bad CRC means corrupted metadata */
		if (error == -EFSBADCRC)
			error = -EFSCORRUPTED;
		goto release_buf;
		return error;
	}

	/*
@@ -546,40 +540,43 @@ xfs_set_inoalignment(xfs_mount_t *mp)
 * Check that the data (and log if separate) is an ok size.
 */
STATIC int
xfs_check_sizes(xfs_mount_t *mp)
xfs_check_sizes(
	struct xfs_mount *mp)
{
	xfs_buf_t	*bp;
	struct xfs_buf	*bp;
	xfs_daddr_t	d;
	int		error;

	d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
	if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) {
		xfs_warn(mp, "filesystem size mismatch detected");
		return -EFBIG;
	}
	bp = xfs_buf_read_uncached(mp->m_ddev_targp,
	error = xfs_buf_read_uncached(mp->m_ddev_targp,
					d - XFS_FSS_TO_BB(mp, 1),
					XFS_FSS_TO_BB(mp, 1), 0, NULL);
	if (!bp) {
					XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
	if (error) {
		xfs_warn(mp, "last sector read failed");
		return -EIO;
		return error;
	}
	xfs_buf_relse(bp);

	if (mp->m_logdev_targp != mp->m_ddev_targp) {
	if (mp->m_logdev_targp == mp->m_ddev_targp)
		return 0;

	d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
	if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
		xfs_warn(mp, "log size mismatch detected");
		return -EFBIG;
	}
		bp = xfs_buf_read_uncached(mp->m_logdev_targp,
	error = xfs_buf_read_uncached(mp->m_logdev_targp,
					d - XFS_FSB_TO_BB(mp, 1),
					XFS_FSB_TO_BB(mp, 1), 0, NULL);
		if (!bp) {
					XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
	if (error) {
		xfs_warn(mp, "log device read failed");
			return -EIO;
		return error;
	}
	xfs_buf_relse(bp);
	}
	return 0;
}

+12 −18
Original line number Diff line number Diff line
@@ -972,16 +972,11 @@ xfs_growfs_rt(
	/*
	 * Read in the last block of the device, make sure it exists.
	 */
	bp = xfs_buf_read_uncached(mp->m_rtdev_targp,
	error = xfs_buf_read_uncached(mp->m_rtdev_targp,
				XFS_FSB_TO_BB(mp, nrblocks - 1),
				XFS_FSB_TO_BB(mp, 1), 0, NULL);
	if (!bp)
		return -EIO;
	if (bp->b_error) {
		error = bp->b_error;
		xfs_buf_relse(bp);
				XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
	if (error)
		return error;
	}
	xfs_buf_relse(bp);

	/*
@@ -1235,11 +1230,12 @@ xfs_rtallocate_extent(
 */
int				/* error */
xfs_rtmount_init(
	xfs_mount_t	*mp)	/* file system mount structure */
	struct xfs_mount	*mp)	/* file system mount structure */
{
	xfs_buf_t	*bp;	/* buffer for last block of subvolume */
	struct xfs_buf		*bp;	/* buffer for last block of subvolume */
	struct xfs_sb		*sbp;	/* filesystem superblock copy in mount */
	xfs_daddr_t		d;	/* address of last block of subvolume */
	xfs_sb_t	*sbp;	/* filesystem superblock copy in mount */
	int			error;

	sbp = &mp->m_sb;
	if (sbp->sb_rblocks == 0)
@@ -1265,14 +1261,12 @@ xfs_rtmount_init(
			(unsigned long long) mp->m_sb.sb_rblocks);
		return -EFBIG;
	}
	bp = xfs_buf_read_uncached(mp->m_rtdev_targp,
	error = xfs_buf_read_uncached(mp->m_rtdev_targp,
					d - XFS_FSB_TO_BB(mp, 1),
					XFS_FSB_TO_BB(mp, 1), 0, NULL);
	if (!bp || bp->b_error) {
					XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
	if (error) {
		xfs_warn(mp, "realtime device size check failed");
		if (bp)
			xfs_buf_relse(bp);
		return -EIO;
		return error;
	}
	xfs_buf_relse(bp);
	return 0;