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: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
Dave Chinner 2014-10-02 09:05:32 +10:00 committed by Dave Chinner
parent 595bff75dc
commit ba3726742c
5 changed files with 59 additions and 63 deletions

View File

@ -688,29 +688,39 @@ xfs_buf_readahead_map(
* Read an uncached buffer from disk. Allocates and returns a locked * Read an uncached buffer from disk. Allocates and returns a locked
* buffer containing the disk contents or nothing. * buffer containing the disk contents or nothing.
*/ */
struct xfs_buf * int
xfs_buf_read_uncached( xfs_buf_read_uncached(
struct xfs_buftarg *target, struct xfs_buftarg *target,
xfs_daddr_t daddr, xfs_daddr_t daddr,
size_t numblks, size_t numblks,
int flags, int flags,
struct xfs_buf **bpp,
const struct xfs_buf_ops *ops) const struct xfs_buf_ops *ops)
{ {
struct xfs_buf *bp; struct xfs_buf *bp;
*bpp = NULL;
bp = xfs_buf_get_uncached(target, numblks, flags); bp = xfs_buf_get_uncached(target, numblks, flags);
if (!bp) if (!bp)
return NULL; return -ENOMEM;
/* set up the buffer for a read IO */ /* set up the buffer for a read IO */
ASSERT(bp->b_map_count == 1); 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_maps[0].bm_bn = daddr;
bp->b_flags |= XBF_READ; bp->b_flags |= XBF_READ;
bp->b_ops = ops; bp->b_ops = ops;
xfs_buf_submit_wait(bp); 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;
} }
/* /*

View File

@ -269,9 +269,9 @@ 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, struct xfs_buf *xfs_buf_get_uncached(struct xfs_buftarg *target, size_t numblks,
int flags); int flags);
struct xfs_buf *xfs_buf_read_uncached(struct xfs_buftarg *target, int xfs_buf_read_uncached(struct xfs_buftarg *target, xfs_daddr_t daddr,
xfs_daddr_t daddr, size_t numblks, int flags, size_t numblks, int flags, struct xfs_buf **bpp,
const struct xfs_buf_ops *ops); const struct xfs_buf_ops *ops);
void xfs_buf_hold(struct xfs_buf *bp); void xfs_buf_hold(struct xfs_buf *bp);
/* Releasing Buffers */ /* Releasing Buffers */

View File

@ -172,16 +172,11 @@ xfs_growfs_data_private(
if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb))) if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
return error; return error;
dpct = pct - mp->m_sb.sb_imax_pct; 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_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
XFS_FSS_TO_BB(mp, 1), 0, NULL); XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
if (!bp) if (error)
return -EIO;
if (bp->b_error) {
error = bp->b_error;
xfs_buf_relse(bp);
return error; return error;
}
xfs_buf_relse(bp); xfs_buf_relse(bp);
new = nb; /* use new as a temporary here */ new = nb; /* use new as a temporary here */

View File

@ -302,21 +302,15 @@ xfs_readsb(
* access to the superblock. * access to the superblock.
*/ */
reread: reread:
bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR, error = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
BTOBB(sector_size), 0, buf_ops); BTOBB(sector_size), 0, &bp, buf_ops);
if (!bp) { if (error) {
if (loud)
xfs_warn(mp, "SB buffer read failed");
return -EIO;
}
if (bp->b_error) {
error = bp->b_error;
if (loud) if (loud)
xfs_warn(mp, "SB validate failed with error %d.", error); xfs_warn(mp, "SB validate failed with error %d.", error);
/* bad CRC means corrupted metadata */ /* bad CRC means corrupted metadata */
if (error == -EFSBADCRC) if (error == -EFSBADCRC)
error = -EFSCORRUPTED; 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. * Check that the data (and log if separate) is an ok size.
*/ */
STATIC int 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; xfs_daddr_t d;
int error;
d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); 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) { if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) {
xfs_warn(mp, "filesystem size mismatch detected"); xfs_warn(mp, "filesystem size mismatch detected");
return -EFBIG; 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), d - XFS_FSS_TO_BB(mp, 1),
XFS_FSS_TO_BB(mp, 1), 0, NULL); XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
if (!bp) { if (error) {
xfs_warn(mp, "last sector read failed"); xfs_warn(mp, "last sector read failed");
return -EIO; return error;
} }
xfs_buf_relse(bp); xfs_buf_relse(bp);
if (mp->m_logdev_targp != mp->m_ddev_targp) { if (mp->m_logdev_targp == mp->m_ddev_targp)
d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); return 0;
if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
xfs_warn(mp, "log size mismatch detected"); d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
return -EFBIG; if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
} xfs_warn(mp, "log size mismatch detected");
bp = xfs_buf_read_uncached(mp->m_logdev_targp, return -EFBIG;
d - XFS_FSB_TO_BB(mp, 1),
XFS_FSB_TO_BB(mp, 1), 0, NULL);
if (!bp) {
xfs_warn(mp, "log device read failed");
return -EIO;
}
xfs_buf_relse(bp);
} }
error = xfs_buf_read_uncached(mp->m_logdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
if (error) {
xfs_warn(mp, "log device read failed");
return error;
}
xfs_buf_relse(bp);
return 0; return 0;
} }

View File

@ -972,16 +972,11 @@ xfs_growfs_rt(
/* /*
* Read in the last block of the device, make sure it exists. * 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, nrblocks - 1),
XFS_FSB_TO_BB(mp, 1), 0, NULL); XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
if (!bp) if (error)
return -EIO;
if (bp->b_error) {
error = bp->b_error;
xfs_buf_relse(bp);
return error; return error;
}
xfs_buf_relse(bp); xfs_buf_relse(bp);
/* /*
@ -1235,11 +1230,12 @@ xfs_rtallocate_extent(
*/ */
int /* error */ int /* error */
xfs_rtmount_init( 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 */
xfs_daddr_t d; /* address of last block of subvolume */ struct xfs_sb *sbp; /* filesystem superblock copy in mount */
xfs_sb_t *sbp; /* filesystem superblock copy in mount */ xfs_daddr_t d; /* address of last block of subvolume */
int error;
sbp = &mp->m_sb; sbp = &mp->m_sb;
if (sbp->sb_rblocks == 0) if (sbp->sb_rblocks == 0)
@ -1265,14 +1261,12 @@ xfs_rtmount_init(
(unsigned long long) mp->m_sb.sb_rblocks); (unsigned long long) mp->m_sb.sb_rblocks);
return -EFBIG; 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), d - XFS_FSB_TO_BB(mp, 1),
XFS_FSB_TO_BB(mp, 1), 0, NULL); XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
if (!bp || bp->b_error) { if (error) {
xfs_warn(mp, "realtime device size check failed"); xfs_warn(mp, "realtime device size check failed");
if (bp) return error;
xfs_buf_relse(bp);
return -EIO;
} }
xfs_buf_relse(bp); xfs_buf_relse(bp);
return 0; return 0;