@@ -457,6 +457,47 @@ static inline int xfs_bio_add_buffer(struct bio *bio, struct buffer_head *bh)
return bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh));
}
+#ifdef DEBUG
+static int
+xfs_validate_ioend(
+ struct xfs_ioend *ioend)
+{
+ struct xfs_inode *ip = XFS_I(ioend->io_inode);
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+ struct xfs_mount *mp = ip->i_mount;
+ xfs_fileoff_t offset = XFS_B_TO_FSB(mp, ioend->io_offset);
+ xfs_filblks_t count = XFS_B_TO_FSB(mp, ioend->io_size);
+ xfs_extnum_t idx;
+ struct xfs_bmbt_irec got;
+ int error;
+
+ xfs_ilock(ip, XFS_ILOCK_SHARED);
+
+ error = -EFSCORRUPTED;
+ while (count) {
+ if (!xfs_iext_lookup_extent(ip, ifp, offset, &idx, &got))
+ goto out;
+ if (isnullstartblock(got.br_startblock))
+ goto out;
+ offset += got.br_blockcount;
+ count -= min_t(xfs_filblks_t, count, got.br_blockcount);
+ }
+
+ error = 0;
+out:
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ if (error) {
+ xfs_alert(mp,
+ "I/O submission to invalid extent (ino 0x%llx offset 0x%llx).",
+ ip->i_ino, ioend->io_offset);
+ xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+ }
+ return error;
+}
+#else
+#define xfs_validate_ioend(ioend) (0)
+#endif
+
/*
* Submit the bio for an ioend. We are passed an ioend with a bio attached to
* it, and we submit that bio. The ioend may be used for multiple bio
@@ -506,6 +547,10 @@ xfs_submit_ioend(
return status;
}
+ status = xfs_validate_ioend(ioend);
+ if (status)
+ return status;
+
ioend->io_bio->bi_write_hint = ioend->io_inode->i_write_hint;
submit_bio(ioend->io_bio);
return 0;