return error;
}
+void
+libxfs_readbuf_verify(struct xfs_buf *bp, const struct xfs_buf_ops *ops)
+{
+ if (!ops)
+ return;
+ bp->b_ops = ops;
+ bp->b_ops->verify_read(bp);
+ bp->b_flags &= ~LIBXFS_B_UNCHECKED;
+}
+
+
xfs_buf_t *
libxfs_readbuf(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, int flags,
const struct xfs_buf_ops *ops)
bp = libxfs_getbuf(btp, blkno, len);
if (!bp)
return NULL;
- if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY)))
+
+ /*
+ * if the buffer was prefetched, it is likely that it was not validated.
+ * Hence if we are supplied an ops function and the buffer is marked as
+ * unchecked, we need to validate it now.
+ *
+ * We do this verification even if the buffer is dirty - the
+ * verification is almost certainly going to fail the CRC check in this
+ * case as a dirty buffer has not had the CRC recalculated. However, we
+ * should not be dirtying unchecked buffers and therefore failing it
+ * here because it's dirty and unchecked indicates we've screwed up
+ * somewhere else.
+ */
+ bp->b_error = 0;
+ if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) {
+ if (bp->b_flags & LIBXFS_B_UNCHECKED)
+ libxfs_readbuf_verify(bp, ops);
return bp;
+ }
/*
- * only set the ops on a cache miss (i.e. first physical read) as the
- * verifier may change the ops to match the typ eof buffer it contains.
+ * Set the ops on a cache miss (i.e. first physical read) as the
+ * verifier may change the ops to match the type of buffer it contains.
* A cache hit might reset the verifier to the original type if we set
* it again, but it won't get called again and set to match the buffer
* contents. *cough* xfs_da_node_buf_ops *cough*.
*/
- bp->b_error = 0;
- bp->b_ops = ops;
error = libxfs_readbufr(btp, blkno, bp, len, flags);
if (error)
bp->b_error = error;
- else if (bp->b_ops)
- bp->b_ops->verify_read(bp);
+ else
+ libxfs_readbuf_verify(bp, ops);
return bp;
}
return NULL;
bp->b_error = 0;
- bp->b_ops = ops;
- if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY)))
+ if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) {
+ if (bp->b_flags & LIBXFS_B_UNCHECKED)
+ libxfs_readbuf_verify(bp, ops);
return bp;
-
- error = libxfs_readbufr_map(btp, bp, flags);
- if (!error) {
- bp->b_flags |= LIBXFS_B_UPTODATE;
- if (bp->b_ops)
- bp->b_ops->verify_read(bp);
}
+ error = libxfs_readbufr_map(btp, bp, flags);
+ if (!error)
+ libxfs_readbuf_verify(bp, ops);
+
#ifdef IO_DEBUG
printf("%lx: %s: read %lu bytes, error %d, blkno=%llu(%llu), %p\n",
pthread_self(), __FUNCTION__, buf - (char *)bp->b_addr, error,
#endif
if (!error) {
bp->b_flags |= LIBXFS_B_UPTODATE;
- bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT);
+ bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT |
+ LIBXFS_B_UNCHECKED);
}
return error;
}
int hasdir = 0;
int isadir;
- bp->b_ops = &xfs_inode_buf_ops;
- bp->b_ops->verify_read(bp);
+ libxfs_readbuf_verify(bp, &xfs_inode_buf_ops);
if (bp->b_error)
return;
pthread_mutex_unlock(&args->lock);
libxfs_readbufr_map(mp->m_ddev_targp, bp, 0);
+ bp->b_flags |= LIBXFS_B_UNCHECKED;
libxfs_putbuf(bp);
pthread_mutex_lock(&args->lock);
}
if (len < size)
break;
memcpy(XFS_BUF_PTR(bplist[i]), pbuf, size);
- bplist[i]->b_flags |= LIBXFS_B_UPTODATE;
+ bplist[i]->b_flags |= (LIBXFS_B_UPTODATE |
+ LIBXFS_B_UNCHECKED);
len -= size;
if (B_IS_INODE(XFS_BUF_PRIORITY(bplist[i])))
pf_read_inode_dirs(args, bplist[i]);