From nobody Mon Feb 9 16:00:54 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=suse.de Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1652543644389935.0377836493436; Sat, 14 May 2022 08:54:04 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-502-mN70Z6eLOiuaLlsqwTHNmw-1; Sat, 14 May 2022 11:53:42 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 205E0833975; Sat, 14 May 2022 15:53:35 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (unknown [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id F3427DCC486; Sat, 14 May 2022 15:53:34 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 0602E196637E; Sat, 14 May 2022 15:53:29 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 7CA8C196637E for ; Sat, 14 May 2022 15:53:25 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 54CE67C58; Sat, 14 May 2022 15:53:25 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast01.extmail.prod.ext.rdu2.redhat.com [10.11.55.17]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 16ADE814B for ; Sat, 14 May 2022 15:53:22 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4611585A5BE for ; Sat, 14 May 2022 15:53:22 +0000 (UTC) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-596-s0JZhsw7N1SGcWtxz8cU4Q-1; Sat, 14 May 2022 11:53:18 -0400 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id B9D5E21D52; Sat, 14 May 2022 15:53:16 +0000 (UTC) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 8383613ADC; Sat, 14 May 2022 15:53:16 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id cMhnHmzQf2J2ZwAAMHmgww (envelope-from ); Sat, 14 May 2022 15:53:16 +0000 X-MC-Unique: mN70Z6eLOiuaLlsqwTHNmw-1 X-Original-To: libvir-list@listman.corp.redhat.com X-MC-Unique: s0JZhsw7N1SGcWtxz8cU4Q-1 From: Claudio Fontana To: =?UTF-8?q?Daniel=20P=20=2E=20Berrang=C3=A9?= Subject: [libvirt RFCv9 01/31] virfile: introduce virFileDirect APIs Date: Sat, 14 May 2022 17:52:43 +0200 Message-Id: <20220514155313.9615-2-cfontana@suse.de> In-Reply-To: <20220514155313.9615-1-cfontana@suse.de> References: <20220514155313.9615-1-cfontana@suse.de> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: libvir-list@redhat.com, "Dr . David Alan Gilbert" , Claudio Fontana Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.8 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1652543644743100018 Content-Type: text/plain; charset="utf-8"; x-default="true" these functions help with allocating buffers, aligning, reading and writing files opened with O_DIRECT. Signed-off-by: Claudio Fontana --- src/libvirt_private.syms | 6 + src/util/virfile.c | 249 +++++++++++++++++++++++++++++++++++++++ src/util/virfile.h | 10 ++ 3 files changed, 265 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9309259751..48ed75aa16 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2236,7 +2236,13 @@ virFileComparePaths; virFileCopyACLs; virFileDataSync; virFileDeleteTree; +virFileDirectBufferNew; +virFileDirectCopyBuf; virFileDirectFdFlag; +virFileDirectRead; +virFileDirectReadCopy; +virFileDirectReadLim; +virFileDirectWrite; virFileExists; virFileFclose; virFileFdopen; diff --git a/src/util/virfile.c b/src/util/virfile.c index e4522b5f67..3714ca6be4 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -192,6 +192,210 @@ virFileDirectFdFlag(void) return O_DIRECT ? O_DIRECT : -1; } =20 +/** + * virFileDirectAlign: align a value, which may include a pointer. + * + * @value: the value that will be incremented to reach alignment + * + * Returns the aligned value. + */ +static inline uintptr_t +virFileDirectAlign(uintptr_t value) +{ + return (value + VIR_FILE_DIRECT_ALIGN_MASK) & ~VIR_FILE_DIRECT_ALIGN_M= ASK; +} + +/** + * virFileDirectRead: perform a single aligned read. + * @fd: O_DIRECT file descriptor + * @buf: aligned buffer to read into + * @count: the desired read size. Note that if unaligned, + * extra bytes will be read based on alignment. + * + * Note that buf should be able to contain count plus the alignment! + * + * Returns < 0 and errno set on error, or the number of bytes read, + * which may be smaller or even greater than count. + */ +ssize_t +virFileDirectRead(int fd, void *buf, size_t count) +{ + size_t aligned_count =3D virFileDirectAlign(count); + while (count > 0) { + ssize_t r =3D read(fd, buf, aligned_count); + if (r < 0 && errno =3D=3D EINTR) + continue; + return r; + } + return 0; +} + +/** + * virFileDirectReadLim: perform multiple aligned reads up to limit + * @fd: O_DIRECT file descriptor + * @buf: aligned buffer to read into + * @limit: the desired limit to read into buffer. + * Note that if unaligned, extra bytes will be read based on align= ment. + * + * Note that buf should be able to contain limit plus the alignment! + * + * Compared with virFileDirectRead, this function reads potentially + * multiple times to fill up to buffer with up to limit bytes plus alignme= nt, + * so on success it does not return a number of bytes smaller than limit. + * + * Returns < 0 and errno set on error, + * and on success the number of bytes read, which may be greater than limit + * due to alignment. + */ +ssize_t +virFileDirectReadLim(int fd, void *buf, size_t lim) +{ + ssize_t nread =3D 0; + + while (lim > 0) { + ssize_t r =3D virFileDirectRead(fd, buf, lim); + if (r < 0) + return r; + if (r =3D=3D 0) + return nread; + buf =3D (char *)buf + r; + nread +=3D r; + if (lim < r) + break; + lim -=3D r; + } + return nread; +} + +/** + * virFileDirectCopyBuf: copy a buffer contents to destination in memory + * @buf: aligned buffer to copy from + * @count: amount of data to copy + * @dst: the destination in memory + * @dst_len: the maximum the destination can hold. + * + * copies up to count bytes from buf into dst, but not more than dst_len. + * increments buf pointer and dst pointer, as well as decrementing the + * maximum the destination can hold (dst_len). + * + * Returns the amount copied. + */ +size_t +virFileDirectCopyBuf(void **buf, size_t count, void **dst, size_t *dst_len) +{ + size_t to_copy; + + to_copy =3D count > *dst_len ? *dst_len : count; + memcpy(*dst, *buf, to_copy); + *dst_len -=3D to_copy; + *(char **)dst +=3D to_copy; + *(char **)buf +=3D to_copy; + return to_copy; +} + +/** + * virFileDirectReadCopy: read an fd and copy contents to memory + * @fd: O_DIRECT file descriptor + * @buf: aligned buffer to read the fd into, and then copy from + * @buflen: size of the buffer + * @dst: the destination in memory + * @dst_len: the maximum the destination can hold. + * + * reads data from the fd file descriptor into the buffer, + * and then copy to the destination, filling it up to dst_len. + * + * Returns < 0 and errno set on error, + * or the number of bytes read, which may be past the requested dst_len, + * or may be smaller if the fd does not contain enough data. + * + * The buf pointer is updated to point to eventual exccess data in the buf= fer. + */ +ssize_t +virFileDirectReadCopy(int fd, void **buf, size_t buflen, void *dst, size_t= dst_len) +{ + ssize_t nread =3D 0; + void *d =3D dst; + char *s =3D *buf; + + while (dst_len > 0) { + ssize_t rv; + *buf =3D s; + rv =3D virFileDirectReadLim(fd, s, dst_len < buflen ? dst_len : bu= flen); + if (rv < 0) + return rv; + if (rv =3D=3D 0) + return nread; /* not enough data to fulfill request */ + + nread +=3D rv; /* note, we might read past the requested len = */ + virFileDirectCopyBuf(buf, rv, &d, &dst_len); + } + return nread; +} + +/** + * virFileDirectWrite: perform a single aligned write. + * @fd: O_DIRECT file descriptor to write to + * @buf: aligned buffer to write from + * @count: the desired write size. Note that if unaligned, + * extra 0 bytes will be written based on alignment. + * + * Returns < 0 and errno set on error, or the number of bytes written, + * which may be smaller or even greater than count. + */ +ssize_t +virFileDirectWrite(int fd, void *buf, size_t count) +{ + size_t aligned_count =3D virFileDirectAlign(count); + if (aligned_count > count) { + memset((char *)buf + count, 0, aligned_count - count); + } + while (count > 0) { + ssize_t r =3D write(fd, buf, aligned_count); /* sc_avoid_write */ + if (r < 0 && errno =3D=3D EINTR) + continue; + return r; + } + return 0; +} + +/** + * virFileDirectWriteLim: perform multiple aligned writes up to limit + * @fd: O_DIRECT file descriptor + * @buf: aligned buffer to write from + * @limit: the desired limit for the total write size + * Note that if unaligned, extra bytes will be written based on al= ignment. + * + * Note that buf should be able to contain limit plus the alignment! + * + * Compared with virFileDirectWrite, this function writes potentially + * multiple times to drain the buffer up to the limit bytes plus alignment, + * so on success it does not return a number of bytes smaller than limit. + * + * Returns < 0 and errno set on error, + * and on success the number of bytes written, which may be greater than l= imit + * due to alignment. + */ + +ssize_t +virFileDirectWriteLim(int fd, void *buf, size_t lim) +{ + ssize_t nwritten =3D 0; + + while (lim > 0) { + ssize_t r =3D virFileDirectWrite(fd, buf, lim); + if (r < 0) + return r; + if (r =3D=3D 0) + return nwritten; + buf =3D (char *)buf + r; + nwritten +=3D r; + if (lim < r) + break; + lim -=3D r; + } + return nwritten; +} + /* Opaque type for managing a wrapper around a fd. For now, * read-write is not supported, just a single direction. */ struct _virFileWrapperFd { @@ -202,6 +406,41 @@ struct _virFileWrapperFd { =20 #ifndef WIN32 =20 +/** + * virFileDirectBufferNew: allocate a buffer and return the first + * block-aligned address in it. + * + * @alloc_base: pointer to the to-be-allocated memory buffer. + * @buflen: desired length, which should be greater than alignment. + * + * Allocate a memory area large enough to accommodate an aligned + * buffer of size buflen. + * + * On success, *alloc_base is set to the newly allocated memory, + * and the aligned buffer within it is returned. + * + * On failure, *alloc_base is set to NULL and the function + * returns NULL. + */ +void * +virFileDirectBufferNew(void **alloc_base, size_t buflen) +{ + void *buf; + buflen =3D virFileDirectAlign(buflen); + +# if WITH_POSIX_MEMALIGN + if (posix_memalign(alloc_base, VIR_FILE_DIRECT_ALIGN_MASK + 1, buflen)= ) { + *alloc_base =3D NULL; + return NULL; + } + buf =3D *alloc_base; +# else + *alloc_base =3D g_malloc(buflen + VIR_FILE_DIRECT_ALIGN_MASK); + buf =3D virFileDirectAlign((uintptr_t)*alloc_base); +# endif + return buf; +} + # ifdef __linux__ =20 /** @@ -372,6 +611,16 @@ virFileWrapperFdNew(int *fd, const char *name, unsigne= d int flags) return NULL; } #else /* WIN32 */ + +void * +virFileDirectBufferNew(void **alloc_base G_GNUC_UNUSED, + size_t buflen G_GNUC_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("virFileDirectBufferNew unsupported on this platform"= )); + return NULL; +} + virFileWrapperFd * virFileWrapperFdNew(int *fd G_GNUC_UNUSED, const char *name G_GNUC_UNUSED, diff --git a/src/util/virfile.h b/src/util/virfile.h index 8e378efe30..5031f99f7c 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -104,6 +104,16 @@ typedef struct _virFileWrapperFd virFileWrapperFd; =20 int virFileDirectFdFlag(void); =20 +#define VIR_FILE_DIRECT_ALIGN_MASK ((64 * 1024) - 1) + +void *virFileDirectBufferNew(void **alloc_base, size_t buflen); +ssize_t virFileDirectRead(int fd, void *buf, size_t count); +ssize_t virFileDirectWrite(int fd, void *buf, size_t count); +ssize_t virFileDirectReadLim(int fd, void *buf, size_t lim); +ssize_t virFileDirectWriteLim(int fd, void *buf, size_t lim); +size_t virFileDirectCopyBuf(void **buf, size_t count, void **dst, size_t *= dst_len); +ssize_t virFileDirectReadCopy(int fd, void **buf, size_t buflen, void *dst= , size_t dst_len); + typedef enum { VIR_FILE_WRAPPER_BYPASS_CACHE =3D (1 << 0), VIR_FILE_WRAPPER_NON_BLOCKING =3D (1 << 1), --=20 2.35.3