Skip to content

Commit

Permalink
xfs: make buffer read verication an IO completion function
Browse files Browse the repository at this point in the history
Add a verifier function callback capability to the buffer read
interfaces.  This will be used by the callers to supply a function
that verifies the contents of the buffer when it is read from disk.
This patch does not provide callback functions, but simply modifies
the interfaces to allow them to be called.

The reason for adding this to the read interfaces is that it is very
difficult to tell fom the outside is a buffer was just read from
disk or whether we just pulled it out of cache. Supplying a callbck
allows the buffer cache to use it's internal knowledge of the buffer
to execute it only when the buffer is read from disk.

It is intended that the verifier functions will mark the buffer with
an EFSCORRUPTED error when verification fails. This allows the
reading context to distinguish a verification error from an IO
error, and potentially take further actions on the buffer (e.g.
attempt repair) based on the error reported.

Signed-off-by: Dave Chinner <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
Reviewed-by: Phil White <[email protected]>
Signed-off-by: Ben Myers <[email protected]>
  • Loading branch information
Dave Chinner authored and Ben Myers committed Nov 16, 2012
1 parent fb59581 commit c3f8fc7
Show file tree
Hide file tree
Showing 19 changed files with 75 additions and 61 deletions.
4 changes: 2 additions & 2 deletions fs/xfs/xfs_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ xfs_alloc_read_agfl(
error = xfs_trans_read_buf(
mp, tp, mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1), 0, &bp);
XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
if (error)
return error;
ASSERT(!xfs_buf_geterror(bp));
Expand Down Expand Up @@ -2110,7 +2110,7 @@ xfs_read_agf(
error = xfs_trans_read_buf(
mp, tp, mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1), flags, bpp);
XFS_FSS_TO_BB(mp, 1), flags, bpp, NULL);
if (error)
return error;
if (!*bpp)
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1994,7 +1994,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
dblkno, blkcnt, 0, &bp);
dblkno, blkcnt, 0, &bp, NULL);
if (error)
return(error);

Expand Down
21 changes: 12 additions & 9 deletions fs/xfs/xfs_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,12 @@ xfs_btree_dup_cursor(
for (i = 0; i < new->bc_nlevels; i++) {
new->bc_ptrs[i] = cur->bc_ptrs[i];
new->bc_ra[i] = cur->bc_ra[i];
if ((bp = cur->bc_bufs[i])) {
if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp))) {
bp = cur->bc_bufs[i];
if (bp) {
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
XFS_BUF_ADDR(bp), mp->m_bsize,
0, &bp, NULL);
if (error) {
xfs_btree_del_cursor(new, error);
*ncur = NULL;
return error;
Expand Down Expand Up @@ -624,10 +627,10 @@ xfs_btree_read_bufl(

ASSERT(fsbno != NULLFSBLOCK);
d = XFS_FSB_TO_DADDR(mp, fsbno);
if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
mp->m_bsize, lock, &bp))) {
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
mp->m_bsize, lock, &bp, NULL);
if (error)
return error;
}
ASSERT(!xfs_buf_geterror(bp));
if (bp)
xfs_buf_set_ref(bp, refval);
Expand All @@ -650,7 +653,7 @@ xfs_btree_reada_bufl(

ASSERT(fsbno != NULLFSBLOCK);
d = XFS_FSB_TO_DADDR(mp, fsbno);
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count);
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, NULL);
}

/*
Expand All @@ -670,7 +673,7 @@ xfs_btree_reada_bufs(
ASSERT(agno != NULLAGNUMBER);
ASSERT(agbno != NULLAGBLOCK);
d = XFS_AGB_TO_DADDR(mp, agno, agbno);
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count);
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, NULL);
}

STATIC int
Expand Down Expand Up @@ -1013,7 +1016,7 @@ xfs_btree_read_buf_block(

d = xfs_btree_ptr_to_daddr(cur, ptr);
error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d,
mp->m_bsize, flags, bpp);
mp->m_bsize, flags, bpp, NULL);
if (error)
return error;

Expand Down
13 changes: 9 additions & 4 deletions fs/xfs/xfs_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,8 @@ xfs_buf_read_map(
struct xfs_buftarg *target,
struct xfs_buf_map *map,
int nmaps,
xfs_buf_flags_t flags)
xfs_buf_flags_t flags,
xfs_buf_iodone_t verify)
{
struct xfs_buf *bp;

Expand All @@ -666,6 +667,7 @@ xfs_buf_read_map(

if (!XFS_BUF_ISDONE(bp)) {
XFS_STATS_INC(xb_get_read);
bp->b_iodone = verify;
_xfs_buf_read(bp, flags);
} else if (flags & XBF_ASYNC) {
/*
Expand All @@ -691,13 +693,14 @@ void
xfs_buf_readahead_map(
struct xfs_buftarg *target,
struct xfs_buf_map *map,
int nmaps)
int nmaps,
xfs_buf_iodone_t verify)
{
if (bdi_read_congested(target->bt_bdi))
return;

xfs_buf_read_map(target, map, nmaps,
XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD);
XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD, verify);
}

/*
Expand All @@ -709,7 +712,8 @@ xfs_buf_read_uncached(
struct xfs_buftarg *target,
xfs_daddr_t daddr,
size_t numblks,
int flags)
int flags,
xfs_buf_iodone_t verify)
{
xfs_buf_t *bp;
int error;
Expand All @@ -723,6 +727,7 @@ xfs_buf_read_uncached(
bp->b_bn = daddr;
bp->b_maps[0].bm_bn = daddr;
bp->b_flags |= XBF_READ;
bp->b_iodone = verify;

xfsbdstrat(target->bt_mount, bp);
error = xfs_buf_iowait(bp);
Expand Down
20 changes: 12 additions & 8 deletions fs/xfs/xfs_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ typedef struct xfs_buftarg {
struct xfs_buf;
typedef void (*xfs_buf_iodone_t)(struct xfs_buf *);


#define XB_PAGES 2

struct xfs_buf_map {
Expand Down Expand Up @@ -159,7 +160,6 @@ typedef struct xfs_buf {
#endif
} xfs_buf_t;


/* Finding and Reading Buffers */
struct xfs_buf *_xfs_buf_find(struct xfs_buftarg *target,
struct xfs_buf_map *map, int nmaps,
Expand Down Expand Up @@ -196,9 +196,10 @@ struct xfs_buf *xfs_buf_get_map(struct xfs_buftarg *target,
xfs_buf_flags_t flags);
struct xfs_buf *xfs_buf_read_map(struct xfs_buftarg *target,
struct xfs_buf_map *map, int nmaps,
xfs_buf_flags_t flags);
xfs_buf_flags_t flags, xfs_buf_iodone_t verify);
void xfs_buf_readahead_map(struct xfs_buftarg *target,
struct xfs_buf_map *map, int nmaps);
struct xfs_buf_map *map, int nmaps,
xfs_buf_iodone_t verify);

static inline struct xfs_buf *
xfs_buf_get(
Expand All @@ -216,20 +217,22 @@ xfs_buf_read(
struct xfs_buftarg *target,
xfs_daddr_t blkno,
size_t numblks,
xfs_buf_flags_t flags)
xfs_buf_flags_t flags,
xfs_buf_iodone_t verify)
{
DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
return xfs_buf_read_map(target, &map, 1, flags);
return xfs_buf_read_map(target, &map, 1, flags, verify);
}

static inline void
xfs_buf_readahead(
struct xfs_buftarg *target,
xfs_daddr_t blkno,
size_t numblks)
size_t numblks,
xfs_buf_iodone_t verify)
{
DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
return xfs_buf_readahead_map(target, &map, 1);
return xfs_buf_readahead_map(target, &map, 1, verify);
}

struct xfs_buf *xfs_buf_get_empty(struct xfs_buftarg *target, size_t numblks);
Expand All @@ -239,7 +242,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);
xfs_daddr_t daddr, size_t numblks, int flags,
xfs_buf_iodone_t verify);
void xfs_buf_hold(struct xfs_buf *bp);

/* Releasing Buffers */
Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_da_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -2161,7 +2161,7 @@ xfs_da_read_buf(

error = xfs_trans_read_buf_map(dp->i_mount, trans,
dp->i_mount->m_ddev_targp,
mapp, nmap, 0, &bp);
mapp, nmap, 0, &bp, NULL);
if (error)
goto out_free;

Expand Down Expand Up @@ -2237,7 +2237,7 @@ xfs_da_reada_buf(
}

mappedbno = mapp[0].bm_bn;
xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap);
xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap, NULL);

out_free:
if (mapp != &map)
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_dir2_leaf.c
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ xfs_dir2_leaf_readbuf(
XFS_FSB_TO_DADDR(mp,
map[mip->ra_index].br_startblock +
mip->ra_offset),
(int)BTOBB(mp->m_dirblksize));
(int)BTOBB(mp->m_dirblksize), NULL);
mip->ra_current = i;
}

Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ xfs_qm_dqtobp(
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen,
0, &bp);
0, &bp, NULL);
if (error || !bp)
return XFS_ERROR(error);
}
Expand Down Expand Up @@ -920,7 +920,7 @@ xfs_qm_dqflush(
* Get the buffer containing the on-disk dquot
*/
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen, 0, &bp);
mp->m_quotainfo->qi_dqchunklen, 0, &bp, NULL);
if (error)
goto out_unlock;

Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_fsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ xfs_growfs_data_private(
dpct = pct - mp->m_sb.sb_imax_pct;
bp = 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);
XFS_FSS_TO_BB(mp, 1), 0, NULL);
if (!bp)
return EIO;
xfs_buf_relse(bp);
Expand Down Expand Up @@ -439,7 +439,7 @@ xfs_growfs_data_private(
if (agno < oagcount) {
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
XFS_FSS_TO_BB(mp, 1), 0, &bp);
XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
} else {
bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,7 @@ xfs_read_agi(

error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1), 0, bpp);
XFS_FSS_TO_BB(mp, 1), 0, bpp, NULL);
if (error)
return error;

Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ xfs_imap_to_bp(

buf_flags |= XBF_UNMAPPED;
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
(int)imap->im_len, buf_flags, &bp);
(int)imap->im_len, buf_flags, &bp, NULL);
if (error) {
if (error != EAGAIN) {
xfs_warn(mp,
Expand Down
3 changes: 1 addition & 2 deletions fs/xfs/xfs_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -1129,8 +1129,7 @@ xlog_iodone(xfs_buf_t *bp)
* with it being freed after writing the unmount record to the
* log.
*/

} /* xlog_iodone */
}

/*
* Return size of each in-core log record buffer.
Expand Down
8 changes: 5 additions & 3 deletions fs/xfs/xfs_log_recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -2144,7 +2144,7 @@ xlog_recover_buffer_pass2(
buf_flags |= XBF_UNMAPPED;

bp = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len,
buf_flags);
buf_flags, NULL);
if (!bp)
return XFS_ERROR(ENOMEM);
error = bp->b_error;
Expand Down Expand Up @@ -2237,7 +2237,8 @@ xlog_recover_inode_pass2(
}
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);
bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, 0,
NULL);
if (!bp) {
error = ENOMEM;
goto error;
Expand Down Expand Up @@ -2548,7 +2549,8 @@ xlog_recover_dquot_pass2(
ASSERT(dq_f->qlf_len == 1);

error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp);
XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,
NULL);
if (error)
return error;

Expand Down
6 changes: 3 additions & 3 deletions fs/xfs/xfs_mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ xfs_readsb(xfs_mount_t *mp, int flags)

reread:
bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
BTOBB(sector_size), 0);
BTOBB(sector_size), 0, NULL);
if (!bp) {
if (loud)
xfs_warn(mp, "SB buffer read failed");
Expand Down Expand Up @@ -1002,7 +1002,7 @@ xfs_check_sizes(xfs_mount_t *mp)
}
bp = xfs_buf_read_uncached(mp->m_ddev_targp,
d - XFS_FSS_TO_BB(mp, 1),
XFS_FSS_TO_BB(mp, 1), 0);
XFS_FSS_TO_BB(mp, 1), 0, NULL);
if (!bp) {
xfs_warn(mp, "last sector read failed");
return EIO;
Expand All @@ -1017,7 +1017,7 @@ xfs_check_sizes(xfs_mount_t *mp)
}
bp = xfs_buf_read_uncached(mp->m_logdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
XFS_FSB_TO_BB(mp, 1), 0);
XFS_FSB_TO_BB(mp, 1), 0, NULL);
if (!bp) {
xfs_warn(mp, "log device read failed");
return EIO;
Expand Down
5 changes: 3 additions & 2 deletions fs/xfs/xfs_qm.c
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,7 @@ xfs_qm_dqiter_bufs(
while (blkcnt--) {
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp, bno),
mp->m_quotainfo->qi_dqchunklen, 0, &bp);
mp->m_quotainfo->qi_dqchunklen, 0, &bp, NULL);
if (error)
break;

Expand Down Expand Up @@ -979,7 +979,8 @@ xfs_qm_dqiterate(
while (rablkcnt--) {
xfs_buf_readahead(mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp, rablkno),
mp->m_quotainfo->qi_dqchunklen);
mp->m_quotainfo->qi_dqchunklen,
NULL);
rablkno++;
}
}
Expand Down
6 changes: 3 additions & 3 deletions fs/xfs/xfs_rtalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ xfs_rtbuf_get(
ASSERT(map.br_startblock != NULLFSBLOCK);
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp, map.br_startblock),
mp->m_bsize, 0, &bp);
mp->m_bsize, 0, &bp, NULL);
if (error)
return error;
ASSERT(!xfs_buf_geterror(bp));
Expand Down Expand Up @@ -1873,7 +1873,7 @@ xfs_growfs_rt(
*/
bp = xfs_buf_read_uncached(mp->m_rtdev_targp,
XFS_FSB_TO_BB(mp, nrblocks - 1),
XFS_FSB_TO_BB(mp, 1), 0);
XFS_FSB_TO_BB(mp, 1), 0, NULL);
if (!bp)
return EIO;
xfs_buf_relse(bp);
Expand Down Expand Up @@ -2220,7 +2220,7 @@ xfs_rtmount_init(
}
bp = xfs_buf_read_uncached(mp->m_rtdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
XFS_FSB_TO_BB(mp, 1), 0);
XFS_FSB_TO_BB(mp, 1), 0, NULL);
if (!bp) {
xfs_warn(mp, "realtime device size check failed");
return EIO;
Expand Down
Loading

0 comments on commit c3f8fc7

Please sign in to comment.