From nobody Sun Feb 8 21:28:14 2026 Received: from mail-pl1-f228.google.com (mail-pl1-f228.google.com [209.85.214.228]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E4AC923EA8B for ; Sat, 3 Jan 2026 00:45:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.228 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767401142; cv=none; b=dnguPgc2B0hEs5UNVzHla7HXaY2Xph90+jZOKatE7+mdCewDfyeFkHILC1hpCAsM5yIdu3UX3v2YIbDXj5gx6jenH7wMOPgaZj5iXdRCPMMj6g9+0qPdNdOCH4f5eVCGci/0WDRVhFMeKGlsE98dV/q/LDYcI2eesiTUqdgSwII= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767401142; c=relaxed/simple; bh=f8EP+bPK1MvqaUPNHimhlYSpt7ZjD3QQvEFMsrXub80=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nSbmpUd6PIEP0nmRlytA1wVrDN9fkhZh3oIxnWxKZUBGm365IoYj1qV+h5SRasrCvq8TvR3a8+Dshx6Sls+rPO5i3nJxtc2BtUXI3W2sKo8bulmFeoEtmn0MDnVp+03gyEch087a31M3XO342G1GIQdJ4/JLeFgJfNyvmRrGHyA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=purestorage.com; spf=fail smtp.mailfrom=purestorage.com; dkim=pass (2048-bit key) header.d=purestorage.com header.i=@purestorage.com header.b=CfvfZnk7; arc=none smtp.client-ip=209.85.214.228 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=purestorage.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=purestorage.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=purestorage.com header.i=@purestorage.com header.b="CfvfZnk7" Received: by mail-pl1-f228.google.com with SMTP id d9443c01a7336-2a355c8b808so11821245ad.3 for ; Fri, 02 Jan 2026 16:45:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=purestorage.com; s=google2022; t=1767401135; x=1768005935; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0K5vEftPdYiPKum60OYL4RUxMxughkX0Uvdp3aFS+SM=; b=CfvfZnk7bDH+nJOM3yZl+8AArxpZJjt4FBqpkgGh4t+bMwCc4prAWHorbgZTTW66qD ZvGDoCc+E7RPs4KT0KzRJKjtc4y5I8tah4Dre1RmM8GA8vNTiWNOHkVHTtLPOt6rMiNG 14TFufkdcscqvyWkbW3RdKx/mKfPUiTzSl9DHFNwuEkNAa3v33SGTNUl8/gzDJ6q3az5 IgOF3ZwQmfhrHOtoIFHjGlWyLVQDaY+mvvIdmBd/LOmgHsdf0RXsOtvokcF1z5ZjxQrl YsGpyhpjpNk0uLI+silil1op+2UxFBKmFzq+QaJ9DMGGoF+TgkNTGLPigG2M2Byn45xc u9AA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767401135; x=1768005935; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=0K5vEftPdYiPKum60OYL4RUxMxughkX0Uvdp3aFS+SM=; b=LSQuGQ8FTmzbT17EUWaOvmjXfrtCeMhPrX3xJ1sH6JC/5yOqQHy4lZftrY9i8ZU0yr iDQEVq93sKHh7nc2daw4HwSStWgjAXTfCkS2plCLhLLAlV0jG0Fgg43HbZXGzla+V5yY 9rqGhcsRD4BFrLRCa9sZThBdfSlveKROaphoC69qMn2e+Ihm0MNUUfDX5bRk9/U3oGmk g3Z/D5hzdOgw4/HZFaKULueBmp2ePhg9/101MagzW29+HL0bEamNSRcJJyH63dtMsUmE 8NomNPiWaANHeRoOWKFlSp0Bd572JKsFdisX3Wog++tjOTjz9heP8eAzGo07kn7vj27y cksw== X-Forwarded-Encrypted: i=1; AJvYcCUW5HH6oJa8eYK+Y72glOv7RvoknkVENMXx5GwHi1tg9fn4G1XnXQzk6caDC6YNpbaxE5ncY418XwR8II4=@vger.kernel.org X-Gm-Message-State: AOJu0YxeIL9du1mYxdwR9+R4SvtV3WBD53vPrvBXUsXzN7uFm2R0qs9R zwtYt6ZxpGJc3hmhqvmjz82/hIM8KtxM2G+dPE6ZNS2myPJ03VrUpp0aLBnsIjxaZP90BMTFuaU +t5GFbFcqvCY0/e0S1oVz2uz2RSo0VY9YUtz7aXDIvrKXUpJo7l5h X-Gm-Gg: AY/fxX4UwpdabdeEwxGJUjArWYh5wQ5wyANotvk5A+Lvbd1WWJXolnkgMXJEoinqg+I mKgMrwYDeGbbAPJAyeH2Q/POeVMccj9wmHEfPwfumdDknYRpT7LOgrbmB1fQMakH1aOYci40V8N k0940Kc/4eYdkcvXqUqxrTJZXr0fut+3bQGNl+L1EqZaz3tcxZryXak0emWsr1+GAM5lgnDSBLE qgxnnDmBcSMFW9+AtoGCxvH3hj2P97ljfHmvOfmyVq/tiOar8Pch0u7u0Q2hM/QT18xqI3NIy02 X4IQXg3pPMYVhUS3F0KdI3KfY1GM1Wzt9SMADY//wyTWbmT1ubYzpeMDpnXhCSctnYeM5dZvLY2 s6LzbzlllDS74kTI1NjHrKMSxX0I= X-Google-Smtp-Source: AGHT+IHcX+CRfh1yJ1dtOuSX3HDSSImX9jo+Oulvfyxwk7ticvfgzH1fRPZhYJFZLxwgd2hA8WknWNn4BYl9 X-Received: by 2002:a17:902:c405:b0:297:df7c:ed32 with SMTP id d9443c01a7336-2a2f1f7c269mr304827635ad.0.1767401135319; Fri, 02 Jan 2026 16:45:35 -0800 (PST) Received: from c7-smtp-2023.dev.purestorage.com ([2620:125:9017:12:36:3:5:0]) by smtp-relay.gmail.com with ESMTPS id d9443c01a7336-2a2f3d1c1f5sm48601045ad.49.2026.01.02.16.45.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Jan 2026 16:45:35 -0800 (PST) X-Relaying-Domain: purestorage.com Received: from dev-csander.dev.purestorage.com (dev-csander.dev.purestorage.com [10.49.34.222]) by c7-smtp-2023.dev.purestorage.com (Postfix) with ESMTP id C0943341FDC; Fri, 2 Jan 2026 17:45:34 -0700 (MST) Received: by dev-csander.dev.purestorage.com (Postfix, from userid 1557716354) id BE7F3E4426F; Fri, 2 Jan 2026 17:45:34 -0700 (MST) From: Caleb Sander Mateos To: Ming Lei , Jens Axboe , Shuah Khan Cc: linux-block@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Stanley Zhang , Uday Shankar , Caleb Sander Mateos Subject: [PATCH v2 17/19] selftests: ublk: add integrity data support to loop target Date: Fri, 2 Jan 2026 17:45:27 -0700 Message-ID: <20260103004529.1582405-18-csander@purestorage.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20260103004529.1582405-1-csander@purestorage.com> References: <20260103004529.1582405-1-csander@purestorage.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" To perform and end-to-end test of integrity information through a ublk device, we need to actually store it somewhere and retrieve it. Add this support to kublk's loop target. It uses a second backing file for the integrity data corresponding to the data stored in the first file. The integrity file is opened without O_DIRECT since it will be accessed at sub-block granularity. Each incoming read/write results in a pair of reads/writes, one to the data file, and one to the integrity file. If either backing I/O fails, the error is propagated to the ublk request. If both backing I/Os read/write some bytes, the ublk request is completed with the smaller of the number of blocks accessed by each I/O. Signed-off-by: Caleb Sander Mateos --- tools/testing/selftests/ublk/file_backed.c | 63 +++++++++++++++------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/ublk/file_backed.c b/tools/testing/sel= ftests/ublk/file_backed.c index db4c176a4f28..b8aacaa928a4 100644 --- a/tools/testing/selftests/ublk/file_backed.c +++ b/tools/testing/selftests/ublk/file_backed.c @@ -33,48 +33,62 @@ static int loop_queue_tgt_rw_io(struct ublk_thread *t, = struct ublk_queue *q, unsigned ublk_op =3D ublksrv_get_op(iod); unsigned zc =3D ublk_queue_use_zc(q); unsigned auto_zc =3D ublk_queue_use_auto_zc(q); enum io_uring_op op =3D ublk_to_uring_op(iod, zc | auto_zc); struct ublk_io *io =3D ublk_get_io(q, tag); + __u64 offset =3D iod->start_sector << 9; + __u32 len =3D iod->nr_sectors << 9; struct io_uring_sqe *sqe[3]; void *addr =3D io->buf_addr; =20 + if (iod->op_flags & UBLK_IO_F_INTEGRITY) { + ublk_io_alloc_sqes(t, sqe, 1); + /* Use second backing file for integrity data */ + io_uring_prep_rw(op, sqe[0], ublk_get_registered_fd(q, 2), + io->integrity_buf, + ublk_integrity_len(q, len), + ublk_integrity_len(q, offset)); + sqe[0]->flags =3D IOSQE_FIXED_FILE; + /* tgt_data =3D 1 indicates integrity I/O */ + sqe[0]->user_data =3D build_user_data(tag, ublk_op, 1, q->q_id, 1); + } + if (!zc || auto_zc) { ublk_io_alloc_sqes(t, sqe, 1); if (!sqe[0]) return -ENOMEM; =20 io_uring_prep_rw(op, sqe[0], ublk_get_registered_fd(q, 1) /*fds[1]*/, addr, - iod->nr_sectors << 9, - iod->start_sector << 9); + len, + offset); if (auto_zc) sqe[0]->buf_index =3D tag; io_uring_sqe_set_flags(sqe[0], IOSQE_FIXED_FILE); /* bit63 marks us as tgt io */ sqe[0]->user_data =3D build_user_data(tag, ublk_op, 0, q->q_id, 1); - return 1; + return !!(iod->op_flags & UBLK_IO_F_INTEGRITY) + 1; } =20 ublk_io_alloc_sqes(t, sqe, 3); =20 io_uring_prep_buf_register(sqe[0], q, tag, q->q_id, io->buf_index); sqe[0]->flags |=3D IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK; sqe[0]->user_data =3D build_user_data(tag, ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1); =20 io_uring_prep_rw(op, sqe[1], ublk_get_registered_fd(q, 1) /*fds[1]*/, 0, - iod->nr_sectors << 9, - iod->start_sector << 9); + len, + offset); sqe[1]->buf_index =3D tag; sqe[1]->flags |=3D IOSQE_FIXED_FILE | IOSQE_IO_HARDLINK; sqe[1]->user_data =3D build_user_data(tag, ublk_op, 0, q->q_id, 1); =20 io_uring_prep_buf_unregister(sqe[2], q, tag, q->q_id, io->buf_index); sqe[2]->user_data =3D build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op)= , 0, q->q_id, 1); =20 - return 2; + return !!(iod->op_flags & UBLK_IO_F_INTEGRITY) + 2; } =20 static int loop_queue_tgt_io(struct ublk_thread *t, struct ublk_queue *q, = int tag) { const struct ublksrv_io_desc *iod =3D ublk_get_iod(q, tag); @@ -117,16 +131,21 @@ static void ublk_loop_io_done(struct ublk_thread *t, = struct ublk_queue *q, { unsigned tag =3D user_data_to_tag(cqe->user_data); unsigned op =3D user_data_to_op(cqe->user_data); struct ublk_io *io =3D ublk_get_io(q, tag); =20 - if (cqe->res < 0 || op !=3D ublk_cmd_op_nr(UBLK_U_IO_UNREGISTER_IO_BUF)) { - if (!io->result) - io->result =3D cqe->res; - if (cqe->res < 0) - ublk_err("%s: io failed op %x user_data %lx\n", - __func__, op, cqe->user_data); + if (cqe->res < 0) { + io->result =3D cqe->res; + ublk_err("%s: io failed op %x user_data %lx\n", + __func__, op, cqe->user_data); + } else if (op !=3D ublk_cmd_op_nr(UBLK_U_IO_UNREGISTER_IO_BUF)) { + __s32 data_len =3D user_data_to_tgt_data(cqe->user_data) + ? ublk_integrity_data_len(q, cqe->res) + : cqe->res; + + if (!io->result || data_len < io->result) + io->result =3D data_len; } =20 /* buffer register op is IOSQE_CQE_SKIP_SUCCESS */ if (op =3D=3D ublk_cmd_op_nr(UBLK_U_IO_REGISTER_IO_BUF)) io->tgt_ios +=3D 1; @@ -136,10 +155,11 @@ static void ublk_loop_io_done(struct ublk_thread *t, = struct ublk_queue *q, } =20 static int ublk_loop_tgt_init(const struct dev_ctx *ctx, struct ublk_dev *= dev) { unsigned long long bytes; + unsigned long blocks; int ret; struct ublk_params p =3D { .types =3D UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DMA_ALIGN, .basic =3D { .attrs =3D UBLK_ATTR_VOLATILE_CACHE, @@ -152,27 +172,34 @@ static int ublk_loop_tgt_init(const struct dev_ctx *c= tx, struct ublk_dev *dev) .dma =3D { .alignment =3D 511, }, }; =20 + ublk_set_integrity_params(ctx, &p); if (ctx->auto_zc_fallback) { 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; - } =20 + /* Use O_DIRECT only for data file */ ret =3D backing_file_tgt_init(dev, 1); if (ret) return ret; =20 - if (dev->tgt.nr_backing_files !=3D 1) + /* Expect a second file for integrity data */ + if (dev->tgt.nr_backing_files !=3D 1 + !!ctx->metadata_size) return -EINVAL; =20 - bytes =3D dev->tgt.backing_file_size[0]; + blocks =3D dev->tgt.backing_file_size[0] >> p.basic.logical_bs_shift; + if (ctx->metadata_size) { + unsigned long metadata_blocks =3D + dev->tgt.backing_file_size[1] / ctx->metadata_size; + + /* Ensure both data and integrity data fit in backing files */ + blocks =3D min(blocks, metadata_blocks); + } + bytes =3D blocks << p.basic.logical_bs_shift; dev->tgt.dev_size =3D bytes; p.basic.dev_sectors =3D bytes >> 9; dev->tgt.params =3D p; =20 return 0; --=20 2.45.2