From patchwork Fri Oct 11 12:12:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832775 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C18B2D0EE12 for ; Fri, 11 Oct 2024 17:20:34 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJJ3-00038y-Dv; Fri, 11 Oct 2024 13:20:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7q-0004AI-OF for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:34 -0400 Received: from mail-pl1-x632.google.com ([2607:f8b0:4864:20::632]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEVq-0004qq-3c for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:12:57 -0400 Received: by mail-pl1-x632.google.com with SMTP id d9443c01a7336-20ca1b6a80aso5015635ad.2 for ; Fri, 11 Oct 2024 05:12:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648772; x=1729253572; darn=nongnu.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=fmBCyXbDFDXZfd++HuSOGkWXjW5DHdU1ZXFrWmEMcuM=; b=RPFWK7t7rCYpIuiht6haFaQbiFEx9yBvSpokKd1CpcjEu3gntMoX9SSVfGv3fK3z5Y pNurYG9RclaCvygCqpafNcwde5gzqMl/Msa94hao+BIbfCkMNJaGhkJvyBOhWu4FQHbk ATRgPN1+5RLKHar3Ou/UhGikM+tuHrQUiSziVgj2Qv1nBhZtrseYDLJqZTfgmjz4s7WY zxB2TRqcX1zkaZgpimomOJtHAJhbx3ARjRWn5mprwRxlZTIqqVvBSyAtGUmExecq0CYD P94HZqhFED7xXfambaySLL6NXlMg1535GyPVFqow/UsOGBewYiBknAPSH7rQKvjjrFox LQLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648772; x=1729253572; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fmBCyXbDFDXZfd++HuSOGkWXjW5DHdU1ZXFrWmEMcuM=; b=mM2Md1DG3+t+FCjxuGp16OsKPGwpkPZzJU7h7ZgUF+4X4skeHrDJ6TDRFhJfLg+xN9 7I98pa3Pb4pSsgCiJS+GF5jJ4DNzoGbu4TqIvUMjoDP76pzjZ7XYb25djoNzcdpyRfg2 sp2vKaQNCpU9H2pzv5iJEowTQEHcYMVXDZIxy4R4DjAJLPgCRfVuqejkZsN4Z3k9IMk+ HovRGJje5q/ZkNMB1ZrNQihb4CRVT41pcGG1anUNw5Re1Njrah4KvJh7mrVb78MA8Gla R+7HNVkeha/x6/h+yAMCXhwBT7LQW4iCDDkk45WlaE8qWR67Eyq7S/hNY8jo7bg3xNzs XuIw== X-Forwarded-Encrypted: i=1; AJvYcCWfQOoRNZ7xukq25V51kskuKQqy82dv+Klw2D9h2KJQ/F09cxlnTpvP0kJUOU4DiAgY5XcevLzqi0jq@nongnu.org X-Gm-Message-State: AOJu0Ywz+rpd9mPo9tECoxWIIkh2Z7MDDYR0V0jo3GvVdPrlqvz7R7Ws QRBNJZlo0CPTYnZclxP/TnOruj7xlvxbbLr5WMWJFjwLXFXaU2I/dV9rMl2DlVx+Z+fO6kUfso7 sU64= X-Google-Smtp-Source: AGHT+IEyQBRjrtnjPjUR/9WLeHv29C1fK0YswJhiyyd09acDTyezd24M3pabFmj6ix9KiqpSkC5Dqw== X-Received: by 2002:a17:902:ce83:b0:20b:80e6:bcdf with SMTP id d9443c01a7336-20ca1472256mr36644645ad.23.1728648772447; Fri, 11 Oct 2024 05:12:52 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.12.47 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:12:52 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 01/10] block: add persistent reservation in/out api Date: Fri, 11 Oct 2024 20:12:22 +0800 Message-Id: <20241011121231.18333-2-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::632; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x632.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add persistent reservation in/out operations at the block level. The following operations are included: - read_keys: retrieves the list of registered keys. - read_reservation: retrieves the current reservation status. - register: registers a new reservation key. - reserve: initiates a reservation for a specific key. - release: releases a reservation for a specific key. - clear: clears all existing reservations. - preempt: preempts a reservation held by another key. Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi Reviewed-by: Stefan Hajnoczi --- block/block-backend.c | 403 ++++++++++++++++++++++++++++++ block/io.c | 164 ++++++++++++ include/block/block-common.h | 40 +++ include/block/block-io.h | 20 ++ include/block/block_int-common.h | 84 +++++++ include/sysemu/block-backend-io.h | 24 ++ 6 files changed, 735 insertions(+) diff --git a/block/block-backend.c b/block/block-backend.c index db6f9b92a3..b74aaba23f 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1770,6 +1770,409 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, return blk_aio_prwv(blk, req, 0, buf, blk_aio_ioctl_entry, 0, cb, opaque); } +typedef struct BlkPrInCo { + BlockBackend *blk; + uint32_t *generation; + uint32_t num_keys; + BlockPrType *type; + uint64_t *keys; + int ret; +} BlkPrInCo; + +typedef struct BlkPrInCB { + BlockAIOCB common; + BlkPrInCo prco; + bool has_returned; +} BlkPrInCB; + +static const AIOCBInfo blk_pr_in_aiocb_info = { + .aiocb_size = sizeof(BlkPrInCB), +}; + +static void blk_pr_in_complete(BlkPrInCB *acb) +{ + if (acb->has_returned) { + acb->common.cb(acb->common.opaque, acb->prco.ret); + + /* This is paired with blk_inc_in_flight() in blk_aio_pr_in(). */ + blk_dec_in_flight(acb->prco.blk); + qemu_aio_unref(acb); + } +} + +static void blk_pr_in_complete_bh(void *opaque) +{ + BlkPrInCB *acb = opaque; + assert(acb->has_returned); + blk_pr_in_complete(acb); +} + +static BlockAIOCB *blk_aio_pr_in(BlockBackend *blk, uint32_t *generation, + uint32_t num_keys, BlockPrType *type, + uint64_t *keys, CoroutineEntry co_entry, + BlockCompletionFunc *cb, void *opaque) +{ + BlkPrInCB *acb; + Coroutine *co; + + /* This is paired with blk_dec_in_flight() in blk_pr_in_complete(). */ + blk_inc_in_flight(blk); + acb = blk_aio_get(&blk_pr_in_aiocb_info, blk, cb, opaque); + acb->prco = (BlkPrInCo) { + .blk = blk, + .generation = generation, + .num_keys = num_keys, + .type = type, + .ret = NOT_DONE, + .keys = keys, + }; + acb->has_returned = false; + + co = qemu_coroutine_create(co_entry, acb); + aio_co_enter(qemu_get_current_aio_context(), co); + + acb->has_returned = true; + if (acb->prco.ret != NOT_DONE) { + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), + blk_pr_in_complete_bh, acb); + } + + return &acb->common; +} + +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_aio_pr_do_read_keys(BlockBackend *blk, uint32_t *generation, + uint32_t num_keys, uint64_t *keys) +{ + IO_CODE(); + + blk_wait_while_drained(blk); + GRAPH_RDLOCK_GUARD(); + + if (!blk_co_is_available(blk)) { + return -ENOMEDIUM; + } + + return bdrv_co_pr_read_keys(blk_bs(blk), generation, num_keys, keys); +} + +static void coroutine_fn blk_aio_pr_read_keys_entry(void *opaque) +{ + BlkPrInCB *acb = opaque; + BlkPrInCo *prco = &acb->prco; + + prco->ret = blk_aio_pr_do_read_keys(prco->blk, prco->generation, + prco->num_keys, prco->keys); + blk_pr_in_complete(acb); +} + +BlockAIOCB *blk_aio_pr_read_keys(BlockBackend *blk, uint32_t *generation, + uint32_t num_keys, uint64_t *keys, + BlockCompletionFunc *cb, void *opaque) +{ + IO_CODE(); + return blk_aio_pr_in(blk, generation, num_keys, NULL, keys, + blk_aio_pr_read_keys_entry, cb, opaque); +} + +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_aio_pr_do_read_reservation(BlockBackend *blk, uint32_t *generation, + uint64_t *key, BlockPrType *type) +{ + IO_CODE(); + + blk_wait_while_drained(blk); + GRAPH_RDLOCK_GUARD(); + + if (!blk_co_is_available(blk)) { + return -ENOMEDIUM; + } + + return bdrv_co_pr_read_reservation(blk_bs(blk), generation, key, type); +} + +static void coroutine_fn blk_aio_pr_read_reservation_entry(void *opaque) +{ + BlkPrInCB *acb = opaque; + BlkPrInCo *prco = &acb->prco; + + prco->ret = blk_aio_pr_do_read_reservation(prco->blk, prco->generation, + prco->keys, prco->type); + blk_pr_in_complete(acb); +} + +BlockAIOCB *blk_aio_pr_read_reservation(BlockBackend *blk, uint32_t *generation, + uint64_t *key, BlockPrType *type, + BlockCompletionFunc *cb, void *opaque) +{ + IO_CODE(); + return blk_aio_pr_in(blk, generation, 0, type, key, + blk_aio_pr_read_reservation_entry, cb, opaque); +} + +typedef struct BlkPrOutCo { + BlockBackend *blk; + uint64_t old_key; + uint64_t new_key; + bool ptpl; + BlockPrType type; + bool ignore_key; + bool abort; + int ret; +} BlkPrOutCo; + +typedef struct BlkPrOutCB { + BlockAIOCB common; + BlkPrOutCo prco; + bool has_returned; +} BlkPrOutCB; + +static const AIOCBInfo blk_pr_out_aiocb_info = { + .aiocb_size = sizeof(BlkPrOutCB), +}; + +static void blk_pr_out_complete(BlkPrOutCB *acb) +{ + if (acb->has_returned) { + acb->common.cb(acb->common.opaque, acb->prco.ret); + + /* This is paired with blk_inc_in_flight() in blk_aio_pr_out(). */ + blk_dec_in_flight(acb->prco.blk); + qemu_aio_unref(acb); + } +} + +static void blk_pr_out_complete_bh(void *opaque) +{ + BlkPrOutCB *acb = opaque; + assert(acb->has_returned); + blk_pr_out_complete(acb); +} + +static BlockAIOCB *blk_aio_pr_out(BlockBackend *blk, uint64_t old_key, + uint64_t new_key, bool ptpl, + BlockPrType type, bool ignore_key, + bool abort, CoroutineEntry co_entry, + BlockCompletionFunc *cb, void *opaque) +{ + BlkPrOutCB *acb; + Coroutine *co; + + /* This is paired with blk_dec_in_flight() in blk_pr_out_complete(). */ + blk_inc_in_flight(blk); + acb = blk_aio_get(&blk_pr_out_aiocb_info, blk, cb, opaque); + acb->prco = (BlkPrOutCo) { + .blk = blk, + .old_key = old_key, + .new_key = new_key, + .ptpl = ptpl, + .type = type, + .ignore_key = ignore_key, + .abort = abort, + .ret = NOT_DONE, + }; + acb->has_returned = false; + + co = qemu_coroutine_create(co_entry, acb); + aio_co_enter(qemu_get_current_aio_context(), co); + + acb->has_returned = true; + if (acb->prco.ret != NOT_DONE) { + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), + blk_pr_out_complete_bh, acb); + } + + return &acb->common; +} + +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_aio_pr_do_register(BlockBackend *blk, uint64_t old_key, + uint64_t new_key, BlockPrType type, + bool ptpl, bool ignore_key) +{ + IO_CODE(); + + blk_wait_while_drained(blk); + GRAPH_RDLOCK_GUARD(); + + if (!blk_co_is_available(blk)) { + return -ENOMEDIUM; + } + + return bdrv_co_pr_register(blk_bs(blk), old_key, new_key, type, + ptpl, ignore_key); +} + +static void coroutine_fn blk_aio_pr_register_entry(void *opaque) +{ + BlkPrOutCB *acb = opaque; + BlkPrOutCo *prco = &acb->prco; + + prco->ret = blk_aio_pr_do_register(prco->blk, prco->old_key, prco->new_key, + prco->type, prco->ptpl, + prco->ignore_key); + blk_pr_out_complete(acb); +} + +BlockAIOCB *blk_aio_pr_register(BlockBackend *blk, uint64_t old_key, + uint64_t new_key, BlockPrType type, + bool ptpl, bool ignore_key, + BlockCompletionFunc *cb, + void *opaque) +{ + IO_CODE(); + return blk_aio_pr_out(blk, old_key, new_key, ptpl, type, ignore_key, false, + blk_aio_pr_register_entry, cb, opaque); +} + +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_aio_pr_do_reserve(BlockBackend *blk, uint64_t key, BlockPrType type) +{ + IO_CODE(); + + blk_wait_while_drained(blk); + GRAPH_RDLOCK_GUARD(); + + if (!blk_co_is_available(blk)) { + return -ENOMEDIUM; + } + + return bdrv_co_pr_reserve(blk_bs(blk), key, type); +} + +static void coroutine_fn blk_aio_pr_reserve_entry(void *opaque) +{ + BlkPrOutCB *acb = opaque; + BlkPrOutCo *prco = &acb->prco; + + prco->ret = blk_aio_pr_do_reserve(prco->blk, prco->old_key, + prco->type); + blk_pr_out_complete(acb); +} + + +BlockAIOCB *blk_aio_pr_reserve(BlockBackend *blk, uint64_t key, + BlockPrType type, + BlockCompletionFunc *cb, + void *opaque) +{ + IO_CODE(); + return blk_aio_pr_out(blk, key, 0, false, type, false, false, + blk_aio_pr_reserve_entry, cb, opaque); +} + +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_aio_pr_do_release(BlockBackend *blk, uint64_t key, BlockPrType type) +{ + IO_CODE(); + + blk_wait_while_drained(blk); + GRAPH_RDLOCK_GUARD(); + + if (!blk_co_is_available(blk)) { + return -ENOMEDIUM; + } + + return bdrv_co_pr_release(blk_bs(blk), key, type); +} + +static void coroutine_fn blk_aio_pr_release_entry(void *opaque) +{ + BlkPrOutCB *acb = opaque; + BlkPrOutCo *prco = &acb->prco; + + prco->ret = blk_aio_pr_do_release(prco->blk, prco->old_key, prco->type); + blk_pr_out_complete(acb); +} + + +BlockAIOCB *blk_aio_pr_release(BlockBackend *blk, uint64_t key, + BlockPrType type, BlockCompletionFunc *cb, + void *opaque) +{ + IO_CODE(); + return blk_aio_pr_out(blk, key, 0, false, type, false, false, + blk_aio_pr_release_entry, cb, opaque); +} + +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_aio_pr_do_clear(BlockBackend *blk, uint64_t key) +{ + IO_CODE(); + + blk_wait_while_drained(blk); + GRAPH_RDLOCK_GUARD(); + + if (!blk_co_is_available(blk)) { + return -ENOMEDIUM; + } + + return bdrv_co_pr_clear(blk_bs(blk), key); +} + +static void coroutine_fn blk_aio_pr_clear_entry(void *opaque) +{ + BlkPrOutCB *acb = opaque; + BlkPrOutCo *prco = &acb->prco; + + prco->ret = blk_aio_pr_do_clear(prco->blk, prco->old_key); + blk_pr_out_complete(acb); +} + + +BlockAIOCB *blk_aio_pr_clear(BlockBackend *blk, uint64_t key, + BlockCompletionFunc *cb, void *opaque) +{ + IO_CODE(); + return blk_aio_pr_out(blk, key, 0, false, 0, false, false, + blk_aio_pr_clear_entry, cb, opaque); +} + +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_aio_pr_do_preempt(BlockBackend *blk, uint64_t cr_key, + uint64_t pr_key, BlockPrType type, bool abort) +{ + IO_CODE(); + + blk_wait_while_drained(blk); + GRAPH_RDLOCK_GUARD(); + + if (!blk_co_is_available(blk)) { + return -ENOMEDIUM; + } + + return bdrv_co_pr_preempt(blk_bs(blk), cr_key, pr_key, type, abort); +} + +static void coroutine_fn blk_aio_pr_preempt_entry(void *opaque) +{ + BlkPrOutCB *acb = opaque; + BlkPrOutCo *prco = &acb->prco; + + prco->ret = blk_aio_pr_do_preempt(prco->blk, prco->old_key, + prco->new_key, prco->type, + prco->abort); + blk_pr_out_complete(acb); +} + + +BlockAIOCB *blk_aio_pr_preempt(BlockBackend *blk, uint64_t cr_key, + uint64_t pr_key, BlockPrType type, + bool abort, BlockCompletionFunc *cb, + void *opaque) +{ + IO_CODE(); + return blk_aio_pr_out(blk, cr_key, pr_key, false, type, false, abort, + blk_aio_pr_preempt_entry, cb, opaque); +} + /* To be called between exactly one pair of blk_inc/dec_in_flight() */ static int coroutine_fn blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) diff --git a/block/io.c b/block/io.c index 7217cf811b..105161930e 100644 --- a/block/io.c +++ b/block/io.c @@ -146,6 +146,7 @@ static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src) src->min_mem_alignment); dst->max_iov = MIN_NON_ZERO(dst->max_iov, src->max_iov); dst->max_hw_iov = MIN_NON_ZERO(dst->max_hw_iov, src->max_hw_iov); + dst->pr_cap |= src->pr_cap; } typedef struct BdrvRefreshLimitsState { @@ -3220,6 +3221,169 @@ out: return co.ret; } +int coroutine_fn bdrv_co_pr_read_keys(BlockDriverState *bs, + uint32_t *generation, uint32_t num_keys, + uint64_t *keys) +{ + BlockDriver *drv = bs->drv; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + IO_CODE(); + assert_bdrv_graph_readable(); + + bdrv_inc_in_flight(bs); + if (!drv || !drv->bdrv_co_pr_read_keys) { + co.ret = -ENOTSUP; + goto out; + } + + co.ret = drv->bdrv_co_pr_read_keys(bs, generation, num_keys, keys); +out: + bdrv_dec_in_flight(bs); + return co.ret; +} + +int coroutine_fn bdrv_co_pr_read_reservation(BlockDriverState *bs, + uint32_t *generation, uint64_t *key, BlockPrType *type) +{ + BlockDriver *drv = bs->drv; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + IO_CODE(); + assert_bdrv_graph_readable(); + + bdrv_inc_in_flight(bs); + if (!drv || !drv->bdrv_co_pr_read_reservation) { + co.ret = -ENOTSUP; + goto out; + } + + co.ret = drv->bdrv_co_pr_read_reservation(bs, generation, key, type); +out: + bdrv_dec_in_flight(bs); + return co.ret; +} + +int coroutine_fn bdrv_co_pr_register(BlockDriverState *bs, uint64_t old_key, + uint64_t new_key, BlockPrType type, bool ptpl, + bool ignore_key) +{ + BlockDriver *drv = bs->drv; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + IO_CODE(); + assert_bdrv_graph_readable(); + + bdrv_inc_in_flight(bs); + if (!drv || !drv->bdrv_co_pr_register) { + co.ret = -ENOTSUP; + goto out; + } + + co.ret = drv->bdrv_co_pr_register(bs, old_key, new_key, type, + ptpl, ignore_key); +out: + bdrv_dec_in_flight(bs); + return co.ret; +} + +int coroutine_fn bdrv_co_pr_reserve(BlockDriverState *bs, uint64_t key, + BlockPrType type) +{ + BlockDriver *drv = bs->drv; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + IO_CODE(); + assert_bdrv_graph_readable(); + + bdrv_inc_in_flight(bs); + if (!drv || !drv->bdrv_co_pr_reserve) { + co.ret = -ENOTSUP; + goto out; + } + + co.ret = drv->bdrv_co_pr_reserve(bs, key, type); +out: + bdrv_dec_in_flight(bs); + return co.ret; +} + +int coroutine_fn bdrv_co_pr_release(BlockDriverState *bs, uint64_t key, + BlockPrType type) +{ + BlockDriver *drv = bs->drv; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + IO_CODE(); + assert_bdrv_graph_readable(); + + bdrv_inc_in_flight(bs); + if (!drv || !drv->bdrv_co_pr_release) { + co.ret = -ENOTSUP; + goto out; + } + + co.ret = drv->bdrv_co_pr_release(bs, key, type); +out: + bdrv_dec_in_flight(bs); + return co.ret; +} + +int coroutine_fn bdrv_co_pr_clear(BlockDriverState *bs, uint64_t key) +{ + BlockDriver *drv = bs->drv; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + IO_CODE(); + assert_bdrv_graph_readable(); + + bdrv_inc_in_flight(bs); + if (!drv || !drv->bdrv_co_pr_clear) { + co.ret = -ENOTSUP; + goto out; + } + + co.ret = drv->bdrv_co_pr_clear(bs, key); +out: + bdrv_dec_in_flight(bs); + return co.ret; +} + +int coroutine_fn bdrv_co_pr_preempt(BlockDriverState *bs, uint64_t cr_key, + uint64_t pr_key, BlockPrType type, bool abort) +{ + BlockDriver *drv = bs->drv; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + IO_CODE(); + assert_bdrv_graph_readable(); + + bdrv_inc_in_flight(bs); + if (!drv || !drv->bdrv_co_pr_preempt) { + co.ret = -ENOTSUP; + goto out; + } + + co.ret = drv->bdrv_co_pr_preempt(bs, cr_key, pr_key, type, abort); +out: + bdrv_dec_in_flight(bs); + return co.ret; +} + int coroutine_fn bdrv_co_zone_report(BlockDriverState *bs, int64_t offset, unsigned int *nr_zones, BlockZoneDescriptor *zones) diff --git a/include/block/block-common.h b/include/block/block-common.h index 338fe5ff7a..725b6174c2 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -526,6 +526,46 @@ typedef enum { BDRV_FIX_ERRORS = 2, } BdrvCheckMode; +/** + * According SCSI protocol(chapter 5.9 of SCSI Primary Commands - 4) + * and NVMe protocol(chapter 7.2 of NVMe Base Specification 2.0), + * the persistent reservation types and persistent capabilities of + * the public layer block are abstracted. + */ +typedef enum { + BLK_PR_WRITE_EXCLUSIVE = 0x1, + BLK_PR_EXCLUSIVE_ACCESS = 0x2, + BLK_PR_WRITE_EXCLUSIVE_REGS_ONLY = 0x3, + BLK_PR_EXCLUSIVE_ACCESS_REGS_ONLY = 0x4, + BLK_PR_WRITE_EXCLUSIVE_ALL_REGS = 0x5, + BLK_PR_EXCLUSIVE_ACCESS_ALL_REGS = 0x6, +} BlockPrType; + +typedef enum BLKPrCap { + /* Persist Through Power Loss */ + BLK_PR_CAP_PTPL = 1 << 0, + /* Write Exclusive reservation type */ + BLK_PR_CAP_WR_EX = 1 << 1, + /* Exclusive Access reservation type */ + BLK_PR_CAP_EX_AC = 1 << 2, + /* Write Exclusive Registrants Only reservation type */ + BLK_PR_CAP_WR_EX_RO = 1 << 3, + /* Exclusive Access Registrants Only reservation type */ + BLK_PR_CAP_EX_AC_RO = 1 << 4, + /* Write Exclusive All Registrants reservation type */ + BLK_PR_CAP_WR_EX_AR = 1 << 5, + /* Exclusive Access All Registrants reservation type */ + BLK_PR_CAP_EX_AC_AR = 1 << 6, + + BLK_PR_CAP_ALL = (BLK_PR_CAP_PTPL | + BLK_PR_CAP_WR_EX | + BLK_PR_CAP_EX_AC | + BLK_PR_CAP_WR_EX_RO | + BLK_PR_CAP_EX_AC_RO | + BLK_PR_CAP_WR_EX_AR | + BLK_PR_CAP_EX_AC_AR), +} BLKPrCap; + typedef struct BlockSizes { uint32_t phys; uint32_t log; diff --git a/include/block/block-io.h b/include/block/block-io.h index b49e0537dd..908361862b 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -106,6 +106,26 @@ void bdrv_aio_cancel_async(BlockAIOCB *acb); int coroutine_fn GRAPH_RDLOCK bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_pr_read_keys(BlockDriverState *bs, uint32_t *generation, + uint32_t num_keys, uint64_t *keys); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_pr_read_reservation(BlockDriverState *bs, uint32_t *generation, + uint64_t *key, BlockPrType *type); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_pr_register(BlockDriverState *bs, uint64_t old_key, + uint64_t new_key, BlockPrType type, + bool ptpl, bool ignore_key); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_pr_reserve(BlockDriverState *bs, uint64_t key, BlockPrType type); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_pr_release(BlockDriverState *bs, uint64_t key, BlockPrType type); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_pr_clear(BlockDriverState *bs, uint64_t key); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_pr_preempt(BlockDriverState *bs, uint64_t cr_key, uint64_t pr_key, + BlockPrType type, bool abort); + /* Ensure contents are flushed to disk. */ int coroutine_fn GRAPH_RDLOCK bdrv_co_flush(BlockDriverState *bs); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 761276127e..6e628069e9 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -766,6 +766,87 @@ struct BlockDriver { int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_ioctl)( BlockDriverState *bs, unsigned long int req, void *buf); + /* + * Persistent reservation series api. + * Please refer to chapter 5.9 of SCSI Primary Commands - 4 or + * chapter 7 of NVMe Base Specification 2.0. + * + * The block layer driver should implement all the following APIs + * or none at all, including: bdrv_co_pr_read_keys, + * bdrv_co_pr_read_reservation, bdrv_co_pr_register, + * bdrv_co_pr_reserve, bdrv_co_pr_release, + * bdrv_co_pr_clear and bdrv_co_pr_preempt. + * + * Read the registered keys and return them in the @keys. + * @generation: The generation of the reservation key. + * @num_keys: The maximum number of keys that can be transmitted. + * @keys: Registered keys array. + * + * On success, store generation in @generation and store keys @keys + * and return the number of @keys. + * On failure return -errno. + */ + int coroutine_fn GRAPH_RDLOCK_PTR(*bdrv_co_pr_read_keys)( + BlockDriverState *bs, uint32_t *generation, + uint32_t num_keys, uint64_t *keys); + /* + * Read the reservation key and store it in the @key. + * @generation: The generation of the reservation key. + * @key: The reservation key. + * @type: Type of the reservation key. + * + * On success, store generation in @generation, store the + * reservation key in @key and return the number of @key + * which used to determine whether the reservation key exists. + * On failure return -errno. + */ + int coroutine_fn GRAPH_RDLOCK_PTR(*bdrv_co_pr_read_reservation)( + BlockDriverState *bs, uint32_t *generation, + uint64_t *key, BlockPrType *type); + /* + * Register, unregister, or replace a reservation key. + * @old_key: The current reservation key associated with the host. + * @new_key: The new reservation Key. + * @type: Type of the reservation key. + * @ignore_key: Ignore or not @old_key. + * @ptpl: Whether to support Persist Through Power Loss(PTPL). + */ + int coroutine_fn GRAPH_RDLOCK_PTR(*bdrv_co_pr_register)( + BlockDriverState *bs, uint64_t old_key, + uint64_t new_key, BlockPrType type, + bool ptpl, bool ignore_key); + /* + * Acquire a reservation on a host. + * @key: The current reservation key associated with the host. + * @type: Type of the reservation key. + */ + int coroutine_fn GRAPH_RDLOCK_PTR(*bdrv_co_pr_reserve)( + BlockDriverState *bs, uint64_t key, BlockPrType type); + /* + * Release a reservation on a host. + * @key: The current reservation key associated with the host. + * @type: Type of the reservation key. + */ + int coroutine_fn GRAPH_RDLOCK_PTR(*bdrv_co_pr_release)( + BlockDriverState *bs, uint64_t key, BlockPrType type); + /** + * Clear reservations on a host. + * @key: The current reservation key associated with the host. + */ + int coroutine_fn GRAPH_RDLOCK_PTR(*bdrv_co_pr_clear)( + BlockDriverState *bs, uint64_t key); + /* + * Preempt a reservation held on a host. + * @cr_key: The current reservation key associated with the host. + * @pr_key: The preempt reservation Key which to be + * unregistered from the namespace. + * @type: Type of the reservation key. + * @abort: Whether to abort a reservation held on a host. + */ + int coroutine_fn GRAPH_RDLOCK_PTR(*bdrv_co_pr_preempt)( + BlockDriverState *bs, uint64_t cr_key, + uint64_t pr_key, BlockPrType type, bool abort); + /* * Returns 0 for completed check, -errno for internal errors. * The check results are stored in result. @@ -899,6 +980,9 @@ typedef struct BlockLimits { uint32_t max_active_zones; uint32_t write_granularity; + + /* Persistent reservation capacities. */ + uint8_t pr_cap; } BlockLimits; typedef struct BdrvOpBlocker BdrvOpBlocker; diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index d174275a5c..b3d49a3c6f 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -62,6 +62,30 @@ void blk_aio_cancel_async(BlockAIOCB *acb); BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, BlockCompletionFunc *cb, void *opaque); +BlockAIOCB *blk_aio_pr_read_keys(BlockBackend *blk, uint32_t *generation, + uint32_t num_keys, uint64_t *keys, + BlockCompletionFunc *cb, void *opaque); +BlockAIOCB *blk_aio_pr_read_reservation(BlockBackend *blk, uint32_t *generation, + uint64_t *key, BlockPrType *type, + BlockCompletionFunc *cb, void *opaque); +BlockAIOCB *blk_aio_pr_register(BlockBackend *blk, uint64_t old_key, + uint64_t new_key, BlockPrType type, + bool ptpl, bool ignore_key, + BlockCompletionFunc *cb, + void *opaque); +BlockAIOCB *blk_aio_pr_reserve(BlockBackend *blk, uint64_t key, + BlockPrType type, + BlockCompletionFunc *cb, + void *opaque); +BlockAIOCB *blk_aio_pr_release(BlockBackend *blk, uint64_t key, + BlockPrType type, BlockCompletionFunc *cb, + void *opaque); +BlockAIOCB *blk_aio_pr_clear(BlockBackend *blk, uint64_t key, + BlockCompletionFunc *cb, void *opaque); +BlockAIOCB *blk_aio_pr_preempt(BlockBackend *blk, uint64_t cr_key, + uint64_t pr_key, BlockPrType type, bool abort, + BlockCompletionFunc *cb, void *opaque); + void blk_inc_in_flight(BlockBackend *blk); void blk_dec_in_flight(BlockBackend *blk); From patchwork Fri Oct 11 12:12:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832776 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A5F00D24470 for ; Fri, 11 Oct 2024 17:21:35 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJFa-0004zH-6a; Fri, 11 Oct 2024 13:16:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7n-00054C-0o for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:27 -0400 Received: from mail-pl1-x62f.google.com ([2607:f8b0:4864:20::62f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEVv-0004rk-Ji for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:13:00 -0400 Received: by mail-pl1-x62f.google.com with SMTP id d9443c01a7336-20c9978a221so13132265ad.1 for ; Fri, 11 Oct 2024 05:12:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648778; x=1729253578; darn=nongnu.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=ROim7xG4VeV7okIeoWk1lldyf4YzP1rLfO+fx4YPjhw=; b=lz5nv3J8tdNvEOjkpIgCPgojMTlGFLTeJ8HnKWUsysAGRR6q4SFtIePW1HkM+QDr08 c8LNDqxfvkKtat3Tb/PeIHmuZSF0JYO+7dlbdNEVffFLbbTCY+MNfO1jc7KpU+AOvpTJ mLHA/LkOrspzLf4nLe/BX13rmsHP4a10ScqTZ9BNThO0atz0G+KNu798GCSmMFYAEdu9 wFYYDaqEHsW68hZ1MjpfWmdxx2WKjsQv4vIDlg6jKH+sqS0zYvUrmCtSmPwZCra47w/4 8dk+1BqHHU+2QECsnkz36NJJLNIbD/wCMr4zSxELq0sd7T0Co9qAbixOJtxdii87L3xW XxZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648778; x=1729253578; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ROim7xG4VeV7okIeoWk1lldyf4YzP1rLfO+fx4YPjhw=; b=UEKHuqvSDdzjQTRBbTnAWNfIoT+m6tIul2ThLKlNXsrHzyERjakHEVElo5JMeebg5/ oXXfdrpZAkEF6rwRVi99F7RVSPLlfDeZSgDZemnptZColI0WfrqH8H0hAaGPouynPXuB rlWm+Qn+xZZwNhsKrnrJugFRn97LkOQbOAp/H0/mIv1kzW5jtaa5uPw2il5ZFe4uK9/G td/ohrD1lgI5o+FLMLHq8JD3SCHHgXygPUVH+L8vwQrfWikODQRm87yCfSmVwdGc4yOd zQyM4eXFI/p1b0C5xRx28GTjO+OZKIB1q/hC1snFDasC1n/lFg7nICoVB0HCzpSioA5D ztcg== X-Forwarded-Encrypted: i=1; AJvYcCUFbggkj+lmyGkv4+v4wb6eiH1CHbjHHBD9peiC/jBsdMptXNNzMUJEIKD9Odtxh+QLfHjlq/ZElN6I@nongnu.org X-Gm-Message-State: AOJu0YxIOkuPBDDmgLysgFdptTlyTdBf0hqbPN9rcD1PKGw5jthF2u0o jXOnD26EwdOwfIuMTf4YOL5+n5dN4m9GgqGkfn4R78GF4QwHacTVj9aa5xtMe44= X-Google-Smtp-Source: AGHT+IGqJ4u58f3/ekJdJVOUQpD+AfDwRiLQyZEFQAkFrlz2hVOJNcioccaWkZfycD9lCYhykNgmcw== X-Received: by 2002:a17:902:d2c1:b0:20c:8abc:733a with SMTP id d9443c01a7336-20ca16ebe21mr32049825ad.53.1728648778262; Fri, 11 Oct 2024 05:12:58 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.12.52 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:12:57 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 02/10] block/raw: add persistent reservation in/out driver Date: Fri, 11 Oct 2024 20:12:23 +0800 Message-Id: <20241011121231.18333-3-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::62f; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x62f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add persistent reservation in/out operations for raw driver. The following methods are implemented: bdrv_co_pr_read_keys, bdrv_co_pr_read_reservation, bdrv_co_pr_register, bdrv_co_pr_reserve, bdrv_co_pr_release, bdrv_co_pr_clear and bdrv_co_pr_preempt. Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi Reviewed-by: Stefan Hajnoczi --- block/raw-format.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/block/raw-format.c b/block/raw-format.c index ac7e8495f6..3746bc1bd3 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -454,6 +454,55 @@ raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) return bdrv_co_ioctl(bs->file->bs, req, buf); } +static int coroutine_fn GRAPH_RDLOCK +raw_co_pr_read_keys(BlockDriverState *bs, uint32_t *generation, + uint32_t num_keys, uint64_t *keys) +{ + + return bdrv_co_pr_read_keys(bs->file->bs, generation, num_keys, keys); +} + +static int coroutine_fn GRAPH_RDLOCK +raw_co_pr_read_reservation(BlockDriverState *bs, uint32_t *generation, + uint64_t *key, BlockPrType *type) +{ + return bdrv_co_pr_read_reservation(bs->file->bs, generation, key, type); +} + +static int coroutine_fn GRAPH_RDLOCK +raw_co_pr_register(BlockDriverState *bs, uint64_t old_key, + uint64_t new_key, BlockPrType type, + bool ptpl, bool ignore_key) +{ + return bdrv_co_pr_register(bs->file->bs, old_key, new_key, + type, ptpl, ignore_key); +} + +static int coroutine_fn GRAPH_RDLOCK +raw_co_pr_reserve(BlockDriverState *bs, uint64_t key, BlockPrType type) +{ + return bdrv_co_pr_reserve(bs->file->bs, key, type); +} + +static int coroutine_fn GRAPH_RDLOCK +raw_co_pr_release(BlockDriverState *bs, uint64_t key, BlockPrType type) +{ + return bdrv_co_pr_release(bs->file->bs, key, type); +} + +static int coroutine_fn GRAPH_RDLOCK +raw_co_pr_clear(BlockDriverState *bs, uint64_t key) +{ + return bdrv_co_pr_clear(bs->file->bs, key); +} + +static int coroutine_fn GRAPH_RDLOCK +raw_co_pr_preempt(BlockDriverState *bs, uint64_t old_key, + uint64_t new_key, BlockPrType type, bool abort) +{ + return bdrv_co_pr_preempt(bs->file->bs, old_key, new_key, type, abort); +} + static int GRAPH_RDLOCK raw_has_zero_init(BlockDriverState *bs) { return bdrv_has_zero_init(bs->file->bs); @@ -672,6 +721,13 @@ BlockDriver bdrv_raw = { .strong_runtime_opts = raw_strong_runtime_opts, .mutable_opts = mutable_opts, .bdrv_cancel_in_flight = raw_cancel_in_flight, + .bdrv_co_pr_read_keys = raw_co_pr_read_keys, + .bdrv_co_pr_read_reservation = raw_co_pr_read_reservation, + .bdrv_co_pr_register = raw_co_pr_register, + .bdrv_co_pr_reserve = raw_co_pr_reserve, + .bdrv_co_pr_release = raw_co_pr_release, + .bdrv_co_pr_clear = raw_co_pr_clear, + .bdrv_co_pr_preempt = raw_co_pr_preempt, }; static void bdrv_raw_init(void) From patchwork Fri Oct 11 12:12:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832788 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9312CD24470 for ; Fri, 11 Oct 2024 17:26:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJHA-0008MG-LY; Fri, 11 Oct 2024 13:18:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7j-0000hu-52 for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:24 -0400 Received: from mail-pl1-x62f.google.com ([2607:f8b0:4864:20::62f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEW1-0004sM-GA for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:13:06 -0400 Received: by mail-pl1-x62f.google.com with SMTP id d9443c01a7336-20c544d34bcso18509605ad.1 for ; Fri, 11 Oct 2024 05:13:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648784; x=1729253584; darn=nongnu.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=USEpHR6NMIBW3vxaZJ60aZgKZIewwnVEOQkR5GTNazo=; b=FE3u4rtFbMrqESaeb6WRRpCWSvfR9fQtN8hYuhN2wj/AeIuLeqCd50Czbp1a6wVGOj kfcKLKNYK0oxC5XW4RBYwNNjH1vmXWZhCgevTHEkL1XxRf8Mgg95ZrXKBTHUw7oStL9U 3DqA6k25akezh6pTHZ5z+YAdvDmiIMtBVJVcCMHNI8HBQVdMGwoSNYNPeZrY8+efKwHI IN49uP04ShjqHuRdT42ByUIXTQV0stJf/BcetzBD48P2IHZdQ/DCWcn6NLqsInl4VhqR ZRazXGjuhdciqNaoc+3bbPDQq4PA5DjpH65dR40Xhh8lFJT8L4J2LSaeYiJj4PTGovHq 6sfA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648784; x=1729253584; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=USEpHR6NMIBW3vxaZJ60aZgKZIewwnVEOQkR5GTNazo=; b=lxR+3TBQSCsTvsy7UrBPKXPnaMSe1sj5JRCc6B0UYnH/S/weu4+8kdf4GlvqrQd5Yn 2cMzEx1TS+MuAgAafMZekPYWIjQHl5ajduc674D4bpoIr6tkCYsY80ufX3fVW8Eahvq0 rcP4cUoj+o+K7dgHz3W3n9YzMqbSSW98M+XyQDpA72GkrwffUWVeDXttt0Z0veLgKRTy agvgrVdsl/eJGOO9ykCW61xH+LMR6gBW9Jkzpgc4F2y+XZtR9q548gYz7DN/aael9PWQ RYhhQ31RDS2kTsRKO0NXPNuzwanuN9qwfL0wyOYXvkSEY2VHa5y0wtJSkN9lwrywSgPu i6ug== X-Forwarded-Encrypted: i=1; AJvYcCXkbaZsGfEvhl/ABSn4AEKEhVDhgQVUYHpg4l56CitaOxkHOP84d96f8NX2IxF0BO/g2u/reKLnf+Ow@nongnu.org X-Gm-Message-State: AOJu0YxKM79lA7/3j+HnTk5TNc+KpjHJyVXBUvW+C10dM70Nx6pO+Qa1 YlIsw4Kz+Cp41ggvG8k1r4zsWz57RDN0wMl+7hD+Hc/Rj+leXhD4IKWA5epfLZo= X-Google-Smtp-Source: AGHT+IHOeP+ieKVDOb9YqNP2fONackQXfHki2UBcSG+w/1oKwCN2ixu6UYkdVJrj4/dxb6g1yJULNg== X-Received: by 2002:a17:902:e845:b0:20c:5c52:5184 with SMTP id d9443c01a7336-20ca1431aa1mr40422045ad.17.1728648783717; Fri, 11 Oct 2024 05:13:03 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.12.58 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:13:03 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 03/10] scsi/constant: add persistent reservation in/out protocol constants Date: Fri, 11 Oct 2024 20:12:24 +0800 Message-Id: <20241011121231.18333-4-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::62f; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x62f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add constants for the persistent reservation in/out protocol in the scsi/constant module. The constants include the persistent reservation command, type, and scope values defined in sections 6.13 and 6.14 of the SCSI Primary Commands-4 (SPC-4) specification. Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi Reviewed-by: Stefan Hajnoczi --- include/scsi/constants.h | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/include/scsi/constants.h b/include/scsi/constants.h index 9b98451912..922a314535 100644 --- a/include/scsi/constants.h +++ b/include/scsi/constants.h @@ -319,4 +319,56 @@ #define IDENT_DESCR_TGT_DESCR_SIZE 32 #define XCOPY_BLK2BLK_SEG_DESC_SIZE 28 +typedef enum { + SCSI_PR_WRITE_EXCLUSIVE = 0x01, + SCSI_PR_EXCLUSIVE_ACCESS = 0x03, + SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY = 0x05, + SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY = 0x06, + SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS = 0x07, + SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS = 0x08, +} SCSIPrType; + +typedef enum { + SCSI_PR_LU_SCOPE = 0x00, +} SCSIPrScope; + +typedef enum { + SCSI_PR_OUT_REGISTER = 0x0, + SCSI_PR_OUT_RESERVE = 0x1, + SCSI_PR_OUT_RELEASE = 0x2, + SCSI_PR_OUT_CLEAR = 0x3, + SCSI_PR_OUT_PREEMPT = 0x4, + SCSI_PR_OUT_PREEMPT_AND_ABORT = 0x5, + SCSI_PR_OUT_REG_AND_IGNORE_KEY = 0x6, + SCSI_PR_OUT_REG_AND_MOVE = 0x7, +} SCSIPrOutAction; + +typedef enum { + SCSI_PR_IN_READ_KEYS = 0x0, + SCSI_PR_IN_READ_RESERVATION = 0x1, + SCSI_PR_IN_REPORT_CAPABILITIES = 0x2, +} SCSIPrInAction; + +typedef enum { + /* Exclusive Access All Registrants reservation type */ + SCSI_PR_CAP_EX_AC_AR = 1 << 0, + /* Write Exclusive reservation type */ + SCSI_PR_CAP_WR_EX = 1 << 9, + /* Exclusive Access reservation type */ + SCSI_PR_CAP_EX_AC = 1 << 11, + /* Write Exclusive Registrants Only reservation type */ + SCSI_PR_CAP_WR_EX_RO = 1 << 13, + /* Exclusive Access Registrants Only reservation type */ + SCSI_PR_CAP_EX_AC_RO = 1 << 14, + /* Write Exclusive All Registrants reservation type */ + SCSI_PR_CAP_WR_EX_AR = 1 << 15, + + SCSI_PR_CAP_ALL = (SCSI_PR_CAP_EX_AC_AR | + SCSI_PR_CAP_WR_EX | + SCSI_PR_CAP_EX_AC | + SCSI_PR_CAP_WR_EX_RO | + SCSI_PR_CAP_EX_AC_RO | + SCSI_PR_CAP_WR_EX_AR), +} SCSIPrCap; + #endif From patchwork Fri Oct 11 12:12:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832791 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1EBC8D24470 for ; Fri, 11 Oct 2024 17:27:37 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJFA-00049p-MV; Fri, 11 Oct 2024 13:16:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7i-0004AI-7u for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:19 -0400 Received: from mail-pl1-x62d.google.com ([2607:f8b0:4864:20::62d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEW6-0004tP-QZ for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:13:12 -0400 Received: by mail-pl1-x62d.google.com with SMTP id d9443c01a7336-20ca388d242so4213245ad.2 for ; Fri, 11 Oct 2024 05:13:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648789; x=1729253589; darn=nongnu.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=CUQGygF7ax3lHkGrG99vLN6/xen2jiCuqCocfv+MI40=; b=AbKpzPuVzItF1V7ReqEWqH4fRKEx4wU98JJfaB4ZqFxH1xqBU91QqRflFH5gDNwE6a 4sFCefnZfBsbewMIQfxDj/XXNbdy9oEg6vtrEYBTmsSOvutjC3Kfu0EcupNFdiRxnazR skcLsAQbdRykJcIgR5bw8WsjaI8wohz5JHe9VFZoP+7oHWhQu9BXfluQ2h2bObr4voBF EDPBfjfhe5/hJ1vK1uWvHBy1Cggi0iS/lRzVXnXS5u45uh7OpNZLc6xT3VHRWQu3+LcR CmqCgCAA30SE+OomLzz5+HG9ipK2TwumbRaQqH4KVrwyQATYBbcmrcmRbhsGXTpWbp/t SKdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648789; x=1729253589; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CUQGygF7ax3lHkGrG99vLN6/xen2jiCuqCocfv+MI40=; b=ohefkHrdvA+RRusqfbsjKJj7gpxFWECVyxa/icsPZon4h5lkDcZz9wDywyNYUOdcgk U+fG5xvP/GqkPwY5BKvE6dcDq84P8y2xeuUYbDBaScaBOTHgsUNSyeURQ9V510zWtAas svHtG/NQJXJwT97BFrh2rSA1vhdoUuZoLFQqYfZAj5MLbDX0HbJ21FjLHLBvyS/caGJ8 HRpl5nd40JzgoU1YHA9VJ1hv1VK0yIgQGnrW3FdUkjkbqYKSK73NcfjTYiXZZQ5K+AYs W0ZUarnKnUtxNNM+eMnlVVW/iNySlEQ9GszsCKa9RXDd+7Bd0dQmzOIOa1WabR8Wdnz5 KxCw== X-Forwarded-Encrypted: i=1; AJvYcCVybO1ehN+UYr/uhOtVpz6GSMl1OqXfKvMrGGPaJGCA6nBKsrz+/ydB13X954nIuwaN2TlVHx2he4Ig@nongnu.org X-Gm-Message-State: AOJu0YwnFuZl9Amw3P7+vFB7e6OAQDk54emmfYze83IlVIM5RFGYE2rh RUArWHvX4YlXiEnS3ntoHZ9VzLNmfXRq8cGf2eyo+8fTINTxfjX+NNaiYhQxbW8= X-Google-Smtp-Source: AGHT+IGtAbrKtQaXIau5W4nalaZrL9YM4AdjlLjIse3y6ZkmvZ45eKwslztWYIo/Oou/qBRNTXhoxw== X-Received: by 2002:a17:902:cf04:b0:20b:ce88:1b9d with SMTP id d9443c01a7336-20ca16a0d51mr34316845ad.45.1728648789207; Fri, 11 Oct 2024 05:13:09 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.13.04 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:13:08 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 04/10] scsi/util: add helper functions for persistent reservation types conversion Date: Fri, 11 Oct 2024 20:12:25 +0800 Message-Id: <20241011121231.18333-5-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::62d; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x62d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This commit introduces two helper functions that facilitate the conversion between the persistent reservation types used in the SCSI protocol and those used in the block layer. Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi Reviewed-by: Stefan Hajnoczi --- include/scsi/utils.h | 8 +++++ scsi/utils.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/include/scsi/utils.h b/include/scsi/utils.h index d5c8efa16e..89a0b082fb 100644 --- a/include/scsi/utils.h +++ b/include/scsi/utils.h @@ -1,6 +1,8 @@ #ifndef SCSI_UTILS_H #define SCSI_UTILS_H +#include "block/block-common.h" +#include "scsi/constants.h" #ifdef CONFIG_LINUX #include #endif @@ -135,6 +137,12 @@ uint32_t scsi_data_cdb_xfer(uint8_t *buf); uint32_t scsi_cdb_xfer(uint8_t *buf); int scsi_cdb_length(uint8_t *buf); +BlockPrType scsi_pr_type_to_block(SCSIPrType type); +SCSIPrType block_pr_type_to_scsi(BlockPrType type); + +uint8_t scsi_pr_cap_to_block(uint16_t scsi_pr_cap); +uint16_t block_pr_cap_to_scsi(uint8_t block_pr_cap); + /* Linux SG_IO interface. */ #ifdef CONFIG_LINUX #define SG_ERR_DRIVER_TIMEOUT 0x06 diff --git a/scsi/utils.c b/scsi/utils.c index 357b036671..0dfdeb499d 100644 --- a/scsi/utils.c +++ b/scsi/utils.c @@ -658,3 +658,84 @@ int scsi_sense_from_host_status(uint8_t host_status, } return GOOD; } + +BlockPrType scsi_pr_type_to_block(SCSIPrType type) +{ + switch (type) { + case SCSI_PR_WRITE_EXCLUSIVE: + return BLK_PR_WRITE_EXCLUSIVE; + case SCSI_PR_EXCLUSIVE_ACCESS: + return BLK_PR_EXCLUSIVE_ACCESS; + case SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY: + return BLK_PR_WRITE_EXCLUSIVE_REGS_ONLY; + case SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY: + return BLK_PR_EXCLUSIVE_ACCESS_REGS_ONLY; + case SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS: + return BLK_PR_WRITE_EXCLUSIVE_ALL_REGS; + case SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS: + return BLK_PR_EXCLUSIVE_ACCESS_ALL_REGS; + } + + return 0; +} + +SCSIPrType block_pr_type_to_scsi(BlockPrType type) +{ + switch (type) { + case BLK_PR_WRITE_EXCLUSIVE: + return SCSI_PR_WRITE_EXCLUSIVE; + case BLK_PR_EXCLUSIVE_ACCESS: + return SCSI_PR_EXCLUSIVE_ACCESS; + case BLK_PR_WRITE_EXCLUSIVE_REGS_ONLY: + return SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY; + case BLK_PR_EXCLUSIVE_ACCESS_REGS_ONLY: + return SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY; + case BLK_PR_WRITE_EXCLUSIVE_ALL_REGS: + return SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS; + case BLK_PR_EXCLUSIVE_ACCESS_ALL_REGS: + return SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS; + } + + return 0; +} + + +uint8_t scsi_pr_cap_to_block(uint16_t scsi_pr_cap) +{ + uint8_t res = 0; + + res |= (scsi_pr_cap & SCSI_PR_CAP_WR_EX) ? + BLK_PR_CAP_WR_EX : 0; + res |= (scsi_pr_cap & SCSI_PR_CAP_EX_AC) ? + BLK_PR_CAP_EX_AC : 0; + res |= (scsi_pr_cap & SCSI_PR_CAP_WR_EX_RO) ? + BLK_PR_CAP_WR_EX_RO : 0; + res |= (scsi_pr_cap & SCSI_PR_CAP_EX_AC_RO) ? + BLK_PR_CAP_EX_AC_RO : 0; + res |= (scsi_pr_cap & SCSI_PR_CAP_WR_EX_AR) ? + BLK_PR_CAP_WR_EX_AR : 0; + res |= (scsi_pr_cap & SCSI_PR_CAP_EX_AC_AR) ? + BLK_PR_CAP_EX_AC_AR : 0; + + return res; +} + +uint16_t block_pr_cap_to_scsi(uint8_t block_pr_cap) +{ + uint16_t res = 0; + + res |= (block_pr_cap & BLK_PR_CAP_WR_EX) ? + SCSI_PR_CAP_WR_EX : 0; + res |= (block_pr_cap & BLK_PR_CAP_EX_AC) ? + SCSI_PR_CAP_EX_AC : 0; + res |= (block_pr_cap & BLK_PR_CAP_WR_EX_RO) ? + SCSI_PR_CAP_WR_EX_RO : 0; + res |= (block_pr_cap & BLK_PR_CAP_EX_AC_RO) ? + SCSI_PR_CAP_EX_AC_RO : 0; + res |= (block_pr_cap & BLK_PR_CAP_WR_EX_AR) ? + SCSI_PR_CAP_WR_EX_AR : 0; + res |= (block_pr_cap & BLK_PR_CAP_EX_AC_AR) ? + SCSI_PR_CAP_EX_AC_AR : 0; + + return res; +} From patchwork Fri Oct 11 12:12:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832852 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3434ED24470 for ; Fri, 11 Oct 2024 17:35:39 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJEg-00036U-LW; Fri, 11 Oct 2024 13:15:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7h-0005L4-U7 for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:18 -0400 Received: from mail-pl1-x630.google.com ([2607:f8b0:4864:20::630]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEWC-0004uD-Jg for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:13:19 -0400 Received: by mail-pl1-x630.google.com with SMTP id d9443c01a7336-20c7edf2872so16066065ad.1 for ; Fri, 11 Oct 2024 05:13:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648795; x=1729253595; darn=nongnu.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=84OioOP0ZM/IAvh4Obcp6J9Lygm5s0teJZRgY3hNxb0=; b=LNrlUsvWSeSB1HNgTzylx1Am3wkLVI5sFkuhJMzT/1vr7UGE5Llog6tYQ83CARk/HT eQO7oxxOFf5qrXwSWveT4IwCpZ7ZfECI/ySezEpdvTSA/FvNTvWjUoI3VN/mykAeFZWh tZZfHseW+RfJxMps8V5GxIRU7Tsj77EQJwRyCnKaNiD5ZfMihKjQQ3q+d4alFPQUL9Bz JGkB2F65wPCVTX69ilHPQycw4fAuUDUqO8hyA8YnQQY3ql9Rj3ftCqPQMw3a4MA20tos 95fjnMieYYJz7l7JSXxMrz3EfB0NP7cEwQ1CfytM0rUjmP5AlM+xwzHSdSicC4eo7l3l yy+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648795; x=1729253595; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=84OioOP0ZM/IAvh4Obcp6J9Lygm5s0teJZRgY3hNxb0=; b=Y8RrgLZKQZjd1kiKZi8/Kv46911KzJto75Ut3TmhV8VBF9AVIUuUK0kzK6zVRdwvCf USJf4mMaZnIwVIDPtaZXnrhIUW9Nlz7Z7KKi7aLQfegPNV/ORDJUfxS+M9LflJq2uPC9 1ZR9GZqkjAbdk5X9fmH+b8fcQKyQR0KigyCil3FG/d4G5Bxu/O9PiJHc3mHLfq6gaPTq Iun/FCRyw3we6En5g1rQeJa9BE8uBRLC3pvqv4qauw9pjBgR8F5Cy4Nw/g5saUK6QDS5 txxD5JspibaMiKTl1wK2i/pPSk7XibkIiPKgpDUHs2m3CbjbLwyDPTqhq1FsQTEckbf1 lHiw== X-Forwarded-Encrypted: i=1; AJvYcCVobHBY+MFaMfcS87l8xXFgVK7abyV01bhtDZ9kFbALh9narPZhfDt0CaOGMbtF0STUIMZCVmMHc2N8@nongnu.org X-Gm-Message-State: AOJu0Yz1xchtLWqSIMyOZGj9BEk9Dtt2XV4GY7QslDuaRgbvhJvk5D0d nk78CDIiSF+ijOUg06/N7R81xktbx9eHsfj089dr6CzOHt2L8HFU5YwkjDx3lGA= X-Google-Smtp-Source: AGHT+IEEBqcWSnMmOw7jNb4yId3h5eKY4tNqEjGSBMymBAc4HuItcHlipj7IbhZiBpjvH+jcNs+hrg== X-Received: by 2002:a17:902:f683:b0:20c:7848:4f50 with SMTP id d9443c01a7336-20c80496f9fmr108400675ad.16.1728648795145; Fri, 11 Oct 2024 05:13:15 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.13.09 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:13:14 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 05/10] hw/scsi: add persistent reservation in/out api for scsi device Date: Fri, 11 Oct 2024 20:12:26 +0800 Message-Id: <20241011121231.18333-6-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::630; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x630.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add persistent reservation in/out operations in the SCSI device layer. By introducing the persistent reservation in/out api, this enables the SCSI device to perform reservation-related tasks, including querying keys, querying reservation status, registering reservation keys, initiating and releasing reservations, as well as clearing and preempting reservations held by other keys. These operations are crucial for management and control of shared storage resources in a persistent manner. Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi Reviewed-by: Stefan Hajnoczi --- hw/scsi/scsi-disk.c | 374 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 0812d39c02..581dffa5c0 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -32,6 +32,7 @@ #include "migration/vmstate.h" #include "hw/scsi/emulation.h" #include "scsi/constants.h" +#include "scsi/utils.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "hw/block/block.h" @@ -42,6 +43,7 @@ #include "qemu/cutils.h" #include "trace.h" #include "qom/object.h" +#include "block/block_int.h" #ifdef __linux #include @@ -61,6 +63,8 @@ #define MAX_SERIAL_LEN 36 #define MAX_SERIAL_LEN_FOR_DEVID 20 +#define SCSI_MAX_RESERVATION_KEYS 128 + OBJECT_DECLARE_TYPE(SCSIDiskState, SCSIDiskClass, SCSI_DISK_BASE) struct SCSIDiskClass { @@ -1477,6 +1481,366 @@ static void scsi_disk_emulate_read_data(SCSIRequest *req) scsi_req_complete(&r->req, GOOD); } +typedef struct SCSIPrReadKeys { + uint32_t generation; + uint32_t num_keys; + uint64_t *keys; + SCSIDiskReq *req; +} SCSIPrReadKeys; + +typedef struct SCSIPrReadReservation { + uint32_t generation; + uint64_t key; + BlockPrType type; + SCSIDiskReq *req; +} SCSIPrReadReservation; + +static void scsi_pr_read_keys_complete(void *opaque, int ret) +{ + int num_keys; + uint8_t *buf; + SCSIPrReadKeys *blk_keys = (SCSIPrReadKeys *)opaque; + SCSIDiskReq *r = blk_keys->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + + assert(blk_get_aio_context(s->qdev.conf.blk) == + qemu_get_current_aio_context()); + + assert(r->req.aiocb != NULL); + r->req.aiocb = NULL; + + if (scsi_disk_req_check_error(r, ret, true)) { + goto done; + } + + buf = scsi_req_get_buf(&r->req); + num_keys = MIN(blk_keys->num_keys, ret > 0 ? ret : 0); + blk_keys->generation = cpu_to_be32(blk_keys->generation); + memcpy(&buf[0], &blk_keys->generation, 4); + for (int i = 0; i < num_keys; i++) { + blk_keys->keys[i] = cpu_to_be64(blk_keys->keys[i]); + memcpy(&buf[8 + i * 8], &blk_keys->keys[i], 8); + } + num_keys = cpu_to_be32(num_keys * 8); + memcpy(&buf[4], &num_keys, 4); + + scsi_req_data(&r->req, r->buflen); +done: + scsi_req_unref(&r->req); + g_free(blk_keys->keys); + g_free(blk_keys); +} + +static void scsi_disk_emulate_pr_read_keys(SCSIRequest *req) +{ + SCSIPrReadKeys *blk_keys; + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + int buflen = MIN(r->req.cmd.xfer, r->buflen); + int num_keys = (buflen - sizeof(uint32_t) * 2) / sizeof(uint64_t); + + /* + * The maximum number of keys that can be transmitted is 128. + */ + num_keys = MIN(num_keys, SCSI_MAX_RESERVATION_KEYS); + if (num_keys <= 0) { + scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); + return; + } + + blk_keys = g_new0(SCSIPrReadKeys, 1); + blk_keys->generation = 0; + /* num_keys is the maximum number of keys that can be transmitted */ + blk_keys->num_keys = num_keys; + blk_keys->keys = g_malloc(sizeof(uint64_t) * num_keys); + blk_keys->req = r; + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + r->req.aiocb = blk_aio_pr_read_keys(s->qdev.conf.blk, &blk_keys->generation, + blk_keys->num_keys, blk_keys->keys, + scsi_pr_read_keys_complete, blk_keys); + return; +} + +static void scsi_pr_read_reservation_complete(void *opaque, int ret) +{ + uint8_t *buf; + uint32_t additional_len = 0; + SCSIPrReadReservation *blk_rsv = (SCSIPrReadReservation *)opaque; + SCSIDiskReq *r = blk_rsv->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + + assert(blk_get_aio_context(s->qdev.conf.blk) == + qemu_get_current_aio_context()); + + assert(r->req.aiocb != NULL); + r->req.aiocb = NULL; + + if (scsi_disk_req_check_error(r, ret, true)) { + goto done; + } + + buf = scsi_req_get_buf(&r->req); + blk_rsv->generation = cpu_to_be32(blk_rsv->generation); + memcpy(&buf[0], &blk_rsv->generation, 4); + if (ret) { + additional_len = cpu_to_be32(16); + blk_rsv->key = cpu_to_be64(blk_rsv->key); + memcpy(&buf[8], &blk_rsv->key, 8); + buf[21] = block_pr_type_to_scsi(blk_rsv->type) & 0xf; + } else { + additional_len = cpu_to_be32(0); + } + + memcpy(&buf[4], &additional_len, 4); + scsi_req_data(&r->req, r->buflen); + +done: + scsi_req_unref(&r->req); + g_free(blk_rsv); +} + +static void scsi_disk_emulate_pr_read_reservation(SCSIRequest *req) +{ + SCSIPrReadReservation *blk_rsv; + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + int buflen = MIN(r->req.cmd.xfer, r->buflen); + int count = sizeof(uint32_t) * 2 + sizeof(uint64_t) + + sizeof(uint32_t) + sizeof(uint8_t) * 2; + + if (buflen < count) { + scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); + return; + } + + blk_rsv = g_malloc(sizeof(*blk_rsv)); + blk_rsv->generation = 0; + blk_rsv->key = 0; + blk_rsv->type = 0; + blk_rsv->req = r; + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + r->req.aiocb = blk_aio_pr_read_reservation(s->qdev.conf.blk, + &blk_rsv->generation, &blk_rsv->key, &blk_rsv->type, + scsi_pr_read_reservation_complete, blk_rsv); + return; +} + +static void scsi_disk_emulate_pr_report_capabilities(SCSIRequest *req) +{ + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + BlockDriverState *bs = blk_bs(s->qdev.conf.blk); + uint8_t blk_pr_cap = bs->bl.pr_cap; + uint8_t *buf = scsi_req_get_buf(req); + uint16_t pr_cap; + /* + * according to response of report_capabilities + * command of chapter 6.13 of spc4 + */ + int len = sizeof(uint16_t) * 2 + sizeof(uint8_t) * 4; + + if (len > r->buflen) { + scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); + return; + } + + len = cpu_to_be16(len); + memcpy(&buf[0], &len, 2); + /* enable PTPL_C */ + buf[2] = 1; + buf[3] = (blk_pr_cap & BLK_PR_CAP_PTPL) ? 1 : 0; + /* enable TMV */ + buf[3] |= 1 << 7; + + /* enable persistent reservation type */ + pr_cap = block_pr_cap_to_scsi(blk_pr_cap); + buf[4] = pr_cap >> 8 & 0xff; + buf[5] = pr_cap & 0xff; + + scsi_req_data(&r->req, len); + return; +} + +static void scsi_aio_pr_complete(void *opaque, int ret) +{ + SCSIDiskReq *r = (SCSIDiskReq *)opaque; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + + /* The request must only run in the BlockBackend's AioContext */ + assert(blk_get_aio_context(s->qdev.conf.blk) == + qemu_get_current_aio_context()); + + assert(r->req.aiocb != NULL); + r->req.aiocb = NULL; + + if (scsi_disk_req_check_error(r, ret, true)) { + goto done; + } + + scsi_req_complete(&r->req, GOOD); + +done: + scsi_req_unref(&r->req); +} + +static void scsi_disk_emulate_pr_register(SCSIDiskReq *r, uint64_t r_key, + uint64_t sa_key, SCSIPrType type, + uint8_t aptpl, bool ignore_key) +{ + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + r->req.aiocb = blk_aio_pr_register(s->qdev.conf.blk, r_key, sa_key, + scsi_pr_type_to_block(type), + aptpl ? true : false, + ignore_key, scsi_aio_pr_complete, r); + + return; +} + +static void scsi_disk_emulate_pr_reserve(SCSIDiskReq *r, uint64_t r_key, + SCSIPrType type) +{ + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + r->req.aiocb = blk_aio_pr_reserve(s->qdev.conf.blk, r_key, + scsi_pr_type_to_block(type), + scsi_aio_pr_complete, r); + + return; +} + +static void scsi_disk_emulate_pr_release(SCSIDiskReq *r, uint64_t r_key, + SCSIPrType type) +{ + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + r->req.aiocb = blk_aio_pr_release(s->qdev.conf.blk, r_key, + scsi_pr_type_to_block(type), + scsi_aio_pr_complete, r); + + return; +} + +static void scsi_disk_emulate_pr_clear(SCSIDiskReq *r, uint64_t r_key) +{ + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + r->req.aiocb = blk_aio_pr_clear(s->qdev.conf.blk, r_key, + scsi_aio_pr_complete, r); + + return; +} + +static void scsi_disk_emulate_pr_preempt(SCSIDiskReq *r, uint64_t r_key, + uint64_t sa_key, SCSIPrType type, + bool abort) +{ + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + r->req.aiocb = blk_aio_pr_preempt(s->qdev.conf.blk, r_key, sa_key, + scsi_pr_type_to_block(type), abort, + scsi_aio_pr_complete, r); + + return; +} + +static void scsi_disk_emulate_pr_in(SCSIRequest *req) +{ + SCSIPrInAction action = req->cmd.buf[1] & 0x1f; + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); + + switch (action) { + case SCSI_PR_IN_READ_KEYS: + scsi_disk_emulate_pr_read_keys(req); + break; + case SCSI_PR_IN_READ_RESERVATION: + scsi_disk_emulate_pr_read_reservation(req); + break; + case SCSI_PR_IN_REPORT_CAPABILITIES: + scsi_disk_emulate_pr_report_capabilities(req); + break; + default: + scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); + return; + } + + return; +} + +static void scsi_disk_emulate_pr_out(SCSIDiskReq *r, uint8_t *inbuf) +{ + uint8_t aptpl; + uint64_t r_key, sa_key; + SCSIPrOutAction action; + SCSIPrScope scope; + SCSIPrType type; + SCSIRequest *req = &r->req; + + memcpy(&r_key, &inbuf[0], 8); + r_key = be64_to_cpu(r_key); + memcpy(&sa_key, &inbuf[8], 8); + sa_key = be64_to_cpu(sa_key); + memcpy(&aptpl, &inbuf[20], 1); + aptpl = aptpl & 0x01; + action = req->cmd.buf[1] & 0x1f; + scope = (req->cmd.buf[2] >> 4) & 0x0f; + type = req->cmd.buf[2] & 0x0f; + + if (scope != SCSI_PR_LU_SCOPE) { + scsi_req_complete(&r->req, TASK_ABORTED); + return; + } + + switch (action) { + case SCSI_PR_OUT_REGISTER: + scsi_disk_emulate_pr_register(r, r_key, sa_key, type, + aptpl, false); + break; + case SCSI_PR_OUT_REG_AND_IGNORE_KEY: + scsi_disk_emulate_pr_register(r, r_key, sa_key, type, aptpl, true); + break; + case SCSI_PR_OUT_RESERVE: + scsi_disk_emulate_pr_reserve(r, r_key, type); + break; + case SCSI_PR_OUT_RELEASE: + scsi_disk_emulate_pr_release(r, r_key, type); + break; + case SCSI_PR_OUT_CLEAR: + scsi_disk_emulate_pr_clear(r, r_key); + break; + case SCSI_PR_OUT_PREEMPT: + scsi_disk_emulate_pr_preempt(r, r_key, sa_key, type, false); + break; + case SCSI_PR_OUT_PREEMPT_AND_ABORT: + scsi_disk_emulate_pr_preempt(r, r_key, sa_key, type, true); + break; + default: + scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); + return; + } + + return; +} + static int scsi_disk_check_mode_select(SCSIDiskState *s, int page, uint8_t *inbuf, int inlen) { @@ -1960,6 +2324,9 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req) scsi_req_complete(&r->req, GOOD); break; + case PERSISTENT_RESERVE_OUT: + scsi_disk_emulate_pr_out(r, r->iov.iov_base); + break; default: abort(); } @@ -2216,6 +2583,11 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) case FORMAT_UNIT: trace_scsi_disk_emulate_command_FORMAT_UNIT(r->req.cmd.xfer); break; + case PERSISTENT_RESERVE_OUT: + break; + case PERSISTENT_RESERVE_IN: + scsi_disk_emulate_pr_in(req); + return 0; default: trace_scsi_disk_emulate_command_UNKNOWN(buf[0], scsi_command_name(buf[0])); @@ -2646,6 +3018,8 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = { [VERIFY_12] = &scsi_disk_emulate_reqops, [VERIFY_16] = &scsi_disk_emulate_reqops, [FORMAT_UNIT] = &scsi_disk_emulate_reqops, + [PERSISTENT_RESERVE_IN] = &scsi_disk_emulate_reqops, + [PERSISTENT_RESERVE_OUT] = &scsi_disk_emulate_reqops, [READ_6] = &scsi_disk_dma_reqops, [READ_10] = &scsi_disk_dma_reqops, From patchwork Fri Oct 11 12:12:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832853 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3D54CD24470 for ; Fri, 11 Oct 2024 17:37:32 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJEj-0003FI-Nm; Fri, 11 Oct 2024 13:15:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7h-0003l6-Px for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:18 -0400 Received: from mail-pl1-x62f.google.com ([2607:f8b0:4864:20::62f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEWI-0004um-6D for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:13:24 -0400 Received: by mail-pl1-x62f.google.com with SMTP id d9443c01a7336-20caea61132so2622035ad.2 for ; Fri, 11 Oct 2024 05:13:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648801; x=1729253601; darn=nongnu.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=LNfE2FvcIsikcgtI6Krtxtj2etktds/RmL9xP+AY0Zg=; b=frgDzAB+UkIhdo5oCQWUCKNVZBwL3F0qNfeEF1ub6k90zBP3m3ICkv3NrVVIDPeH9C AKZFfRoe0woQ0cNWnSp9JbbwZ0cK8X71BK0OQmxAq1Uq9C+iIxM1t0KV9/Uv8GC78V1U hoEhVYNNnjkTSMWgqKQicaPehitE65IPnCpmnl8Y+AdDJF+HxOYg+yLgiz3YHfsRVwmd dz+hoXoFJv21e1/L3oGLrD7zM+iP2eWIz5ityXQ6A58+yTAUoppfadamQycuLT9vdt51 6N4DN5O/4MwczlynNJEfa3YLNosO1VXtmQTJ+q04fwuoTjTn+0jdeU9elyZx0m/eU5lT NIww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648801; x=1729253601; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LNfE2FvcIsikcgtI6Krtxtj2etktds/RmL9xP+AY0Zg=; b=fwuxPcuZKWCIfuSAVQ3siSibb9aVl2Xh33ixJKIRpho4pxylNqy1cFIWDRNGKhWDud jl1MX5PyGC/W+Nfc4kflMHmiB4avh8Od8R21osJukPrhoVxPB6fYpPH6r/clSsUfNfSQ XBa9elAy/GAGWinx4eNz6UnwkBloHzO+p2BOl5RUd95gF9tdb8ExXYCxGnYj9mWq3SMJ 0CQieLGoJSkDaqbFsaalqU5Gw634oSyw86nYxaBRC7X813bS/+Jlf2PPHhgai3XW7alz stnTJjT2OrGROn9krTYMw3WDz01969k757Ih9GwB2Y4V+iT5dcn9FpdKUa1uz2P0rm7n JiJw== X-Forwarded-Encrypted: i=1; AJvYcCXf1Q5CBMqEW2YbILhymIixIZBAOZB6pITP5xJ8378tgR3Yv67LuiNcCT7xUzDRpKGruDjjmQ4rf8Bm@nongnu.org X-Gm-Message-State: AOJu0YxFqlmMbhBfsfGyWaXsmtHmN+ICA8gTEXmPAXacgomJ1vEBbCuo DTY6kcULprzk6HZhDmlIZ0QN/y27ZZnr8eY+vfFjUx+4nIJ/anz/zA0JkRMjUg3Lx2fkGpN2RuH JRBU= X-Google-Smtp-Source: AGHT+IEh4LLc/+bqY6X2nvxu4aasx8ocawMKkkbF/iDndQ0VGJj1wrdQKntd1Rko8JvCmZqGM+N92w== X-Received: by 2002:a17:903:240e:b0:20b:a89a:1d3a with SMTP id d9443c01a7336-20ca14661b7mr46470025ad.28.1728648800931; Fri, 11 Oct 2024 05:13:20 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.13.15 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:13:20 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 06/10] block/nvme: add reservation command protocol constants Date: Fri, 11 Oct 2024 20:12:27 +0800 Message-Id: <20241011121231.18333-7-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::62f; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x62f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add constants for the NVMe persistent command protocol. The constants include the reservation command opcode and reservation type values defined in section 7 of the NVMe 2.0 specification. Reviewed-by: Stefan Hajnoczi Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi --- include/block/nvme.h | 61 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/include/block/nvme.h b/include/block/nvme.h index bb231d0b9a..8b125f7769 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -633,7 +633,11 @@ enum NvmeIoCommands { NVME_CMD_WRITE_ZEROES = 0x08, NVME_CMD_DSM = 0x09, NVME_CMD_VERIFY = 0x0c, + NVME_CMD_RESV_REGISTER = 0x0d, + NVME_CMD_RESV_REPORT = 0x0e, + NVME_CMD_RESV_ACQUIRE = 0x11, NVME_CMD_IO_MGMT_RECV = 0x12, + NVME_CMD_RESV_RELEASE = 0x15, NVME_CMD_COPY = 0x19, NVME_CMD_IO_MGMT_SEND = 0x1d, NVME_CMD_ZONE_MGMT_SEND = 0x79, @@ -641,6 +645,63 @@ enum NvmeIoCommands { NVME_CMD_ZONE_APPEND = 0x7d, }; +typedef enum { + NVME_RESV_REGISTER_ACTION_REGISTER = 0x00, + NVME_RESV_REGISTER_ACTION_UNREGISTER = 0x01, + NVME_RESV_REGISTER_ACTION_REPLACE = 0x02, +} NvmeReservationRegisterAction; + +typedef enum { + NVME_RESV_RELEASE_ACTION_RELEASE = 0x00, + NVME_RESV_RELEASE_ACTION_CLEAR = 0x01, +} NvmeReservationReleaseAction; + +typedef enum { + NVME_RESV_ACQUIRE_ACTION_ACQUIRE = 0x00, + NVME_RESV_ACQUIRE_ACTION_PREEMPT = 0x01, + NVME_RESV_ACQUIRE_ACTION_PREEMPT_AND_ABORT = 0x02, +} NvmeReservationAcquireAction; + +typedef enum { + NVME_RESV_WRITE_EXCLUSIVE = 0x01, + NVME_RESV_EXCLUSIVE_ACCESS = 0x02, + NVME_RESV_WRITE_EXCLUSIVE_REGS_ONLY = 0x03, + NVME_RESV_EXCLUSIVE_ACCESS_REGS_ONLY = 0x04, + NVME_RESV_WRITE_EXCLUSIVE_ALL_REGS = 0x05, + NVME_RESV_EXCLUSIVE_ACCESS_ALL_REGS = 0x06, +} NvmeResvType; + +typedef enum { + NVME_RESV_PTPL_NO_CHANGE = 0x00, + NVME_RESV_PTPL_DISABLE = 0x02, + NVME_RESV_PTPL_ENABLE = 0x03, +} NvmeResvPTPL; + +typedef enum NVMEPrCap { + /* Persist Through Power Loss */ + NVME_PR_CAP_PTPL = 1 << 0, + /* Write Exclusive reservation type */ + NVME_PR_CAP_WR_EX = 1 << 1, + /* Exclusive Access reservation type */ + NVME_PR_CAP_EX_AC = 1 << 2, + /* Write Exclusive Registrants Only reservation type */ + NVME_PR_CAP_WR_EX_RO = 1 << 3, + /* Exclusive Access Registrants Only reservation type */ + NVME_PR_CAP_EX_AC_RO = 1 << 4, + /* Write Exclusive All Registrants reservation type */ + NVME_PR_CAP_WR_EX_AR = 1 << 5, + /* Exclusive Access All Registrants reservation type */ + NVME_PR_CAP_EX_AC_AR = 1 << 6, + + NVME_PR_CAP_ALL = (NVME_PR_CAP_PTPL | + NVME_PR_CAP_WR_EX | + NVME_PR_CAP_EX_AC | + NVME_PR_CAP_WR_EX_RO | + NVME_PR_CAP_EX_AC_RO | + NVME_PR_CAP_WR_EX_AR | + NVME_PR_CAP_EX_AC_AR), +} NvmePrCap; + typedef struct QEMU_PACKED NvmeDeleteQ { uint8_t opcode; uint8_t flags; From patchwork Fri Oct 11 12:12:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832780 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C8AF8D0EE12 for ; Fri, 11 Oct 2024 17:24:01 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJIr-0001rn-3H; Fri, 11 Oct 2024 13:19:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7h-0003aE-IV for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:18 -0400 Received: from mail-pl1-x631.google.com ([2607:f8b0:4864:20::631]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEWN-0004vC-Pa for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:13:31 -0400 Received: by mail-pl1-x631.google.com with SMTP id d9443c01a7336-20c805a0753so16927935ad.0 for ; Fri, 11 Oct 2024 05:13:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648806; x=1729253606; darn=nongnu.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=Tjqh17JUE1WkBpchsBFPlHMHCUXRZeQxBDgeEciSrXM=; b=b9utYs0/amEyOh566GS5xhCCz11IVtONLnkiqjZtctIaKuq0dXxy9Ej0ZafZC6WT5N B70Hlr8poPyl77HevRX1J5pHs4MQVzw/5qIT9y0Yld07pJdOySzWEX9bREMh08uXO6DX bazlx7ZQ9A+xVte/ysLr+garDb65RAW6HkkPWvjC9TbKhtNMshxRTJu047lThdsTOvpJ 3UU2K0MZ4vmntiHPJx8OqCLkWOnRTR1dsMbi65HmNnifq4pouxwplGRzFWBziia8DoeR Poftag7fOmgrQh46sUQKbBpNE+K5YXloT4Ke+9I8FcFEG349FcbxXlm04L2LAkThtl2J n2bw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648806; x=1729253606; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Tjqh17JUE1WkBpchsBFPlHMHCUXRZeQxBDgeEciSrXM=; b=VV1Wnt/XTr+0H1dXPWfrdW/qtdST73vOUKZ/3wW836K8tE2e0Cj3xgjv2vgqM8jdDe fGnSGn2cf/3T+xORtnNuo/MK/5h9p9hEIVUVt+HYYeJmI/qxav29AyksPtdO+VImTcdc 1IkU57iIVDNu9qppDMFwVpuea/+pwGcgZwMOJheq+MDOqfCyPjaR3KKSNpJDaHGfruIK 2cpiKqc73dX7bL7nAzSFOsMuJYOr+Mc68S4z8/7ubQVsc39UoLZthzIbrWbjpDpBPLBo pHw3FgOAgpVtCVHWmyRQfy7YVch+Z77/Ij3vAdXp5/VMHBsxNbWqey1J5mUt81qU/oG2 YSrw== X-Forwarded-Encrypted: i=1; AJvYcCXeLmr85ffXCvhwPeCIgNK3idycGN3+aSRyF6kXJrLlCnWZqbqc7+olca/lnjGCaOPNsDfVXWfNfrBx@nongnu.org X-Gm-Message-State: AOJu0Yxv3P31JfmlObjCSHf47gBc05zrS1IP8TrHdV09uCtx8TWaG/2Z H5UwxRReRJQNTBSMwwPm90rYTYYUGEK82lVXK97DGPlvScLSheVRSZdOaWOWFJs= X-Google-Smtp-Source: AGHT+IHr3k/GjowYMBaarGF5ocWNMxBhuHUNF9vLD3vpoOBjQNJwn6N7i9YrHNtn0084x+6Cc74yog== X-Received: by 2002:a17:902:e845:b0:20b:a6f5:2780 with SMTP id d9443c01a7336-20ca1459d58mr42210685ad.17.1728648806488; Fri, 11 Oct 2024 05:13:26 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.13.21 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:13:26 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 07/10] hw/nvme: add helper functions for converting reservation types Date: Fri, 11 Oct 2024 20:12:28 +0800 Message-Id: <20241011121231.18333-8-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::631; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x631.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This commit introduces two helper functions that facilitate the conversion between the reservation types used in the NVME protocol and those used in the block layer. Reviewed-by: Klaus Jensen Reviewed-by: Stefan Hajnoczi Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi --- hw/nvme/nvme.h | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index bed8191bd5..6d0e456348 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -474,6 +474,90 @@ static inline const char *nvme_io_opc_str(uint8_t opc) } } +static inline NvmeResvType block_pr_type_to_nvme(BlockPrType type) +{ + switch (type) { + case BLK_PR_WRITE_EXCLUSIVE: + return NVME_RESV_WRITE_EXCLUSIVE; + case BLK_PR_EXCLUSIVE_ACCESS: + return NVME_RESV_EXCLUSIVE_ACCESS; + case BLK_PR_WRITE_EXCLUSIVE_REGS_ONLY: + return NVME_RESV_WRITE_EXCLUSIVE_REGS_ONLY; + case BLK_PR_EXCLUSIVE_ACCESS_REGS_ONLY: + return NVME_RESV_EXCLUSIVE_ACCESS_REGS_ONLY; + case BLK_PR_WRITE_EXCLUSIVE_ALL_REGS: + return NVME_RESV_WRITE_EXCLUSIVE_ALL_REGS; + case BLK_PR_EXCLUSIVE_ACCESS_ALL_REGS: + return NVME_RESV_EXCLUSIVE_ACCESS_ALL_REGS; + } + + return 0; +} + +static inline BlockPrType nvme_pr_type_to_block(NvmeResvType type) +{ + switch (type) { + case NVME_RESV_WRITE_EXCLUSIVE: + return BLK_PR_WRITE_EXCLUSIVE; + case NVME_RESV_EXCLUSIVE_ACCESS: + return BLK_PR_EXCLUSIVE_ACCESS; + case NVME_RESV_WRITE_EXCLUSIVE_REGS_ONLY: + return BLK_PR_WRITE_EXCLUSIVE_REGS_ONLY; + case NVME_RESV_EXCLUSIVE_ACCESS_REGS_ONLY: + return BLK_PR_EXCLUSIVE_ACCESS_REGS_ONLY; + case NVME_RESV_WRITE_EXCLUSIVE_ALL_REGS: + return BLK_PR_WRITE_EXCLUSIVE_ALL_REGS; + case NVME_RESV_EXCLUSIVE_ACCESS_ALL_REGS: + return BLK_PR_EXCLUSIVE_ACCESS_ALL_REGS; + } + + return 0; +} + +static inline uint8_t nvme_pr_cap_to_block(uint16_t nvme_pr_cap) +{ + uint8_t res = 0; + + res |= (nvme_pr_cap & NVME_PR_CAP_PTPL) ? + NVME_PR_CAP_PTPL : 0; + res |= (nvme_pr_cap & NVME_PR_CAP_WR_EX) ? + BLK_PR_CAP_WR_EX : 0; + res |= (nvme_pr_cap & NVME_PR_CAP_EX_AC) ? + BLK_PR_CAP_EX_AC : 0; + res |= (nvme_pr_cap & NVME_PR_CAP_WR_EX_RO) ? + BLK_PR_CAP_WR_EX_RO : 0; + res |= (nvme_pr_cap & NVME_PR_CAP_EX_AC_RO) ? + BLK_PR_CAP_EX_AC_RO : 0; + res |= (nvme_pr_cap & NVME_PR_CAP_WR_EX_AR) ? + BLK_PR_CAP_WR_EX_AR : 0; + res |= (nvme_pr_cap & NVME_PR_CAP_EX_AC_AR) ? + BLK_PR_CAP_EX_AC_AR : 0; + + return res; +} + +static inline uint8_t block_pr_cap_to_nvme(uint8_t block_pr_cap) +{ + uint16_t res = 0; + + res |= (block_pr_cap & BLK_PR_CAP_PTPL) ? + NVME_PR_CAP_PTPL : 0; + res |= (block_pr_cap & BLK_PR_CAP_WR_EX) ? + NVME_PR_CAP_WR_EX : 0; + res |= (block_pr_cap & BLK_PR_CAP_EX_AC) ? + NVME_PR_CAP_EX_AC : 0; + res |= (block_pr_cap & BLK_PR_CAP_WR_EX_RO) ? + NVME_PR_CAP_WR_EX_RO : 0; + res |= (block_pr_cap & BLK_PR_CAP_EX_AC_RO) ? + NVME_PR_CAP_EX_AC_RO : 0; + res |= (block_pr_cap & BLK_PR_CAP_WR_EX_AR) ? + NVME_PR_CAP_WR_EX_AR : 0; + res |= (block_pr_cap & BLK_PR_CAP_EX_AC_AR) ? + NVME_PR_CAP_EX_AC_AR : 0; + + return res; +} + typedef struct NvmeSQueue { struct NvmeCtrl *ctrl; uint16_t sqid; From patchwork Fri Oct 11 12:12:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832792 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7C052D0EE12 for ; Fri, 11 Oct 2024 17:28:12 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJF9-00047I-UT; Fri, 11 Oct 2024 13:16:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7h-0003Vw-DO for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:18 -0400 Received: from mail-pl1-x629.google.com ([2607:f8b0:4864:20::629]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEWU-0004vk-LR for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:13:36 -0400 Received: by mail-pl1-x629.google.com with SMTP id d9443c01a7336-20cb7088cbcso184095ad.0 for ; Fri, 11 Oct 2024 05:13:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648812; x=1729253612; darn=nongnu.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=FpXCvHD2Qslc03OqNFilh7DiBfbBLmsoxBWva+ViCzE=; b=Dwy+yxtU18dt5DAGadYaPTr/wzxmKcyyaWdemJiYVYv87cye8AoUHHLchZlymeMLN4 X0EDXftvvWXuXIuZE1kKRUu8dTkRf2DbpgqjNwVVFWZNe8AMDkG2FMNpqmzEmvVzeFSb Mmsx1dF+LrOAhugNibLkz+kK3o6dIJvB8fHaW49kpo1lPPadCnQC8gPtVZa4APzJEc// X9x087ih7LiMaxndJkId74NChpqx2sPB7rugqV7hrmjA22KCxYCBYwNtUfBDgfzUHPbT W+Vo+VIwo18eND9fp4FGltcpA0eYhusLdErQYgVFO26a8eYyk5yMhVHqvSltzb+Nt54E hvZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648812; x=1729253612; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=FpXCvHD2Qslc03OqNFilh7DiBfbBLmsoxBWva+ViCzE=; b=ao3QevUAT/MwOEs8m7LqjarbI0l/ZNsVlgaccQY6TUleIrIPsfz9FDrGTwZD5lh/zC xJBJLOBE13lVPAiUj1JH90lD9+FxJakN8Izjkf5ZiU9X52U0w+TLQGwT347tOaajYL0D eMk0pjKm5lgQO/202FNBL8+FZufWLoI2/a745vZWqxoXwYLYRlx0HIf/C5JFFWkYsbxV P1GLkOTTzTz1lnOkYGpvlJQLW8zihKjLEJq9+HrfNqUn/kSRwIgQUpFSKfg5waIdIRpV 1UfyPfipLV/VG2OuQ5guFqRyp6WD3q5LlrUYQSZtZqZTNDADIrz7OHfqYsULSrgE+fzT nN0A== X-Forwarded-Encrypted: i=1; AJvYcCWVVq0ldkd5CbKGWvXMk3B1jorCQ9HAixM/hzVItj4oDyC+eJLabZPD5JVOmHiq5pv4zd2tQPFWrg4u@nongnu.org X-Gm-Message-State: AOJu0YxdQ+eEaeXPvp9xndDs4MxRm4/sKw5gGuYJ3p0BxPsEAePr9t6u QD6dcIo4pmcGmJCViR329PesemM6hrJRd67N66Jl6txuOPRWS4tdQ7IaEzyYIaI= X-Google-Smtp-Source: AGHT+IHtoTboo/18qIKh7A8Q82OQyAnCfJw6dAMf5Lb4aeVp0/+CbmIQAMSRWcOfy3Ymt/5ZVsDzfw== X-Received: by 2002:a17:902:e5ca:b0:20c:805a:524 with SMTP id d9443c01a7336-20ca16be1b7mr27660885ad.39.1728648812157; Fri, 11 Oct 2024 05:13:32 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.13.26 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:13:31 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 08/10] hw/nvme: enable ONCS and rescap function Date: Fri, 11 Oct 2024 20:12:29 +0800 Message-Id: <20241011121231.18333-9-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::629; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x629.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This commit enables ONCS to support the reservation function at the controller level. Also enables rescap function in the namespace by detecting the supported reservation function in the backend driver. Reviewed-by: Klaus Jensen Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi Reviewed-by: Stefan Hajnoczi --- hw/nvme/ctrl.c | 3 ++- hw/nvme/ns.c | 5 +++++ include/block/nvme.h | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 127c3d2383..ad212de723 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -8248,7 +8248,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->nn = cpu_to_le32(NVME_MAX_NAMESPACES); id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP | NVME_ONCS_FEATURES | NVME_ONCS_DSM | - NVME_ONCS_COMPARE | NVME_ONCS_COPY); + NVME_ONCS_COMPARE | NVME_ONCS_COPY | + NVME_ONCS_RESERVATIONS); /* * NOTE: If this device ever supports a command set that does NOT use 0x0 diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index ea8db175db..a5c903d727 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -20,6 +20,7 @@ #include "qemu/bitops.h" #include "sysemu/sysemu.h" #include "sysemu/block-backend.h" +#include "block/block_int.h" #include "nvme.h" #include "trace.h" @@ -33,6 +34,7 @@ void nvme_ns_init_format(NvmeNamespace *ns) BlockDriverInfo bdi; int npdg, ret; int64_t nlbas; + uint8_t blk_pr_cap; ns->lbaf = id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; ns->lbasz = 1 << ns->lbaf.ds; @@ -55,6 +57,9 @@ void nvme_ns_init_format(NvmeNamespace *ns) } id_ns->npda = id_ns->npdg = npdg - 1; + + blk_pr_cap = blk_bs(ns->blkconf.blk)->bl.pr_cap; + id_ns->rescap = block_pr_cap_to_nvme(blk_pr_cap); } static int nvme_ns_init(NvmeNamespace *ns, Error **errp) diff --git a/include/block/nvme.h b/include/block/nvme.h index 8b125f7769..9b9eaeb3a7 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -1251,7 +1251,7 @@ enum NvmeIdCtrlOncs { NVME_ONCS_DSM = 1 << 2, NVME_ONCS_WRITE_ZEROES = 1 << 3, NVME_ONCS_FEATURES = 1 << 4, - NVME_ONCS_RESRVATIONS = 1 << 5, + NVME_ONCS_RESERVATIONS = 1 << 5, NVME_ONCS_TIMESTAMP = 1 << 6, NVME_ONCS_VERIFY = 1 << 7, NVME_ONCS_COPY = 1 << 8, From patchwork Fri Oct 11 12:12:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832789 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D08C2D24470 for ; Fri, 11 Oct 2024 17:26:28 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJEi-0003Hu-HF; Fri, 11 Oct 2024 13:15:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7h-0003ly-66 for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:18 -0400 Received: from mail-pl1-x62e.google.com ([2607:f8b0:4864:20::62e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEWZ-0004wD-C1 for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:13:42 -0400 Received: by mail-pl1-x62e.google.com with SMTP id d9443c01a7336-20c805a0753so16929425ad.0 for ; Fri, 11 Oct 2024 05:13:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648818; x=1729253618; darn=nongnu.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=wPOuih7QTJeqWd4JETHDI5STMsR4FXqjkFwum7IHLUE=; b=QRYiUVWXJ1IvdHqJJDHiVgjd5Bs+VA6M3cgSRGFJm1UNGaIFvlbccXIeIuOL3VoGjB /dK3Ba/nxwL0/U+jdmivsOioQKSf1NUYSrGTctyX3NXESxQxfzUSwnPZy9tFBUsxTl/O jVdjos9NTsqP+IuVo2jCs4cuuBNDj7NEVjCMLxuItuU07e04VAVyevNnZS6qXC+TwSLF uXHnp9F6a2iww5VhBB+c17BwS9mvRpzn7eS8/Lpx4q8088w8bzGATyp77xluS3DPQo9/ gHD+Qdi08t2lo6lZ000XqU+gNqh1Y8pQGH0k1AfQIuvqmqbWr3bXi+0J5rTQ8zNvh2+j mbkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648818; x=1729253618; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=wPOuih7QTJeqWd4JETHDI5STMsR4FXqjkFwum7IHLUE=; b=UpAozjTZEM1emqm1tpABGziA2uHojiupdfEUUS4MG9tti0fqF5e+qVTk79OcPXleMH 8V1helizuofUQvFVQ9E7AWo6sioGtE3InrafqIezP4793AUItAkNLkLvcPirFmdLEltw oNRlSzfED6KxgNhjWg8lCN/E1Venw5wpLpdyDicODCsc4wRuVTYrGH1GBiuKCoy6DZCi /pVAI6p90JMU1i7o6FN9078GirOlmaKDbgDnjOH01RCn59d+4At1h1a9C1Pokb8yOTTk Y01TrTisSXDSvda07NEWGJqFpVFIUfRkeQ2ZYMyS2EMJtIlx6Q2nT81y8tL82vGEpxA+ d4iw== X-Forwarded-Encrypted: i=1; AJvYcCXLbJIo1UXCWdrP8a1A8x6NbDj58vGwCzYYvJ5wB/iKhmffgPO+53lUJuuPviljG6/A1tMqMGmRCYVp@nongnu.org X-Gm-Message-State: AOJu0YyGvT9HwN7AAO2qsczo8b1PTCnGa31v+RwCqwd/KWJT9LYKym5P AVsAftN8aSTOxu1uT8Gt3TJxdNr1IJLy1Ares9Yk7usnyJhxzqjinPOjhq0/Weo= X-Google-Smtp-Source: AGHT+IEMovayvMXj4r05sgvCypp8tGdDIAvxPd32CnEug7dXxhwU9ddg08be04VWGMtHdVOHuK87vw== X-Received: by 2002:a17:902:e5ca:b0:20b:5351:f69a with SMTP id d9443c01a7336-20ca16fb895mr38159625ad.58.1728648817981; Fri, 11 Oct 2024 05:13:37 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.13.32 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:13:37 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 09/10] hw/nvme: add reservation protocal command Date: Fri, 11 Oct 2024 20:12:30 +0800 Message-Id: <20241011121231.18333-10-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::62e; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x62e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add reservation acquire, reservation register, reservation release and reservation report commands in the nvme device layer. By introducing these commands, this enables the nvme device to perform reservation-related tasks, including querying keys, querying reservation status, registering reservation keys, initiating and releasing reservations, as well as clearing and preempting reservations held by other keys. These commands are crucial for management and control of shared storage resources in a persistent manner. Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi Acked-by: Klaus Jensen --- hw/nvme/ctrl.c | 347 +++++++++++++++++++++++++++++++++++++++++++ hw/nvme/ns.c | 6 + hw/nvme/nvme.h | 9 ++ include/block/nvme.h | 58 ++++++++ 4 files changed, 420 insertions(+) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index ad212de723..4821a7ff3b 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -294,6 +294,10 @@ static const uint32_t nvme_cse_iocs_nvm[256] = { [NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP, [NVME_CMD_IO_MGMT_RECV] = NVME_CMD_EFF_CSUPP, [NVME_CMD_IO_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, + [NVME_CMD_RESV_REGISTER] = NVME_CMD_EFF_CSUPP, + [NVME_CMD_RESV_REPORT] = NVME_CMD_EFF_CSUPP, + [NVME_CMD_RESV_ACQUIRE] = NVME_CMD_EFF_CSUPP, + [NVME_CMD_RESV_RELEASE] = NVME_CMD_EFF_CSUPP, }; static const uint32_t nvme_cse_iocs_zoned[256] = { @@ -308,6 +312,10 @@ static const uint32_t nvme_cse_iocs_zoned[256] = { [NVME_CMD_ZONE_APPEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_ZONE_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_ZONE_MGMT_RECV] = NVME_CMD_EFF_CSUPP, + [NVME_CMD_RESV_REGISTER] = NVME_CMD_EFF_CSUPP, + [NVME_CMD_RESV_REPORT] = NVME_CMD_EFF_CSUPP, + [NVME_CMD_RESV_ACQUIRE] = NVME_CMD_EFF_CSUPP, + [NVME_CMD_RESV_RELEASE] = NVME_CMD_EFF_CSUPP, }; static void nvme_process_sq(void *opaque); @@ -1745,6 +1753,7 @@ static void nvme_aio_err(NvmeRequest *req, int ret) switch (req->cmd.opcode) { case NVME_CMD_READ: + case NVME_CMD_RESV_REPORT: status = NVME_UNRECOVERED_READ; break; case NVME_CMD_FLUSH: @@ -1752,6 +1761,9 @@ static void nvme_aio_err(NvmeRequest *req, int ret) case NVME_CMD_WRITE_ZEROES: case NVME_CMD_ZONE_APPEND: case NVME_CMD_COPY: + case NVME_CMD_RESV_REGISTER: + case NVME_CMD_RESV_ACQUIRE: + case NVME_CMD_RESV_RELEASE: status = NVME_WRITE_FAULT; break; default: @@ -2692,6 +2704,333 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req) return NVME_NO_COMPLETE; } +static uint16_t nvme_resv_register(NvmeCtrl *n, NvmeRequest *req) +{ + int ret; + NvmeReservationKeyInfo key_info; + NvmeNamespace *ns = req->ns; + uint32_t cdw10 = le32_to_cpu(req->cmd.cdw10); + bool ignore_key = ((cdw10 >> 3) & 0x1); + uint8_t action = cdw10 & 0x7; + uint8_t cptpl = ((cdw10 >> 30) & 0x3); + bool aptpl; + + if (!nvme_support_pr(ns)) { + return NVME_INVALID_OPCODE; + } + + switch (cptpl) { + case NVME_RESV_PTPL_NO_CHANGE: + aptpl = (ns->id_ns.rescap & NVME_PR_CAP_PTPL) ? true : false; + break; + case NVME_RESV_PTPL_DISABLE: + aptpl = false; + break; + case NVME_RESV_PTPL_ENABLE: + aptpl = true; + break; + default: + return NVME_INVALID_FIELD; + } + + ret = nvme_h2c(n, (uint8_t *)&key_info, + sizeof(NvmeReservationKeyInfo), req); + if (ret) { + return ret; + } + + key_info.cr_key = le64_to_cpu(key_info.cr_key); + key_info.nr_key = le64_to_cpu(key_info.nr_key); + + switch (action) { + case NVME_RESV_REGISTER_ACTION_REGISTER: + req->aiocb = blk_aio_pr_register(ns->blkconf.blk, 0, + key_info.nr_key, 0, aptpl, + ignore_key, nvme_misc_cb, + req); + break; + case NVME_RESV_REGISTER_ACTION_UNREGISTER: + req->aiocb = blk_aio_pr_register(ns->blkconf.blk, key_info.cr_key, 0, + 0, aptpl, ignore_key, + nvme_misc_cb, req); + break; + case NVME_RESV_REGISTER_ACTION_REPLACE: + req->aiocb = blk_aio_pr_register(ns->blkconf.blk, key_info.cr_key, + key_info.nr_key, 0, aptpl, ignore_key, + nvme_misc_cb, req); + break; + default: + return NVME_INVALID_FIELD; + } + + return NVME_NO_COMPLETE; +} + +static uint16_t nvme_resv_release(NvmeCtrl *n, NvmeRequest *req) +{ + int ret; + uint64_t cr_key; + NvmeNamespace *ns = req->ns; + uint32_t cdw10 = le32_to_cpu(req->cmd.cdw10); + uint8_t action = cdw10 & 0x7; + NvmeResvType type = ((cdw10 >> 8) & 0xff); + + /* + * According to the specification, the 03 bit is set to a '1', + * NVME_INVALID_FIELD error should be returned. + */ + if ((cdw10 >> 3) & 1) { + return NVME_INVALID_FIELD; + } + + if (!nvme_support_pr(ns)) { + return NVME_INVALID_OPCODE; + } + + ret = nvme_h2c(n, (uint8_t *)&cr_key, sizeof(cr_key), req); + if (ret) { + return ret; + } + + cr_key = le64_to_cpu(cr_key); + + switch (action) { + case NVME_RESV_RELEASE_ACTION_RELEASE: + req->aiocb = blk_aio_pr_release(ns->blkconf.blk, cr_key, + nvme_pr_type_to_block(type), + nvme_misc_cb, req); + break; + case NVME_RESV_RELEASE_ACTION_CLEAR: + req->aiocb = blk_aio_pr_clear(ns->blkconf.blk, cr_key, + nvme_misc_cb, req); + break; + default: + return NVME_INVALID_FIELD; + } + + return NVME_NO_COMPLETE; +} + +static uint16_t nvme_resv_acquire(NvmeCtrl *n, NvmeRequest *req) +{ + int ret; + NvmeReservationKeyInfo key_info; + NvmeNamespace *ns = req->ns; + uint32_t cdw10 = le32_to_cpu(req->cmd.cdw10); + uint8_t action = cdw10 & 0x7; + NvmeResvType type = ((cdw10 >> 8) & 0xff); + + /* + * According to the specification, the 03 bit is set to a '1', + * NVME_INVALID_FIELD error should be returned. + */ + if ((cdw10 >> 3) & 1) { + return NVME_INVALID_FIELD; + } + + if (!nvme_support_pr(ns)) { + return NVME_INVALID_OPCODE; + } + + ret = nvme_h2c(n, (uint8_t *)&key_info, + sizeof(NvmeReservationKeyInfo), req); + if (ret) { + return ret; + } + + key_info.cr_key = le64_to_cpu(key_info.cr_key); + key_info.pr_key = le64_to_cpu(key_info.pr_key); + + switch (action) { + case NVME_RESV_ACQUIRE_ACTION_ACQUIRE: + req->aiocb = blk_aio_pr_reserve(ns->blkconf.blk, key_info.cr_key, + nvme_pr_type_to_block(type), + nvme_misc_cb, req); + break; + case NVME_RESV_ACQUIRE_ACTION_PREEMPT: + req->aiocb = blk_aio_pr_preempt(ns->blkconf.blk, + key_info.cr_key, key_info.pr_key, + nvme_pr_type_to_block(type), + false, nvme_misc_cb, req); + break; + case NVME_RESV_ACQUIRE_ACTION_PREEMPT_AND_ABORT: + req->aiocb = blk_aio_pr_preempt(ns->blkconf.blk, key_info.cr_key, + key_info.pr_key, type, true, + nvme_misc_cb, req); + break; + default: + return NVME_INVALID_FIELD; + } + + return NVME_NO_COMPLETE; +} + +typedef struct NvmeResvKeys { + uint32_t generation; + uint32_t num_keys; + uint64_t *keys; + NvmeRequest *req; +} NvmeResvKeys; + +typedef struct NvmeReadReservation { + uint32_t generation; + uint64_t key; + BlockPrType type; + NvmeRequest *req; + NvmeResvKeys *keys_info; +} NvmeReadReservation; + +static int nvme_read_reservation_cb(NvmeReadReservation *reservation) +{ + int rc; + NvmeReservationStatus *nvme_status; + NvmeRequest *req = reservation->req; + NvmeCtrl *n = req->sq->ctrl; + NvmeResvKeys *keys_info = reservation->keys_info; + int len = sizeof(NvmeReservationStatusHeader) + + sizeof(NvmeRegisteredCtrl) * keys_info->num_keys; + + nvme_status = g_malloc0(len); + nvme_status->header.gen = cpu_to_le32(reservation->generation); + nvme_status->header.rtype = block_pr_type_to_nvme(reservation->type); + nvme_status->header.regstrnt = cpu_to_le32(keys_info->num_keys); + for (int i = 0; i < keys_info->num_keys; i++) { + uint16_t ctnlid = nvme_ctrl(req)->cntlid; + nvme_status->regctl_ds[i].cntlid = cpu_to_le16(ctnlid); + nvme_status->regctl_ds[i].rkey = cpu_to_le64(keys_info->keys[i]); + nvme_status->regctl_ds[i].rcsts = keys_info->keys[i] == + reservation->key ? 1 : 0; + } + + rc = nvme_c2h(n, (uint8_t *)nvme_status, len, req); + g_free(nvme_status); + return rc; +} + +static int nvme_read_reservation_ext_cb(NvmeReadReservation *reservation) +{ + int rc; + NvmeReservationStatusExt *nvme_status_ext; + NvmeRequest *req = reservation->req; + NvmeCtrl *n = req->sq->ctrl; + NvmeResvKeys *keys_info = reservation->keys_info; + int len = sizeof(NvmeReservationStatusExt) + + sizeof(NvmeRegisteredCtrlExt) * keys_info->num_keys; + + nvme_status_ext = g_malloc0(len); + nvme_status_ext->header.gen = cpu_to_le32(reservation->generation); + nvme_status_ext->header.rtype = block_pr_type_to_nvme(reservation->type); + nvme_status_ext->header.regstrnt = cpu_to_le32(keys_info->num_keys); + + for (int i = 0; i < keys_info->num_keys; i++) { + uint16_t ctnlid = nvme_ctrl(req)->cntlid; + nvme_status_ext->regctl_eds[i].cntlid = cpu_to_le16(ctnlid); + nvme_status_ext->regctl_eds[i].rkey = cpu_to_le64(keys_info->keys[i]); + nvme_status_ext->regctl_eds[i].rcsts = keys_info->keys[i] == + reservation->key ? 1 : 0; + } + + rc = nvme_c2h(n, (uint8_t *)nvme_status_ext, len, req); + g_free(nvme_status_ext); + return rc; +} + +static void nvme_resv_read_reservation_cb(void *opaque, int ret) +{ + NvmeReadReservation *reservation = opaque; + NvmeRequest *req = reservation->req; + bool eds = le32_to_cpu(req->cmd.cdw11) & 0x1; + NvmeResvKeys *keys_info = reservation->keys_info; + + if (ret < 0) { + goto out; + } + + if (eds) { + ret = nvme_read_reservation_ext_cb(reservation); + } else { + ret = nvme_read_reservation_cb(reservation); + } + +out: + g_free(keys_info->keys); + g_free(keys_info); + g_free(reservation); + nvme_misc_cb(req, ret); +} + +static void nvme_resv_read_keys_cb(void *opaque, int ret) +{ + NvmeResvKeys *keys_info = opaque; + NvmeRequest *req = keys_info->req; + NvmeNamespace *ns = req->ns; + NvmeReadReservation *reservation; + + if (ret < 0) { + goto out; + } + + keys_info->num_keys = MIN(ret, keys_info->num_keys); + reservation = g_new0(NvmeReadReservation, 1); + reservation->req = req; + reservation->keys_info = keys_info; + + req->aiocb = blk_aio_pr_read_reservation(ns->blkconf.blk, + &reservation->generation, &reservation->key, + &reservation->type, nvme_resv_read_reservation_cb, + reservation); + return; + +out: + g_free(keys_info->keys); + g_free(keys_info); + nvme_misc_cb(req, ret); +} + + +static uint16_t nvme_resv_report(NvmeCtrl *n, NvmeRequest *req) +{ + int num_keys; + uint32_t cdw10 = le32_to_cpu(req->cmd.cdw10); + uint32_t cdw11 = le32_to_cpu(req->cmd.cdw11); + size_t buflen = (cdw10 + 1) * sizeof(uint32_t); + bool eds = cdw11 & 0x1; + NvmeNamespace *ns = req->ns; + NvmeResvKeys *keys_info; + + if (!nvme_support_pr(ns)) { + return NVME_INVALID_OPCODE; + } + + if (eds) { + if (buflen < sizeof(NvmeReservationStatusExt)) { + return NVME_INVALID_FIELD; + } + + num_keys = (buflen - sizeof(NvmeReservationStatusExt)) / + sizeof(struct NvmeRegisteredCtrlExt); + } else { + if (buflen < sizeof(NvmeReservationStatusHeader)) { + return NVME_INVALID_FIELD; + } + + num_keys = (buflen - sizeof(NvmeReservationStatusHeader)) / + sizeof(struct NvmeRegisteredCtrl); + } + + keys_info = g_new0(NvmeResvKeys, 1); + /* num_keys is the maximum number of keys that can be transmitted */ + keys_info->num_keys = MAX(num_keys, 0); + keys_info->keys = g_malloc(sizeof(uint64_t) * num_keys); + keys_info->req = req; + + req->aiocb = blk_aio_pr_read_keys(ns->blkconf.blk, &keys_info->generation, + keys_info->num_keys, keys_info->keys, + nvme_resv_read_keys_cb, keys_info); + + return NVME_NO_COMPLETE; +} + typedef struct NvmeCopyAIOCB { BlockAIOCB common; BlockAIOCB *aiocb; @@ -4469,6 +4808,14 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) return nvme_dsm(n, req); case NVME_CMD_VERIFY: return nvme_verify(n, req); + case NVME_CMD_RESV_REGISTER: + return nvme_resv_register(n, req); + case NVME_CMD_RESV_REPORT: + return nvme_resv_report(n, req); + case NVME_CMD_RESV_ACQUIRE: + return nvme_resv_acquire(n, req); + case NVME_CMD_RESV_RELEASE: + return nvme_resv_release(n, req); case NVME_CMD_COPY: return nvme_copy(n, req); case NVME_CMD_ZONE_MGMT_SEND: diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index a5c903d727..833bcbae08 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -60,6 +60,12 @@ void nvme_ns_init_format(NvmeNamespace *ns) blk_pr_cap = blk_bs(ns->blkconf.blk)->bl.pr_cap; id_ns->rescap = block_pr_cap_to_nvme(blk_pr_cap); + if (id_ns->rescap != NVME_PR_CAP_ALL && + id_ns->rescap != NVME_PR_CAP_RW) { + + /* Rescap either supports all or none of them */ + id_ns->rescap = 0; + } } static int nvme_ns_init(NvmeNamespace *ns, Error **errp) diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h index 6d0e456348..23d7173a36 100644 --- a/hw/nvme/nvme.h +++ b/hw/nvme/nvme.h @@ -470,6 +470,10 @@ static inline const char *nvme_io_opc_str(uint8_t opc) case NVME_CMD_ZONE_MGMT_SEND: return "NVME_ZONED_CMD_MGMT_SEND"; case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_MGMT_RECV"; case NVME_CMD_ZONE_APPEND: return "NVME_ZONED_CMD_ZONE_APPEND"; + case NVME_CMD_RESV_REGISTER: return "NVME_CMD_RESV_REGISTER"; + case NVME_CMD_RESV_REPORT: return "NVME_CMD_RESV_REPORT"; + case NVME_CMD_RESV_ACQUIRE: return "NVME_CMD_RESV_ACQUIRE"; + case NVME_CMD_RESV_RELEASE: return "NVME_CMD_RESV_RELEASE"; default: return "NVME_NVM_CMD_UNKNOWN"; } } @@ -558,6 +562,11 @@ static inline uint8_t block_pr_cap_to_nvme(uint8_t block_pr_cap) return res; } +static inline bool nvme_support_pr(NvmeNamespace *ns) +{ + return (ns->id_ns.rescap & NVME_PR_CAP_RW) == NVME_PR_CAP_RW; +} + typedef struct NvmeSQueue { struct NvmeCtrl *ctrl; uint16_t sqid; diff --git a/include/block/nvme.h b/include/block/nvme.h index 9b9eaeb3a7..c6436fc4bb 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -692,6 +692,13 @@ typedef enum NVMEPrCap { NVME_PR_CAP_WR_EX_AR = 1 << 5, /* Exclusive Access All Registrants reservation type */ NVME_PR_CAP_EX_AC_AR = 1 << 6, + /* Write and Read reservation type */ + NVME_PR_CAP_RW = (NVME_PR_CAP_WR_EX | + NVME_PR_CAP_EX_AC | + NVME_PR_CAP_WR_EX_RO | + NVME_PR_CAP_EX_AC_RO | + NVME_PR_CAP_WR_EX_AR | + NVME_PR_CAP_EX_AC_AR), NVME_PR_CAP_ALL = (NVME_PR_CAP_PTPL | NVME_PR_CAP_WR_EX | @@ -702,6 +709,51 @@ typedef enum NVMEPrCap { NVME_PR_CAP_EX_AC_AR), } NvmePrCap; +typedef struct QEMU_PACKED NvmeReservationKeyInfo { + uint64_t cr_key; + union { + uint64_t nr_key; + uint64_t pr_key; + }; +} NvmeReservationKeyInfo; + +typedef struct QEMU_PACKED NvmeRegisteredCtrl { + uint16_t cntlid; + uint8_t rcsts; + uint8_t rsvd3[5]; + uint8_t hostid[8]; + uint64_t rkey; +} NvmeRegisteredCtrl; + +typedef struct QEMU_PACKED NvmeRegisteredCtrlExt { + uint16_t cntlid; + uint8_t rcsts; + uint8_t rsvd3[5]; + uint64_t rkey; + uint8_t hostid[16]; + uint8_t rsvd32[32]; +} NvmeRegisteredCtrlExt; + +typedef struct QEMU_PACKED NvmeReservationStatusHeader { + uint32_t gen; + uint8_t rtype; + uint16_t regstrnt; + uint16_t resv5; + uint8_t ptpls; + uint8_t resv10[14]; +} NvmeReservationStatusHeader; + +typedef struct QEMU_PACKED NvmeReservationStatus { + NvmeReservationStatusHeader header; + NvmeRegisteredCtrl regctl_ds[]; +} NvmeReservationStatus; + +typedef struct QEMU_PACKED NvmeReservationStatusExt { + NvmeReservationStatusHeader header; + uint8_t rsvd24[40]; + NvmeRegisteredCtrlExt regctl_eds[]; +} NvmeReservationStatusExt; + typedef struct QEMU_PACKED NvmeDeleteQ { uint8_t opcode; uint8_t flags; @@ -1926,5 +1978,11 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeSecCtrlList) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeEndGrpLog) != 512); QEMU_BUILD_BUG_ON(sizeof(NvmeDirectiveIdentify) != 4096); + QEMU_BUILD_BUG_ON(sizeof(NvmeReservationKeyInfo) != 16); + QEMU_BUILD_BUG_ON(sizeof(NvmeRegisteredCtrl) != 24); + QEMU_BUILD_BUG_ON(sizeof(NvmeRegisteredCtrlExt) != 64); + QEMU_BUILD_BUG_ON(sizeof(NvmeReservationStatusHeader) != 24); + QEMU_BUILD_BUG_ON(sizeof(NvmeReservationStatus) != 24); + QEMU_BUILD_BUG_ON(sizeof(NvmeReservationStatusExt) != 64); } #endif From patchwork Fri Oct 11 12:12:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changqi Lu X-Patchwork-Id: 13832786 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E4C4FD0EE12 for ; Fri, 11 Oct 2024 17:25:21 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szJIl-0001Sx-S1; Fri, 11 Oct 2024 13:19:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szJ7f-0003Vx-Uj for qemu-devel@nongnu.org; Fri, 11 Oct 2024 13:08:17 -0400 Received: from mail-pl1-x62b.google.com ([2607:f8b0:4864:20::62b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1szEWe-0004wa-TM for qemu-devel@nongnu.org; Fri, 11 Oct 2024 08:13:48 -0400 Received: by mail-pl1-x62b.google.com with SMTP id d9443c01a7336-20c714cd9c8so15625955ad.0 for ; Fri, 11 Oct 2024 05:13:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1728648824; x=1729253624; darn=nongnu.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=D1H1tgefHez5i+plGQ3DfK7W7Zdn6pb/fC/rPvGnh+Q=; b=C7lvg8B5xKGBC+jcxbL6PRuC0PkcLe9/JuEy6wG4D2Yn3j8neYbY4e0bwKDJKyeJ2k PhdG09kEczIXhJ0GWwMO7nFdGIVSHQolLW8ibac+tSk54/+7Q997EfSm2NfS0CLRjHYv QdoIaA4aVZxbKy0+DuFvJumtC7jx7sBhiMZ1EQk2sHp0BREUDMwXv88tzeEZxB+A4Yte muqxlfM7xH2fm+Ij8sjWevhgIGVrxjBlIdsTeDuJCbfFOmr0dWAa8I/FhNamhneZV9VQ 4VOZjiYYZHJN+Lh2542M4tJRvx/3AuFMTo+xr8CBFE4oqFaTebC1pdoYxZzc7wBF2h3h tu7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728648824; x=1729253624; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=D1H1tgefHez5i+plGQ3DfK7W7Zdn6pb/fC/rPvGnh+Q=; b=qSg7/pCfek0jFTYkhS1bo7O+Haw2BJQ0lyICjBK3uxdlNl/iEISS3Ra7UK5L4bGn4X JzlBbOjKX0R4I/wMy6an/OzIJvn7obW6rq49OncHVcI0dR/1lby5SXqRO963xnfmU+2q ajGkeGY8Z/MV3GGe38DB4a0ghj12j2oyl2Vnfk0qeY0ZKxrpkhFm4TSo8Pj5Way65JBh I12bpaxHLeOyrn5i8+gjHKSwKuTGPa8+a/ROyLf/z+ichWXMWXZhSXyUEBi/s0/oMVl7 W9gya+VbAv9YcJjBBmlRumN237eFtzKOUT3b6l+8i1nFljG+s23VhDqI/m9/7/uBbxrB Veig== X-Forwarded-Encrypted: i=1; AJvYcCVsuSrKF03vQ6ivDjYgPL+NVR7lTl3ZnVBgY4QWq95tXST63hby1l10QjUtcmjGF0vfy4WkGtd7wE9k@nongnu.org X-Gm-Message-State: AOJu0YyNvitkp8q+mqTM/GG+FsbvsOQfyCgSuKu0tkXWFiygFWO/TjnW PSX30oBJ4cfjqmvs7KCHyq++xrXf6HKbLJfygfMzx0CBX2o0kZo+v7Yx6RbuviU= X-Google-Smtp-Source: AGHT+IFR5inEKX4TRZy+YSj2mZv3yxqfQ2JkfJSPaC7TEnmB7wejUhJ4KyYAOWtqsKBPLKIVH42y9Q== X-Received: by 2002:a17:902:e751:b0:20c:a122:e6c4 with SMTP id d9443c01a7336-20ca142c079mr42153065ad.14.1728648823572; Fri, 11 Oct 2024 05:13:43 -0700 (PDT) Received: from TF4D9JK212.bytedance.net ([139.177.225.232]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20c8bc13551sm22569305ad.88.2024.10.11.05.13.38 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 11 Oct 2024 05:13:43 -0700 (PDT) From: Changqi Lu To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, ronniesahlberg@gmail.com, pbonzini@redhat.com, pl@dlhnet.de, kbusch@kernel.org, its@irrelevant.dk, foss@defmacro.it, philmd@linaro.org, pizhenwei@bytedance.com, k.jensen@samsung.com, Changqi Lu Subject: [PATCH v14 10/10] block/iscsi: add persistent reservation in/out driver Date: Fri, 11 Oct 2024 20:12:31 +0800 Message-Id: <20241011121231.18333-11-luchangqi.123@bytedance.com> X-Mailer: git-send-email 2.39.2 (Apple Git-143) In-Reply-To: <20241011121231.18333-1-luchangqi.123@bytedance.com> References: <20241011121231.18333-1-luchangqi.123@bytedance.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::62b; envelope-from=luchangqi.123@bytedance.com; helo=mail-pl1-x62b.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add persistent reservation in/out operations for iscsi driver. The following methods are implemented: bdrv_co_pr_read_keys, bdrv_co_pr_read_reservation, bdrv_co_pr_register, bdrv_co_pr_reserve, bdrv_co_pr_release, bdrv_co_pr_clear and bdrv_co_pr_preempt. Signed-off-by: Changqi Lu Signed-off-by: zhenwei pi Reviewed-by: Stefan Hajnoczi --- block/iscsi.c | 428 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 428 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index 2ff14b7472..245ee77e19 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -96,6 +96,7 @@ typedef struct IscsiLun { unsigned long *allocmap_valid; long allocmap_size; int cluster_size; + uint8_t pr_cap; bool use_16_for_rw; bool write_protected; bool lbpme; @@ -280,6 +281,10 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, iTask->err_code = -error; iTask->err_str = g_strdup(iscsi_get_error(iscsi)); } + } else if (status == SCSI_STATUS_RESERVATION_CONFLICT) { + iTask->err_code = -EBADE; + error_report("iSCSI Persistent Reservation Conflict: %s", + iscsi_get_error(iscsi)); } } } @@ -1792,6 +1797,50 @@ static void iscsi_save_designator(IscsiLun *lun, } } +/* + * Ensure iscsi_open() must succeed, weather or not the target + * implement SCSI_PR_IN_REPORT_CAPABILITIES. + */ +static void iscsi_get_pr_cap_sync(IscsiLun *iscsilun) +{ + struct scsi_task *task = NULL; + struct scsi_persistent_reserve_in_report_capabilities *rc = NULL; + int retries = ISCSI_CMD_RETRIES; + int xferlen = sizeof(struct scsi_persistent_reserve_in_report_capabilities); + + do { + if (task != NULL) { + scsi_free_scsi_task(task); + task = NULL; + } + + task = iscsi_persistent_reserve_in_sync(iscsilun->iscsi, + iscsilun->lun, SCSI_PR_IN_REPORT_CAPABILITIES, xferlen); + if (task != NULL && task->status == SCSI_STATUS_GOOD) { + rc = scsi_datain_unmarshall(task); + if (rc == NULL) { + error_report("iSCSI: Failed to unmarshall " + "report capabilities data."); + } else { + iscsilun->pr_cap = + scsi_pr_cap_to_block(rc->persistent_reservation_type_mask); + iscsilun->pr_cap |= (rc->ptpl_a) ? BLK_PR_CAP_PTPL : 0; + } + break; + } + } while (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION + && task->sense.key == SCSI_SENSE_UNIT_ATTENTION + && retries-- > 0); + + if (task == NULL || task->status != SCSI_STATUS_GOOD) { + error_report("iSCSI: failed to send report capabilities command."); + } + + if (task) { + scsi_free_scsi_task(task); + } +} + static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { @@ -2024,6 +2073,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP; } + iscsi_get_pr_cap_sync(iscsilun); out: qemu_opts_del(opts); g_free(initiator_name); @@ -2110,6 +2160,8 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) bs->bl.opt_transfer = pow2floor(iscsilun->bl.opt_xfer_len * iscsilun->block_size); } + + bs->bl.pr_cap = iscsilun->pr_cap; } /* Note that this will not re-establish a connection with an iSCSI target - it @@ -2408,6 +2460,374 @@ out_unlock: return r; } +static int coroutine_fn +iscsi_co_pr_read_keys(BlockDriverState *bs, uint32_t *generation, + uint32_t num_keys, uint64_t *keys) +{ + IscsiLun *iscsilun = bs->opaque; + QEMUIOVector qiov; + struct IscsiTask iTask; + int xferlen = sizeof(struct scsi_persistent_reserve_in_read_keys) + + sizeof(uint64_t) * num_keys; + g_autofree uint8_t *buf = g_malloc0(xferlen); + int32_t num_collect_keys = 0; + int r = 0; + + qemu_iovec_init_buf(&qiov, buf, xferlen); + iscsi_co_init_iscsitask(iscsilun, &iTask); + qemu_mutex_lock(&iscsilun->mutex); +retry: + iTask.task = iscsi_persistent_reserve_in_task(iscsilun->iscsi, + iscsilun->lun, SCSI_PR_IN_READ_KEYS, xferlen, + iscsi_co_generic_cb, &iTask); + + if (iTask.task == NULL) { + qemu_mutex_unlock(&iscsilun->mutex); + return -ENOMEM; + } + + scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *)qiov.iov, qiov.niov); + iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + iTask.task = NULL; + } + + if (iTask.do_retry) { + iTask.complete = 0; + goto retry; + } + + if (iTask.status != SCSI_STATUS_GOOD) { + error_report("iSCSI PERSISTENT_RESERVE_IN failed: %s", iTask.err_str); + r = iTask.err_code; + goto out; + } + + memcpy(generation, &buf[0], 4); + *generation = be32_to_cpu(*generation); + memcpy(&num_collect_keys, &buf[4], 4); + num_collect_keys = be32_to_cpu(num_collect_keys) / sizeof(uint64_t); + if (num_collect_keys > num_keys) { + r = -EINVAL; + goto out; + } + + for (int i = 0; i < num_collect_keys; i++) { + memcpy(&keys[i], &buf[8 + i * 8], 8); + keys[i] = be64_to_cpu(keys[i]); + } + r = num_collect_keys; + +out: + qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); + return r; +} + +static int coroutine_fn +iscsi_co_pr_read_reservation(BlockDriverState *bs, uint32_t *generation, + uint64_t *key, BlockPrType *type) +{ + IscsiLun *iscsilun = bs->opaque; + QEMUIOVector qiov; + struct IscsiTask iTask; + int xferlen = sizeof(struct scsi_persistent_reserve_in_read_reservation); + g_autofree uint8_t *buf = g_malloc0(xferlen); + uint8_t scope_type = 0; + int32_t num_collect_keys = 0; + int r = 0; + + qemu_iovec_init_buf(&qiov, buf, xferlen); + iscsi_co_init_iscsitask(iscsilun, &iTask); + qemu_mutex_lock(&iscsilun->mutex); +retry: + iTask.task = iscsi_persistent_reserve_in_task(iscsilun->iscsi, + iscsilun->lun, SCSI_PR_IN_READ_RESERVATION, + xferlen, iscsi_co_generic_cb, &iTask); + + if (iTask.task == NULL) { + qemu_mutex_unlock(&iscsilun->mutex); + return -ENOMEM; + } + + scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *)qiov.iov, qiov.niov); + iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + iTask.task = NULL; + } + + if (iTask.do_retry) { + iTask.complete = 0; + goto retry; + } + + if (iTask.status != SCSI_STATUS_GOOD) { + error_report("iSCSI PERSISTENT_RESERVE_IN failed: %s", iTask.err_str); + r = iTask.err_code; + goto out; + } + + memcpy(generation, &buf[0], 4); + *generation = be32_to_cpu(*generation); + memcpy(key, &buf[8], 8); + *key = be64_to_cpu(*key); + memcpy(&scope_type, &buf[21], 1); + *type = scsi_pr_type_to_block(scope_type & 0xf); + memcpy(&num_collect_keys, &buf[4], 4); + r = be32_to_cpu(num_collect_keys) / sizeof(uint64_t); +out: + qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); + return r; +} + +static int coroutine_fn +iscsi_co_pr_register(BlockDriverState *bs, uint64_t old_key, + uint64_t new_key, BlockPrType type, + bool ptpl, bool ignore_key) +{ + IscsiLun *iscsilun = bs->opaque; + struct IscsiTask iTask; + struct scsi_persistent_reserve_out_basic basic; + SCSIPrOutAction action = ignore_key ? SCSI_PR_OUT_REG_AND_IGNORE_KEY : + SCSI_PR_OUT_REGISTER; + int r = 0; + + memset(&basic, 0, sizeof(basic)); + basic.reservation_key = old_key; + basic.service_action_reservation_key = new_key; + basic.aptpl = ptpl ? 1 : 0; + + iscsi_co_init_iscsitask(iscsilun, &iTask); + qemu_mutex_lock(&iscsilun->mutex); +retry: + iTask.task = iscsi_persistent_reserve_out_task(iscsilun->iscsi, + iscsilun->lun, action, 0, block_pr_type_to_scsi(type), + &basic, iscsi_co_generic_cb, &iTask); + + if (iTask.task == NULL) { + qemu_mutex_unlock(&iscsilun->mutex); + return -ENOMEM; + } + + iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + iTask.task = NULL; + } + + if (iTask.do_retry) { + iTask.complete = 0; + goto retry; + } + + if (iTask.status != SCSI_STATUS_GOOD) { + error_report("iSCSI PERSISTENT_RESERVE_OUT failed: %s", iTask.err_str); + r = iTask.err_code; + } + + qemu_mutex_unlock(&iscsilun->mutex); + + g_free(iTask.err_str); + return r; +} + +static int coroutine_fn +iscsi_co_pr_reserve(BlockDriverState *bs, uint64_t key, BlockPrType type) +{ + IscsiLun *iscsilun = bs->opaque; + struct IscsiTask iTask; + struct scsi_persistent_reserve_out_basic basic; + int r = 0; + + memset(&basic, 0, sizeof(basic)); + basic.reservation_key = key; + iscsi_co_init_iscsitask(iscsilun, &iTask); + qemu_mutex_lock(&iscsilun->mutex); +retry: + iTask.task = iscsi_persistent_reserve_out_task(iscsilun->iscsi, + iscsilun->lun, SCSI_PR_OUT_RESERVE, 0, + block_pr_type_to_scsi(type), &basic, + iscsi_co_generic_cb, &iTask); + + if (iTask.task == NULL) { + qemu_mutex_unlock(&iscsilun->mutex); + return -ENOMEM; + } + + + iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + iTask.task = NULL; + } + + if (iTask.do_retry) { + iTask.complete = 0; + goto retry; + } + + if (iTask.status != SCSI_STATUS_GOOD) { + error_report("iSCSI PERSISTENT_RESERVE_OUT failed: %s", iTask.err_str); + r = iTask.err_code; + } + + qemu_mutex_unlock(&iscsilun->mutex); + + g_free(iTask.err_str); + return r; +} + +static int coroutine_fn +iscsi_co_pr_release(BlockDriverState *bs, uint64_t key, BlockPrType type) +{ + IscsiLun *iscsilun = bs->opaque; + struct IscsiTask iTask; + struct scsi_persistent_reserve_out_basic basic; + int r = 0; + + memset(&basic, 0, sizeof(basic)); + basic.reservation_key = key; + iscsi_co_init_iscsitask(iscsilun, &iTask); + qemu_mutex_lock(&iscsilun->mutex); +retry: + iTask.task = iscsi_persistent_reserve_out_task(iscsilun->iscsi, + iscsilun->lun, SCSI_PR_OUT_RELEASE, 0, + block_pr_type_to_scsi(type), &basic, + iscsi_co_generic_cb, &iTask); + + if (iTask.task == NULL) { + qemu_mutex_unlock(&iscsilun->mutex); + return -ENOMEM; + } + + + iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + iTask.task = NULL; + } + + if (iTask.do_retry) { + iTask.complete = 0; + goto retry; + } + + if (iTask.status != SCSI_STATUS_GOOD) { + error_report("iSCSI PERSISTENT_RESERVE_OUT failed: %s", iTask.err_str); + r = iTask.err_code; + } + + qemu_mutex_unlock(&iscsilun->mutex); + + g_free(iTask.err_str); + return r; +} + +static int coroutine_fn +iscsi_co_pr_clear(BlockDriverState *bs, uint64_t key) +{ + IscsiLun *iscsilun = bs->opaque; + struct IscsiTask iTask; + struct scsi_persistent_reserve_out_basic basic; + int r = 0; + + memset(&basic, 0, sizeof(basic)); + basic.reservation_key = key; + iscsi_co_init_iscsitask(iscsilun, &iTask); + qemu_mutex_lock(&iscsilun->mutex); +retry: + iTask.task = iscsi_persistent_reserve_out_task(iscsilun->iscsi, + iscsilun->lun, SCSI_PR_OUT_CLEAR, 0, 0, &basic, + iscsi_co_generic_cb, &iTask); + + if (iTask.task == NULL) { + qemu_mutex_unlock(&iscsilun->mutex); + return -ENOMEM; + } + + + iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + iTask.task = NULL; + } + + if (iTask.do_retry) { + iTask.complete = 0; + goto retry; + } + + if (iTask.status != SCSI_STATUS_GOOD) { + error_report("iSCSI PERSISTENT_RESERVE_OUT failed: %s", iTask.err_str); + r = iTask.err_code; + } + + qemu_mutex_unlock(&iscsilun->mutex); + + g_free(iTask.err_str); + return r; +} + +static int coroutine_fn +iscsi_co_pr_preempt(BlockDriverState *bs, uint64_t old_key, + uint64_t new_key, BlockPrType type, bool abort) +{ + IscsiLun *iscsilun = bs->opaque; + struct IscsiTask iTask; + struct scsi_persistent_reserve_out_basic basic; + SCSIPrOutAction action = abort ? SCSI_PR_OUT_PREEMPT_AND_ABORT : + SCSI_PR_OUT_PREEMPT; + int r = 0; + + memset(&basic, 0, sizeof(basic)); + basic.reservation_key = old_key; + basic.service_action_reservation_key = new_key; + + iscsi_co_init_iscsitask(iscsilun, &iTask); + qemu_mutex_lock(&iscsilun->mutex); +retry: + iTask.task = iscsi_persistent_reserve_out_task(iscsilun->iscsi, + iscsilun->lun, action, 0, block_pr_type_to_scsi(type), + &basic, iscsi_co_generic_cb, &iTask); + + if (iTask.task == NULL) { + qemu_mutex_unlock(&iscsilun->mutex); + return -ENOMEM; + } + + + iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + iTask.task = NULL; + } + + if (iTask.do_retry) { + iTask.complete = 0; + goto retry; + } + + if (iTask.status != SCSI_STATUS_GOOD) { + error_report("iSCSI PERSISTENT_RESERVE_OUT failed: %s", iTask.err_str); + r = iTask.err_code; + } + + qemu_mutex_unlock(&iscsilun->mutex); + + g_free(iTask.err_str); + return r; +} + static const char *const iscsi_strong_runtime_opts[] = { "transport", @@ -2451,6 +2871,14 @@ static BlockDriver bdrv_iscsi = { .bdrv_co_writev = iscsi_co_writev, .bdrv_co_flush_to_disk = iscsi_co_flush, + .bdrv_co_pr_read_keys = iscsi_co_pr_read_keys, + .bdrv_co_pr_read_reservation = iscsi_co_pr_read_reservation, + .bdrv_co_pr_register = iscsi_co_pr_register, + .bdrv_co_pr_reserve = iscsi_co_pr_reserve, + .bdrv_co_pr_release = iscsi_co_pr_release, + .bdrv_co_pr_clear = iscsi_co_pr_clear, + .bdrv_co_pr_preempt = iscsi_co_pr_preempt, + #ifdef __linux__ .bdrv_aio_ioctl = iscsi_aio_ioctl, #endif