From nobody Sun Feb 8 19:48:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=intel.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1636952195623660.3426316390355; Sun, 14 Nov 2021 20:56:35 -0800 (PST) Received: from localhost ([::1]:33852 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mmU2k-0007ur-5l for importer@patchew.org; Sun, 14 Nov 2021 23:56:34 -0500 Received: from eggs.gnu.org ([209.51.188.92]:41206) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mmU0a-0004yO-IL; Sun, 14 Nov 2021 23:54:20 -0500 Received: from mga17.intel.com ([192.55.52.151]:4464) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mmU0W-0008OU-N7; Sun, 14 Nov 2021 23:54:20 -0500 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Nov 2021 20:54:14 -0800 Received: from yadong-antec.sh.intel.com ([10.239.158.125]) by fmsmga001.fm.intel.com with ESMTP; 14 Nov 2021 20:54:10 -0800 X-IronPort-AV: E=McAfee;i="6200,9189,10168"; a="214101233" X-IronPort-AV: E=Sophos;i="5.87,235,1631602800"; d="scan'208";a="214101233" X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.87,235,1631602800"; d="scan'208";a="644710439" From: yadong.qi@intel.com To: qemu-block@nongnu.org, kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, mst@redhat.com Subject: [PATCH 1/2] block:hdev: support BLKSECDISCARD Date: Mon, 15 Nov 2021 12:51:59 +0800 Message-Id: <20211115045200.3567293-2-yadong.qi@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211115045200.3567293-1-yadong.qi@intel.com> References: <20211115045200.3567293-1-yadong.qi@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=192.55.52.151; envelope-from=yadong.qi@intel.com; helo=mga17.intel.com X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, 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: , Cc: kai.z.wang@intel.com, yadong.qi@intel.com, luhai.chen@intel.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZM-MESSAGEID: 1636952196869100001 Content-Type: text/plain; charset="utf-8" From: Yadong Qi Add a new option "secdiscard" for block drive. Parse it and record it in bs->open_flags as bit(BDRV_O_SECDISCARD). Add a new BDRV_REQ_SECDISCARD bit for secure discard request from virtual device. For host_device backend: implement by ioctl(BLKSECDISCARD) on real host block device. For other backend, no implementation. E.g.: qemu-system-x86_64 \ ... \ -drive file=3D/dev/mmcblk0p2,if=3Dnone,format=3Draw,discard=3Don,secdis= card=3Don,id=3Dsd0 \ -device virtio-blk-pci,drive=3Dsd0,id=3Dsd0_vblk \ ... Signed-off-by: Yadong Qi --- block.c | 46 +++++++++++++++++++++++++++++ block/blkdebug.c | 5 ++-- block/blklogwrites.c | 6 ++-- block/blkreplay.c | 5 ++-- block/block-backend.c | 15 ++++++---- block/copy-before-write.c | 5 ++-- block/copy-on-read.c | 5 ++-- block/coroutines.h | 6 ++-- block/file-posix.c | 50 ++++++++++++++++++++++++++++---- block/filter-compress.c | 5 ++-- block/io.c | 5 ++-- block/mirror.c | 5 ++-- block/nbd.c | 3 +- block/nvme.c | 3 +- block/preallocate.c | 5 ++-- block/qcow2-refcount.c | 4 +-- block/qcow2.c | 3 +- block/raw-format.c | 5 ++-- block/throttle.c | 5 ++-- hw/block/virtio-blk.c | 2 +- hw/ide/core.c | 1 + hw/nvme/ctrl.c | 3 +- hw/scsi/scsi-disk.c | 2 +- include/block/block.h | 13 +++++++-- include/block/block_int.h | 2 +- include/block/raw-aio.h | 4 ++- include/sysemu/block-backend.h | 1 + tests/unit/test-block-iothread.c | 9 +++--- 28 files changed, 171 insertions(+), 52 deletions(-) diff --git a/block.c b/block.c index 580cb77a70..4f05e96d12 100644 --- a/block.c +++ b/block.c @@ -1128,6 +1128,32 @@ int bdrv_parse_discard_flags(const char *mode, int *= flags) return 0; } =20 +/** + * Set open flags for a given secdiscard mode + * + * Return 0 on success, -1 if the secdiscard mode was invalid. + */ +int bdrv_parse_secdiscard_flags(const char *mode, int *flags, Error **errp) +{ + *flags &=3D ~BDRV_O_SECDISCARD; + + if (!strcmp(mode, "off")) { + /* do nothing */ + } else if (!strcmp(mode, "on")) { + if (!(*flags & BDRV_O_UNMAP)) { + error_setg(errp, "cannot enable secdiscard when discard is " + "disabled!"); + return -1; + } + + *flags |=3D BDRV_O_SECDISCARD; + } else { + return -1; + } + + return 0; +} + /** * Set open flags for a given cache mode * @@ -1695,6 +1721,11 @@ QemuOptsList bdrv_runtime_opts =3D { .type =3D QEMU_OPT_STRING, .help =3D "discard operation (ignore/off, unmap/on)", }, + { + .name =3D BDRV_OPT_SECDISCARD, + .type =3D QEMU_OPT_STRING, + .help =3D "secure discard operation (off, on)", + }, { .name =3D BDRV_OPT_FORCE_SHARE, .type =3D QEMU_OPT_BOOL, @@ -1735,6 +1766,7 @@ static int bdrv_open_common(BlockDriverState *bs, Blo= ckBackend *file, const char *driver_name =3D NULL; const char *node_name =3D NULL; const char *discard; + const char *secdiscard; QemuOpts *opts; BlockDriver *drv; Error *local_err =3D NULL; @@ -1829,6 +1861,16 @@ static int bdrv_open_common(BlockDriverState *bs, Bl= ockBackend *file, } } =20 + + secdiscard =3D qemu_opt_get(opts, BDRV_OPT_SECDISCARD); + if (secdiscard !=3D NULL) { + if (bdrv_parse_secdiscard_flags(secdiscard, &bs->open_flags, + errp) !=3D 0) { + ret =3D -EINVAL; + goto fail_opts; + } + } + bs->detect_zeroes =3D bdrv_parse_detect_zeroes(opts, bs->open_flags, &local_err); if (local_err) { @@ -3685,6 +3727,10 @@ static BlockDriverState *bdrv_open_inherit(const cha= r *filename, &flags, options, flags, options); } =20 + if (g_strcmp0(qdict_get_try_str(options, BDRV_OPT_SECDISCARD), "on")) { + flags |=3D BDRV_O_SECDISCARD; + } + bs->open_flags =3D flags; bs->options =3D options; options =3D qdict_clone_shallow(options); diff --git a/block/blkdebug.c b/block/blkdebug.c index bbf2948703..b49bb6a3e9 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -717,7 +717,8 @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(Block= DriverState *bs, } =20 static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t bytes) + int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { uint32_t align =3D bs->bl.pdiscard_alignment; int err; @@ -747,7 +748,7 @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDrive= rState *bs, return err; } =20 - return bdrv_co_pdiscard(bs->file, offset, bytes); + return bdrv_co_pdiscard(bs->file, offset, bytes, 0); } =20 static int coroutine_fn blkdebug_co_block_status(BlockDriverState *bs, diff --git a/block/blklogwrites.c b/block/blklogwrites.c index f7a251e91f..d8d81a40ae 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -456,7 +456,8 @@ static int coroutine_fn blk_log_writes_co_do_file_flush= (BlkLogWritesFileReq *fr) static int coroutine_fn blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr) { - return bdrv_co_pdiscard(fr->bs->file, fr->offset, fr->bytes); + return bdrv_co_pdiscard(fr->bs->file, fr->offset, fr->bytes, + fr->file_flags); } =20 static int coroutine_fn @@ -484,7 +485,8 @@ static int coroutine_fn blk_log_writes_co_flush_to_disk= (BlockDriverState *bs) } =20 static int coroutine_fn -blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t b= ytes) +blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t b= ytes, + BdrvRequestFlags flags) { return blk_log_writes_co_log(bs, offset, bytes, NULL, 0, blk_log_writes_co_do_file_pdiscard, diff --git a/block/blkreplay.c b/block/blkreplay.c index dcbe780ddb..65e66d0766 100644 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -105,10 +105,11 @@ static int coroutine_fn blkreplay_co_pwrite_zeroes(Bl= ockDriverState *bs, } =20 static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t byte= s) + int64_t offset, int64_t byte= s, + BdrvRequestFlags flags) { uint64_t reqid =3D blkreplay_next_id(); - int ret =3D bdrv_co_pdiscard(bs->file, offset, bytes); + int ret =3D bdrv_co_pdiscard(bs->file, offset, bytes, flags); block_request_create(reqid, bs, qemu_coroutine_self()); qemu_coroutine_yield(); =20 diff --git a/block/block-backend.c b/block/block-backend.c index 12ef80ea17..f2c5776172 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1597,7 +1597,8 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned= long int req, void *buf, =20 /* To be called between exactly one pair of blk_inc/dec_in_flight() */ int coroutine_fn -blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) +blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { int ret; =20 @@ -1608,7 +1609,7 @@ blk_co_do_pdiscard(BlockBackend *blk, int64_t offset,= int64_t bytes) return ret; } =20 - return bdrv_co_pdiscard(blk->root, offset, bytes); + return bdrv_co_pdiscard(blk->root, offset, bytes, flags); } =20 static void blk_aio_pdiscard_entry(void *opaque) @@ -1616,15 +1617,17 @@ static void blk_aio_pdiscard_entry(void *opaque) BlkAioEmAIOCB *acb =3D opaque; BlkRwCo *rwco =3D &acb->rwco; =20 - rwco->ret =3D blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes); + rwco->ret =3D blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes, + rwco->flags); blk_aio_complete(acb); } =20 BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes, + BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque) { - return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, = 0, + return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, = flags, cb, opaque); } =20 @@ -1634,7 +1637,7 @@ int coroutine_fn blk_co_pdiscard(BlockBackend *blk, i= nt64_t offset, int ret; =20 blk_inc_in_flight(blk); - ret =3D blk_co_do_pdiscard(blk, offset, bytes); + ret =3D blk_co_do_pdiscard(blk, offset, bytes, 0); blk_dec_in_flight(blk); =20 return ret; @@ -1645,7 +1648,7 @@ int blk_pdiscard(BlockBackend *blk, int64_t offset, i= nt64_t bytes) int ret; =20 blk_inc_in_flight(blk); - ret =3D blk_do_pdiscard(blk, offset, bytes); + ret =3D blk_do_pdiscard(blk, offset, bytes, 0); blk_dec_in_flight(blk); =20 return ret; diff --git a/block/copy-before-write.c b/block/copy-before-write.c index c30a5ff8de..8d60a3028f 100644 --- a/block/copy-before-write.c +++ b/block/copy-before-write.c @@ -64,14 +64,15 @@ static coroutine_fn int cbw_do_copy_before_write(BlockD= riverState *bs, } =20 static int coroutine_fn cbw_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t bytes) + int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { int ret =3D cbw_do_copy_before_write(bs, offset, bytes, 0); if (ret < 0) { return ret; } =20 - return bdrv_co_pdiscard(bs->file, offset, bytes); + return bdrv_co_pdiscard(bs->file, offset, bytes, 0); } =20 static int coroutine_fn cbw_co_pwrite_zeroes(BlockDriverState *bs, diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 1fc7fb3333..52183cc9a2 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -201,9 +201,10 @@ static int coroutine_fn cor_co_pwrite_zeroes(BlockDriv= erState *bs, =20 =20 static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t bytes) + int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { - return bdrv_co_pdiscard(bs->file, offset, bytes); + return bdrv_co_pdiscard(bs->file, offset, bytes, 0); } =20 =20 diff --git a/block/coroutines.h b/block/coroutines.h index c8c14a29c8..b0ba771bef 100644 --- a/block/coroutines.h +++ b/block/coroutines.h @@ -98,9 +98,11 @@ int coroutine_fn blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf); =20 int generated_co_wrapper -blk_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); +blk_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes, + BdrvRequestFlags flags); int coroutine_fn -blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes); +blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes, + BdrvRequestFlags flags); =20 int generated_co_wrapper blk_do_flush(BlockBackend *blk); int coroutine_fn blk_co_do_flush(BlockBackend *blk); diff --git a/block/file-posix.c b/block/file-posix.c index 7a27c83060..caa406e429 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -160,6 +160,7 @@ typedef struct BDRVRawState { bool is_xfs:1; #endif bool has_discard:1; + bool has_secdiscard:1; bool has_write_zeroes:1; bool discard_zeroes:1; bool use_linux_aio:1; @@ -727,6 +728,7 @@ static int raw_open_common(BlockDriverState *bs, QDict = *options, #endif /* !defined(CONFIG_LINUX_IO_URING) */ =20 s->has_discard =3D true; + s->has_secdiscard =3D false; s->has_write_zeroes =3D true; if ((bs->open_flags & BDRV_O_NOCACHE) !=3D 0 && !dio_byte_aligned(s->f= d)) { s->needs_alignment =3D true; @@ -765,6 +767,7 @@ static int raw_open_common(BlockDriverState *bs, QDict = *options, s->discard_zeroes =3D true; } #endif + #ifdef __linux__ /* On Linux 3.10, BLKDISCARD leaves stale data in the page cache. = Do * not rely on the contents of discarded blocks unless using O_DIR= ECT. @@ -1859,6 +1862,35 @@ static int handle_aiocb_discard(void *opaque) return ret; } =20 +static int handle_aiocb_secdiscard(void *opaque) +{ + RawPosixAIOData *aiocb =3D opaque; + int ret =3D -ENOTSUP; + BlockDriverState *bs =3D aiocb->bs; + + if (!(bs->open_flags & BDRV_O_SECDISCARD)) { + return -ENOTSUP; + } + + if (aiocb->aio_type & QEMU_AIO_BLKDEV) { +#ifdef BLKSECDISCARD + do { + uint64_t range[2] =3D { aiocb->aio_offset, aiocb->aio_nbytes }; + if (ioctl(aiocb->aio_fildes, BLKSECDISCARD, range) =3D=3D 0) { + return 0; + } + } while (errno =3D=3D EINTR); + + ret =3D translate_err(-errno); +#endif + } + + if (ret =3D=3D -ENOTSUP) { + bs->open_flags &=3D ~BDRV_O_SECDISCARD; + } + return ret; +} + /* * Help alignment probing by allocating the first block. * @@ -2953,7 +2985,7 @@ static void raw_account_discard(BDRVRawState *s, uint= 64_t nbytes, int ret) =20 static coroutine_fn int raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes, - bool blkdev) + bool blkdev, BdrvRequestFlags flags) { BDRVRawState *s =3D bs->opaque; RawPosixAIOData acb; @@ -2971,15 +3003,20 @@ raw_do_pdiscard(BlockDriverState *bs, int64_t offse= t, int64_t bytes, acb.aio_type |=3D QEMU_AIO_BLKDEV; } =20 - ret =3D raw_thread_pool_submit(bs, handle_aiocb_discard, &acb); + if (flags & BDRV_REQ_SECDISCARD) { + ret =3D raw_thread_pool_submit(bs, handle_aiocb_secdiscard, &acb); + } else { + ret =3D raw_thread_pool_submit(bs, handle_aiocb_discard, &acb); + } raw_account_discard(s, bytes, ret); return ret; } =20 static coroutine_fn int -raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) +raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { - return raw_do_pdiscard(bs, offset, bytes, false); + return raw_do_pdiscard(bs, offset, bytes, false, flags); } =20 static int coroutine_fn @@ -3602,7 +3639,8 @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int= req, void *buf) #endif /* linux */ =20 static coroutine_fn int -hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) +hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { BDRVRawState *s =3D bs->opaque; int ret; @@ -3612,7 +3650,7 @@ hdev_co_pdiscard(BlockDriverState *bs, int64_t offset= , int64_t bytes) raw_account_discard(s, bytes, ret); return ret; } - return raw_do_pdiscard(bs, offset, bytes, true); + return raw_do_pdiscard(bs, offset, bytes, true, flags); } =20 static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs, diff --git a/block/filter-compress.c b/block/filter-compress.c index d5be538619..aced5d6c8f 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -94,9 +94,10 @@ static int coroutine_fn compress_co_pwrite_zeroes(BlockD= riverState *bs, =20 =20 static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t bytes) + int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { - return bdrv_co_pdiscard(bs->file, offset, bytes); + return bdrv_co_pdiscard(bs->file, offset, bytes, 0); } =20 =20 diff --git a/block/io.c b/block/io.c index bb0a254def..b6ff244795 100644 --- a/block/io.c +++ b/block/io.c @@ -3054,7 +3054,7 @@ early_exit: } =20 int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, - int64_t bytes) + int64_t bytes, BdrvRequestFlags flags) { BdrvTrackedRequest req; int ret; @@ -3139,8 +3139,9 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, i= nt64_t offset, ret =3D -ENOMEDIUM; goto out; } + if (bs->drv->bdrv_co_pdiscard) { - ret =3D bs->drv->bdrv_co_pdiscard(bs, offset, num); + ret =3D bs->drv->bdrv_co_pdiscard(bs, offset, num, flags); } else { BlockAIOCB *acb; CoroutineIOCompletion co =3D { diff --git a/block/mirror.c b/block/mirror.c index efec2c7674..d91a6fe2ac 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1440,7 +1440,7 @@ static int coroutine_fn bdrv_mirror_top_do_write(Bloc= kDriverState *bs, break; =20 case MIRROR_METHOD_DISCARD: - ret =3D bdrv_co_pdiscard(bs->backing, offset, bytes); + ret =3D bdrv_co_pdiscard(bs->backing, offset, bytes, 0); break; =20 default: @@ -1516,7 +1516,8 @@ static int coroutine_fn bdrv_mirror_top_pwrite_zeroes= (BlockDriverState *bs, } =20 static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t bytes) + int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_DISCARD, offset, byt= es, NULL, 0); diff --git a/block/nbd.c b/block/nbd.c index 5ef462db1b..54fc433c0f 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1296,7 +1296,8 @@ static int nbd_client_co_flush(BlockDriverState *bs) } =20 static int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, - int64_t bytes) + int64_t bytes, + BdrvRequestFlags flags) { BDRVNBDState *s =3D (BDRVNBDState *)bs->opaque; NBDRequest request =3D { diff --git a/block/nvme.c b/block/nvme.c index e4f336d79c..217523438a 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -1363,7 +1363,8 @@ static coroutine_fn int nvme_co_pwrite_zeroes(BlockDr= iverState *bs, =20 static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs, int64_t offset, - int64_t bytes) + int64_t bytes, + BdrvRequestFlags flags) { BDRVNVMeState *s =3D bs->opaque; NVMeQueuePair *ioq =3D s->queues[INDEX_IO(0)]; diff --git a/block/preallocate.c b/block/preallocate.c index 1d4233f730..4a098747d1 100644 --- a/block/preallocate.c +++ b/block/preallocate.c @@ -235,9 +235,10 @@ static coroutine_fn int preallocate_co_preadv_part( } =20 static int coroutine_fn preallocate_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t byt= es) + int64_t offset, int64_t byt= es, + BdrvRequestFlags flags) { - return bdrv_co_pdiscard(bs->file, offset, bytes); + return bdrv_co_pdiscard(bs->file, offset, bytes, flags); } =20 static bool can_write_resize(uint64_t perm) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 4614572252..6a81dfd13a 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -738,7 +738,7 @@ void qcow2_process_discards(BlockDriverState *bs, int r= et) =20 /* Discard is optional, ignore the return value */ if (ret >=3D 0) { - int r2 =3D bdrv_pdiscard(bs->file, d->offset, d->bytes); + int r2 =3D bdrv_pdiscard(bs->file, d->offset, d->bytes, 0); if (r2 < 0) { trace_qcow2_process_discards_failed_region(d->offset, d->b= ytes, r2); @@ -1169,7 +1169,7 @@ void qcow2_free_any_cluster(BlockDriverState *bs, uin= t64_t l2_entry, ctype =3D=3D QCOW2_CLUSTER_ZERO_ALLOC)) { bdrv_pdiscard(s->data_file, l2_entry & L2E_OFFSET_MASK, - s->cluster_size); + s->cluster_size, 0); } return; } diff --git a/block/qcow2.c b/block/qcow2.c index d509016756..258f4f94e0 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3996,7 +3996,8 @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockD= riverState *bs, } =20 static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t bytes) + int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { int ret; BDRVQcow2State *s =3D bs->opaque; diff --git a/block/raw-format.c b/block/raw-format.c index bda757fd19..d149982e8e 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -302,7 +302,8 @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDrive= rState *bs, } =20 static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t bytes) + int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { int ret; =20 @@ -310,7 +311,7 @@ static int coroutine_fn raw_co_pdiscard(BlockDriverStat= e *bs, if (ret) { return ret; } - return bdrv_co_pdiscard(bs->file, offset, bytes); + return bdrv_co_pdiscard(bs->file, offset, bytes, flags); } =20 static int64_t raw_getlength(BlockDriverState *bs) diff --git a/block/throttle.c b/block/throttle.c index 6e8d52fa24..d7e6967296 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -145,12 +145,13 @@ static int coroutine_fn throttle_co_pwrite_zeroes(Blo= ckDriverState *bs, } =20 static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t bytes) + int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { ThrottleGroupMember *tgm =3D bs->opaque; throttle_group_co_io_limits_intercept(tgm, bytes, true); =20 - return bdrv_co_pdiscard(bs->file, offset, bytes); + return bdrv_co_pdiscard(bs->file, offset, bytes, flags); } =20 static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *b= s, diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index f139cd7cc9..dbc4c5a3cd 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -600,7 +600,7 @@ static uint8_t virtio_blk_handle_discard_write_zeroes(V= irtIOBlockReq *req, goto err; } =20 - blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes, + blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes, 0, virtio_blk_discard_write_zeroes_complete, req); } =20 diff --git a/hw/ide/core.c b/hw/ide/core.c index e28f8aad61..47c6cf116d 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -483,6 +483,7 @@ static void ide_issue_trim_cb(void *opaque, int ret) iocb->aiocb =3D blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, count << BDRV_SECTOR_BITS, + 0, ide_issue_trim_cb, opaque); return; } diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 6a571d18cf..45c45b83c7 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -2325,7 +2325,7 @@ next: } =20 iocb->aiocb =3D blk_aio_pdiscard(ns->blkconf.blk, nvme_l2b(ns, slba), - nvme_l2b(ns, nlb), + nvme_l2b(ns, nlb), 0, nvme_dsm_md_cb, iocb); return; =20 @@ -5429,6 +5429,7 @@ static uint16_t nvme_format(NvmeCtrl *n, NvmeRequest = *req) uint32_t nsid =3D le32_to_cpu(req->cmd.nsid); uint16_t status; =20 + iocb =3D qemu_aio_get(&nvme_format_aiocb_info, NULL, nvme_misc_cb, req= ); =20 iocb->req =3D req; diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index e8a547dbb7..b83ab3e471 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1634,7 +1634,7 @@ static void scsi_unmap_complete_noio(UnmapCBData *dat= a, int ret) r->req.aiocb =3D blk_aio_pdiscard(s->qdev.conf.blk, r->sector * BDRV_SECTOR_SIZE, r->sector_count * BDRV_SECTOR_SIZE, - scsi_unmap_complete, data); + 0, scsi_unmap_complete, data); data->count--; data->inbuf +=3D 16; return; diff --git a/include/block/block.h b/include/block/block.h index e5dd22b034..bfa26de835 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -87,6 +87,11 @@ typedef enum { */ BDRV_REQ_NO_WAIT =3D 0x400, =20 + /* + * Request for secure discard + */ + BDRV_REQ_SECDISCARD =3D 0x800, + /* Mask of valid flags */ BDRV_REQ_MASK =3D 0x7ff, } BdrvRequestFlags; @@ -122,6 +127,7 @@ typedef struct HDGeometry { #define BDRV_O_NO_IO 0x10000 /* don't initialize for I/O */ #define BDRV_O_AUTO_RDONLY 0x20000 /* degrade to read-only if opening read= -write fails */ #define BDRV_O_IO_URING 0x40000 /* use io_uring instead of the thread p= ool */ +#define BDRV_O_SECDISCARD 0x80000 /* guest SECDISCARD operations */ =20 #define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH) =20 @@ -134,6 +140,7 @@ typedef struct HDGeometry { #define BDRV_OPT_READ_ONLY "read-only" #define BDRV_OPT_AUTO_READ_ONLY "auto-read-only" #define BDRV_OPT_DISCARD "discard" +#define BDRV_OPT_SECDISCARD "secdiscard" #define BDRV_OPT_FORCE_SHARE "force-share" =20 =20 @@ -370,6 +377,7 @@ int bdrv_drop_filter(BlockDriverState *bs, Error **errp= ); int bdrv_parse_aio(const char *mode, int *flags); int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough= ); int bdrv_parse_discard_flags(const char *mode, int *flags); +int bdrv_parse_secdiscard_flags(const char *mode, int *flags, Error **errp= ); BdrvChild *bdrv_open_child(const char *filename, QDict *options, const char *bdref_key, BlockDriverState* parent, @@ -513,8 +521,9 @@ void bdrv_drain_all(void); cond); }) =20 int generated_co_wrapper bdrv_pdiscard(BdrvChild *child, int64_t offset, - int64_t bytes); -int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); + int64_t bytes, BdrvRequestFlags fla= gs); +int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes, + BdrvRequestFlags flags); int bdrv_has_zero_init_1(BlockDriverState *bs); int bdrv_has_zero_init(BlockDriverState *bs); bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); diff --git a/include/block/block_int.h b/include/block/block_int.h index f4c75e8ba9..773e5131d4 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -303,7 +303,7 @@ struct BlockDriver { int coroutine_fn (*bdrv_co_pwrite_zeroes)(BlockDriverState *bs, int64_t offset, int64_t bytes, BdrvRequestFlags flags); int coroutine_fn (*bdrv_co_pdiscard)(BlockDriverState *bs, - int64_t offset, int64_t bytes); + int64_t offset, int64_t bytes, BdrvRequestFlags flags); =20 /* Map [offset, offset + nbytes) range onto a child of @bs to copy fro= m, * and invoke bdrv_co_copy_range_from(child, ...), or invoke diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h index 21fc10c4c9..d9138277e3 100644 --- a/include/block/raw-aio.h +++ b/include/block/raw-aio.h @@ -29,6 +29,7 @@ #define QEMU_AIO_WRITE_ZEROES 0x0020 #define QEMU_AIO_COPY_RANGE 0x0040 #define QEMU_AIO_TRUNCATE 0x0080 +#define QEMU_AIO_SECDISCARD 0x0100 #define QEMU_AIO_TYPE_MASK \ (QEMU_AIO_READ | \ QEMU_AIO_WRITE | \ @@ -37,7 +38,8 @@ QEMU_AIO_DISCARD | \ QEMU_AIO_WRITE_ZEROES | \ QEMU_AIO_COPY_RANGE | \ - QEMU_AIO_TRUNCATE) + QEMU_AIO_TRUNCATE | \ + QEMU_AIO_SECDISCARD) =20 /* AIO flags */ #define QEMU_AIO_MISALIGNED 0x1000 diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index e5e1524f06..53630ff791 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -179,6 +179,7 @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t = offset, BlockAIOCB *blk_aio_flush(BlockBackend *blk, BlockCompletionFunc *cb, void *opaque); BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, int64_t offset, int64_t by= tes, + BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); void blk_aio_cancel(BlockAIOCB *acb); void blk_aio_cancel_async(BlockAIOCB *acb); diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothr= ead.c index aea660aeed..fa0a1b0fed 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -48,7 +48,8 @@ static int coroutine_fn bdrv_test_co_pwritev(BlockDriverS= tate *bs, } =20 static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs, - int64_t offset, int64_t byte= s) + int64_t offset, int64_t byte= s, + BdrvRequestFlags flags) { return 0; } @@ -164,16 +165,16 @@ static void test_sync_op_pdiscard(BdrvChild *c) =20 /* Normal success path */ c->bs->open_flags |=3D BDRV_O_UNMAP; - ret =3D bdrv_pdiscard(c, 0, 512); + ret =3D bdrv_pdiscard(c, 0, 512, 0); g_assert_cmpint(ret, =3D=3D, 0); =20 /* Early success: UNMAP not supported */ c->bs->open_flags &=3D ~BDRV_O_UNMAP; - ret =3D bdrv_pdiscard(c, 0, 512); + ret =3D bdrv_pdiscard(c, 0, 512, 0); g_assert_cmpint(ret, =3D=3D, 0); =20 /* Early error: Negative offset */ - ret =3D bdrv_pdiscard(c, -2, 512); + ret =3D bdrv_pdiscard(c, -2, 512, 0); g_assert_cmpint(ret, =3D=3D, -EIO); } =20 --=20 2.25.1 From nobody Sun Feb 8 19:48:42 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=intel.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 16369522062181018.9730763942767; Sun, 14 Nov 2021 20:56:46 -0800 (PST) Received: from localhost ([::1]:34528 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mmU2v-0008MK-48 for importer@patchew.org; Sun, 14 Nov 2021 23:56:45 -0500 Received: from eggs.gnu.org ([209.51.188.92]:41212) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mmU0b-00050E-Gz; Sun, 14 Nov 2021 23:54:21 -0500 Received: from mga17.intel.com ([192.55.52.151]:4467) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mmU0Y-0008Ol-Rm; Sun, 14 Nov 2021 23:54:20 -0500 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Nov 2021 20:54:17 -0800 Received: from yadong-antec.sh.intel.com ([10.239.158.125]) by fmsmga001.fm.intel.com with ESMTP; 14 Nov 2021 20:54:14 -0800 X-IronPort-AV: E=McAfee;i="6200,9189,10168"; a="214101235" X-IronPort-AV: E=Sophos;i="5.87,235,1631602800"; d="scan'208";a="214101235" X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.87,235,1631602800"; d="scan'208";a="644710452" From: yadong.qi@intel.com To: qemu-block@nongnu.org, kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com, fam@euphon.net, mst@redhat.com Subject: [PATCH 2/2] virtio-blk: support BLKSECDISCARD Date: Mon, 15 Nov 2021 12:52:00 +0800 Message-Id: <20211115045200.3567293-3-yadong.qi@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211115045200.3567293-1-yadong.qi@intel.com> References: <20211115045200.3567293-1-yadong.qi@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=192.55.52.151; envelope-from=yadong.qi@intel.com; helo=mga17.intel.com X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, 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: , Cc: kai.z.wang@intel.com, yadong.qi@intel.com, luhai.chen@intel.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZM-MESSAGEID: 1636952207370100001 Content-Type: text/plain; charset="utf-8" From: Yadong Qi Add new virtio feature: VIRTIO_BLK_F_SECDISCARD. Add new virtio command: VIRTIO_BLK_T_SECDISCARD. This feature is disabled by default, it will check the backend bs->open_flags & BDRV_O_SECDISCARD, enable it if BDRV_O_SECDISCARD is supported. Signed-off-by: Yadong Qi --- hw/block/virtio-blk.c | 26 +++++++++++++++++---- include/standard-headers/linux/virtio_blk.h | 4 ++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index dbc4c5a3cd..7bc3484521 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -536,7 +536,8 @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev, } =20 static uint8_t virtio_blk_handle_discard_write_zeroes(VirtIOBlockReq *req, - struct virtio_blk_discard_write_zeroes *dwz_hdr, bool is_write_zeroes) + struct virtio_blk_discard_write_zeroes *dwz_hdr, bool is_write_zeroes, + bool is_secdiscard) { VirtIOBlock *s =3D req->dev; VirtIODevice *vdev =3D VIRTIO_DEVICE(s); @@ -577,8 +578,8 @@ static uint8_t virtio_blk_handle_discard_write_zeroes(V= irtIOBlockReq *req, goto err; } =20 + int blk_aio_flags =3D 0; if (is_write_zeroes) { /* VIRTIO_BLK_T_WRITE_ZEROES */ - int blk_aio_flags =3D 0; =20 if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) { blk_aio_flags |=3D BDRV_REQ_MAY_UNMAP; @@ -600,7 +601,12 @@ static uint8_t virtio_blk_handle_discard_write_zeroes(= VirtIOBlockReq *req, goto err; } =20 - blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes, 0, + if (is_secdiscard) { + blk_aio_flags |=3D BDRV_REQ_SECDISCARD; + } + + blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes, + blk_aio_flags, virtio_blk_discard_write_zeroes_complete, req); } =20 @@ -622,6 +628,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re= q, MultiReqBuffer *mrb) unsigned out_num =3D req->elem.out_num; VirtIOBlock *s =3D req->dev; VirtIODevice *vdev =3D VIRTIO_DEVICE(s); + bool is_secdiscard =3D false; =20 if (req->elem.out_num < 1 || req->elem.in_num < 1) { virtio_error(vdev, "virtio-blk missing headers"); @@ -722,6 +729,9 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re= q, MultiReqBuffer *mrb) * VIRTIO_BLK_T_OUT flag set. We masked this flag in the switch statem= ent, * so we must mask it for these requests, then we will check if it is = set. */ + case VIRTIO_BLK_T_SECDISCARD & ~VIRTIO_BLK_T_OUT: + is_secdiscard =3D true; + __attribute__((fallthrough)); case VIRTIO_BLK_T_DISCARD & ~VIRTIO_BLK_T_OUT: case VIRTIO_BLK_T_WRITE_ZEROES & ~VIRTIO_BLK_T_OUT: { @@ -752,7 +762,8 @@ static int virtio_blk_handle_request(VirtIOBlockReq *re= q, MultiReqBuffer *mrb) } =20 err_status =3D virtio_blk_handle_discard_write_zeroes(req, &dwz_hd= r, - is_write_zeroe= s); + is_write_zeroe= s, + is_secdiscard); if (err_status !=3D VIRTIO_BLK_S_OK) { virtio_blk_req_complete(req, err_status); virtio_blk_free_request(req); @@ -1201,6 +1212,11 @@ static void virtio_blk_device_realize(DeviceState *d= ev, Error **errp) return; } =20 + if (blk_get_flags(conf->conf.blk) & BDRV_O_SECDISCARD) + virtio_add_feature(&s->host_features, VIRTIO_BLK_F_SECDISCARD); + else + virtio_clear_feature(&s->host_features, VIRTIO_BLK_F_SECDISCARD); + if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_WRITE_ZEROES) && (!conf->max_write_zeroes_sectors || conf->max_write_zeroes_sectors > BDRV_REQUEST_MAX_SECTORS)) { @@ -1307,6 +1323,8 @@ static Property virtio_blk_properties[] =3D { conf.report_discard_granularity, true), DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features, VIRTIO_BLK_F_WRITE_ZEROES, true), + DEFINE_PROP_BIT64("secdiscard", VirtIOBlock, host_features, + VIRTIO_BLK_F_SECDISCARD, false), DEFINE_PROP_UINT32("max-discard-sectors", VirtIOBlock, conf.max_discard_sectors, BDRV_REQUEST_MAX_SECTORS), DEFINE_PROP_UINT32("max-write-zeroes-sectors", VirtIOBlock, diff --git a/include/standard-headers/linux/virtio_blk.h b/include/standard= -headers/linux/virtio_blk.h index 2dcc90826a..c55a07840c 100644 --- a/include/standard-headers/linux/virtio_blk.h +++ b/include/standard-headers/linux/virtio_blk.h @@ -40,6 +40,7 @@ #define VIRTIO_BLK_F_MQ 12 /* support more than one vq */ #define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */ #define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */ +#define VIRTIO_BLK_F_SECDISCARD 15 /* WRITE ZEROES is supported */ =20 /* Legacy feature bits */ #ifndef VIRTIO_BLK_NO_LEGACY @@ -153,6 +154,9 @@ struct virtio_blk_config { /* Write zeroes command */ #define VIRTIO_BLK_T_WRITE_ZEROES 13 =20 +/* Secure discard command */ +#define VIRTIO_BLK_T_SECDISCARD 14 + #ifndef VIRTIO_BLK_NO_LEGACY /* Barrier before this op. */ #define VIRTIO_BLK_T_BARRIER 0x80000000 --=20 2.25.1