|
|
65aaff |
From 62cd6c9d2dd62dd24cc04b16437bfb816a6f4357 Mon Sep 17 00:00:00 2001
|
|
|
65aaff |
From: Laszlo Ersek <lersek@redhat.com>
|
|
|
65aaff |
Date: Mon, 2 May 2022 10:56:01 +0200
|
|
|
65aaff |
Subject: [PATCH] guestfs_readdir(): minimize the number of send_file_write()
|
|
|
65aaff |
calls
|
|
|
65aaff |
|
|
|
65aaff |
In guestfs_readdir(), the daemon currently sends each XDR-encoded
|
|
|
65aaff |
"guestfs_int_dirent" to the library with a separate send_file_write()
|
|
|
65aaff |
call.
|
|
|
65aaff |
|
|
|
65aaff |
Determine the largest encoded size (from the longest filename that a
|
|
|
65aaff |
"guestfs_int_dirent" could carry, from readdir()'s "struct dirent"), and
|
|
|
65aaff |
batch up the XDR encodings until the next encoding might not fit in
|
|
|
65aaff |
GUESTFS_MAX_CHUNK_SIZE. Call send_file_write() only then.
|
|
|
65aaff |
|
|
|
65aaff |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1674392
|
|
|
65aaff |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
65aaff |
Message-Id: <20220502085601.15012-3-lersek@redhat.com>
|
|
|
65aaff |
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
|
|
|
65aaff |
(cherry picked from commit 4864d21cb8eb991f0fc98d03a068173837cba50e)
|
|
|
65aaff |
---
|
|
|
65aaff |
daemon/readdir.c | 38 ++++++++++++++++++++++++++++++++------
|
|
|
65aaff |
1 file changed, 32 insertions(+), 6 deletions(-)
|
|
|
65aaff |
|
|
|
65aaff |
diff --git a/daemon/readdir.c b/daemon/readdir.c
|
|
|
65aaff |
index 9ab0b0aec..3084ba939 100644
|
|
|
65aaff |
--- a/daemon/readdir.c
|
|
|
65aaff |
+++ b/daemon/readdir.c
|
|
|
65aaff |
@@ -35,6 +35,9 @@ do_internal_readdir (const char *dir)
|
|
|
65aaff |
DIR *dirstream;
|
|
|
65aaff |
void *xdr_buf;
|
|
|
65aaff |
XDR xdr;
|
|
|
65aaff |
+ struct dirent fill;
|
|
|
65aaff |
+ guestfs_int_dirent v;
|
|
|
65aaff |
+ unsigned max_encoded;
|
|
|
65aaff |
|
|
|
65aaff |
/* Prepare to fail. */
|
|
|
65aaff |
ret = -1;
|
|
|
65aaff |
@@ -55,6 +58,20 @@ do_internal_readdir (const char *dir)
|
|
|
65aaff |
}
|
|
|
65aaff |
xdrmem_create (&xdr, xdr_buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
|
|
|
65aaff |
|
|
|
65aaff |
+ /* Calculate the max number of bytes a "guestfs_int_dirent" can be encoded to.
|
|
|
65aaff |
+ */
|
|
|
65aaff |
+ memset (fill.d_name, 'a', sizeof fill.d_name - 1);
|
|
|
65aaff |
+ fill.d_name[sizeof fill.d_name - 1] = '\0';
|
|
|
65aaff |
+ v.ino = INT64_MAX;
|
|
|
65aaff |
+ v.ftyp = '?';
|
|
|
65aaff |
+ v.name = fill.d_name;
|
|
|
65aaff |
+ if (!xdr_guestfs_int_dirent (&xdr, &v)) {
|
|
|
65aaff |
+ fprintf (stderr, "xdr_guestfs_int_dirent failed\n");
|
|
|
65aaff |
+ goto release_xdr;
|
|
|
65aaff |
+ }
|
|
|
65aaff |
+ max_encoded = xdr_getpos (&xdr;;
|
|
|
65aaff |
+ xdr_setpos (&xdr, 0);
|
|
|
65aaff |
+
|
|
|
65aaff |
/* Send an "OK" reply, before starting the file transfer. */
|
|
|
65aaff |
reply (NULL, NULL);
|
|
|
65aaff |
|
|
|
65aaff |
@@ -63,7 +80,6 @@ do_internal_readdir (const char *dir)
|
|
|
65aaff |
*/
|
|
|
65aaff |
for (;;) {
|
|
|
65aaff |
struct dirent *d;
|
|
|
65aaff |
- guestfs_int_dirent v;
|
|
|
65aaff |
|
|
|
65aaff |
errno = 0;
|
|
|
65aaff |
d = readdir (dirstream);
|
|
|
65aaff |
@@ -94,22 +110,32 @@ do_internal_readdir (const char *dir)
|
|
|
65aaff |
v.ftyp = 'u';
|
|
|
65aaff |
#endif
|
|
|
65aaff |
|
|
|
65aaff |
+ /* Flush "xdr_buf" if we may not have enough room for encoding "v". */
|
|
|
65aaff |
+ if (GUESTFS_MAX_CHUNK_SIZE - xdr_getpos (&xdr) < max_encoded) {
|
|
|
65aaff |
+ if (send_file_write (xdr_buf, xdr_getpos (&xdr)) != 0)
|
|
|
65aaff |
+ break;
|
|
|
65aaff |
+
|
|
|
65aaff |
+ xdr_setpos (&xdr, 0);
|
|
|
65aaff |
+ }
|
|
|
65aaff |
+
|
|
|
65aaff |
if (!xdr_guestfs_int_dirent (&xdr, &v)) {
|
|
|
65aaff |
fprintf (stderr, "xdr_guestfs_int_dirent failed\n");
|
|
|
65aaff |
break;
|
|
|
65aaff |
}
|
|
|
65aaff |
-
|
|
|
65aaff |
- if (send_file_write (xdr_buf, xdr_getpos (&xdr)) != 0)
|
|
|
65aaff |
- break;
|
|
|
65aaff |
-
|
|
|
65aaff |
- xdr_setpos (&xdr, 0);
|
|
|
65aaff |
}
|
|
|
65aaff |
|
|
|
65aaff |
+ /* Flush "xdr_buf" if the loop completed successfully and "xdr_buf" is not
|
|
|
65aaff |
+ * empty. */
|
|
|
65aaff |
+ if (ret == 0 && xdr_getpos (&xdr) > 0 &&
|
|
|
65aaff |
+ send_file_write (xdr_buf, xdr_getpos (&xdr)) != 0)
|
|
|
65aaff |
+ ret = -1;
|
|
|
65aaff |
+
|
|
|
65aaff |
/* Finish or cancel the transfer. Note that if (ret == -1) because the library
|
|
|
65aaff |
* canceled, we still need to cancel back!
|
|
|
65aaff |
*/
|
|
|
65aaff |
send_file_end (ret == -1);
|
|
|
65aaff |
|
|
|
65aaff |
+release_xdr:
|
|
|
65aaff |
xdr_destroy (&xdr;;
|
|
|
65aaff |
free (xdr_buf);
|
|
|
65aaff |
|
|
|
65aaff |
--
|
|
|
65aaff |
2.31.1
|
|
|
65aaff |
|