diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2019-10-16 22:35:26 -0400 |
---|---|---|
committer | Eric Sandeen <sandeen@sandeen.net> | 2019-10-16 22:35:26 -0400 |
commit | cac2b8b0a2bc343c3846299f544396add813e691 (patch) | |
tree | eb700c1ee4e667b530bdb96a5cbb2e0dbaf49fa2 | |
parent | 27464242956facd1cefb68164f546be12c88f6ba (diff) | |
download | xfsprogs-dev-cac2b8b0a2bc343c3846299f544396add813e691.tar.gz |
xfs_scrub: simulate errors in the read-verify phase
Add a debugging hook so that we can simulate disk errors during the
media scan to test that the code works.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
-rw-r--r-- | scrub/disk.c | 67 | ||||
-rw-r--r-- | scrub/xfs_scrub.c | 2 |
2 files changed, 69 insertions, 0 deletions
diff --git a/scrub/disk.c b/scrub/disk.c index bf9c795aa0..214a534601 100644 --- a/scrub/disk.c +++ b/scrub/disk.c @@ -276,6 +276,59 @@ disk_close( #define LBASIZE(d) (1ULL << (d)->d_lbalog) #define BTOLBA(d, bytes) (((uint64_t)(bytes) + LBASIZE(d) - 1) >> (d)->d_lbalog) +/* Simulate disk errors. */ +static int +disk_simulate_read_error( + struct disk *disk, + uint64_t start, + uint64_t *length) +{ + static int64_t interval; + uint64_t start_interval; + + /* Simulated disk errors are disabled. */ + if (interval < 0) + return 0; + + /* Figure out the disk read error interval. */ + if (interval == 0) { + char *p; + + /* Pretend there's bad media every so often, in bytes. */ + p = getenv("XFS_SCRUB_DISK_ERROR_INTERVAL"); + if (p == NULL) { + interval = -1; + return 0; + } + interval = strtoull(p, NULL, 10); + interval &= ~((1U << disk->d_lbalog) - 1); + } + + /* + * We simulate disk errors by pretending that there are media errors at + * predetermined intervals across the disk. If a read verify request + * crosses one of those intervals we shorten it so that the next read + * will start on an interval threshold. If the read verify request + * starts on an interval threshold, we send back EIO as if it had + * failed. + */ + if ((start % interval) == 0) { + dbg_printf("fd %d: simulating disk error at %"PRIu64".\n", + disk->d_fd, start); + return EIO; + } + + start_interval = start / interval; + if (start_interval != (start + *length) / interval) { + *length = ((start_interval + 1) * interval) - start; + dbg_printf( +"fd %d: simulating short read at %"PRIu64" to length %"PRIu64".\n", + disk->d_fd, start, *length); + } + + return 0; +} + /* Read-verify an extent of a disk device. */ ssize_t disk_read_verify( @@ -284,6 +337,20 @@ disk_read_verify( uint64_t start, uint64_t length) { + if (debug) { + int ret; + + ret = disk_simulate_read_error(disk, start, &length); + if (ret) { + errno = ret; + return -1; + } + + /* Don't actually issue the IO */ + if (getenv("XFS_SCRUB_DISK_VERIFY_SKIP")) + return length; + } + /* Convert to logical block size. */ if (disk->d_flags & DISK_FLAG_SCSI_VERIFY) return disk_scsi_verify(disk, BTOLBAT(disk, start), diff --git a/scrub/xfs_scrub.c b/scrub/xfs_scrub.c index 05478093f8..b6a012742e 100644 --- a/scrub/xfs_scrub.c +++ b/scrub/xfs_scrub.c @@ -111,6 +111,8 @@ * XFS_SCRUB_NO_SCSI_VERIFY -- disable SCSI VERIFY (if present) * XFS_SCRUB_PHASE -- run only this scrub phase * XFS_SCRUB_THREADS -- start exactly this number of threads + * XFS_SCRUB_DISK_ERROR_INTERVAL-- simulate a disk error every this many bytes + * XFS_SCRUB_DISK_VERIFY_SKIP -- pretend disk verify read calls succeeded * * Available even in non-debug mode: * SERVICE_MODE -- compress all error codes to 1 for LSB |