From nobody Wed Feb 11 07:09:32 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1492682660706220.46398987792907; Thu, 20 Apr 2017 03:04:20 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BDD51C04BD4D; Thu, 20 Apr 2017 10:04:18 +0000 (UTC) Received: from colo-mx.corp.redhat.com (unknown [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 920BB8279E; Thu, 20 Apr 2017 10:04:18 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 3A0A8B3187; Thu, 20 Apr 2017 10:04:00 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v3KA2LXb001341 for ; Thu, 20 Apr 2017 06:02:21 -0400 Received: by smtp.corp.redhat.com (Postfix) id 957C67F6B7; Thu, 20 Apr 2017 10:02:21 +0000 (UTC) Received: from moe.brq.redhat.com (dhcp129-131.brq.redhat.com [10.34.129.131]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1EAAE7F6C1 for ; Thu, 20 Apr 2017 10:02:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com BDD51C04BD4D Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com BDD51C04BD4D From: Michal Privoznik To: libvir-list@redhat.com Date: Thu, 20 Apr 2017 12:01:37 +0200 Message-Id: <9fee4e923416977a18b600f319cdb79e7354dfe6.1492682033.git.mprivozn@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v2 08/38] util: Introduce virFileInData X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Thu, 20 Apr 2017 10:04:19 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" This function takes a FD and determines whether the current position is in data section or in a hole. In addition to that, it also determines how much bytes are there remaining till the current section ends. Signed-off-by: Michal Privoznik --- src/libvirt_private.syms | 1 + src/util/virfile.c | 81 +++++++++++++++++++ src/util/virfile.h | 3 + tests/virfiletest.c | 203 +++++++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 288 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 181e178..7132b3a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1620,6 +1620,7 @@ virFileGetHugepageSize; virFileGetMountReverseSubtree; virFileGetMountSubtree; virFileHasSuffix; +virFileInData; virFileIsAbsPath; virFileIsDir; virFileIsExecutable; diff --git a/src/util/virfile.c b/src/util/virfile.c index cbfa384..093125c 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -3793,6 +3793,87 @@ virFileComparePaths(const char *p1, const char *p2) cleanup: VIR_FREE(res1); VIR_FREE(res2); + + return ret; +} + + +int virFileInData(int fd, + int *inData, + unsigned long long *length) +{ + int ret =3D -1; + off_t cur, data, hole, end; + + /* Get current position */ + cur =3D lseek(fd, 0, SEEK_CUR); + if (cur =3D=3D (off_t) -1) { + virReportSystemError(errno, "%s", + _("Unable to get current position in file")); + goto cleanup; + } + + /* Now try to get data and hole offsets */ + data =3D lseek(fd, cur, SEEK_DATA); + + /* There are four options: + * 1) data =3D=3D cur; @cur is in data + * 2) data > cur; @cur is in a hole, next data at @data + * 3) data < 0, errno =3D ENXIO; either @cur is in trailing hole, or @= cur is beyond EOF. + * 4) data < 0, errno !=3D ENXIO; we learned nothing + */ + + if (data =3D=3D (off_t) -1) { + /* cases 3 and 4 */ + if (errno !=3D ENXIO) { + virReportSystemError(errno, "%s", + _("Unable to seek to data")); + goto cleanup; + } + + *inData =3D 0; + /* There are two situations now. There is always an + * implicit hole at EOF. However, there might be a + * trailing hole just before EOF too. If that's the case + * report it. */ + if ((end =3D lseek(fd, 0, SEEK_END)) =3D=3D (off_t) -1) { + virReportSystemError(errno, "%s", + _("Unable to seek to EOF")); + goto cleanup; + } + *length =3D end - cur; + } else if (data > cur) { + /* case 2 */ + *inData =3D 0; + *length =3D data - cur; + } else { + /* case 1 */ + *inData =3D 1; + + /* We don't know where does the next hole start. Let's + * find out. Here we get the same 4 possibilities as + * described above.*/ + hole =3D lseek(fd, data, SEEK_HOLE); + if (hole =3D=3D (off_t) -1 || hole =3D=3D data) { + /* cases 1, 3 and 4 */ + /* Wait a second. The reason why we are here is + * because we are in data. But at the same time we + * are in a trailing hole? Wut!? Do the best what we + * can do here. */ + virReportSystemError(errno, "%s", + _("unable to seek to hole")); + goto cleanup; + } else { + /* case 2 */ + *length =3D (hole - data); + } + } + + ret =3D 0; + cleanup: + /* At any rate, reposition back to where we started. */ + if (cur !=3D (off_t) -1) + ignore_value(lseek(fd, cur, SEEK_SET)); return ret; } =20 diff --git a/src/util/virfile.h b/src/util/virfile.h index 41c25a2..32a1d3c 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -340,4 +340,7 @@ int virFileReadValueInt(const char *path, int *value); int virFileReadValueUint(const char *path, unsigned int *value); int virFileReadValueBitmap(const char *path, int maxlen, virBitmapPtr *val= ue); =20 +int virFileInData(int fd, + int *inData, + unsigned long long *length); #endif /* __VIR_FILE_H */ diff --git a/tests/virfiletest.c b/tests/virfiletest.c index 702a76a..3e298dc 100644 --- a/tests/virfiletest.c +++ b/tests/virfiletest.c @@ -21,6 +21,7 @@ #include =20 #include +#include =20 #include "testutils.h" #include "virfile.h" @@ -119,6 +120,190 @@ testFileSanitizePath(const void *opaque) =20 =20 static int +makeSparseFile(const off_t offsets[], + const bool startData); + +#ifdef __linux__ +/* Create a sparse file. @offsets in KiB. */ +static int +makeSparseFile(const off_t offsets[], + const bool startData) +{ + int fd =3D -1; + char path[] =3D abs_builddir "fileInData.XXXXXX"; + off_t len =3D 0; + size_t i; + + if ((fd =3D mkostemp(path, O_CLOEXEC|O_RDWR)) < 0) + goto error; + + if (unlink(path) < 0) + goto error; + + for (i =3D 0; offsets[i] !=3D (off_t) -1; i++) + len +=3D offsets[i] * 1024; + + while (len) { + const char buf[] =3D "abcdefghijklmnopqrstuvwxyz"; + off_t toWrite =3D sizeof(buf); + + if (toWrite > len) + toWrite =3D len; + + if (safewrite(fd, buf, toWrite) < 0) { + fprintf(stderr, "unable to write to %s (errno=3D%d)\n", path, = errno); + goto error; + } + + len -=3D toWrite; + } + + len =3D 0; + for (i =3D 0; offsets[i] !=3D (off_t) -1; i++) { + bool inData =3D startData; + + if (i % 2) + inData =3D !inData; + + if (!inData && + fallocate(fd, + FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + len, offsets[i] * 1024) < 0) { + fprintf(stderr, "unable to punch a hole at offset %lld length = %lld\n", + (long long) len, (long long) offsets[i]); + goto error; + } + + len +=3D offsets[i] * 1024; + } + + if (lseek(fd, 0, SEEK_SET) =3D=3D (off_t) -1) { + fprintf(stderr, "unable to lseek (errno=3D%d)\n", errno); + goto error; + } + + return fd; + error: + VIR_FORCE_CLOSE(fd); + return -1; +} + +#else /* !__linux__ */ + +static int +makeSparseFile(const off_t offsets[] ATTRIBUTE_UNUSED, + const bool startData ATTRIBUTE_UNUSED) +{ + return -1; +} + +#endif /* !__linux__ */ + + +#define EXTENT 4 +static bool +holesSupported(void) +{ + off_t offsets[] =3D {EXTENT, EXTENT, EXTENT, -1}; + off_t tmp; + int fd; + bool ret =3D false; + + if ((fd =3D makeSparseFile(offsets, true)) < 0) + goto cleanup; + + /* The way this works is: there are 4K of data followed by 4K hole fol= lowed + * by 4K hole again. Check if the filesystem we are running the test s= uite + * on supports holes. */ + if ((tmp =3D lseek(fd, 0, SEEK_DATA)) =3D=3D (off_t) -1) + goto cleanup; + + if (tmp !=3D 0) + goto cleanup; + + if ((tmp =3D lseek(fd, tmp, SEEK_HOLE)) =3D=3D (off_t) -1) + goto cleanup; + + if (tmp !=3D EXTENT * 1024) + goto cleanup; + + if ((tmp =3D lseek(fd, tmp, SEEK_DATA)) =3D=3D (off_t) -1) + goto cleanup; + + if (tmp !=3D 2 * EXTENT * 1024) + goto cleanup; + + if ((tmp =3D lseek(fd, tmp, SEEK_HOLE)) =3D=3D (off_t) -1) + goto cleanup; + + if (tmp !=3D 3 * EXTENT * 1024) + goto cleanup; + + ret =3D true; + cleanup: + VIR_FORCE_CLOSE(fd); + return ret; +} + + +struct testFileInData { + bool startData; /* whether the list of offsets starts with data se= ction */ + off_t *offsets; +}; + + +static int +testFileInData(const void *opaque) +{ + const struct testFileInData *data =3D opaque; + int fd =3D -1; + int ret =3D -1; + size_t i; + + if ((fd =3D makeSparseFile(data->offsets, data->startData)) < 0) + goto cleanup; + + for (i =3D 0; data->offsets[i] !=3D (off_t) -1; i++) { + bool shouldInData =3D data->startData; + int realInData; + unsigned long long shouldLen; + unsigned long long realLen; + + if (i % 2) + shouldInData =3D !shouldInData; + + if (virFileInData(fd, &realInData, &realLen) < 0) + goto cleanup; + + if (realInData !=3D shouldInData) { + fprintf(stderr, "Unexpected data/hole. Expected %s got %s\n", + shouldInData ? "data" : "hole", + realInData ? "data" : "hole"); + goto cleanup; + } + + shouldLen =3D data->offsets[i] * 1024; + if (realLen !=3D shouldLen) { + fprintf(stderr, "Unexpected section length. Expected %lld got = %lld\n", + shouldLen, realLen); + goto cleanup; + } + + if (lseek(fd, shouldLen, SEEK_CUR) < 0) { + fprintf(stderr, "Unable to seek\n"); + goto cleanup; + } + } + + ret =3D 0; + + cleanup: + VIR_FORCE_CLOSE(fd); + return ret; +} + + +static int mymain(void) { int ret =3D 0; @@ -186,6 +371,24 @@ mymain(void) DO_TEST_SANITIZE_PATH_SAME("gluster://bar.baz/fooo//hoo"); DO_TEST_SANITIZE_PATH_SAME("gluster://bar.baz/fooo///////hoo"); =20 +#define DO_TEST_IN_DATA(inData, ...) = \ + do { = \ + off_t offsets[] =3D {__VA_ARGS__, -1}; = \ + struct testFileInData data =3D { = \ + .startData =3D inData, .offsets =3D offsets, = \ + }; = \ + if (virTestRun(virTestCounterNext(), testFileInData, &data) < 0) = \ + ret =3D -1; = \ + } while (0) + + if (holesSupported()) { + DO_TEST_IN_DATA(true, 4, 4, 4); + DO_TEST_IN_DATA(false, 4, 4, 4); + DO_TEST_IN_DATA(true, 8, 8, 8); + DO_TEST_IN_DATA(false, 8, 8, 8); + DO_TEST_IN_DATA(true, 8, 16, 32, 64, 128, 256, 512); + DO_TEST_IN_DATA(false, 8, 16, 32, 64, 128, 256, 512); + } return ret !=3D 0 ? EXIT_FAILURE : EXIT_SUCCESS; } =20 --=20 2.10.2 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list