From patchwork Thu Mar 26 21:24:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Schoenebeck X-Patchwork-Id: 1262383 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=crudebyte.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=crudebyte.com header.i=@crudebyte.com header.a=rsa-sha256 header.s=lizzy header.b=OlT2j1mC; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 48pKRX66dkz9sR4 for ; Fri, 27 Mar 2020 09:29:44 +1100 (AEDT) Received: from localhost ([::1]:33544 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jHb0Q-0005El-Nd for incoming@patchwork.ozlabs.org; Thu, 26 Mar 2020 18:29:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:53770) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <9af3bcdb597c83dc305a9fbc40c903a93d23293a@lizzy.crudebyte.com>) id 1jHb04-0005BZ-IS for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:29:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from <9af3bcdb597c83dc305a9fbc40c903a93d23293a@lizzy.crudebyte.com>) id 1jHb03-0006Ft-96 for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:29:20 -0400 Received: from lizzy.crudebyte.com ([91.194.90.13]:37977) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from <9af3bcdb597c83dc305a9fbc40c903a93d23293a@lizzy.crudebyte.com>) id 1jHb03-0005AE-2B for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:29:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=crudebyte.com; s=lizzy; h=Cc:To:Subject:Date:From:References:In-Reply-To: Message-Id:Content-Type:Content-Transfer-Encoding:MIME-Version:Content-ID: Content-Description; bh=IezmcX2Zz1GFPAfr+8apNBJ7XzlcmwBnC7ZbeGtNK9Q=; b=OlT2j 1mCI5fBJi9Q9cKoUyCroKNGdOP4VIfplf3IoAr8cWltl4yFcRQv0MmUDHUZ8NNKajwbPoSETImEiI 86LHPnHuheP3blskkPGhTPwZpYmouvXsLMW8EbfUJkPDQGbwB4iFw4a0cyddZpZg0kQNPNMap+qVD txRQgNLHpNzTWXdb2Q4oflw2a2ifk20SwfHNqEJbQUi9azkcaE/jo5Ccy3dzNZU79P8z7Jrb6DM/p IjyPG9PQgcRZkOisBvUNSvaV5fqFiTVGRIODH3sMuLn9SQrSDv5k+eP9Uxe4c1WsyKiOmKUAJjGhQ luA8BZ+wEknS/AcEd3lIkJNYRnXtQ==; Message-Id: <9af3bcdb597c83dc305a9fbc40c903a93d23293a.1585258105.git.qemu_oss@crudebyte.com> In-Reply-To: References: From: Christian Schoenebeck Date: Thu, 26 Mar 2020 22:24:16 +0100 Subject: [PATCH v5 1/6] tests/virtio-9p: added split readdir tests To: qemu-devel@nongnu.org Cc: Greg Kurz X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 91.194.90.13 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The previous, already existing 'basic' readdir test simply used a 'count' parameter big enough to retrieve all directory entries with a single Treaddir request. In the 3 new 'split' readdir tests added by this patch, directory entries are retrieved, split over several Treaddir requests by picking small 'count' parameters which force the server to truncate the response. So the test client sends as many Treaddir requests as necessary to get all directory entries. The following 3 new tests are added (executed in this sequence): 1. Split readdir test with count=512 2. Split readdir test with count=256 3. Split readdir test with count=128 This test case sequence is chosen because the smaller the 'count' value, the higher the chance of errors in case of implementation bugs on server side. Signed-off-by: Christian Schoenebeck --- tests/qtest/virtio-9p-test.c | 108 +++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c index 2167322985..de30b717b6 100644 --- a/tests/qtest/virtio-9p-test.c +++ b/tests/qtest/virtio-9p-test.c @@ -578,6 +578,7 @@ static bool fs_dirents_contain_name(struct V9fsDirent *e, const char* name) return false; } +/* basic readdir test where reply fits into a single response message */ static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; @@ -631,6 +632,89 @@ static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc) g_free(wnames[0]); } +/* readdir test where overall request is split over several messages */ +static void fs_readdir_split(void *obj, void *data, QGuestAllocator *t_alloc, + uint32_t count) +{ + QVirtio9P *v9p = obj; + alloc = t_alloc; + char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; + uint16_t nqid; + v9fs_qid qid; + uint32_t nentries, npartialentries; + struct V9fsDirent *entries, *tail, *partialentries; + P9Req *req; + int fid; + uint64_t offset; + + fs_attach(v9p, NULL, t_alloc); + + fid = 1; + offset = 0; + entries = NULL; + nentries = 0; + tail = NULL; + + req = v9fs_twalk(v9p, 0, fid, 1, wnames, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rwalk(req, &nqid, NULL); + g_assert_cmpint(nqid, ==, 1); + + req = v9fs_tlopen(v9p, fid, O_DIRECTORY, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rlopen(req, &qid, NULL); + + /* + * send as many Treaddir requests as required to get all directory + * entries + */ + while (true) { + npartialentries = 0; + partialentries = NULL; + + req = v9fs_treaddir(v9p, fid, offset, count, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rreaddir(req, &count, &npartialentries, &partialentries); + if (npartialentries > 0 && partialentries) { + if (!entries) { + entries = partialentries; + nentries = npartialentries; + tail = partialentries; + } else { + tail->next = partialentries; + nentries += npartialentries; + } + while (tail->next) { + tail = tail->next; + } + offset = tail->offset; + } else { + break; + } + } + + g_assert_cmpint( + nentries, ==, + QTEST_V9FS_SYNTH_READDIR_NFILES + 2 /* "." and ".." */ + ); + + /* + * Check all file names exist in returned entries, ignore their order + * though. + */ + g_assert_cmpint(fs_dirents_contain_name(entries, "."), ==, true); + g_assert_cmpint(fs_dirents_contain_name(entries, ".."), ==, true); + for (int i = 0; i < QTEST_V9FS_SYNTH_READDIR_NFILES; ++i) { + char *name = g_strdup_printf(QTEST_V9FS_SYNTH_READDIR_FILE, i); + g_assert_cmpint(fs_dirents_contain_name(entries, name), ==, true); + g_free(name); + } + + v9fs_free_dirents(entries); + + g_free(wnames[0]); +} + static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; @@ -793,6 +877,24 @@ static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc) g_free(wnames[0]); } +static void fs_readdir_split_128(void *obj, void *data, + QGuestAllocator *t_alloc) +{ + fs_readdir_split(obj, data, t_alloc, 128); +} + +static void fs_readdir_split_256(void *obj, void *data, + QGuestAllocator *t_alloc) +{ + fs_readdir_split(obj, data, t_alloc, 256); +} + +static void fs_readdir_split_512(void *obj, void *data, + QGuestAllocator *t_alloc) +{ + fs_readdir_split(obj, data, t_alloc, 512); +} + static void register_virtio_9p_test(void) { qos_add_test("config", "virtio-9p", pci_config, NULL); @@ -810,6 +912,12 @@ static void register_virtio_9p_test(void) qos_add_test("fs/flush/ignored", "virtio-9p", fs_flush_ignored, NULL); qos_add_test("fs/readdir/basic", "virtio-9p", fs_readdir, NULL); + qos_add_test("fs/readdir/split_512", "virtio-9p", + fs_readdir_split_512, NULL); + qos_add_test("fs/readdir/split_256", "virtio-9p", + fs_readdir_split_256, NULL); + qos_add_test("fs/readdir/split_128", "virtio-9p", + fs_readdir_split_128, NULL); } libqos_init(register_virtio_9p_test); From patchwork Thu Mar 26 21:24:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Schoenebeck X-Patchwork-Id: 1262388 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=crudebyte.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=crudebyte.com header.i=@crudebyte.com header.a=rsa-sha256 header.s=lizzy header.b=lbTBwCWT; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 48pKTd1Fcdz9sR4 for ; Fri, 27 Mar 2020 09:31:33 +1100 (AEDT) Received: from localhost ([::1]:33588 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jHb2A-0007Cq-R4 for incoming@patchwork.ozlabs.org; Thu, 26 Mar 2020 18:31:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:55798) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jHb15-0006ek-A2 for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:30:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jHb13-0007ZC-Vv for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:30:23 -0400 Received: from lizzy.crudebyte.com ([91.194.90.13]:60355) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jHb13-0006G6-Or for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:30:21 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=crudebyte.com; s=lizzy; h=Cc:To:Subject:Date:From:References:In-Reply-To: Message-Id:Content-Type:Content-Transfer-Encoding:MIME-Version:Content-ID: Content-Description; bh=YBRAdZSum7slsAPGovqqlyFqpgUjqJhoi03R04g10bk=; b=lbTBw CWT0n02DHIYTX3FR5TnpEPETUKcriFZiMarMLKCuV2DWKxg0KUrd4tkkCjEcIGdLk+5EBux+ZpPZw llqCfefva1zj9yyHiWXC6/YgAKFlrpb7SOnucVcpiFy9wE5FVvauWJvuWd0mZUGqXopaBwzu/dTGn b9DfbdJI+2F83tPdAwZjv96dZMUrXBpqE61n+oQQW4J7TbyyVetb/GZw4rPAJWFhO6sMAI/l9e3Pm 5hPdkIg/j3tmcaxPyhRTIbezUHEqi8lC70GMp75jeJ/iPinut07cTkLl/gCySnSH+Sjth9uEpbAIa pTRDkAzrzVo41PQo1fEJqEScN6UZQ==; Message-Id: In-Reply-To: References: From: Christian Schoenebeck Date: Thu, 26 Mar 2020 22:24:37 +0100 Subject: [PATCH v5 2/6] 9pfs readdir: rename max_count -> maxsize To: qemu-devel@nongnu.org Cc: Greg Kurz X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 91.194.90.13 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Although the 9p protocol specs use the term 'max_count' as argument for Treaddir, let's rename our variables for that to 'maxsize' instead, because 'max_count' is semantically completely wrong. This variable does not count integral entries, it is rather a maximum size (in bytes) of the destination (response) buffer being filled. Since this is just refactoring, hence this patch does not introduce any behaviour change at all. Signed-off-by: Christian Schoenebeck --- hw/9pfs/9p.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 9e046f7acb..1aff4f1fa8 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -2162,7 +2162,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu, V9fsFidState *fidp, - uint32_t max_count) + uint32_t maxsize) { V9fsPath path; V9fsStat v9stat; @@ -2199,7 +2199,7 @@ static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu, if (err < 0) { break; } - if ((count + v9stat.size + 2) > max_count) { + if ((count + v9stat.size + 2) > maxsize) { v9fs_readdir_unlock(&fidp->fs.dir); /* Ran out of buffer. Set dir back to old position and return */ @@ -2332,7 +2332,7 @@ static size_t v9fs_readdir_data_size(V9fsString *name) } static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, - int32_t max_count) + int32_t maxsize) { size_t size; V9fsQID qid; @@ -2357,7 +2357,7 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, } v9fs_string_init(&name); v9fs_string_sprintf(&name, "%s", dent->d_name); - if ((count + v9fs_readdir_data_size(&name)) > max_count) { + if ((count + v9fs_readdir_data_size(&name)) > maxsize) { v9fs_readdir_unlock(&fidp->fs.dir); /* Ran out of buffer. Set dir back to old position and return */ @@ -2432,20 +2432,20 @@ static void coroutine_fn v9fs_readdir(void *opaque) size_t offset = 7; uint64_t initial_offset; int32_t count; - uint32_t max_count; + uint32_t maxsize; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; retval = pdu_unmarshal(pdu, offset, "dqd", &fid, - &initial_offset, &max_count); + &initial_offset, &maxsize); if (retval < 0) { goto out_nofid; } - trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count); + trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, maxsize); /* Enough space for a R_readdir header: size[4] Rreaddir tag[2] count[4] */ - if (max_count > s->msize - 11) { - max_count = s->msize - 11; + if (maxsize > s->msize - 11) { + maxsize = s->msize - 11; warn_report_once( "9p: bad client: T_readdir with count > msize - 11" ); @@ -2465,7 +2465,7 @@ static void coroutine_fn v9fs_readdir(void *opaque) } else { v9fs_co_seekdir(pdu, fidp, initial_offset); } - count = v9fs_do_readdir(pdu, fidp, max_count); + count = v9fs_do_readdir(pdu, fidp, maxsize); if (count < 0) { retval = count; goto out; From patchwork Thu Mar 26 21:24:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Schoenebeck X-Patchwork-Id: 1262392 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=crudebyte.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=crudebyte.com header.i=@crudebyte.com header.a=rsa-sha256 header.s=lizzy header.b=noevhA1Q; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 48pKYB61MPz9sR4 for ; Fri, 27 Mar 2020 09:34:38 +1100 (AEDT) Received: from localhost ([::1]:33640 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jHb5A-0001Rq-PR for incoming@patchwork.ozlabs.org; Thu, 26 Mar 2020 18:34:36 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59755) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <5a33d980a7965aa008c72147d634d50a4ef5f842@lizzy.crudebyte.com>) id 1jHb47-0000qv-3t for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:33:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from <5a33d980a7965aa008c72147d634d50a4ef5f842@lizzy.crudebyte.com>) id 1jHb45-0001Px-CR for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:33:30 -0400 Received: from lizzy.crudebyte.com ([91.194.90.13]:35183) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from <5a33d980a7965aa008c72147d634d50a4ef5f842@lizzy.crudebyte.com>) id 1jHb45-0000aj-0X for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:33:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=crudebyte.com; s=lizzy; h=Cc:To:Subject:Date:From:References:In-Reply-To: Message-Id:Content-Type:Content-Transfer-Encoding:MIME-Version:Content-ID: Content-Description; bh=YOsEy9iFF3iyS0l7bD6DplUEjZ6KwgpDGHxOkThI0cw=; b=noevh A1QCELRPyuzViZxcMWwGGGIv8C8WNAlwjqtUCxbDhhxSr+oBsrZRZV2MpbEVSMrqE12ytw8IlhL4v s8J6rdIYI66e27XDq6tJD3I4tSqhyyp1k1yfofgXEOP7bR5VmyuARcnS7c6dCL/XmFpS8HtQ+8JGi 09EY+dQLxNVQhSurJr6+jusX2HlM5ZeEJ7/w9zGIKVqpg7nqIeCHPR7KJpDoyf65mlbl+e40Y7QMo eVqlYdC1gvoxkQiHF2MHZoY1rZ8hJgvl976xZRQDqcpm8Sv0UGglPbFG4mJSngLEyZ3GoXEUlKDVU ocaEsmO9iuyynr91oMosm7tHLkG7A==; Message-Id: <5a33d980a7965aa008c72147d634d50a4ef5f842.1585258105.git.qemu_oss@crudebyte.com> In-Reply-To: References: From: Christian Schoenebeck Date: Thu, 26 Mar 2020 22:24:51 +0100 Subject: [PATCH v5 3/6] 9pfs: make v9fs_readdir_response_size() public To: qemu-devel@nongnu.org Cc: Greg Kurz X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 91.194.90.13 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Rename function v9fs_readdir_data_size() -> v9fs_readdir_response_size() and make it callable from other units. So far this function is only used by 9p.c, however subsequent patch requires the function to be callable from another 9pfs unit. And as we're at it; also make it clear for what this function is used for. Signed-off-by: Christian Schoenebeck --- hw/9pfs/9p.c | 10 ++++++++-- hw/9pfs/9p.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 1aff4f1fa8..bd8a7cbfac 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -2322,7 +2322,13 @@ out_nofid: pdu_complete(pdu, err); } -static size_t v9fs_readdir_data_size(V9fsString *name) +/** + * Returns size required in Rreaddir response for the passed dirent @p name. + * + * @param name - directory entry's name (i.e. file name, directory name) + * @returns required size in bytes + */ +size_t v9fs_readdir_response_size(V9fsString *name) { /* * Size of each dirent on the wire: size of qid (13) + size of offset (8) @@ -2357,7 +2363,7 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, } v9fs_string_init(&name); v9fs_string_sprintf(&name, "%s", dent->d_name); - if ((count + v9fs_readdir_data_size(&name)) > maxsize) { + if ((count + v9fs_readdir_response_size(&name)) > maxsize) { v9fs_readdir_unlock(&fidp->fs.dir); /* Ran out of buffer. Set dir back to old position and return */ diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index b8f72a3bd9..9553700dbb 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -419,6 +419,7 @@ void v9fs_path_init(V9fsPath *path); void v9fs_path_free(V9fsPath *path); void v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...); void v9fs_path_copy(V9fsPath *dst, const V9fsPath *src); +size_t v9fs_readdir_response_size(V9fsString *name); int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, const char *name, V9fsPath *path); int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, From patchwork Thu Mar 26 21:25:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Schoenebeck X-Patchwork-Id: 1262380 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=crudebyte.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=crudebyte.com header.i=@crudebyte.com header.a=rsa-sha256 header.s=lizzy header.b=TNaNNuRJ; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 48pKPP6C2Cz9sSQ for ; Fri, 27 Mar 2020 09:27:52 +1100 (AEDT) Received: from localhost ([::1]:33514 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jHaya-0003ei-Ly for incoming@patchwork.ozlabs.org; Thu, 26 Mar 2020 18:27:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:50436) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <7bd25ce5a682052bf7212b40fb9a1308b8972b31@lizzy.crudebyte.com>) id 1jHay5-0003dM-AF for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:27:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from <7bd25ce5a682052bf7212b40fb9a1308b8972b31@lizzy.crudebyte.com>) id 1jHay3-0004DO-FU for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:27:17 -0400 Received: from lizzy.crudebyte.com ([91.194.90.13]:33879) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from <7bd25ce5a682052bf7212b40fb9a1308b8972b31@lizzy.crudebyte.com>) id 1jHay3-0003Ct-0C for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:27:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=crudebyte.com; s=lizzy; h=Cc:To:Subject:Date:From:References:In-Reply-To: Message-Id:Content-Type:Content-Transfer-Encoding:MIME-Version:Content-ID: Content-Description; bh=Exi2eVU0aC9WtbkX7/D0N5Fl28ExllAxepKnldAijZ4=; b=TNaNN uRJbXnD8QZDAg2T8qouYsiMU3Ir1A68TEfBKelgSb9TTLUb7N4gqPWRrJ/v1+gyFYiw6l59h0m2Ad VkUxoy7qZ4Dfd7xhnxHs/1qjYdwpDGeu+H5b9fkijfnU/Qe9WK/RHiRh1NkLFJMCGCeZvFaWuUtvL mIIEXCqH+uxxyQyJCBVGjmEf3icannN+HEenaO6ftH7kntG5b7zVjFSCSXoELSyLnx+d44HlljJxj hgzJoJ8lW5Qu36jbYfZTimfHCRJ7bziFJvbSdwp69/flx1ftM3xILtd5gdV82ApQuIQYlK3Bg0V+7 6U02dNkT2g5jK5eL6UtxDq5jcDGQA==; Message-Id: <7bd25ce5a682052bf7212b40fb9a1308b8972b31.1585258105.git.qemu_oss@crudebyte.com> In-Reply-To: References: From: Christian Schoenebeck Date: Thu, 26 Mar 2020 22:25:05 +0100 Subject: [PATCH v5 4/6] 9pfs: add new function v9fs_co_readdir_many() To: qemu-devel@nongnu.org Cc: Greg Kurz X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 91.194.90.13 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The newly added function v9fs_co_readdir_many() retrieves multiple directory entries with a single fs driver request. It is intended to replace uses of v9fs_co_readdir(), the latter only retrives a single directory entry per fs driver request instead. The reason for this planned replacement is that for every fs driver request the coroutine is dispatched from main I/O thread to a background I/O thread and eventually dispatched back to main I/O thread. Hopping between threads adds latency. So if a 9pfs Treaddir request reads a large amount of directory entries, this currently sums up to huge latencies of several hundred ms or even more. So using v9fs_co_readdir_many() instead of v9fs_co_readdir() will provide significant performance improvements. Signed-off-by: Christian Schoenebeck --- hw/9pfs/9p.h | 22 ++++++ hw/9pfs/codir.c | 181 +++++++++++++++++++++++++++++++++++++++++++++--- hw/9pfs/coth.h | 3 + 3 files changed, 195 insertions(+), 11 deletions(-) diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 9553700dbb..116977939b 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -215,6 +215,28 @@ static inline void v9fs_readdir_init(V9fsDir *dir) qemu_mutex_init(&dir->readdir_mutex); } +/** + * Type for 9p fs drivers' (a.k.a. 9p backends) result of readdir requests, + * which is a chained list of directory entries. + */ +typedef struct V9fsDirEnt { + /* mandatory (must not be NULL) information for all readdir requests */ + struct dirent *dent; + /* + * optional (may be NULL): A full stat of each directory entry is just + * done if explicitly told to fs driver. + */ + struct stat *st; + /* + * instead of an array, directory entries are always returned as + * chained list, that's because the amount of entries retrieved by fs + * drivers is dependent on the individual entries' name (since response + * messages are size limited), so the final amount cannot be estimated + * before hand + */ + struct V9fsDirEnt *next; +} V9fsDirEnt; + /* * Filled by fs driver on open and other * calls. diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 73f9a751e1..45c65a8f5b 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -18,28 +18,187 @@ #include "qemu/main-loop.h" #include "coth.h" +/* + * This is solely executed on a background IO thread. + */ +static int do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent **dent) +{ + int err = 0; + V9fsState *s = pdu->s; + struct dirent *entry; + + errno = 0; + entry = s->ops->readdir(&s->ctx, &fidp->fs); + if (!entry && errno) { + *dent = NULL; + err = -errno; + } else { + *dent = entry; + } + return err; +} + +/* + * TODO: This will be removed for performance reasons. + * Use v9fs_co_readdir_many() instead. + */ int coroutine_fn v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent **dent) { int err; - V9fsState *s = pdu->s; if (v9fs_request_cancelled(pdu)) { return -EINTR; } - v9fs_co_run_in_worker( - { - struct dirent *entry; + v9fs_co_run_in_worker({ + err = do_readdir(pdu, fidp, dent); + }); + return err; +} + +/* + * This is solely executed on a background IO thread. + * + * See v9fs_co_readdir_many() (as its only user) below for details. + */ +static int do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, + struct V9fsDirEnt **entries, + int32_t maxsize, bool dostat) +{ + V9fsState *s = pdu->s; + V9fsString name; + int len, err = 0; + int32_t size = 0; + off_t saved_dir_pos; + struct dirent *dent; + struct V9fsDirEnt *e = NULL; + V9fsPath path; + struct stat stbuf; - errno = 0; - entry = s->ops->readdir(&s->ctx, &fidp->fs); - if (!entry && errno) { + *entries = NULL; + v9fs_path_init(&path); + + /* + * TODO: Here should be a warn_report_once() if lock failed. + * + * With a good 9p client we should not get into concurrency here, + * because a good client would not use the same fid for concurrent + * requests. We do the lock here for safety reasons though. However + * the client would then suffer performance issues, so better log that + * issue here. + */ + v9fs_readdir_lock(&fidp->fs.dir); + + /* save the directory position */ + saved_dir_pos = s->ops->telldir(&s->ctx, &fidp->fs); + if (saved_dir_pos < 0) { + err = saved_dir_pos; + goto out; + } + + while (true) { + /* get directory entry from fs driver */ + err = do_readdir(pdu, fidp, &dent); + if (err || !dent) { + break; + } + + /* + * stop this loop as soon as it would exceed the allowed maximum + * response message size for the directory entries collected so far, + * because anything beyond that size would need to be discarded by + * 9p controller (main thread / top half) anyway + */ + v9fs_string_init(&name); + v9fs_string_sprintf(&name, "%s", dent->d_name); + len = v9fs_readdir_response_size(&name); + v9fs_string_free(&name); + if (size + len > maxsize) { + /* this is not an error case actually */ + break; + } + + /* append next node to result chain */ + if (!e) { + *entries = e = g_malloc0(sizeof(V9fsDirEnt)); + } else { + e = e->next = g_malloc0(sizeof(V9fsDirEnt)); + } + e->dent = g_malloc0(sizeof(struct dirent)); + memcpy(e->dent, dent, sizeof(struct dirent)); + + /* perform a full stat() for directory entry if requested by caller */ + if (dostat) { + err = s->ops->name_to_path( + &s->ctx, &fidp->path, dent->d_name, &path + ); + if (err < 0) { err = -errno; - } else { - *dent = entry; - err = 0; + break; } - }); + + err = s->ops->lstat(&s->ctx, &path, &stbuf); + if (err < 0) { + err = -errno; + break; + } + + e->st = g_malloc0(sizeof(struct stat)); + memcpy(e->st, &stbuf, sizeof(struct stat)); + } + + size += len; + saved_dir_pos = dent->d_off; + } + + /* restore (last) saved position */ + s->ops->seekdir(&s->ctx, &fidp->fs, saved_dir_pos); + +out: + v9fs_readdir_unlock(&fidp->fs.dir); + v9fs_path_free(&path); + if (err < 0) { + return err; + } + return size; +} + +/** + * @brief Reads multiple directory entries in one rush. + * + * Retrieves the requested (max. amount of) directory entries from the fs + * driver. This function must only be called by the main IO thread (top half). + * Internally this function call will be dispatched to a background IO thread + * (bottom half) where it is eventually executed by the fs driver. + * + * Acquiring multiple directory entries in one rush from the fs driver, + * instead of retrieving each directory entry individually, is very beneficial + * from performance point of view. Because for every fs driver request latency + * is added, which in practice could lead to overall latencies of several + * hundred ms for reading all entries (of just a single directory) if every + * directory entry was individually requested from driver. + * + * @param pdu - the causing 9p (T_readdir) client request + * @param fidp - already opened directory where readdir shall be performed on + * @param entries - output for directory entries (must not be NULL) + * @param maxsize - maximum result message body size (in bytes) + * @param dostat - whether a stat() should be performed and returned for + * each directory entry + * @returns resulting response message body size (in bytes) on success, + * negative error code otherwise + */ +int coroutine_fn v9fs_co_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, + struct V9fsDirEnt **entries, + int32_t maxsize, bool dostat) +{ + int err = 0; + + if (v9fs_request_cancelled(pdu)) { + return -EINTR; + } + v9fs_co_run_in_worker({ + err = do_readdir_many(pdu, fidp, entries, maxsize, dostat); + }); return err; } diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index c2cdc7a9ea..a6851822d5 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -49,6 +49,9 @@ void co_run_in_worker_bh(void *); int coroutine_fn v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *); int coroutine_fn v9fs_co_readdir(V9fsPDU *, V9fsFidState *, struct dirent **); +int coroutine_fn v9fs_co_readdir_many(V9fsPDU *, V9fsFidState *, + struct V9fsDirEnt **, + int32_t, bool); off_t coroutine_fn v9fs_co_telldir(V9fsPDU *, V9fsFidState *); void coroutine_fn v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t); void coroutine_fn v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *); From patchwork Thu Mar 26 21:25:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Schoenebeck X-Patchwork-Id: 1262391 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=crudebyte.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=crudebyte.com header.i=@crudebyte.com header.a=rsa-sha256 header.s=lizzy header.b=JyGl3g4H; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 48pKWn24knz9sR4 for ; Fri, 27 Mar 2020 09:33:23 +1100 (AEDT) Received: from localhost ([::1]:33612 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jHb3w-00006M-BN for incoming@patchwork.ozlabs.org; Thu, 26 Mar 2020 18:33:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58223) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <8ee6bb18b00ccb92ca9ecdeb4ff320503ed6a730@lizzy.crudebyte.com>) id 1jHb37-0008Ul-Ud for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:32:31 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from <8ee6bb18b00ccb92ca9ecdeb4ff320503ed6a730@lizzy.crudebyte.com>) id 1jHb35-0000aC-7U for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:32:28 -0400 Received: from lizzy.crudebyte.com ([91.194.90.13]:34939) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from <8ee6bb18b00ccb92ca9ecdeb4ff320503ed6a730@lizzy.crudebyte.com>) id 1jHb34-0008EU-W5 for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:32:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=crudebyte.com; s=lizzy; h=Cc:To:Subject:Date:From:References:In-Reply-To: Message-Id:Content-Type:Content-Transfer-Encoding:MIME-Version:Content-ID: Content-Description; bh=0NiuoPE9FpFqaIkbmn2TcQVwJNLByVhPkawPEjeTIMs=; b=JyGl3 g4H+waXVS0MRnKRpTOCXQ0CzRsaogdVw8QN8uk4Oaz8FQJ7K+gh2tfu5BbB/mR6fmQ2ieHGxuuWRR FtckUAq8RzTgvRaLJWglEvz+vLqT7tIUuGnPkr94AJNm0XOyKrA6VjU3o2HjncoDCml7lcNv7pWXC R9lZRjVG6Za3HHIYdwdczjFk5DTQKZ1nsI2LHZLMd2MAQJNXlhvcf2HEmDF5+DY62QKJoEt2qUkKU 6yqRjKtU++Fe+s9v/X25o91qLevKnz0YSxI3r15+VULbG+7j83hZd5pNmUBqvwGJcIFC+LaeHCAOh 7U3pZM8tZfG+guRuhwk/Azq4m/0ig==; Message-Id: <8ee6bb18b00ccb92ca9ecdeb4ff320503ed6a730.1585258105.git.qemu_oss@crudebyte.com> In-Reply-To: References: From: Christian Schoenebeck Date: Thu, 26 Mar 2020 22:25:18 +0100 Subject: [PATCH v5 5/6] 9pfs: T_readdir latency optimization To: qemu-devel@nongnu.org Cc: Greg Kurz X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 91.194.90.13 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Make top half really top half and bottom half really bottom half: Each T_readdir request handling is hopping between threads (main I/O thread and background I/O driver threads) several times for every individual directory entry, which sums up to huge latencies for handling just a single T_readdir request. Instead of doing that, collect now all required directory entries (including all potentially required stat buffers for each entry) in one rush on a background I/O thread from fs driver by calling the previously added function v9fs_co_readdir_many() instead of v9fs_co_readdir(), then assemble the entire resulting network response message for the readdir request on main I/O thread. The fs driver is still aborting the directory entry retrieval loop (on the background I/O thread inside of v9fs_co_readdir_many()) as soon as it would exceed the client's requested maximum R_readdir response size. So this will not introduce a performance penalty on another end. Signed-off-by: Christian Schoenebeck --- hw/9pfs/9p.c | 122 +++++++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 67 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index bd8a7cbfac..5246d96a08 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -971,30 +971,6 @@ static int coroutine_fn fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, return 0; } -static int coroutine_fn dirent_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, - struct dirent *dent, V9fsQID *qidp) -{ - struct stat stbuf; - V9fsPath path; - int err; - - v9fs_path_init(&path); - - err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path); - if (err < 0) { - goto out; - } - err = v9fs_co_lstat(pdu, &path, &stbuf); - if (err < 0) { - goto out; - } - err = stat_to_qid(pdu, &stbuf, qidp); - -out: - v9fs_path_free(&path); - return err; -} - V9fsPDU *pdu_alloc(V9fsState *s) { V9fsPDU *pdu = NULL; @@ -2337,6 +2313,18 @@ size_t v9fs_readdir_response_size(V9fsString *name) return 24 + v9fs_string_size(name); } +static void v9fs_free_dirents(struct V9fsDirEnt *e) +{ + struct V9fsDirEnt *next = NULL; + + for (; e; e = next) { + next = e->next; + g_free(e->dent); + g_free(e->st); + g_free(e); + } +} + static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, int32_t maxsize) { @@ -2345,54 +2333,53 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString name; int len, err = 0; int32_t count = 0; - off_t saved_dir_pos; struct dirent *dent; + struct stat *st; + struct V9fsDirEnt *entries = NULL; - /* save the directory position */ - saved_dir_pos = v9fs_co_telldir(pdu, fidp); - if (saved_dir_pos < 0) { - return saved_dir_pos; - } - - while (1) { - v9fs_readdir_lock(&fidp->fs.dir); + /* + * inode remapping requires the device id, which in turn might be + * different for different directory entries, so if inode remapping is + * enabled we have to make a full stat for each directory entry + */ + const bool dostat = pdu->s->ctx.export_flags & V9FS_REMAP_INODES; - err = v9fs_co_readdir(pdu, fidp, &dent); - if (err || !dent) { - break; - } - v9fs_string_init(&name); - v9fs_string_sprintf(&name, "%s", dent->d_name); - if ((count + v9fs_readdir_response_size(&name)) > maxsize) { - v9fs_readdir_unlock(&fidp->fs.dir); + /* + * Fetch all required directory entries altogether on a background IO + * thread from fs driver. We don't want to do that for each entry + * individually, because hopping between threads (this main IO thread + * and background IO driver thread) would sum up to huge latencies. + */ + count = v9fs_co_readdir_many(pdu, fidp, &entries, maxsize, dostat); + if (count < 0) { + err = count; + count = 0; + goto out; + } + count = 0; - /* Ran out of buffer. Set dir back to old position and return */ - v9fs_co_seekdir(pdu, fidp, saved_dir_pos); - v9fs_string_free(&name); - return count; - } + for (struct V9fsDirEnt *e = entries; e; e = e->next) { + dent = e->dent; if (pdu->s->ctx.export_flags & V9FS_REMAP_INODES) { - /* - * dirent_to_qid() implies expensive stat call for each entry, - * we must do that here though since inode remapping requires - * the device id, which in turn might be different for - * different entries; we cannot make any assumption to avoid - * that here. - */ - err = dirent_to_qid(pdu, fidp, dent, &qid); + st = e->st; + /* e->st should never be NULL, but just to be sure */ + if (!st) { + err = -1; + break; + } + + /* remap inode */ + err = stat_to_qid(pdu, st, &qid); if (err < 0) { - v9fs_readdir_unlock(&fidp->fs.dir); - v9fs_co_seekdir(pdu, fidp, saved_dir_pos); - v9fs_string_free(&name); - return err; + break; } } else { /* * Fill up just the path field of qid because the client uses * only that. To fill the entire qid structure we will have * to stat each dirent found, which is expensive. For the - * latter reason we don't call dirent_to_qid() here. Only drawback + * latter reason we don't call stat_to_qid() here. Only drawback * is that no multi-device export detection of stat_to_qid() * would be done and provided as error to the user here. But * user would get that error anyway when accessing those @@ -2405,25 +2392,26 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, qid.version = 0; } + v9fs_string_init(&name); + v9fs_string_sprintf(&name, "%s", dent->d_name); + /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */ len = pdu_marshal(pdu, 11 + count, "Qqbs", &qid, dent->d_off, dent->d_type, &name); - v9fs_readdir_unlock(&fidp->fs.dir); + v9fs_string_free(&name); if (len < 0) { - v9fs_co_seekdir(pdu, fidp, saved_dir_pos); - v9fs_string_free(&name); - return len; + err = len; + break; } + count += len; - v9fs_string_free(&name); - saved_dir_pos = dent->d_off; } - v9fs_readdir_unlock(&fidp->fs.dir); - +out: + v9fs_free_dirents(entries); if (err < 0) { return err; } From patchwork Thu Mar 26 21:25:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Schoenebeck X-Patchwork-Id: 1262382 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=crudebyte.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=crudebyte.com header.i=@crudebyte.com header.a=rsa-sha256 header.s=lizzy header.b=LmoSCKPt; dkim-atps=neutral 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 ozlabs.org (Postfix) with ESMTPS id 48pKQc2M0nz9sR4 for ; Fri, 27 Mar 2020 09:28:56 +1100 (AEDT) Received: from localhost ([::1]:33532 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jHaze-0004Wh-95 for incoming@patchwork.ozlabs.org; Thu, 26 Mar 2020 18:28:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51914) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <7c4e49a783c7b2f77aa81794892cf08b4feba914@lizzy.crudebyte.com>) id 1jHaz5-0004HY-47 for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:28:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from <7c4e49a783c7b2f77aa81794892cf08b4feba914@lizzy.crudebyte.com>) id 1jHaz4-0005A8-3e for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:28:19 -0400 Received: from lizzy.crudebyte.com ([91.194.90.13]:42819) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from <7c4e49a783c7b2f77aa81794892cf08b4feba914@lizzy.crudebyte.com>) id 1jHaz2-0004Dd-Dk for qemu-devel@nongnu.org; Thu, 26 Mar 2020 18:28:17 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=crudebyte.com; s=lizzy; h=Cc:To:Subject:Date:From:References:In-Reply-To: Message-Id:Content-Type:Content-Transfer-Encoding:MIME-Version:Content-ID: Content-Description; bh=jPdUMVvPDb49VGrJsLB5Dy+OTfiFUvEBcazVO3auyKA=; b=LmoSC KPt/p2vnLztv/ExKLe2NSSkJG4t/GCl8C3HNr8PV/3KzOyXDD2HSiOsFzSQkB82Wbz9eTekUo/o+f VNPd/8aYrK5G7M6AHujALQtPa+h4zCNYwZqzreZZ40EN0snWsXqySuW/KlZ6Tq71SBXuHH699/ecy F3gOIIhKfo/rqSbm0T8dQgW1Z9uuv0qTTerrwISHJGBz6eGtbh76FwYdOPyF0rOOtiXxv30KwOWH1 sH/CqMB3RCAbnVgPXyJ7IKWbEyKofceIYY/g1biIYFmvhQcvMmrMOO7WDY4rjF/B8JNVuBTiSq6k2 NP7PpIt1J+vVfPHwCEjYuplFoV1jg==; Message-Id: <7c4e49a783c7b2f77aa81794892cf08b4feba914.1585258105.git.qemu_oss@crudebyte.com> In-Reply-To: References: From: Christian Schoenebeck Date: Thu, 26 Mar 2020 22:25:32 +0100 Subject: [PATCH v5 6/6] 9pfs: clarify latency of v9fs_co_run_in_worker() To: qemu-devel@nongnu.org Cc: Greg Kurz X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 91.194.90.13 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" As we just fixed a severe performance issue with Treaddir request handling, clarify this overall issue as a comment on v9fs_co_run_in_worker() with the intention to hopefully prevent such performance mistakes in future (and fixing other yet outstanding ones). Signed-off-by: Christian Schoenebeck --- hw/9pfs/coth.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index a6851822d5..8b6f76840a 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -19,7 +19,7 @@ #include "qemu/coroutine.h" #include "9p.h" -/* +/** * we want to use bottom half because we want to make sure the below * sequence of events. * @@ -28,6 +28,16 @@ * 3. Enter the coroutine in the worker thread. * we cannot swap step 1 and 2, because that would imply worker thread * can enter coroutine while step1 is still running + * + * @b PERFORMANCE @b CONSIDERATIONS: As a rule of thumb, keep in mind + * that hopping between threads adds @b latency! So when handling a + * 9pfs request, avoid calling v9fs_co_run_in_worker() too often, because + * this might otherwise sum up to a significant, huge overall latency for + * providing the response for just a single request. For that reason it + * is highly recommended to fetch all data from fs driver with a single + * fs driver request on a background I/O thread (bottom half) in one rush + * first and then eventually assembling the final response from that data + * on main I/O thread (top half). */ #define v9fs_co_run_in_worker(code_block) \ do { \