get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 810036,
    "url": "http://patchwork.ozlabs.org/api/patches/810036/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20170905092230.8243-3-berrange@redhat.com/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/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": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20170905092230.8243-3-berrange@redhat.com>",
    "list_archive_url": null,
    "date": "2017-09-05T09:22:23",
    "name": "[PULL,v1,2/9] tests: Add test-listen - a stress test for QEMU socket listen",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "483704d416450c39dc88bc33086d65abd8b08d97",
    "submitter": {
        "id": 2694,
        "url": "http://patchwork.ozlabs.org/api/people/2694/?format=api",
        "name": "Daniel P. Berrangé",
        "email": "berrange@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20170905092230.8243-3-berrange@redhat.com/mbox/",
    "series": [
        {
            "id": 1527,
            "url": "http://patchwork.ozlabs.org/api/series/1527/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=1527",
            "date": "2017-09-05T09:22:21",
            "name": "[PULL,v1,1/9] io: fix temp directory used by test-io-channel-tls test",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/1527/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/810036/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/810036/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)",
            "ext-mx09.extmail.prod.ext.phx2.redhat.com;\n\tdmarc=none (p=none dis=none) header.from=redhat.com",
            "ext-mx09.extmail.prod.ext.phx2.redhat.com;\n\tspf=fail smtp.mailfrom=berrange@redhat.com"
        ],
        "Received": [
            "from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xmhCL6G1cz9sNr\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue,  5 Sep 2017 19:25:34 +1000 (AEST)",
            "from localhost ([::1]:57670 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dpA6u-0002vR-Ry\n\tfor incoming@patchwork.ozlabs.org; Tue, 05 Sep 2017 05:25:32 -0400",
            "from eggs.gnu.org ([2001:4830:134:3::10]:41219)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <berrange@redhat.com>) id 1dpA4H-0001De-5Z\n\tfor qemu-devel@nongnu.org; Tue, 05 Sep 2017 05:22:54 -0400",
            "from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <berrange@redhat.com>) id 1dpA46-0002gv-AS\n\tfor qemu-devel@nongnu.org; Tue, 05 Sep 2017 05:22:49 -0400",
            "from mx1.redhat.com ([209.132.183.28]:45188)\n\tby eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.71) (envelope-from <berrange@redhat.com>) id 1dpA46-0002gQ-1M\n\tfor qemu-devel@nongnu.org; Tue, 05 Sep 2017 05:22:38 -0400",
            "from smtp.corp.redhat.com\n\t(int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby mx1.redhat.com (Postfix) with ESMTPS id 12A124A6F1;\n\tTue,  5 Sep 2017 09:22:37 +0000 (UTC)",
            "from t460.redhat.com (unknown [10.33.36.63])\n\tby smtp.corp.redhat.com (Postfix) with ESMTP id E1F4260BF1;\n\tTue,  5 Sep 2017 09:22:35 +0000 (UTC)"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.3.2 mx1.redhat.com 12A124A6F1",
        "From": "\"Daniel P. Berrange\" <berrange@redhat.com>",
        "To": "qemu-devel@nongnu.org",
        "Date": "Tue,  5 Sep 2017 10:22:23 +0100",
        "Message-Id": "<20170905092230.8243-3-berrange@redhat.com>",
        "In-Reply-To": "<20170905092230.8243-1-berrange@redhat.com>",
        "References": "<20170905092230.8243-1-berrange@redhat.com>",
        "X-Scanned-By": "MIMEDefang 2.79 on 10.5.11.13",
        "X-Greylist": "Sender IP whitelisted, not delayed by milter-greylist-4.5.16\n\t(mx1.redhat.com [10.5.110.38]);\n\tTue, 05 Sep 2017 09:22:37 +0000 (UTC)",
        "X-detected-operating-system": "by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic]\n\t[fuzzy]",
        "X-Received-From": "209.132.183.28",
        "Subject": "[Qemu-devel] [PULL v1 2/9] tests: Add test-listen - a stress test\n\tfor QEMU socket listen",
        "X-BeenThere": "qemu-devel@nongnu.org",
        "X-Mailman-Version": "2.1.21",
        "Precedence": "list",
        "List-Id": "<qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<http://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\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Cc": "Peter Maydell <peter.maydell@linaro.org>,\n\tKnut Omang <knut.omang@oracle.com>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"
    },
    "content": "From: Knut Omang <knut.omang@oracle.com>\n\nThere's a potential race condition between multiple bind()'s\nattempting to bind to the same port, which occasionally\nallows more than one bind to succeed against the same port.\n\nWhen a subsequent listen() call is made with the same socket\nonly one will succeed.\n\nThe current QEMU code does however not take this situation into account\nand the listen will cause the code to break out and fail even\nwhen there are actually available ports to use.\n\nThis test exposes two subtests:\n\n/socket/listen-serial\n/socket/listen-compete\n\nThe \"compete\" subtest creates a number of threads and have them all trying to bind\nto the same port with a large enough offset input to\nallow all threads to get it's own port.\nThe \"serial\" subtest just does the same, except in series in a\nsingle thread.\n\nThe serial version passes, probably in most versions of QEMU.\n\nThe parallel version exposes the problem in a relatively reliable way,\neg. it fails a majority of times, but not with a 100% rate, occasional\npasses can be seen. Nevertheless this is quite good given that\nthe bug was tricky to reproduce and has been left undetected for\na while.\n\nThe problem seems to be present in all versions of QEMU.\n\nThe original failure scenario occurred with VNC port allocation\nin a traditional Xen based build, in different code\nbut with similar functionality.\n\nReported-by: Bhavesh Davda <bhavesh.davda@oracle.com>\nSigned-off-by: Knut Omang <knut.omang@oracle.com>\nReviewed-by: Yuval Shaia <yuval.shaia@oracle.com>\nReviewed-by: Bhavesh Davda <bhavesh.davda@oracle.com>\nReviewed-by: Girish Moodalbail <girish.moodalbail@oracle.com>\nSigned-off-by: Daniel P. Berrange <berrange@redhat.com>\n---\n tests/Makefile.include |   2 +\n tests/test-listen.c    | 253 +++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 255 insertions(+)\n create mode 100644 tests/test-listen.c",
    "diff": "diff --git a/tests/Makefile.include b/tests/Makefile.include\nindex f08b7418f0..a231754517 100644\n--- a/tests/Makefile.include\n+++ b/tests/Makefile.include\n@@ -151,6 +151,7 @@ check-unit-y += tests/test-bufferiszero$(EXESUF)\n gcov-files-check-bufferiszero-y = util/bufferiszero.c\n check-unit-y += tests/test-uuid$(EXESUF)\n check-unit-y += tests/ptimer-test$(EXESUF)\n+#check-unit-y += tests/test-listen$(EXESUF)\n gcov-files-ptimer-test-y = hw/core/ptimer.c\n check-unit-y += tests/test-qapi-util$(EXESUF)\n gcov-files-test-qapi-util-y = qapi/qapi-util.c\n@@ -796,6 +797,7 @@ tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o\n tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y)\n tests/numa-test$(EXESUF): tests/numa-test.o\n tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o\n+tests/test-listen$(EXESUF): tests/test-listen.o $(test-util-obj-y)\n \n tests/migration/stress$(EXESUF): tests/migration/stress.o\n \t$(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,\"LINK\",\"$(TARGET_DIR)$@\")\ndiff --git a/tests/test-listen.c b/tests/test-listen.c\nnew file mode 100644\nindex 0000000000..03c4c8f03b\n--- /dev/null\n+++ b/tests/test-listen.c\n@@ -0,0 +1,253 @@\n+/*\n+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.\n+ *    Author: Knut Omang <knut.omang@oracle.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 or later\n+ * as published by the Free Software Foundation.\n+ *\n+ * Test parallel port listen configuration with\n+ * dynamic port allocation\n+ */\n+\n+#include \"qemu/osdep.h\"\n+#include \"libqtest.h\"\n+#include \"qemu-common.h\"\n+#include \"qemu/thread.h\"\n+#include \"qemu/sockets.h\"\n+#include \"qapi/error.h\"\n+\n+#define NAME_LEN 1024\n+#define PORT_LEN 16\n+\n+struct thr_info {\n+    QemuThread thread;\n+    int to_port;\n+    bool ipv4;\n+    bool ipv6;\n+    int got_port;\n+    int eno;\n+    int fd;\n+    const char *errstr;\n+    char hostname[NAME_LEN + 1];\n+    char port[PORT_LEN + 1];\n+};\n+\n+\n+/* These two functions taken from test-io-channel-socket.c */\n+static int check_bind(const char *hostname, bool *has_proto)\n+{\n+    int fd = -1;\n+    struct addrinfo ai, *res = NULL;\n+    int rc;\n+    int ret = -1;\n+\n+    memset(&ai, 0, sizeof(ai));\n+    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;\n+    ai.ai_family = AF_UNSPEC;\n+    ai.ai_socktype = SOCK_STREAM;\n+\n+    /* lookup */\n+    rc = getaddrinfo(hostname, NULL, &ai, &res);\n+    if (rc != 0) {\n+        if (rc == EAI_ADDRFAMILY ||\n+            rc == EAI_FAMILY) {\n+            *has_proto = false;\n+            goto done;\n+        }\n+        goto cleanup;\n+    }\n+\n+    fd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);\n+    if (fd < 0) {\n+        goto cleanup;\n+    }\n+\n+    if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {\n+        if (errno == EADDRNOTAVAIL) {\n+            *has_proto = false;\n+            goto done;\n+        }\n+        goto cleanup;\n+    }\n+\n+    *has_proto = true;\n+ done:\n+    ret = 0;\n+\n+ cleanup:\n+    if (fd != -1) {\n+        close(fd);\n+    }\n+    if (res) {\n+        freeaddrinfo(res);\n+    }\n+    return ret;\n+}\n+\n+static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)\n+{\n+    if (check_bind(\"127.0.0.1\", has_ipv4) < 0) {\n+        return -1;\n+    }\n+    if (check_bind(\"::1\", has_ipv6) < 0) {\n+        return -1;\n+    }\n+\n+    return 0;\n+}\n+\n+static void *listener_thread(void *arg)\n+{\n+    struct thr_info *thr = (struct thr_info *)arg;\n+    SocketAddress addr = {\n+        .type = SOCKET_ADDRESS_TYPE_INET,\n+        .u = {\n+            .inet = {\n+                .host = thr->hostname,\n+                .port = thr->port,\n+                .has_ipv4 = thr->ipv4,\n+                .ipv4 = thr->ipv4,\n+                .has_ipv6 = thr->ipv6,\n+                .ipv6 = thr->ipv6,\n+                .has_to = true,\n+                .to = thr->to_port,\n+            },\n+        },\n+    };\n+    Error *err = NULL;\n+    int fd;\n+\n+    fd = socket_listen(&addr, &err);\n+    if (fd < 0) {\n+        thr->eno = errno;\n+        thr->errstr = error_get_pretty(err);\n+    } else {\n+        struct sockaddr_in a;\n+        socklen_t a_len = sizeof(a);\n+        g_assert_cmpint(getsockname(fd, (struct sockaddr *)&a, &a_len), ==, 0);\n+        thr->got_port = ntohs(a.sin_port);\n+        thr->fd = fd;\n+    }\n+    return arg;\n+}\n+\n+\n+static void listen_compete_nthr(bool threaded, int nthreads,\n+                                int start_port, int max_offset,\n+                                bool ipv4, bool ipv6)\n+{\n+    int i;\n+    int failed_listens = 0;\n+    struct thr_info *thr = g_new0(struct thr_info, nthreads);\n+    int used[max_offset + 1];\n+\n+    memset(used, 0, sizeof(used));\n+    for (i = 0; i < nthreads; i++) {\n+        snprintf(thr[i].port, PORT_LEN, \"%d\", start_port);\n+        strcpy(thr[i].hostname, \"localhost\");\n+        thr[i].to_port = start_port + max_offset;\n+        thr[i].ipv4 = ipv4;\n+        thr[i].ipv6 = ipv6;\n+    }\n+\n+    for (i = 0; i < nthreads; i++) {\n+        if (threaded) {\n+            qemu_thread_create(&thr[i].thread, \"listener\",\n+                               listener_thread, &thr[i],\n+                               QEMU_THREAD_JOINABLE);\n+        } else {\n+            listener_thread(&thr[i]);\n+        }\n+    }\n+\n+    if (threaded) {\n+        for (i = 0; i < nthreads; i++) {\n+            qemu_thread_join(&thr[i].thread);\n+        }\n+    }\n+    for (i = 0; i < nthreads; i++) {\n+        if (thr[i].got_port) {\n+            closesocket(thr[i].fd);\n+        }\n+    }\n+\n+    for (i = 0; i < nthreads; i++) {\n+        if (thr[i].eno != 0) {\n+            const char *m;\n+            g_printerr(\"** Failed to assign a port to thread %d (errno = %d)\\n\",\n+                   i, thr[i].eno);\n+            /* This is what we are interested in capturing -\n+             * catch and report details if something unexpected happens:\n+             */\n+            m = strstr(thr[i].errstr, \"Failed to listen on socket\");\n+            if (m != NULL) {\n+                g_assert_cmpstr(thr[i].errstr, ==,\n+                    \"Failed to listen on socket: Address already in use\");\n+            }\n+            failed_listens++;\n+        } else {\n+            int assigned_port = thr[i].got_port;\n+            g_assert_cmpint(assigned_port, <= , thr[i].to_port);\n+            g_assert_cmpint(used[assigned_port - start_port], == , 0);\n+        }\n+    }\n+    g_assert_cmpint(failed_listens, ==, 0);\n+    g_free(thr);\n+}\n+\n+\n+static void listen_compete_ipv4(void)\n+{\n+    listen_compete_nthr(true, 200, 5920, 300, true, false);\n+}\n+\n+static void listen_serial_ipv4(void)\n+{\n+    listen_compete_nthr(false, 200, 6300, 300, true, false);\n+}\n+\n+static void listen_compete_ipv6(void)\n+{\n+    listen_compete_nthr(true, 200, 5920, 300, true, false);\n+}\n+\n+static void listen_serial_ipv6(void)\n+{\n+    listen_compete_nthr(false, 200, 6300, 300, false, true);\n+}\n+\n+static void listen_compete_gen(void)\n+{\n+    listen_compete_nthr(true, 200, 5920, 300, true, true);\n+}\n+\n+static void listen_serial_gen(void)\n+{\n+    listen_compete_nthr(false, 200, 6300, 300, true, true);\n+}\n+\n+\n+int main(int argc, char **argv)\n+{\n+    bool has_ipv4, has_ipv6;\n+    g_test_init(&argc, &argv, NULL);\n+\n+    if (check_protocol_support(&has_ipv4, &has_ipv6) < 0) {\n+        return 1;\n+    }\n+\n+    if (has_ipv4) {\n+        g_test_add_func(\"/socket/listen-serial/ipv4\", listen_serial_ipv4);\n+        g_test_add_func(\"/socket/listen-compete/ipv4\", listen_compete_ipv4);\n+    }\n+    if (has_ipv6) {\n+        g_test_add_func(\"/socket/listen-serial/ipv6\", listen_serial_ipv6);\n+        g_test_add_func(\"/socket/listen-compete/ipv6\", listen_compete_ipv6);\n+    }\n+    if (has_ipv4 && has_ipv6) {\n+        g_test_add_func(\"/socket/listen-serial/generic\", listen_serial_gen);\n+        g_test_add_func(\"/socket/listen-compete/generic\", listen_compete_gen);\n+    }\n+    return g_test_run();\n+}\n",
    "prefixes": [
        "PULL",
        "v1",
        "2/9"
    ]
}