get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.1/patches/2229021/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2229021,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229021/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260427170520.101242-4-kwolf@redhat.com/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/1.1/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20260427170520.101242-4-kwolf@redhat.com>",
    "date": "2026-04-27T17:05:19",
    "name": "[3/4] qcow2: Fix corruption on discard during write with COW",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "a060133e61d5b03d36e4bd2f3d8e310a158e5974",
    "submitter": {
        "id": 2714,
        "url": "http://patchwork.ozlabs.org/api/1.1/people/2714/?format=api",
        "name": "Kevin Wolf",
        "email": "kwolf@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260427170520.101242-4-kwolf@redhat.com/mbox/",
    "series": [
        {
            "id": 501688,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/501688/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=501688",
            "date": "2026-04-27T17:05:16",
            "name": "qcow2: Fix corruption on discard during write with COW",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/501688/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2229021/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2229021/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=Koo6UR3+;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g492W0cNCz1xvV\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 03:06:27 +1000 (AEST)",
            "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wHPPA-0007gX-8o; Mon, 27 Apr 2026 13:05:56 -0400",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <kwolf@redhat.com>) id 1wHPP8-0007cP-1x\n for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:54 -0400",
            "from us-smtp-delivery-124.mimecast.com ([170.10.129.124])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <kwolf@redhat.com>) id 1wHPP6-0006UG-6K\n for qemu-devel@nongnu.org; Mon, 27 Apr 2026 13:05:53 -0400",
            "from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-575-0cdDGZf3NhCmrnpO8Hgv1w-1; Mon,\n 27 Apr 2026 13:05:48 -0400",
            "from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id DB3491956059; Mon, 27 Apr 2026 17:05:46 +0000 (UTC)",
            "from merkur.fritz.box (unknown [10.44.49.22])\n by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id CF451180047F; Mon, 27 Apr 2026 17:05:44 +0000 (UTC)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1777309551;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=5mxm+H4XFJxx9sZcIhYP6Y+Z1xUv6tjNOfVcPbR28dE=;\n b=Koo6UR3+Q8J/5ZW6kch0iYA6ZkBQ84jgaAmQKCe1D14EoKEZpsMA4JnzMNxQxj8H2NjGaZ\n XUvDFrPzwfIA9DnUv1pm/42/F+3ATyjdjAPWPyarsDwAqC9BumuXgVWfvYgxeRTo7w/qkg\n DJ9NG8zVMeeq3ZlefUEYu9LnPxSG2yE=",
        "X-MC-Unique": "0cdDGZf3NhCmrnpO8Hgv1w-1",
        "X-Mimecast-MFC-AGG-ID": "0cdDGZf3NhCmrnpO8Hgv1w_1777309547",
        "From": "Kevin Wolf <kwolf@redhat.com>",
        "To": "qemu-block@nongnu.org",
        "Cc": "kwolf@redhat.com, hreitz@redhat.com, den@openvz.org, stefanha@redhat.com,\n qemu-stable@nongnu.org, qemu-devel@nongnu.org",
        "Subject": "[PATCH 3/4] qcow2: Fix corruption on discard during write with COW",
        "Date": "Mon, 27 Apr 2026 19:05:19 +0200",
        "Message-ID": "<20260427170520.101242-4-kwolf@redhat.com>",
        "In-Reply-To": "<20260427170520.101242-1-kwolf@redhat.com>",
        "References": "<20260427170520.101242-1-kwolf@redhat.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.111",
        "Received-SPF": "pass client-ip=170.10.129.124; envelope-from=kwolf@redhat.com;\n helo=us-smtp-delivery-124.mimecast.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, DKIMWL_WL_HIGH=-0.001,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001,\n SPF_HELO_PASS=-0.001,\n 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": "qemu development <qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"
    },
    "content": "Most code in qcow2 that accesses (and potentially modifies) L2 tables\ndoes so while holding s->lock.\n\nThere is one exception, which is allocating writes. They hold the lock\ninitially while allocating clusters, but drop it for writing the guest\npayload before taking the lock again for updating the L2 tables. This\nallows concurrent requests that touch other parts of the image file to\ncontinue in parallel and is an important performance optimisation.\n\nHowever, this means that other requests that run while the lock is\ndropped for writing guest data must synchronise with the list of\nallocating requests in s->cluster_allocs and wait if they would overlap.\nFor writes, this is done in handle_dependencies(), but discard and write\nzeros operations neglect to synchronise with s->cluster_allocs.\n\nThis means that discard can free a cluster whose L2 entry will already\nbe modified in qcow2_alloc_cluster_link_l2() by a previously started\nwrite. In the case of a pre-allocated zero cluster that is in the\nprocess of being overwritten, this means that discard can lead to a\nsituation where the cluster is still mapped (because the write will\nrestore the L2 entry just without the zero flag), but its refcount has\nbeen decreased, resulting in a corrupted image.\n\nAdd the missing synchronisation to qcow2_cluster_discard() and\nqcow2_subcluster_zeroize() to fix the problem.\n\nCc: qemu-stable@nongnu.org\nReported-by: Denis V. Lunev <den@openvz.org>\nSigned-off-by: Kevin Wolf <kwolf@redhat.com>\n---\n block/qcow2-cluster.c | 52 ++++++++++++++++++++++++++++++++++++++++---\n 1 file changed, 49 insertions(+), 3 deletions(-)",
    "diff": "diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c\nindex c655bf6df42..8b1e80bd0b3 100644\n--- a/block/qcow2-cluster.c\n+++ b/block/qcow2-cluster.c\n@@ -1392,6 +1392,9 @@ count_single_write_clusters(BlockDriverState *bs, int nb_clusters,\n  * the same cluster. In this case we need to wait until the previous\n  * request has completed and updated the L2 table accordingly.\n  *\n+ * If allow_shortening == true, instead of waiting for a dependency, *cur_bytes\n+ * can be shortened so that the cluster allocations don't overlap.\n+ *\n  * Returns:\n  *   0       if there was no dependency. *cur_bytes indicates the number of\n  *           bytes from guest_offset that can be read before the next\n@@ -1403,7 +1406,9 @@ count_single_write_clusters(BlockDriverState *bs, int nb_clusters,\n  */\n static int coroutine_fn handle_dependencies(BlockDriverState *bs,\n                                             uint64_t guest_offset,\n-                                            uint64_t *cur_bytes, QCowL2Meta **m)\n+                                            uint64_t *cur_bytes,\n+                                            bool allow_shortening,\n+                                            QCowL2Meta **m)\n {\n     BDRVQcow2State *s = bs->opaque;\n     QCowL2Meta *old_alloc;\n@@ -1434,7 +1439,7 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,\n \n         /* Conflict */\n \n-        if (start < old_start) {\n+        if (start < old_start && allow_shortening) {\n             /* Stop at the start of a running allocation */\n             bytes = old_start - start;\n         } else {\n@@ -1469,6 +1474,29 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,\n     return 0;\n }\n \n+static void coroutine_mixed_fn wait_for_dependencies(BlockDriverState *bs,\n+                                                     uint64_t guest_offset,\n+                                                     uint64_t bytes)\n+{\n+    BDRVQcow2State *s = bs->opaque;\n+    QCowL2Meta *m = NULL;\n+    int ret;\n+\n+    /*\n+     * Discard has some non-coroutine callers (creating internal snapshots and\n+     * make empty). They are calling from qemu-img or in a drained section, so\n+     * we know that no writes can be in progress.\n+     */\n+    if (!qemu_in_coroutine()) {\n+        assert(QLIST_EMPTY(&s->cluster_allocs));\n+        return;\n+    }\n+\n+    do {\n+        ret = handle_dependencies(bs, guest_offset, &bytes, false, &m);\n+    } while (ret == -EAGAIN);\n+}\n+\n /*\n  * Checks how many already allocated clusters that don't require a new\n  * allocation there are at the given guest_offset (up to *bytes).\n@@ -1840,7 +1868,7 @@ again:\n          *         the right synchronisation between the in-flight request and\n          *         the new one.\n          */\n-        ret = handle_dependencies(bs, start, &cur_bytes, m);\n+        ret = handle_dependencies(bs, start, &cur_bytes, true, m);\n         if (ret == -EAGAIN) {\n             /* Currently handle_dependencies() doesn't yield if we already had\n              * an allocation. If it did, we would have to clean up the L2Meta\n@@ -2000,6 +2028,15 @@ int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,\n     int64_t cleared;\n     int ret;\n \n+    /*\n+     * If we're touching a cluster for which allocating writes are in flight,\n+     * wait for them to complete to avoid conflicting metadata updates.\n+     *\n+     * We don't need to allocate a QCowL2Meta for the discard operation because\n+     * s->lock is held for the duration of the whole operation.\n+     */\n+    wait_for_dependencies(bs, offset, bytes);\n+\n     /* Caller must pass aligned values, except at image end */\n     assert(QEMU_IS_ALIGNED(offset, s->cluster_size));\n     assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||\n@@ -2160,6 +2197,15 @@ int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset,\n     int64_t cleared;\n     int ret;\n \n+    /*\n+     * If we're touching a cluster for which allocating writes are in flight,\n+     * wait for them to complete to avoid conflicting metadata updates.\n+     *\n+     * We don't need to allocate a QCowL2Meta for the zeroize operation because\n+     * s->lock is held for the duration of the whole operation.\n+     */\n+    wait_for_dependencies(bs, offset, bytes);\n+\n     /* If we have to stay in sync with an external data file, zero out\n      * s->data_file first. */\n     if (data_file_is_raw(bs)) {\n",
    "prefixes": [
        "3/4"
    ]
}