Commit 99be3f60 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'xfs-5.6-merge-8' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull moar xfs updates from Darrick Wong:
 "This contains the buffer error code refactoring I mentioned last week,
  now that it has had extra time to complete the full xfs fuzz testing
  suite to make sure there aren't any obvious new bugs"

* tag 'xfs-5.6-merge-8' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: fix xfs_buf_ioerror_alert location reporting
  xfs: remove unnecessary null pointer checks from _read_agf callers
  xfs: make xfs_*read_agf return EAGAIN to ALLOC_FLAG_TRYLOCK callers
  xfs: remove the xfs_btree_get_buf[ls] functions
  xfs: make xfs_trans_get_buf return an error code
  xfs: make xfs_trans_get_buf_map return an error code
  xfs: make xfs_buf_read return an error code
  xfs: make xfs_buf_get_uncached return an error code
  xfs: make xfs_buf_get return an error code
  xfs: make xfs_buf_read_map return an error code
  xfs: make xfs_buf_get_map return an error code
  xfs: make xfs_buf_alloc return an error code
parents e310396b cdbcf82b
...@@ -23,25 +23,28 @@ ...@@ -23,25 +23,28 @@
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
#include "xfs_health.h" #include "xfs_health.h"
static struct xfs_buf * static int
xfs_get_aghdr_buf( xfs_get_aghdr_buf(
struct xfs_mount *mp, struct xfs_mount *mp,
xfs_daddr_t blkno, xfs_daddr_t blkno,
size_t numblks, size_t numblks,
struct xfs_buf **bpp,
const struct xfs_buf_ops *ops) const struct xfs_buf_ops *ops)
{ {
struct xfs_buf *bp; struct xfs_buf *bp;
int error;
bp = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, 0); error = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, 0, &bp);
if (!bp) if (error)
return NULL; return error;
xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
bp->b_bn = blkno; bp->b_bn = blkno;
bp->b_maps[0].bm_bn = blkno; bp->b_maps[0].bm_bn = blkno;
bp->b_ops = ops; bp->b_ops = ops;
return bp; *bpp = bp;
return 0;
} }
static inline bool is_log_ag(struct xfs_mount *mp, struct aghdr_init_data *id) static inline bool is_log_ag(struct xfs_mount *mp, struct aghdr_init_data *id)
...@@ -340,13 +343,13 @@ xfs_ag_init_hdr( ...@@ -340,13 +343,13 @@ xfs_ag_init_hdr(
struct aghdr_init_data *id, struct aghdr_init_data *id,
aghdr_init_work_f work, aghdr_init_work_f work,
const struct xfs_buf_ops *ops) const struct xfs_buf_ops *ops)
{ {
struct xfs_buf *bp; struct xfs_buf *bp;
int error;
bp = xfs_get_aghdr_buf(mp, id->daddr, id->numblks, ops); error = xfs_get_aghdr_buf(mp, id->daddr, id->numblks, &bp, ops);
if (!bp) if (error)
return -ENOMEM; return error;
(*work)(mp, bp, id); (*work)(mp, bp, id);
......
...@@ -1070,11 +1070,11 @@ xfs_alloc_ag_vextent_small( ...@@ -1070,11 +1070,11 @@ xfs_alloc_ag_vextent_small(
if (args->datatype & XFS_ALLOC_USERDATA) { if (args->datatype & XFS_ALLOC_USERDATA) {
struct xfs_buf *bp; struct xfs_buf *bp;
bp = xfs_btree_get_bufs(args->mp, args->tp, args->agno, fbno); error = xfs_trans_get_buf(args->tp, args->mp->m_ddev_targp,
if (XFS_IS_CORRUPT(args->mp, !bp)) { XFS_AGB_TO_DADDR(args->mp, args->agno, fbno),
error = -EFSCORRUPTED; args->mp->m_bsize, 0, &bp);
if (error)
goto error; goto error;
}
xfs_trans_binval(args->tp, bp); xfs_trans_binval(args->tp, bp);
} }
*fbnop = args->agbno = fbno; *fbnop = args->agbno = fbno;
...@@ -2347,9 +2347,11 @@ xfs_free_agfl_block( ...@@ -2347,9 +2347,11 @@ xfs_free_agfl_block(
if (error) if (error)
return error; return error;
bp = xfs_btree_get_bufs(tp->t_mountp, tp, agno, agbno); error = xfs_trans_get_buf(tp, tp->t_mountp->m_ddev_targp,
if (XFS_IS_CORRUPT(tp->t_mountp, !bp)) XFS_AGB_TO_DADDR(tp->t_mountp, agno, agbno),
return -EFSCORRUPTED; tp->t_mountp->m_bsize, 0, &bp);
if (error)
return error;
xfs_trans_binval(tp, bp); xfs_trans_binval(tp, bp);
return 0; return 0;
...@@ -2500,12 +2502,11 @@ xfs_alloc_fix_freelist( ...@@ -2500,12 +2502,11 @@ xfs_alloc_fix_freelist(
if (!pag->pagf_init) { if (!pag->pagf_init) {
error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp); error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp);
if (error) if (error) {
/* Couldn't lock the AGF so skip this AG. */
if (error == -EAGAIN)
error = 0;
goto out_no_agbp; goto out_no_agbp;
if (!pag->pagf_init) {
ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK);
ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));
goto out_agbp_relse;
} }
} }
...@@ -2531,11 +2532,10 @@ xfs_alloc_fix_freelist( ...@@ -2531,11 +2532,10 @@ xfs_alloc_fix_freelist(
*/ */
if (!agbp) { if (!agbp) {
error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp); error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp);
if (error) if (error) {
goto out_no_agbp; /* Couldn't lock the AGF so skip this AG. */
if (!agbp) { if (error == -EAGAIN)
ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK); error = 0;
ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING));
goto out_no_agbp; goto out_no_agbp;
} }
} }
...@@ -2766,11 +2766,10 @@ xfs_alloc_pagf_init( ...@@ -2766,11 +2766,10 @@ xfs_alloc_pagf_init(
xfs_buf_t *bp; xfs_buf_t *bp;
int error; int error;
if ((error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp))) error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp);
return error; if (!error)
if (bp)
xfs_trans_brelse(tp, bp); xfs_trans_brelse(tp, bp);
return 0; return error;
} }
/* /*
...@@ -2956,14 +2955,11 @@ xfs_read_agf( ...@@ -2956,14 +2955,11 @@ xfs_read_agf(
trace_xfs_read_agf(mp, agno); trace_xfs_read_agf(mp, agno);
ASSERT(agno != NULLAGNUMBER); ASSERT(agno != NULLAGNUMBER);
error = xfs_trans_read_buf( error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
mp, tp, mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1), flags, bpp, &xfs_agf_buf_ops); XFS_FSS_TO_BB(mp, 1), flags, bpp, &xfs_agf_buf_ops);
if (error) if (error)
return error; return error;
if (!*bpp)
return 0;
ASSERT(!(*bpp)->b_error); ASSERT(!(*bpp)->b_error);
xfs_buf_set_ref(*bpp, XFS_AGF_REF); xfs_buf_set_ref(*bpp, XFS_AGF_REF);
...@@ -2987,14 +2983,15 @@ xfs_alloc_read_agf( ...@@ -2987,14 +2983,15 @@ xfs_alloc_read_agf(
trace_xfs_alloc_read_agf(mp, agno); trace_xfs_alloc_read_agf(mp, agno);
/* We don't support trylock when freeing. */
ASSERT((flags & (XFS_ALLOC_FLAG_FREEING | XFS_ALLOC_FLAG_TRYLOCK)) !=
(XFS_ALLOC_FLAG_FREEING | XFS_ALLOC_FLAG_TRYLOCK));
ASSERT(agno != NULLAGNUMBER); ASSERT(agno != NULLAGNUMBER);
error = xfs_read_agf(mp, tp, agno, error = xfs_read_agf(mp, tp, agno,
(flags & XFS_ALLOC_FLAG_TRYLOCK) ? XBF_TRYLOCK : 0, (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XBF_TRYLOCK : 0,
bpp); bpp);
if (error) if (error)
return error; return error;
if (!*bpp)
return 0;
ASSERT(!(*bpp)->b_error); ASSERT(!(*bpp)->b_error);
agf = XFS_BUF_TO_AGF(*bpp); agf = XFS_BUF_TO_AGF(*bpp);
......
...@@ -418,20 +418,10 @@ xfs_attr_rmtval_get( ...@@ -418,20 +418,10 @@ xfs_attr_rmtval_get(
(map[i].br_startblock != HOLESTARTBLOCK)); (map[i].br_startblock != HOLESTARTBLOCK));
dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
bp = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt, 0, error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
&xfs_attr3_rmt_buf_ops); 0, &bp, &xfs_attr3_rmt_buf_ops);
if (!bp) if (error)
return -ENOMEM;
error = bp->b_error;
if (error) {
xfs_buf_ioerror_alert(bp, __func__);
xfs_buf_relse(bp);
/* bad CRC means corrupted metadata */
if (error == -EFSBADCRC)
error = -EFSCORRUPTED;
return error; return error;
}
error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino, error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
&offset, &valuelen, &offset, &valuelen,
...@@ -555,9 +545,9 @@ xfs_attr_rmtval_set( ...@@ -555,9 +545,9 @@ xfs_attr_rmtval_set(
dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt); error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
if (!bp) if (error)
return -ENOMEM; return error;
bp->b_ops = &xfs_attr3_rmt_buf_ops; bp->b_ops = &xfs_attr3_rmt_buf_ops;
xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset, xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
......
...@@ -730,11 +730,11 @@ xfs_bmap_extents_to_btree( ...@@ -730,11 +730,11 @@ xfs_bmap_extents_to_btree(
cur->bc_private.b.allocated++; cur->bc_private.b.allocated++;
ip->i_d.di_nblocks++; ip->i_d.di_nblocks++;
xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
abp = xfs_btree_get_bufl(mp, tp, args.fsbno); error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
if (XFS_IS_CORRUPT(mp, !abp)) { XFS_FSB_TO_DADDR(mp, args.fsbno),
error = -EFSCORRUPTED; mp->m_bsize, 0, &abp);
if (error)
goto out_unreserve_dquot; goto out_unreserve_dquot;
}
/* /*
* Fill in the child block. * Fill in the child block.
...@@ -878,7 +878,11 @@ xfs_bmap_local_to_extents( ...@@ -878,7 +878,11 @@ xfs_bmap_local_to_extents(
ASSERT(args.fsbno != NULLFSBLOCK); ASSERT(args.fsbno != NULLFSBLOCK);
ASSERT(args.len == 1); ASSERT(args.len == 1);
tp->t_firstblock = args.fsbno; tp->t_firstblock = args.fsbno;
bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno); error = xfs_trans_get_buf(tp, args.mp->m_ddev_targp,
XFS_FSB_TO_DADDR(args.mp, args.fsbno),
args.mp->m_bsize, 0, &bp);
if (error)
goto done;
/* /*
* Initialize the block, copy the data and log the remote buffer. * Initialize the block, copy the data and log the remote buffer.
...@@ -3307,11 +3311,12 @@ xfs_bmap_longest_free_extent( ...@@ -3307,11 +3311,12 @@ xfs_bmap_longest_free_extent(
pag = xfs_perag_get(mp, ag); pag = xfs_perag_get(mp, ag);
if (!pag->pagf_init) { if (!pag->pagf_init) {
error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK); error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK);
if (error) if (error) {
goto out; /* Couldn't lock the AGF, so skip this AG. */
if (error == -EAGAIN) {
if (!pag->pagf_init) {
*notinit = 1; *notinit = 1;
error = 0;
}
goto out; goto out;
} }
} }
......
...@@ -678,42 +678,6 @@ xfs_btree_get_block( ...@@ -678,42 +678,6 @@ xfs_btree_get_block(
return XFS_BUF_TO_BLOCK(*bpp); return XFS_BUF_TO_BLOCK(*bpp);
} }
/*
* Get a buffer for the block, return it with no data read.
* Long-form addressing.
*/
xfs_buf_t * /* buffer for fsbno */
xfs_btree_get_bufl(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_fsblock_t fsbno) /* file system block number */
{
xfs_daddr_t d; /* real disk block address */
ASSERT(fsbno != NULLFSBLOCK);
d = XFS_FSB_TO_DADDR(mp, fsbno);
return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, 0);
}
/*
* Get a buffer for the block, return it with no data read.
* Short-form addressing.
*/
xfs_buf_t * /* buffer for agno/agbno */
xfs_btree_get_bufs(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_agnumber_t agno, /* allocation group number */
xfs_agblock_t agbno) /* allocation group block number */
{
xfs_daddr_t d; /* real disk block address */
ASSERT(agno != NULLAGNUMBER);
ASSERT(agbno != NULLAGBLOCK);
d = XFS_AGB_TO_DADDR(mp, agno, agbno);
return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, 0);
}
/* /*
* Change the cursor to point to the first record at the given level. * Change the cursor to point to the first record at the given level.
* Other levels are unaffected. * Other levels are unaffected.
...@@ -1270,11 +1234,10 @@ xfs_btree_get_buf_block( ...@@ -1270,11 +1234,10 @@ xfs_btree_get_buf_block(
error = xfs_btree_ptr_to_daddr(cur, ptr, &d); error = xfs_btree_ptr_to_daddr(cur, ptr, &d);
if (error) if (error)
return error; return error;
*bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d, error = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d, mp->m_bsize,
mp->m_bsize, 0); 0, bpp);
if (error)
if (!*bpp) return error;
return -ENOMEM;
(*bpp)->b_ops = cur->bc_ops->buf_ops; (*bpp)->b_ops = cur->bc_ops->buf_ops;
*block = XFS_BUF_TO_BLOCK(*bpp); *block = XFS_BUF_TO_BLOCK(*bpp);
......
...@@ -296,27 +296,6 @@ xfs_btree_dup_cursor( ...@@ -296,27 +296,6 @@ xfs_btree_dup_cursor(
xfs_btree_cur_t *cur, /* input cursor */ xfs_btree_cur_t *cur, /* input cursor */
xfs_btree_cur_t **ncur);/* output cursor */ xfs_btree_cur_t **ncur);/* output cursor */
/*
* Get a buffer for the block, return it with no data read.
* Long-form addressing.
*/
struct xfs_buf * /* buffer for fsbno */
xfs_btree_get_bufl(
struct xfs_mount *mp, /* file system mount point */
struct xfs_trans *tp, /* transaction pointer */
xfs_fsblock_t fsbno); /* file system block number */
/*
* Get a buffer for the block, return it with no data read.
* Short-form addressing.
*/
struct xfs_buf * /* buffer for agno/agbno */
xfs_btree_get_bufs(
struct xfs_mount *mp, /* file system mount point */
struct xfs_trans *tp, /* transaction pointer */
xfs_agnumber_t agno, /* allocation group number */
xfs_agblock_t agbno); /* allocation group block number */
/* /*
* Compute first and last byte offsets for the fields given. * Compute first and last byte offsets for the fields given.
* Interprets the offsets table, which contains struct field offsets. * Interprets the offsets table, which contains struct field offsets.
......
...@@ -2591,13 +2591,9 @@ xfs_da_get_buf( ...@@ -2591,13 +2591,9 @@ xfs_da_get_buf(
if (error || nmap == 0) if (error || nmap == 0)
goto out_free; goto out_free;
bp = xfs_trans_get_buf_map(tp, mp->m_ddev_targp, mapp, nmap, 0); error = xfs_trans_get_buf_map(tp, mp->m_ddev_targp, mapp, nmap, 0, &bp);
error = bp ? bp->b_error : -EIO; if (error)
if (error) {
if (bp)
xfs_trans_brelse(tp, bp);
goto out_free; goto out_free;
}
*bpp = bp; *bpp = bp;
......
...@@ -276,6 +276,7 @@ xfs_ialloc_inode_init( ...@@ -276,6 +276,7 @@ xfs_ialloc_inode_init(
int i, j; int i, j;
xfs_daddr_t d; xfs_daddr_t d;
xfs_ino_t ino = 0; xfs_ino_t ino = 0;
int error;
/* /*
* Loop over the new block(s), filling in the inodes. For small block * Loop over the new block(s), filling in the inodes. For small block
...@@ -327,12 +328,11 @@ xfs_ialloc_inode_init( ...@@ -327,12 +328,11 @@ xfs_ialloc_inode_init(
*/ */
d = XFS_AGB_TO_DADDR(mp, agno, agbno + d = XFS_AGB_TO_DADDR(mp, agno, agbno +
(j * M_IGEO(mp)->blocks_per_cluster)); (j * M_IGEO(mp)->blocks_per_cluster));
fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
mp->m_bsize * mp->m_bsize * M_IGEO(mp)->blocks_per_cluster,
M_IGEO(mp)->blocks_per_cluster, XBF_UNMAPPED, &fbuf);
XBF_UNMAPPED); if (error)
if (!fbuf) return error;
return -ENOMEM;
/* Initialize the inode buffers and log them appropriately. */ /* Initialize the inode buffers and log them appropriately. */
fbuf->b_ops = &xfs_inode_buf_ops; fbuf->b_ops = &xfs_inode_buf_ops;
......
...@@ -1177,8 +1177,6 @@ xfs_refcount_finish_one( ...@@ -1177,8 +1177,6 @@ xfs_refcount_finish_one(
XFS_ALLOC_FLAG_FREEING, &agbp); XFS_ALLOC_FLAG_FREEING, &agbp);
if (error) if (error)
return error; return error;
if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
return -EFSCORRUPTED;
rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno); rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
if (!rcur) { if (!rcur) {
...@@ -1718,10 +1716,6 @@ xfs_refcount_recover_cow_leftovers( ...@@ -1718,10 +1716,6 @@ xfs_refcount_recover_cow_leftovers(
error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
if (error) if (error)
goto out_trans; goto out_trans;
if (!agbp) {
error = -ENOMEM;
goto out_trans;
}
cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno); cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
/* Find all the leftover CoW staging extents. */ /* Find all the leftover CoW staging extents. */
......
...@@ -985,9 +985,9 @@ xfs_update_secondary_sbs( ...@@ -985,9 +985,9 @@ xfs_update_secondary_sbs(
for (agno = 1; agno < mp->m_sb.sb_agcount; agno++) { for (agno = 1; agno < mp->m_sb.sb_agcount; agno++) {
struct xfs_buf *bp; struct xfs_buf *bp;
bp = xfs_buf_get(mp->m_ddev_targp, error = xfs_buf_get(mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
XFS_FSS_TO_BB(mp, 1)); XFS_FSS_TO_BB(mp, 1), &bp);
/* /*
* If we get an error reading or writing alternate superblocks, * If we get an error reading or writing alternate superblocks,
* continue. xfs_repair chooses the "best" superblock based * continue. xfs_repair chooses the "best" superblock based
...@@ -995,12 +995,12 @@ xfs_update_secondary_sbs( ...@@ -995,12 +995,12 @@ xfs_update_secondary_sbs(
* superblocks un-updated than updated, and xfs_repair may * superblocks un-updated than updated, and xfs_repair may
* pick them over the properly-updated primary. * pick them over the properly-updated primary.
*/ */
if (!bp) { if (error) {
xfs_warn(mp, xfs_warn(mp,
"error allocating secondary superblock for ag %d", "error allocating secondary superblock for ag %d",
agno); agno);
if (!saved_error) if (!saved_error)
saved_error = -ENOMEM; saved_error = error;
continue; continue;
} }
...@@ -1185,13 +1185,14 @@ xfs_sb_get_secondary( ...@@ -1185,13 +1185,14 @@ xfs_sb_get_secondary(
struct xfs_buf **bpp) struct xfs_buf **bpp)
{ {
struct xfs_buf *bp; struct xfs_buf *bp;
int error;
ASSERT(agno != 0 && agno != NULLAGNUMBER); ASSERT(agno != 0 && agno != NULLAGNUMBER);
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_SB_BLOCK(mp)), XFS_AG_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
XFS_FSS_TO_BB(mp, 1), 0); XFS_FSS_TO_BB(mp, 1), 0, &bp);
if (!bp) if (error)
return -ENOMEM; return error;
bp->b_ops = &xfs_sb_buf_ops; bp->b_ops = &xfs_sb_buf_ops;
xfs_buf_oneshot(bp); xfs_buf_oneshot(bp);
*bpp = bp; *bpp = bp;
......
...@@ -659,8 +659,6 @@ xrep_agfl( ...@@ -659,8 +659,6 @@ xrep_agfl(
error = xfs_alloc_read_agf(mp, sc->tp, sc->sa.agno, 0, &agf_bp); error = xfs_alloc_read_agf(mp, sc->tp, sc->sa.agno, 0, &agf_bp);
if (error) if (error)
return error; return error;
if (!agf_bp)
return -ENOMEM;
/* /*
* Make sure we have the AGFL buffer, as scrub might have decided it * Make sure we have the AGFL buffer, as scrub might have decided it
...@@ -735,8 +733,6 @@ xrep_agi_find_btrees( ...@@ -735,8 +733,6 @@ xrep_agi_find_btrees(
error = xfs_alloc_read_agf(mp, sc->tp, sc->sa.agno, 0, &agf_bp); error = xfs_alloc_read_agf(mp, sc->tp, sc->sa.agno, 0, &agf_bp);
if (error) if (error)
return error; return error;
if (!agf_bp)
return -ENOMEM;
/* Find the btree roots. */ /* Find the btree roots. */
error = xrep_find_ag_btree_roots(sc, agf_bp, fab, NULL); error = xrep_find_ag_btree_roots(sc, agf_bp, fab, NULL);
......
...@@ -83,9 +83,6 @@ xchk_fscount_warmup( ...@@ -83,9 +83,6 @@ xchk_fscount_warmup(
error = xfs_alloc_read_agf(mp, sc->tp, agno, 0, &agf_bp); error = xfs_alloc_read_agf(mp, sc->tp, agno, 0, &agf_bp);
if (error) if (error)
break; break;
error = -ENOMEM;
if (!agf_bp || !agi_bp)
break;
/* /*
* These are supposed to be initialized by the header read * These are supposed to be initialized by the header read
......
...@@ -341,13 +341,17 @@ xrep_init_btblock( ...@@ -341,13 +341,17 @@ xrep_init_btblock(
struct xfs_trans *tp = sc->tp; struct xfs_trans *tp = sc->tp;
struct xfs_mount *mp = sc->mp; struct xfs_mount *mp = sc->mp;
struct xfs_buf *bp; struct xfs_buf *bp;
int error;
trace_xrep_init_btblock(mp, XFS_FSB_TO_AGNO(mp, fsb), trace_xrep_init_btblock(mp, XFS_FSB_TO_AGNO(mp, fsb),
XFS_FSB_TO_AGBNO(mp, fsb), btnum); XFS_FSB_TO_AGBNO(mp, fsb), btnum);
ASSERT(XFS_FSB_TO_AGNO(mp, fsb) == sc->sa.agno); ASSERT(XFS_FSB_TO_AGNO(mp, fsb) == sc->sa.agno);
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, fsb), error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
XFS_FSB_TO_BB(mp, 1), 0); XFS_FSB_TO_DADDR(mp, fsb), XFS_FSB_TO_BB(mp, 1), 0,
&bp);
if (error)
return error;
xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
xfs_btree_init_block(mp, bp, btnum, 0, 0, sc->sa.agno); xfs_btree_init_block(mp, bp, btnum, 0, 0, sc->sa.agno);
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_buf_set_type(tp, bp, XFS_BLFT_BTREE_BUF);
...@@ -542,8 +546,6 @@ xrep_reap_block( ...@@ -542,8 +546,6 @@ xrep_reap_block(
error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, &agf_bp); error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, &agf_bp);
if (error) if (error)
return error; return error;
if (!agf_bp)
return -ENOMEM;
} else { } else {
agf_bp = sc->sa.agf_bp; agf_bp = sc->sa.agf_bp;
} }
......
...@@ -205,11 +205,12 @@ xfs_attr3_node_inactive( ...@@ -205,11 +205,12 @@ xfs_attr3_node_inactive(
/* /*
* Remove the subsidiary block from the cache and from the log. * Remove the subsidiary block from the cache and from the log.
*/ */
child_bp = xfs_trans_get_buf(*trans, mp->m_ddev_targp, error = xfs_trans_get_buf(*trans, mp->m_ddev_targp,
child_blkno, child_blkno,
XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0); XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0,
if (!child_bp) &child_bp);
return -EIO; if (error)
return error;
error = bp->b_error; error = bp->b_error;
if (error) { if (error) {
xfs_trans_brelse(*trans, child_bp); xfs_trans_brelse(*trans, child_bp);
...@@ -298,10 +299,10 @@ xfs_attr3_root_inactive( ...@@ -298,10 +299,10 @@ xfs_attr3_root_inactive(
/* /*
* Invalidate the incore copy of the root block. * Invalidate the incore copy of the root block.
*/ */
bp = xfs_trans_get_buf(*trans, mp->m_ddev_targp, blkno, error = xfs_trans_get_buf(*trans, mp->m_ddev_targp, blkno,
XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0); XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0, &bp);
if (!bp) if (error)
return -EIO; return error;
error = bp->b_error; error = bp->b_error;
if (error) { if (error) {
xfs_trans_brelse(*trans, bp); xfs_trans_brelse(*trans, bp);
......
...@@ -198,20 +198,22 @@ xfs_buf_free_maps( ...@@ -198,20 +198,22 @@ xfs_buf_free_maps(
} }
} }
static struct xfs_buf * static int
_xfs_buf_alloc( _xfs_buf_alloc(
struct xfs_buftarg *target, struct xfs_buftarg *target,
struct xfs_buf_map *map, struct xfs_buf_map *map,
int nmaps, int nmaps,
xfs_buf_flags_t flags) xfs_buf_flags_t flags,
struct xfs_buf **bpp)
{ {
struct xfs_buf *bp; struct xfs_buf *bp;
int error; int error;
int i; int i;
*bpp = NULL;
bp = kmem_zone_zalloc(xfs_buf_zone, KM_NOFS); bp = kmem_zone_zalloc(xfs_buf_zone, KM_NOFS);
if (unlikely(!bp)) if (unlikely(!bp))
return NULL; return -ENOMEM;
/* /*
* We don't want certain flags to appear in b_flags unless they are * We don't want certain flags to appear in b_flags unless they are
...@@ -239,7 +241,7 @@ _xfs_buf_alloc( ...@@ -239,7 +241,7 @@ _xfs_buf_alloc(
error = xfs_buf_get_maps(bp, nmaps); error = xfs_buf_get_maps(bp, nmaps);
if (error) { if (error) {
kmem_cache_free(xfs_buf_zone, bp); kmem_cache_free(xfs_buf_zone, bp);
return NULL; return error;
} }
bp->b_bn = map[0].bm_bn; bp->b_bn = map[0].bm_bn;
...@@ -256,7 +258,8 @@ _xfs_buf_alloc( ...@@ -256,7 +258,8 @@ _xfs_buf_alloc(
XFS_STATS_INC(bp->b_mount, xb_create); XFS_STATS_INC(bp->b_mount, xb_create);
trace_xfs_buf_init(bp, _RET_IP_); trace_xfs_buf_init(bp, _RET_IP_);
return bp; *bpp = bp;
return 0;
} }
/* /*
...@@ -682,53 +685,39 @@ xfs_buf_incore( ...@@ -682,53 +685,39 @@ xfs_buf_incore(
* cache hits, as metadata intensive workloads will see 3 orders of magnitude * cache hits, as metadata intensive workloads will see 3 orders of magnitude
* more hits than misses. * more hits than misses.
*/ */
struct xfs_buf * int
xfs_buf_get_map( xfs_buf_get_map(
struct xfs_buftarg *target, struct xfs_buftarg *target,
struct xfs_buf_map *map, struct xfs_buf_map *map,
int nmaps, int nmaps,
xfs_buf_flags_t flags) xfs_buf_flags_t flags,
struct xfs_buf **bpp)
{ {
struct xfs_buf *bp; struct xfs_buf *bp;
struct xfs_buf *new_bp; struct xfs_buf *new_bp;
int error = 0; int error = 0;
*bpp = NULL;
error = xfs_buf_find(target, map, nmaps, flags, NULL, &bp); error = xfs_buf_find(target, map, nmaps, flags, NULL, &bp);
if (!error)
switch (error) {
case 0:
/* cache hit */
goto found; goto found;
case -EAGAIN: if (error != -ENOENT)
/* cache hit, trylock failure, caller handles failure */ return error;
ASSERT(flags & XBF_TRYLOCK);
return NULL;
case -ENOENT:
/* cache miss, go for insert */
break;
case -EFSCORRUPTED:
default:
/*
* None of the higher layers understand failure types
* yet, so return NULL to signal a fatal lookup error.
*/
return NULL;
}
new_bp = _xfs_buf_alloc(target, map, nmaps, flags); error = _xfs_buf_alloc(target, map, nmaps, flags, &new_bp);
if (unlikely(!new_bp)) if (error)
return NULL; return error;
error = xfs_buf_allocate_memory(new_bp, flags); error = xfs_buf_allocate_memory(new_bp, flags);
if (error) { if (error) {
xfs_buf_free(new_bp); xfs_buf_free(new_bp);
return NULL; return error;
} }
error = xfs_buf_find(target, map, nmaps, flags, new_bp, &bp); error = xfs_buf_find(target, map, nmaps, flags, new_bp, &bp);
if (error) { if (error) {
xfs_buf_free(new_bp); xfs_buf_free(new_bp);
return NULL; return error;
} }
if (bp != new_bp) if (bp != new_bp)
...@@ -741,7 +730,7 @@ xfs_buf_get_map( ...@@ -741,7 +730,7 @@ xfs_buf_get_map(
xfs_warn(target->bt_mount, xfs_warn(target->bt_mount,
"%s: failed to map pagesn", __func__); "%s: failed to map pagesn", __func__);
xfs_buf_relse(bp); xfs_buf_relse(bp);
return NULL; return error;
} }
} }
...@@ -754,7 +743,8 @@ xfs_buf_get_map( ...@@ -754,7 +743,8 @@ xfs_buf_get_map(
XFS_STATS_INC(target->bt_mount, xb_get); XFS_STATS_INC(target->bt_mount, xb_get);
trace_xfs_buf_get(bp, flags, _RET_IP_); trace_xfs_buf_get(bp, flags, _RET_IP_);
return bp; *bpp = bp;
return 0;
} }
STATIC int STATIC int
...@@ -806,46 +796,77 @@ xfs_buf_reverify( ...@@ -806,46 +796,77 @@ xfs_buf_reverify(
return bp->b_error; return bp->b_error;
} }
xfs_buf_t * int
xfs_buf_read_map( xfs_buf_read_map(
struct xfs_buftarg *target, struct xfs_buftarg *target,
struct xfs_buf_map *map, struct xfs_buf_map *map,
int nmaps, int nmaps,
xfs_buf_flags_t flags, xfs_buf_flags_t flags,
const struct xfs_buf_ops *ops) struct xfs_buf **bpp,
const struct xfs_buf_ops *ops,
xfs_failaddr_t fa)
{ {
struct xfs_buf *bp; struct xfs_buf *bp;
int error;
flags |= XBF_READ; flags |= XBF_READ;
*bpp = NULL;
bp = xfs_buf_get_map(target, map, nmaps, flags); error = xfs_buf_get_map(target, map, nmaps, flags, &bp);
if (!bp) if (error)
return NULL; return error;
trace_xfs_buf_read(bp, flags, _RET_IP_); trace_xfs_buf_read(bp, flags, _RET_IP_);
if (!(bp->b_flags & XBF_DONE)) { if (!(bp->b_flags & XBF_DONE)) {
/* Initiate the buffer read and wait. */
XFS_STATS_INC(target->bt_mount, xb_get_read); XFS_STATS_INC(target->bt_mount, xb_get_read);
bp->b_ops = ops; bp->b_ops = ops;
_xfs_buf_read(bp, flags); error = _xfs_buf_read(bp, flags);
return bp;
}
xfs_buf_reverify(bp, ops); /* Readahead iodone already dropped the buffer, so exit. */
if (flags & XBF_ASYNC)
return 0;
} else {
/* Buffer already read; all we need to do is check it. */
error = xfs_buf_reverify(bp, ops);
/* Readahead already finished; drop the buffer and exit. */
if (flags & XBF_ASYNC) { if (flags & XBF_ASYNC) {
/*
* Read ahead call which is already satisfied,
* drop the buffer
*/
xfs_buf_relse(bp); xfs_buf_relse(bp);
return NULL; return 0;
} }
/* We do not want read in the flags */ /* We do not want read in the flags */
bp->b_flags &= ~XBF_READ; bp->b_flags &= ~XBF_READ;
ASSERT(bp->b_ops != NULL || ops == NULL); ASSERT(bp->b_ops != NULL || ops == NULL);
return bp; }
/*
* If we've had a read error, then the contents of the buffer are
* invalid and should not be used. To ensure that a followup read tries
* to pull the buffer from disk again, we clear the XBF_DONE flag and
* mark the buffer stale. This ensures that anyone who has a current
* reference to the buffer will interpret it's contents correctly and
* future cache lookups will also treat it as an empty, uninitialised
* buffer.
*/
if (error) {
if (!XFS_FORCED_SHUTDOWN(target->bt_mount))
xfs_buf_ioerror_alert(bp, fa);
bp->b_flags &= ~XBF_DONE;
xfs_buf_stale(bp);
xfs_buf_relse(bp);
/* bad CRC means corrupted metadata */
if (error == -EFSBADCRC)
error = -EFSCORRUPTED;
return error;
}
*bpp = bp;
return 0;
} }
/* /*
...@@ -859,11 +880,14 @@ xfs_buf_readahead_map( ...@@ -859,11 +880,14 @@ xfs_buf_readahead_map(
int nmaps, int nmaps,
const struct xfs_buf_ops *ops) const struct xfs_buf_ops *ops)
{ {
struct xfs_buf *bp;
if (bdi_read_congested(target->bt_bdev->bd_bdi)) if (bdi_read_congested(target->bt_bdev->bd_bdi))
return; return;
xfs_buf_read_map(target, map, nmaps, xfs_buf_read_map(target, map, nmaps,
XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD, ops); XBF_TRYLOCK | XBF_ASYNC | XBF_READ_AHEAD, &bp, ops,
__this_address);
} }
/* /*
...@@ -880,12 +904,13 @@ xfs_buf_read_uncached( ...@@ -880,12 +904,13 @@ xfs_buf_read_uncached(
const struct xfs_buf_ops *ops) const struct xfs_buf_ops *ops)
{ {
struct xfs_buf *bp; struct xfs_buf *bp;
int error;
*bpp = NULL; *bpp = NULL;
bp = xfs_buf_get_uncached(target, numblks, flags); error = xfs_buf_get_uncached(target, numblks, flags, &bp);
if (!bp) if (error)
return -ENOMEM; return error;
/* 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);
...@@ -896,7 +921,7 @@ xfs_buf_read_uncached( ...@@ -896,7 +921,7 @@ xfs_buf_read_uncached(
xfs_buf_submit(bp); xfs_buf_submit(bp);
if (bp->b_error) { if (bp->b_error) {
int error = bp->b_error; error = bp->b_error;
xfs_buf_relse(bp); xfs_buf_relse(bp);
return error; return error;
} }
...@@ -905,20 +930,23 @@ xfs_buf_read_uncached( ...@@ -905,20 +930,23 @@ xfs_buf_read_uncached(
return 0; return 0;
} }
xfs_buf_t * int
xfs_buf_get_uncached( xfs_buf_get_uncached(
struct xfs_buftarg *target, struct xfs_buftarg *target,
size_t numblks, size_t numblks,
int flags) int flags,
struct xfs_buf **bpp)
{ {
unsigned long page_count; unsigned long page_count;
int error, i; int error, i;
struct xfs_buf *bp; struct xfs_buf *bp;
DEFINE_SINGLE_BUF_MAP(map, XFS_BUF_DADDR_NULL, numblks); DEFINE_SINGLE_BUF_MAP(map, XFS_BUF_DADDR_NULL, numblks);
*bpp = NULL;
/* flags might contain irrelevant bits, pass only what we care about */ /* flags might contain irrelevant bits, pass only what we care about */
bp = _xfs_buf_alloc(target, &map, 1, flags & XBF_NO_IOACCT); error = _xfs_buf_alloc(target, &map, 1, flags & XBF_NO_IOACCT, &bp);
if (unlikely(bp == NULL)) if (error)
goto fail; goto fail;
page_count = PAGE_ALIGN(numblks << BBSHIFT) >> PAGE_SHIFT; page_count = PAGE_ALIGN(numblks << BBSHIFT) >> PAGE_SHIFT;
...@@ -928,9 +956,11 @@ xfs_buf_get_uncached( ...@@ -928,9 +956,11 @@ xfs_buf_get_uncached(
for (i = 0; i < page_count; i++) { for (i = 0; i < page_count; i++) {
bp->b_pages[i] = alloc_page(xb_to_gfp(flags)); bp->b_pages[i] = alloc_page(xb_to_gfp(flags));
if (!bp->b_pages[i]) if (!bp->b_pages[i]) {
error = -ENOMEM;
goto fail_free_mem; goto fail_free_mem;
} }
}
bp->b_flags |= _XBF_PAGES; bp->b_flags |= _XBF_PAGES;
error = _xfs_buf_map_pages(bp, 0); error = _xfs_buf_map_pages(bp, 0);
...@@ -941,7 +971,8 @@ xfs_buf_get_uncached( ...@@ -941,7 +971,8 @@ xfs_buf_get_uncached(
} }
trace_xfs_buf_get_uncached(bp, _RET_IP_); trace_xfs_buf_get_uncached(bp, _RET_IP_);
return bp; *bpp = bp;
return 0;
fail_free_mem: fail_free_mem:
while (--i >= 0) while (--i >= 0)
...@@ -951,7 +982,7 @@ xfs_buf_get_uncached( ...@@ -951,7 +982,7 @@ xfs_buf_get_uncached(
xfs_buf_free_maps(bp); xfs_buf_free_maps(bp);
kmem_cache_free(xfs_buf_zone, bp); kmem_cache_free(xfs_buf_zone, bp);
fail: fail:
return NULL; return error;
} }
/* /*
...@@ -1205,10 +1236,10 @@ __xfs_buf_ioerror( ...@@ -1205,10 +1236,10 @@ __xfs_buf_ioerror(
void void
xfs_buf_ioerror_alert( xfs_buf_ioerror_alert(
struct xfs_buf *bp, struct xfs_buf *bp,
const char *func) xfs_failaddr_t func)
{ {
xfs_alert(bp->b_mount, xfs_alert(bp->b_mount,
"metadata I/O error in \"%s\" at daddr 0x%llx len %d error %d", "metadata I/O error in \"%pS\" at daddr 0x%llx len %d error %d",
func, (uint64_t)XFS_BUF_ADDR(bp), bp->b_length, func, (uint64_t)XFS_BUF_ADDR(bp), bp->b_length,
-bp->b_error); -bp->b_error);
} }
......
...@@ -192,37 +192,40 @@ struct xfs_buf *xfs_buf_incore(struct xfs_buftarg *target, ...@@ -192,37 +192,40 @@ struct xfs_buf *xfs_buf_incore(struct xfs_buftarg *target,
xfs_daddr_t blkno, size_t numblks, xfs_daddr_t blkno, size_t numblks,
xfs_buf_flags_t flags); xfs_buf_flags_t flags);
struct xfs_buf *xfs_buf_get_map(struct xfs_buftarg *target, int xfs_buf_get_map(struct xfs_buftarg *target, struct xfs_buf_map *map,
struct xfs_buf_map *map, int nmaps, int nmaps, xfs_buf_flags_t flags, struct xfs_buf **bpp);
xfs_buf_flags_t flags); int xfs_buf_read_map(struct xfs_buftarg *target, struct xfs_buf_map *map,
struct xfs_buf *xfs_buf_read_map(struct xfs_buftarg *target, int nmaps, xfs_buf_flags_t flags, struct xfs_buf **bpp,
struct xfs_buf_map *map, int nmaps, const struct xfs_buf_ops *ops, xfs_failaddr_t fa);
xfs_buf_flags_t flags,
const struct xfs_buf_ops *ops);
void xfs_buf_readahead_map(struct xfs_buftarg *target, void xfs_buf_readahead_map(struct xfs_buftarg *target,
struct xfs_buf_map *map, int nmaps, struct xfs_buf_map *map, int nmaps,
const struct xfs_buf_ops *ops); const struct xfs_buf_ops *ops);
static inline struct xfs_buf * static inline int
xfs_buf_get( xfs_buf_get(
struct xfs_buftarg *target, struct xfs_buftarg *target,
xfs_daddr_t blkno, xfs_daddr_t blkno,
size_t numblks) size_t numblks,
struct xfs_buf **bpp)
{ {
DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
return xfs_buf_get_map(target, &map, 1, 0);
return xfs_buf_get_map(target, &map, 1, 0, bpp);
} }
static inline struct xfs_buf * static inline int
xfs_buf_read( xfs_buf_read(
struct xfs_buftarg *target, struct xfs_buftarg *target,
xfs_daddr_t blkno, xfs_daddr_t blkno,
size_t numblks, size_t numblks,
xfs_buf_flags_t flags, xfs_buf_flags_t flags,
struct xfs_buf **bpp,
const struct xfs_buf_ops *ops) const struct xfs_buf_ops *ops)
{ {
DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
return xfs_buf_read_map(target, &map, 1, flags, ops);
return xfs_buf_read_map(target, &map, 1, flags, bpp, ops,
__builtin_return_address(0));
} }
static inline void static inline void
...@@ -236,8 +239,8 @@ xfs_buf_readahead( ...@@ -236,8 +239,8 @@ xfs_buf_readahead(
return xfs_buf_readahead_map(target, &map, 1, ops); return xfs_buf_readahead_map(target, &map, 1, ops);
} }
struct xfs_buf *xfs_buf_get_uncached(struct xfs_buftarg *target, size_t numblks, int xfs_buf_get_uncached(struct xfs_buftarg *target, size_t numblks, int flags,
int flags); struct xfs_buf **bpp);
int xfs_buf_read_uncached(struct xfs_buftarg *target, xfs_daddr_t daddr, int xfs_buf_read_uncached(struct xfs_buftarg *target, xfs_daddr_t daddr,
size_t numblks, int flags, struct xfs_buf **bpp, size_t numblks, int flags, struct xfs_buf **bpp,
const struct xfs_buf_ops *ops); const struct xfs_buf_ops *ops);
...@@ -259,7 +262,7 @@ extern void xfs_buf_ioend(struct xfs_buf *bp); ...@@ -259,7 +262,7 @@ extern void xfs_buf_ioend(struct xfs_buf *bp);
extern void __xfs_buf_ioerror(struct xfs_buf *bp, int error, extern void __xfs_buf_ioerror(struct xfs_buf *bp, int error,
xfs_failaddr_t failaddr); xfs_failaddr_t failaddr);
#define xfs_buf_ioerror(bp, err) __xfs_buf_ioerror((bp), (err), __this_address) #define xfs_buf_ioerror(bp, err) __xfs_buf_ioerror((bp), (err), __this_address)
extern void xfs_buf_ioerror_alert(struct xfs_buf *, const char *func); extern void xfs_buf_ioerror_alert(struct xfs_buf *bp, xfs_failaddr_t fa);
extern int __xfs_buf_submit(struct xfs_buf *bp, bool); extern int __xfs_buf_submit(struct xfs_buf *bp, bool);
static inline int xfs_buf_submit(struct xfs_buf *bp) static inline int xfs_buf_submit(struct xfs_buf *bp)
......
...@@ -1113,7 +1113,7 @@ xfs_buf_iodone_callback_error( ...@@ -1113,7 +1113,7 @@ xfs_buf_iodone_callback_error(
if (bp->b_target != lasttarg || if (bp->b_target != lasttarg ||
time_after(jiffies, (lasttime + 5*HZ))) { time_after(jiffies, (lasttime + 5*HZ))) {
lasttime = jiffies; lasttime = jiffies;
xfs_buf_ioerror_alert(bp, __func__); xfs_buf_ioerror_alert(bp, __this_address);
} }
lasttarg = bp->b_target; lasttarg = bp->b_target;
......
...@@ -45,7 +45,7 @@ xfs_trim_extents( ...@@ -45,7 +45,7 @@ xfs_trim_extents(
xfs_log_force(mp, XFS_LOG_SYNC); xfs_log_force(mp, XFS_LOG_SYNC);
error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
if (error || !agbp) if (error)
goto out_put_perag; goto out_put_perag;
cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT); cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT);
......
...@@ -320,10 +320,10 @@ xfs_dquot_disk_alloc( ...@@ -320,10 +320,10 @@ xfs_dquot_disk_alloc(
dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock); dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
/* now we can just get the buffer (there's nothing to read yet) */ /* now we can just get the buffer (there's nothing to read yet) */
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, dqp->q_blkno, error = xfs_trans_get_buf(tp, mp->m_ddev_targp, dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen, 0); mp->m_quotainfo->qi_dqchunklen, 0, &bp);
if (!bp) if (error)
return -ENOMEM; return error;
bp->b_ops = &xfs_dquot_buf_ops; bp->b_ops = &xfs_dquot_buf_ops;
/* /*
......
...@@ -159,16 +159,15 @@ xfs_filestream_pick_ag( ...@@ -159,16 +159,15 @@ xfs_filestream_pick_ag(
if (!pag->pagf_init) { if (!pag->pagf_init) {
err = xfs_alloc_pagf_init(mp, NULL, ag, trylock); err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);
if (err && !trylock) { if (err) {
xfs_perag_put(pag); xfs_perag_put(pag);
if (err != -EAGAIN)
return err; return err;
/* Couldn't lock the AGF, skip this AG. */
continue;
} }
} }
/* Might fail sometimes during the 1st pass with trylock set. */
if (!pag->pagf_init)
goto next_ag;
/* Keep track of the AG with the most free blocks. */ /* Keep track of the AG with the most free blocks. */
if (pag->pagf_freeblks > maxfree) { if (pag->pagf_freeblks > maxfree) {
maxfree = pag->pagf_freeblks; maxfree = pag->pagf_freeblks;
......
...@@ -2546,6 +2546,7 @@ xfs_ifree_cluster( ...@@ -2546,6 +2546,7 @@ xfs_ifree_cluster(
struct xfs_perag *pag; struct xfs_perag *pag;
struct xfs_ino_geometry *igeo = M_IGEO(mp); struct xfs_ino_geometry *igeo = M_IGEO(mp);
xfs_ino_t inum; xfs_ino_t inum;
int error;
inum = xic->first_ino; inum = xic->first_ino;
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, inum)); pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, inum));
...@@ -2574,12 +2575,11 @@ xfs_ifree_cluster( ...@@ -2574,12 +2575,11 @@ xfs_ifree_cluster(
* complete before we get a lock on it, and hence we may fail * complete before we get a lock on it, and hence we may fail
* to mark all the active inodes on the buffer stale. * to mark all the active inodes on the buffer stale.
*/ */
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, error = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno,
mp->m_bsize * igeo->blocks_per_cluster, mp->m_bsize * igeo->blocks_per_cluster,
XBF_UNMAPPED); XBF_UNMAPPED, &bp);
if (error)
if (!bp) return error;
return -ENOMEM;
/* /*
* This buffer may not have been correctly initialised as we * This buffer may not have been correctly initialised as we
......
...@@ -294,7 +294,7 @@ xlog_recover_iodone( ...@@ -294,7 +294,7 @@ xlog_recover_iodone(
* this during recovery. One strike! * this during recovery. One strike!
*/ */
if (!XFS_FORCED_SHUTDOWN(bp->b_mount)) { if (!XFS_FORCED_SHUTDOWN(bp->b_mount)) {
xfs_buf_ioerror_alert(bp, __func__); xfs_buf_ioerror_alert(bp, __this_address);
xfs_force_shutdown(bp->b_mount, SHUTDOWN_META_IO_ERROR); xfs_force_shutdown(bp->b_mount, SHUTDOWN_META_IO_ERROR);
} }
} }
...@@ -2745,15 +2745,10 @@ xlog_recover_buffer_pass2( ...@@ -2745,15 +2745,10 @@ xlog_recover_buffer_pass2(
if (buf_f->blf_flags & XFS_BLF_INODE_BUF) if (buf_f->blf_flags & XFS_BLF_INODE_BUF)
buf_flags |= XBF_UNMAPPED; buf_flags |= XBF_UNMAPPED;
bp = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len, error = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len,
buf_flags, NULL); buf_flags, &bp, NULL);
if (!bp) if (error)
return -ENOMEM; return error;
error = bp->b_error;
if (error) {
xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#1)");
goto out_release;
}
/* /*
* Recover the buffer only if we get an LSN from it and it's less than * Recover the buffer only if we get an LSN from it and it's less than
...@@ -2950,17 +2945,10 @@ xlog_recover_inode_pass2( ...@@ -2950,17 +2945,10 @@ xlog_recover_inode_pass2(
} }
trace_xfs_log_recover_inode_recover(log, in_f); trace_xfs_log_recover_inode_recover(log, in_f);
bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, 0, error = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len,
&xfs_inode_buf_ops); 0, &bp, &xfs_inode_buf_ops);
if (!bp) { if (error)
error = -ENOMEM;
goto error; goto error;
}
error = bp->b_error;
if (error) {
xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#2)");
goto out_release;
}
ASSERT(in_f->ilf_fields & XFS_ILOG_CORE); ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
dip = xfs_buf_offset(bp, in_f->ilf_boffset); dip = xfs_buf_offset(bp, in_f->ilf_boffset);
...@@ -5639,7 +5627,7 @@ xlog_do_recover( ...@@ -5639,7 +5627,7 @@ xlog_do_recover(
error = xfs_buf_submit(bp); error = xfs_buf_submit(bp);
if (error) { if (error) {
if (!XFS_FORCED_SHUTDOWN(mp)) { if (!XFS_FORCED_SHUTDOWN(mp)) {
xfs_buf_ioerror_alert(bp, __func__); xfs_buf_ioerror_alert(bp, __this_address);
ASSERT(0); ASSERT(0);
} }
xfs_buf_relse(bp); xfs_buf_relse(bp);
......
...@@ -143,8 +143,6 @@ xfs_reflink_find_shared( ...@@ -143,8 +143,6 @@ xfs_reflink_find_shared(
error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
if (error) if (error)
return error; return error;
if (!agbp)
return -ENOMEM;
cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno); cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
......
...@@ -826,12 +826,10 @@ xfs_growfs_rt_alloc( ...@@ -826,12 +826,10 @@ xfs_growfs_rt_alloc(
* Get a buffer for the block. * Get a buffer for the block.
*/ */
d = XFS_FSB_TO_DADDR(mp, fsbno); d = XFS_FSB_TO_DADDR(mp, fsbno);
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
mp->m_bsize, 0); mp->m_bsize, 0, &bp);
if (bp == NULL) { if (error)
error = -EIO;
goto out_trans_cancel; goto out_trans_cancel;
}
memset(bp->b_addr, 0, mp->m_sb.sb_blocksize); memset(bp->b_addr, 0, mp->m_sb.sb_blocksize);
xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
/* /*
......
...@@ -53,20 +53,10 @@ xfs_readlink_bmap_ilocked( ...@@ -53,20 +53,10 @@ xfs_readlink_bmap_ilocked(
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0, error = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0,
&xfs_symlink_buf_ops); &bp, &xfs_symlink_buf_ops);
if (!bp) if (error)
return -ENOMEM; return error;
error = bp->b_error;
if (error) {
xfs_buf_ioerror_alert(bp, __func__);
xfs_buf_relse(bp);
/* bad CRC means corrupted metadata */
if (error == -EFSBADCRC)
error = -EFSCORRUPTED;
goto out;
}
byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
if (pathlen < byte_cnt) if (pathlen < byte_cnt)
byte_cnt = pathlen; byte_cnt = pathlen;
...@@ -290,12 +280,10 @@ xfs_symlink( ...@@ -290,12 +280,10 @@ xfs_symlink(
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
BTOBB(byte_cnt), 0); BTOBB(byte_cnt), 0, &bp);
if (!bp) { if (error)
error = -ENOMEM;
goto out_trans_cancel; goto out_trans_cancel;
}
bp->b_ops = &xfs_symlink_buf_ops; bp->b_ops = &xfs_symlink_buf_ops;
byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
...@@ -433,13 +421,12 @@ xfs_inactive_symlink_rmt( ...@@ -433,13 +421,12 @@ xfs_inactive_symlink_rmt(
* Invalidate the block(s). No validation is done. * Invalidate the block(s). No validation is done.
*/ */
for (i = 0; i < nmaps; i++) { for (i = 0; i < nmaps; i++) {
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp, mval[i].br_startblock), XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0); XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0,
if (!bp) { &bp);
error = -ENOMEM; if (error)
goto error_trans_cancel; goto error_trans_cancel;
}
xfs_trans_binval(tp, bp); xfs_trans_binval(tp, bp);
} }
/* /*
......
...@@ -169,21 +169,21 @@ int xfs_trans_alloc_empty(struct xfs_mount *mp, ...@@ -169,21 +169,21 @@ int xfs_trans_alloc_empty(struct xfs_mount *mp,
struct xfs_trans **tpp); struct xfs_trans **tpp);
void xfs_trans_mod_sb(xfs_trans_t *, uint, int64_t); void xfs_trans_mod_sb(xfs_trans_t *, uint, int64_t);
struct xfs_buf *xfs_trans_get_buf_map(struct xfs_trans *tp, int xfs_trans_get_buf_map(struct xfs_trans *tp, struct xfs_buftarg *target,
struct xfs_buftarg *target, struct xfs_buf_map *map, int nmaps, xfs_buf_flags_t flags,
struct xfs_buf_map *map, int nmaps, struct xfs_buf **bpp);
uint flags);
static inline struct xfs_buf * static inline int
xfs_trans_get_buf( xfs_trans_get_buf(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buftarg *target, struct xfs_buftarg *target,
xfs_daddr_t blkno, xfs_daddr_t blkno,
int numblks, int numblks,
uint flags) uint flags,
struct xfs_buf **bpp)
{ {
DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
return xfs_trans_get_buf_map(tp, target, &map, 1, flags); return xfs_trans_get_buf_map(tp, target, &map, 1, flags, bpp);
} }
int xfs_trans_read_buf_map(struct xfs_mount *mp, int xfs_trans_read_buf_map(struct xfs_mount *mp,
......
...@@ -112,19 +112,22 @@ xfs_trans_bjoin( ...@@ -112,19 +112,22 @@ xfs_trans_bjoin(
* If the transaction pointer is NULL, make this just a normal * If the transaction pointer is NULL, make this just a normal
* get_buf() call. * get_buf() call.
*/ */
struct xfs_buf * int
xfs_trans_get_buf_map( xfs_trans_get_buf_map(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buftarg *target, struct xfs_buftarg *target,
struct xfs_buf_map *map, struct xfs_buf_map *map,
int nmaps, int nmaps,
xfs_buf_flags_t flags) xfs_buf_flags_t flags,
struct xfs_buf **bpp)
{ {
xfs_buf_t *bp; xfs_buf_t *bp;
struct xfs_buf_log_item *bip; struct xfs_buf_log_item *bip;
int error;
*bpp = NULL;
if (!tp) if (!tp)
return xfs_buf_get_map(target, map, nmaps, flags); return xfs_buf_get_map(target, map, nmaps, flags, bpp);
/* /*
* If we find the buffer in the cache with this transaction * If we find the buffer in the cache with this transaction
...@@ -146,19 +149,20 @@ xfs_trans_get_buf_map( ...@@ -146,19 +149,20 @@ xfs_trans_get_buf_map(
ASSERT(atomic_read(&bip->bli_refcount) > 0); ASSERT(atomic_read(&bip->bli_refcount) > 0);
bip->bli_recur++; bip->bli_recur++;
trace_xfs_trans_get_buf_recur(bip); trace_xfs_trans_get_buf_recur(bip);
return bp; *bpp = bp;
return 0;
} }
bp = xfs_buf_get_map(target, map, nmaps, flags); error = xfs_buf_get_map(target, map, nmaps, flags, &bp);
if (bp == NULL) { if (error)
return NULL; return error;
}
ASSERT(!bp->b_error); ASSERT(!bp->b_error);
_xfs_trans_bjoin(tp, bp, 1); _xfs_trans_bjoin(tp, bp, 1);
trace_xfs_trans_get_buf(bp->b_log_item); trace_xfs_trans_get_buf(bp->b_log_item);
return bp; *bpp = bp;
return 0;
} }
/* /*
...@@ -276,7 +280,7 @@ xfs_trans_read_buf_map( ...@@ -276,7 +280,7 @@ xfs_trans_read_buf_map(
ASSERT(bp->b_ops != NULL); ASSERT(bp->b_ops != NULL);
error = xfs_buf_reverify(bp, ops); error = xfs_buf_reverify(bp, ops);
if (error) { if (error) {
xfs_buf_ioerror_alert(bp, __func__); xfs_buf_ioerror_alert(bp, __return_address);
if (tp->t_flags & XFS_TRANS_DIRTY) if (tp->t_flags & XFS_TRANS_DIRTY)
xfs_force_shutdown(tp->t_mountp, xfs_force_shutdown(tp->t_mountp,
...@@ -298,36 +302,17 @@ xfs_trans_read_buf_map( ...@@ -298,36 +302,17 @@ xfs_trans_read_buf_map(
return 0; return 0;
} }
bp = xfs_buf_read_map(target, map, nmaps, flags, ops); error = xfs_buf_read_map(target, map, nmaps, flags, &bp, ops,
if (!bp) { __return_address);
if (!(flags & XBF_TRYLOCK)) switch (error) {
return -ENOMEM; case 0:
return tp ? 0 : -EAGAIN; break;
} default:
/*
* If we've had a read error, then the contents of the buffer are
* invalid and should not be used. To ensure that a followup read tries
* to pull the buffer from disk again, we clear the XBF_DONE flag and
* mark the buffer stale. This ensures that anyone who has a current
* reference to the buffer will interpret it's contents correctly and
* future cache lookups will also treat it as an empty, uninitialised
* buffer.
*/
if (bp->b_error) {
error = bp->b_error;
if (!XFS_FORCED_SHUTDOWN(mp))
xfs_buf_ioerror_alert(bp, __func__);
bp->b_flags &= ~XBF_DONE;
xfs_buf_stale(bp);
if (tp && (tp->t_flags & XFS_TRANS_DIRTY)) if (tp && (tp->t_flags & XFS_TRANS_DIRTY))
xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR); xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR);
xfs_buf_relse(bp); /* fall through */
case -ENOMEM:
/* bad CRC means corrupted metadata */ case -EAGAIN:
if (error == -EFSBADCRC)
error = -EFSCORRUPTED;
return error; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment