selftests: ublk: add kublk support for integrity params

Add integrity param command line arguments to kublk. Plumb these to
struct ublk_params for the null and fault_inject targets, as they don't
need to actually read or write the integrity data. Forbid the integrity
params for loop or stripe until the integrity data copy is implemented.

Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Caleb Sander Mateos 2026-01-08 02:19:42 -07:00 committed by Jens Axboe
parent 261b67f4e3
commit 6ed6476c4a
6 changed files with 78 additions and 0 deletions

View File

@ -33,6 +33,7 @@ static int ublk_fault_inject_tgt_init(const struct dev_ctx *ctx,
.dev_sectors = dev_size >> 9,
},
};
ublk_set_integrity_params(ctx, &dev->tgt.params);
dev->private_data = (void *)(unsigned long)(ctx->fault_inject.delay_us * 1000);
return 0;

View File

@ -158,6 +158,10 @@ static int ublk_loop_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *dev)
ublk_err("%s: not support auto_zc_fallback\n", __func__);
return -EINVAL;
}
if (ctx->metadata_size) {
ublk_err("%s: integrity not supported\n", __func__);
return -EINVAL;
}
ret = backing_file_tgt_init(dev);
if (ret)

View File

@ -3,6 +3,7 @@
* Description: uring_cmd based ublk
*/
#include <linux/fs.h>
#include "kublk.h"
#define MAX_NR_TGT_ARG 64
@ -1550,6 +1551,8 @@ static void __cmd_create_help(char *exe, bool recovery)
printf("\t[--foreground] [--quiet] [-z] [--auto_zc] [--auto_zc_fallback] [--debug_mask mask] [-r 0|1] [-g] [-u]\n");
printf("\t[-e 0|1 ] [-i 0|1] [--no_ublk_fixed_fd]\n");
printf("\t[--nthreads threads] [--per_io_tasks]\n");
printf("\t[--integrity_capable] [--integrity_reftag] [--metadata_size SIZE] "
"[--pi_offset OFFSET] [--csum_type ip|t10dif|nvme] [--tag_size SIZE]\n");
printf("\t[target options] [backfile1] [backfile2] ...\n");
printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n");
printf("\tdefault: nthreads=nr_queues");
@ -1613,6 +1616,12 @@ int main(int argc, char *argv[])
{ "nthreads", 1, NULL, 0 },
{ "per_io_tasks", 0, NULL, 0 },
{ "no_ublk_fixed_fd", 0, NULL, 0 },
{ "integrity_capable", 0, NULL, 0 },
{ "integrity_reftag", 0, NULL, 0 },
{ "metadata_size", 1, NULL, 0 },
{ "pi_offset", 1, NULL, 0 },
{ "csum_type", 1, NULL, 0 },
{ "tag_size", 1, NULL, 0 },
{ 0, 0, 0, 0 }
};
const struct ublk_tgt_ops *ops = NULL;
@ -1623,6 +1632,7 @@ int main(int argc, char *argv[])
.nr_hw_queues = 2,
.dev_id = -1,
.tgt_type = "unknown",
.csum_type = LBMD_PI_CSUM_NONE,
};
int ret = -EINVAL, i;
int tgt_argc = 1;
@ -1697,6 +1707,28 @@ int main(int argc, char *argv[])
ctx.per_io_tasks = 1;
if (!strcmp(longopts[option_idx].name, "no_ublk_fixed_fd"))
ctx.no_ublk_fixed_fd = 1;
if (!strcmp(longopts[option_idx].name, "integrity_capable"))
ctx.integrity_flags |= LBMD_PI_CAP_INTEGRITY;
if (!strcmp(longopts[option_idx].name, "integrity_reftag"))
ctx.integrity_flags |= LBMD_PI_CAP_REFTAG;
if (!strcmp(longopts[option_idx].name, "metadata_size"))
ctx.metadata_size = strtoul(optarg, NULL, 0);
if (!strcmp(longopts[option_idx].name, "pi_offset"))
ctx.pi_offset = strtoul(optarg, NULL, 0);
if (!strcmp(longopts[option_idx].name, "csum_type")) {
if (!strcmp(optarg, "ip")) {
ctx.csum_type = LBMD_PI_CSUM_IP;
} else if (!strcmp(optarg, "t10dif")) {
ctx.csum_type = LBMD_PI_CSUM_CRC16_T10DIF;
} else if (!strcmp(optarg, "nvme")) {
ctx.csum_type = LBMD_PI_CSUM_CRC64_NVME;
} else {
ublk_err("invalid csum_type: %s\n", optarg);
return -EINVAL;
}
}
if (!strcmp(longopts[option_idx].name, "tag_size"))
ctx.tag_size = strtoul(optarg, NULL, 0);
break;
case '?':
/*
@ -1739,6 +1771,21 @@ int main(int argc, char *argv[])
return -EINVAL;
}
if (ctx.metadata_size) {
if (!(ctx.flags & UBLK_F_USER_COPY)) {
ublk_err("integrity requires user_copy\n");
return -EINVAL;
}
ctx.flags |= UBLK_F_INTEGRITY;
} else if (ctx.integrity_flags ||
ctx.pi_offset ||
ctx.csum_type != LBMD_PI_CSUM_NONE ||
ctx.tag_size) {
ublk_err("integrity parameters require metadata_size\n");
return -EINVAL;
}
i = optind;
while (i < argc && ctx.nr_files < MAX_BACK_FILES) {
ctx.files[ctx.nr_files++] = argv[i++];

View File

@ -78,6 +78,11 @@ struct dev_ctx {
unsigned int auto_zc_fallback:1;
unsigned int per_io_tasks:1;
unsigned int no_ublk_fixed_fd:1;
__u32 integrity_flags;
__u8 metadata_size;
__u8 pi_offset;
__u8 csum_type;
__u8 tag_size;
int _evtfd;
int _shmid;
@ -202,6 +207,22 @@ struct ublk_dev {
extern int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io);
static inline void ublk_set_integrity_params(const struct dev_ctx *ctx,
struct ublk_params *params)
{
if (!ctx->metadata_size)
return;
params->types |= UBLK_PARAM_TYPE_INTEGRITY;
params->integrity = (struct ublk_param_integrity) {
.flags = ctx->integrity_flags,
.interval_exp = params->basic.logical_bs_shift,
.metadata_size = ctx->metadata_size,
.pi_offset = ctx->pi_offset,
.csum_type = ctx->csum_type,
.tag_size = ctx->tag_size,
};
}
static inline int ublk_io_auto_zc_fallback(const struct ublksrv_io_desc *iod)
{

View File

@ -36,6 +36,7 @@ static int ublk_null_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *dev)
.max_segments = 32,
},
};
ublk_set_integrity_params(ctx, &dev->tgt.params);
if (info->flags & UBLK_F_SUPPORT_ZERO_COPY)
dev->tgt.sq_depth = dev->tgt.cq_depth = 2 * info->queue_depth;

View File

@ -298,6 +298,10 @@ static int ublk_stripe_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *dev)
ublk_err("%s: not support auto_zc_fallback\n", __func__);
return -EINVAL;
}
if (ctx->metadata_size) {
ublk_err("%s: integrity not supported\n", __func__);
return -EINVAL;
}
if ((chunk_size & (chunk_size - 1)) || !chunk_size) {
ublk_err("invalid chunk size %u\n", chunk_size);