[Libguestfs] [libguestfs PATCH v2 2/2] guestfs_readdir(): minimize the number of send_file_write() calls

Laszlo Ersek lersek at redhat.com
Tue May 3 08:56:38 UTC 2022


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

Commit range ac00e603f838..4864d21cb8eb.

Thank you!
Laszlo


More information about the Libguestfs mailing list