From: Christoph Hellwig <hch@lst.de>
To: martin.petersen@oracle.com
Cc: linux-scsi@vger.kernel.org
Subject: [PATCH] scsi_debug: add support to corrupt data and/or reftag
Date: Thu, 23 Jul 2026 16:21:54 +0200 [thread overview]
Message-ID: <20260723142154.107268-1-hch@lst.de> (raw)
Add a new debugfs file to inject corruptions of the data and/or reftag.
This will be used to detect that protection information and/or file
system checksumming can detect random bit errors or misplaced writes.
To use this echo the start LBA, number of logical blocks and type of
corruption into the new "corrupt" debugfs file for each scsi_debug
device.
For example:
echo lba=42,num=1,bit_errors=2 > /sys/kernel/debug/scsi_debug/1:0:0:0/corrupt
or
echo lba=2,num=4,reftag_adjust=8 > /sys/kernel/debug/scsi_debug/1:0:0:0/corrupt
The injection will be used by new xfstests test cases.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/scsi/scsi_debug.c | 153 ++++++++++++++++++++++++++++++++++++++
1 file changed, 153 insertions(+)
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 9d1c9c41d0f9..aa51eccb7061 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -44,6 +44,7 @@
#include <linux/debugfs.h>
#include <linux/async.h>
#include <linux/cleanup.h>
+#include <linux/parser.h>
#include <net/checksum.h>
@@ -1214,6 +1215,94 @@ static const struct file_operations sdebug_error_fops = {
.release = single_release,
};
+enum corrupt_options {
+ Opt_lba = (1u << 0),
+ Opt_num = (1u << 1),
+ Opt_bit_errors = (1u << 2),
+ Opt_reftag_adjust = (1u << 3),
+
+ Opt_invalid,
+};
+
+static const match_table_t corrupt_tokens = {
+ { Opt_lba, "lba=%u" },
+ { Opt_num, "num=%u" },
+ { Opt_bit_errors, "bit_errors=%u" },
+ { Opt_reftag_adjust, "reftag_adjust=%d" },
+ { Opt_invalid, NULL, },
+};
+
+static int corrupt_lbas(struct sdebug_dev_info *devip, u64 lba, u32 num,
+ u32 nr_bit_errors, s32 reftag_adjust);
+static ssize_t sdebug_corrupt_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct scsi_device *sdev = file->f_inode->i_private;
+ struct sdebug_dev_info *devip = sdev->hostdata;
+ substring_t args[MAX_OPT_ARGS];
+ char *buf, *options, *p;
+ int error = 0;
+ u64 lba = 0;
+ u32 num = 1;
+ u32 nr_bit_errors = 0;
+ s32 reftag_adjust = 0;
+
+ buf = memdup_user_nul(ubuf, count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ options = buf;
+ while ((p = strsep(&options, ",\n")) != NULL) {
+ if (!*p)
+ continue;
+ switch (match_token(p, corrupt_tokens, args)) {
+ case Opt_lba:
+ error = match_u64(args, &lba);
+ break;
+ case Opt_num:
+ error = match_uint(args, &num);
+ break;
+ case Opt_bit_errors:
+ error = match_uint(args, &nr_bit_errors);
+ break;
+ case Opt_reftag_adjust:
+ error = match_uint(args, &reftag_adjust);
+ break;
+ default:
+ pr_warn("unknown parameter or missing value '%s'\n", p);
+ error = -EINVAL;
+ }
+ if (error)
+ return error;
+ }
+
+ if (num == 0) {
+ pr_warn("invalid number of logical blocks: %u\n", num);
+ error = -EINVAL;
+ goto out_free_buf;
+ }
+
+ if (reftag_adjust &&
+ (sdebug_dif != T10_PI_TYPE1_PROTECTION &&
+ sdebug_dif != T10_PI_TYPE2_PROTECTION)) {
+ pr_warn("reftag adjust requires type 1 or type 2 PI\n");
+ error = -EINVAL;
+ goto out_free_buf;
+ }
+
+ error = corrupt_lbas(devip, lba, num, nr_bit_errors, reftag_adjust);
+
+out_free_buf:
+ kfree(buf);
+ if (error)
+ return error;
+ return count;
+}
+
+static const struct file_operations sdebug_corrupt_fops = {
+ .write = sdebug_corrupt_write,
+};
+
static int sdebug_target_reset_fail_show(struct seq_file *m, void *p)
{
struct scsi_target *starget = (struct scsi_target *)m->private;
@@ -4908,6 +4997,68 @@ static int resp_write_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
return 0;
}
+static int corrupt_lbas(struct sdebug_dev_info *devip, u64 lba, u32 num,
+ u32 nr_bit_errors, s32 reftag_adjust)
+{
+ struct sdeb_store_info *sip = devip2sip(devip, true);
+ bool meta_data_locked = false;
+ u8 *fsp = sip->storep;
+ u32 block, b, i;
+ int error = 0;
+
+ if (sdebug_dev_is_zoned(devip) ||
+ sdebug_dix ||
+ scsi_debug_lbp()) {
+ sdeb_meta_write_lock(sip);
+ meta_data_locked = true;
+ }
+
+ if (num >= sdebug_capacity || lba > sdebug_capacity - num) {
+ pr_err("logical blocks out of bounds: %llu:%u", lba, num);
+ error = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (scsi_debug_lbp() && !map_state(sip, lba, &num)) {
+ pr_err("can't modify unmapped logical blocks: %llu:%u",
+ lba, num);
+ error = -EINVAL;
+ goto out_unlock;
+ }
+
+ for (b = 0; b < nr_bit_errors; b++) {
+ unsigned int bit;
+
+ bit = get_random_u32_below(sdebug_sector_size * BITS_PER_BYTE);
+
+ div_u64_rem(lba, sdebug_store_sectors, &block);
+ for (i = 0; i < num; i++) {
+ u8 *p = fsp + (block * sdebug_sector_size);
+
+ p[bit / BITS_PER_BYTE] ^= (1 << (bit % BITS_PER_BYTE));
+ pr_info("flipping bit %u in LBA %llu\n", bit, lba + i);
+
+ if (++block >= sdebug_store_sectors)
+ block = 0;
+ }
+ }
+
+ if (reftag_adjust) {
+ for (i = 0; i < num; i++) {
+ struct t10_pi_tuple *sdt = dif_store(sip, lba + i);
+
+ be32_add_cpu(&sdt->ref_tag, reftag_adjust);
+ pr_info("adjusting reftag by %d sectors for LBA %llu\n",
+ reftag_adjust, lba + i);
+ }
+ }
+
+out_unlock:
+ if (meta_data_locked)
+ sdeb_meta_write_unlock(sip);
+ return error;
+}
+
static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
bool check_prot;
@@ -6670,6 +6821,8 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp,
if (IS_ERR_OR_NULL(dentry))
pr_info("failed to create error file for device %s\n",
dev_name(&sdp->sdev_gendev));
+ debugfs_create_file("corrupt", 0600, devip->debugfs_entry, sdp,
+ &sdebug_corrupt_fops);
return 0;
}
--
2.53.0
next reply other threads:[~2026-07-23 14:21 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-23 14:21 Christoph Hellwig [this message]
2026-07-23 14:37 ` [PATCH] scsi_debug: add support to corrupt data and/or reftag sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260723142154.107268-1-hch@lst.de \
--to=hch@lst.de \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox