From nobody Sat Feb 7 09:59:14 2026 Received: from mail-pl1-f227.google.com (mail-pl1-f227.google.com [209.85.214.227]) (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 B9992227B8E for ; Tue, 6 Jan 2026 00:58:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.227 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767661099; cv=none; b=o5a4sW2KMguNrOSNi0qH2q0FgMchKuykXSZuSdwoWsFPwraOITf9PB7HI341RtM5XYDxIrvxmdic8r8GKuOqJ1UVlMd6l9km++sIJ0vI5yRxpjTnWMEti+sLMORFEH7FJ3hrkStGMSB6NNq0yAwWoDxARMvUsOy8XSMY1lyvkkM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767661099; c=relaxed/simple; bh=f8EP+bPK1MvqaUPNHimhlYSpt7ZjD3QQvEFMsrXub80=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IITefIw5UHuZJM4FcZdmckYN8Hdv0j9IWRhtP8lNp8LwJP8G4uUY2QLnXFbTLZWcapHoO4gs+9bHKgU7bVdN4H2V98anxK31rTRFq+g8Rn9hjYPuk1vmOk++t4uBvWQHoE7SVz0b0vudrLTXYHBBXubc9VA9LwAM2G0ni4kdXOA= 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=aCEEN3Jf; arc=none smtp.client-ip=209.85.214.227 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="aCEEN3Jf" Received: by mail-pl1-f227.google.com with SMTP id d9443c01a7336-2a08cb5e30eso1067925ad.1 for ; Mon, 05 Jan 2026 16:58:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=purestorage.com; s=google2022; t=1767661092; x=1768265892; 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=aCEEN3Jfpnfaoz/bhk1xZ3Jps+gYQ7SYddOwmTaD+03+EUd6PtbbjuCPBumAiErIku a8W+gIxjl2xabja9TU+9KRYQjD4YIHRJft68ApBq218GlaOVYdbTAftul6oAxMDQ7JHj VNmdh/6JpKoEwfQBrUB9rlZk3VUWs7iV2lpchSOx8d31EcUejdoILUkDrFe9yF8vthSI q24kptbhAzjVe7bJoSO7rmhNYf+3oS49hX0kIRgpeV3OG/pWW3Mu+RjTXzG+bg5KsOFr 1OsifoQqZ/O+VAJehehxmrJMoj4qDS4Pxui1WsR16egu7Ykxvbp7H2ZI28JCgO54gKMA TL7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767661092; x=1768265892; 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=uFNuT0tghSXWLRk92Idgjb2d1mrkodKdhGLSUvbkm/FKi5IvOXvmvFuCvlJZk3zDA4 Q7KHgK+AnhNRjOPIuQ35yGxbc+doWB5xBAJUIrvGqO+foJpiFB3BEUNaY7VbAS61YrOW MF1sS9D4+9hoSwz+I0CsRSbxwnq7Vp+oVGGLDDj0HZBBeKNpv7kNgNyyduXrFywuIUwK isrGgmvA3tT7MiXrd7M/tH7PCzdXUhDnlE2GD2Dx7o9EYma68i+tyuG5e85+189JaCAa +0jXmWLRPTTXQq3g2J/OpQ2fYpLxNGRHZudlg1H4WBjfOd++jFAhQj96zfvIHd+yRsnL jtdA== X-Forwarded-Encrypted: i=1; AJvYcCXD3I8Y+eFKvYZpgbziZDM6pKfkwMm0b6gDiGLfoEB3wF10CmbjrpWwUbj9OjEQRdJTcRnXxLSo7Slx3FQ=@vger.kernel.org X-Gm-Message-State: AOJu0YxSOhY4ukccsF9HpptYxr399CQhezuJTkMmDqqvhDptnQNbuAZh QfHBpLo5fTvjlFx/dww+jT7eTwTmgYtpnQoLz26m61YnELUioGpor3xIg9Nxv66y+SDQkRItF2y m6lXeLxdX9wl++wvHlU/YRbVYnm6gEnHv5XGPjgnhNtCUS8/0CZX/ X-Gm-Gg: AY/fxX6PhgaQXGqV6WkpmhQC/qNOaZnpE5R1oFD/8BYNJrs8ZxTWUUzY1mHRj5GB9GF uTDyRrKxW01CiKNEgtmrUcJ6WqhKHRUx/+6Ac9jCVSUPnwAAw4mXw0PKQlX9FOwkQa/Yldgtds8 Z6JUh1nb7C7fqnq5+WR0Vyjw5LQr+au7hacKnhYGXIgGlM7fLg8SFWAAUIpTzP8S1HdCrTgGS1R saMoGqHRGamp1YPSop6MRKLfq62SdwUy9mwjNNyo9asz78oCwxp8xdqbltA6GL0VoSbH8aTYuZw 0Wg3HUOey7kKVqqwKpyKWoOjwuagbtydJzzHQ1iHH6ElmtZ6GN/GSA9EBapUvXHPe2Mqw635XV0 4C3EhoXEGfrbm5U5TZyS7KhHCDnk= X-Google-Smtp-Source: AGHT+IEwy3xNj8bx514efu2NZrTdyRXI4rGnHiIIY0NgXLyLfCfNZnpOeahDtpiWh9+nlqkwyb1pWtp8Ofe8 X-Received: by 2002:a17:903:1b6c:b0:2a0:d07a:bb2f with SMTP id d9443c01a7336-2a3e2d944aemr9298545ad.3.1767661091749; Mon, 05 Jan 2026 16:58:11 -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-2a3e3cae722sm892915ad.29.2026.01.05.16.58.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Jan 2026 16:58:11 -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 3E993340960; Mon, 5 Jan 2026 17:58:11 -0700 (MST) Received: by dev-csander.dev.purestorage.com (Postfix, from userid 1557716354) id 306D5E44554; Mon, 5 Jan 2026 17:58:11 -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 , "Martin K . Petersen" , Caleb Sander Mateos Subject: [PATCH v3 17/19] selftests: ublk: add integrity data support to loop target Date: Mon, 5 Jan 2026 17:57:49 -0700 Message-ID: <20260106005752.3784925-18-csander@purestorage.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20260106005752.3784925-1-csander@purestorage.com> References: <20260106005752.3784925-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