[libvirt PATCH] iohelper: some refactoring
Claudio Fontana
cfontana at suse.de
Sat Mar 26 16:54:10 UTC 2022
this is of course broken (missing a write),
will send a v2 to fix it up.
Claudio
On 3/26/22 5:07 PM, Claudio Fontana wrote:
> while doing research with alternative implementations of runIO,
> it seemed necessary to do some refactoring, in order to separate
> parameter setting from the actual copy, so that alternative
> copy methods can be researched and hopefully eventually implemented.
>
> No functional changes are expected.
>
> Signed-off-by: Claudio Fontana <cfontana at suse.de>
> ---
> src/util/iohelper.c | 193 +++++++++++++++++++++++++++-----------------
> 1 file changed, 118 insertions(+), 75 deletions(-)
>
> diff --git a/src/util/iohelper.c b/src/util/iohelper.c
> index 2c91bf4f93..c04c97af27 100644
> --- a/src/util/iohelper.c
> +++ b/src/util/iohelper.c
> @@ -45,21 +45,38 @@
> # define O_DIRECT 0
> #endif
>
> -static int
> -runIO(const char *path, int fd, int oflags)
> +struct runIOParams {
> + bool isBlockDev;
> + bool isDirect;
> + bool isWrite;
> + int fdin;
> + const char *fdinname;
> + int fdout;
> + const char *fdoutname;
> +};
> +
> +/* runIOCopy: execute the IO copy based on the passed parameters */
> +/**
> + * runIOCopy:
> + * @p: the IO parameters
> + *
> + * Execute the copy based on the passed parameters.
> + *
> + * Returns: size transfered, or < 0 on error.
> + * Errors: -1 = read/write error
> + * -2 = read error
> + * -3 = write error
> + * -4 = truncate error
> + */
> +
> +static ssize_t
> +runIOCopy(const struct runIOParams p)
> {
> g_autofree void *base = NULL; /* Location to be freed */
> char *buf = NULL; /* Aligned location within base */
> size_t buflen = 1024*1024;
> intptr_t alignMask = 64*1024 - 1;
> - int ret = -1;
> - int fdin, fdout;
> - const char *fdinname, *fdoutname;
> - unsigned long long total = 0;
> - bool direct = O_DIRECT && ((oflags & O_DIRECT) != 0);
> - off_t end = 0;
> - struct stat sb;
> - bool isBlockDev = false;
> + ssize_t total = 0;
>
> #if WITH_POSIX_MEMALIGN
> if (posix_memalign(&base, alignMask + 1, buflen))
> @@ -71,50 +88,6 @@ runIO(const char *path, int fd, int oflags)
> buf = (char *) (((intptr_t) base + alignMask) & ~alignMask);
> #endif
>
> - if (fstat(fd, &sb) < 0) {
> - virReportSystemError(errno,
> - _("Unable to access file descriptor %d path %s"),
> - fd, path);
> - goto cleanup;
> - }
> - isBlockDev = S_ISBLK(sb.st_mode);
> -
> - switch (oflags & O_ACCMODE) {
> - case O_RDONLY:
> - fdin = fd;
> - fdinname = path;
> - fdout = STDOUT_FILENO;
> - fdoutname = "stdout";
> - /* To make the implementation simpler, we give up on any
> - * attempt to use O_DIRECT in a non-trivial manner. */
> - if (!isBlockDev && direct && ((end = lseek(fd, 0, SEEK_CUR)) != 0)) {
> - virReportSystemError(end < 0 ? errno : EINVAL, "%s",
> - _("O_DIRECT read needs entire seekable file"));
> - goto cleanup;
> - }
> - break;
> - case O_WRONLY:
> - fdin = STDIN_FILENO;
> - fdinname = "stdin";
> - fdout = fd;
> - fdoutname = path;
> - /* To make the implementation simpler, we give up on any
> - * attempt to use O_DIRECT in a non-trivial manner. */
> - if (!isBlockDev && direct && (end = lseek(fd, 0, SEEK_END)) != 0) {
> - virReportSystemError(end < 0 ? errno : EINVAL, "%s",
> - _("O_DIRECT write needs empty seekable file"));
> - goto cleanup;
> - }
> - break;
> -
> - case O_RDWR:
> - default:
> - virReportSystemError(EINVAL,
> - _("Unable to process file with flags %d"),
> - (oflags & O_ACCMODE));
> - goto cleanup;
> - }
> -
> while (1) {
> ssize_t got;
>
> @@ -124,53 +97,123 @@ runIO(const char *path, int fd, int oflags)
> * writes will be aligned.
> * In other cases using saferead reduces number of syscalls.
> */
> - if (fdin == fd && direct) {
> - if ((got = read(fdin, buf, buflen)) < 0 &&
> + if (!p.isWrite && p.isDirect) {
> + if ((got = read(p.fdin, buf, buflen)) < 0 &&
> errno == EINTR)
> continue;
> } else {
> - got = saferead(fdin, buf, buflen);
> - }
> -
> - if (got < 0) {
> - virReportSystemError(errno, _("Unable to read %s"), fdinname);
> - goto cleanup;
> + got = saferead(p.fdin, buf, buflen);
> }
> + if (got < 0)
> + return -2;
> if (got == 0)
> break;
>
> total += got;
>
> /* handle last write size align in direct case */
> - if (got < buflen && direct && fdout == fd) {
> + if (got < buflen && p.isDirect && p.isWrite) {
> ssize_t aligned_got = (got + alignMask) & ~alignMask;
>
> memset(buf + got, 0, aligned_got - got);
>
> - if (safewrite(fdout, buf, aligned_got) < 0) {
> - virReportSystemError(errno, _("Unable to write %s"), fdoutname);
> - goto cleanup;
> + if (safewrite(p.fdout, buf, aligned_got) < 0) {
> + return -3;
> }
> -
> - if (!isBlockDev && ftruncate(fd, total) < 0) {
> - virReportSystemError(errno, _("Unable to truncate %s"), fdoutname);
> - goto cleanup;
> + if (!p.isBlockDev && ftruncate(p.fdout, total) < 0) {
> + return -4;
> }
> -
> break;
> }
> + }
> + return total;
> +}
>
> - if (safewrite(fdout, buf, got) < 0) {
> - virReportSystemError(errno, _("Unable to write %s"), fdoutname);
> +static int
> +runIO(const char *path, int fd, int oflags)
> +{
> + int ret = -1;
> + off_t total = 0;
> + struct stat sb;
> + struct runIOParams p;
> +
> + if (fstat(fd, &sb) < 0) {
> + virReportSystemError(errno,
> + _("Unable to access file descriptor %d path %s"),
> + fd, path);
> + goto cleanup;
> + }
> + p.isBlockDev = S_ISBLK(sb.st_mode);
> + p.isDirect = O_DIRECT && (oflags & O_DIRECT);
> +
> + switch (oflags & O_ACCMODE) {
> + case O_RDONLY:
> + p.isWrite = false;
> + p.fdin = fd;
> + p.fdinname = path;
> + p.fdout = STDOUT_FILENO;
> + p.fdoutname = "stdout";
> + break;
> + case O_WRONLY:
> + p.isWrite = true;
> + p.fdin = STDIN_FILENO;
> + p.fdinname = "stdin";
> + p.fdout = fd;
> + p.fdoutname = path;
> + break;
> + case O_RDWR:
> + default:
> + virReportSystemError(EINVAL,
> + _("Unable to process file with flags %d"),
> + (oflags & O_ACCMODE));
> + goto cleanup;
> + }
> + /* To make the implementation simpler, we give up on any
> + * attempt to use O_DIRECT in a non-trivial manner. */
> + if (!p.isBlockDev && p.isDirect) {
> + off_t end;
> + if (p.isWrite) {
> + if ((end = lseek(fd, 0, SEEK_END)) != 0) {
> + virReportSystemError(end < 0 ? errno : EINVAL, "%s",
> + _("O_DIRECT write needs empty seekable file"));
> + goto cleanup;
> + }
> + } else if ((end = lseek(fd, 0, SEEK_CUR)) != 0) {
> + virReportSystemError(end < 0 ? errno : EINVAL, "%s",
> + _("O_DIRECT read needs entire seekable file"));
> goto cleanup;
> }
> }
>
> + total = runIOCopy(p);
> +
> + if (total < 0) {
> + switch (total) {
> + case -1:
> + virReportSystemError(errno, _("Unable to move data from %s to %s"),
> + p.fdinname, p.fdoutname);
> + break;
> + case -2:
> + virReportSystemError(errno, _("Unable to read %s"), p.fdinname);
> + break;
> + case -3:
> + virReportSystemError(errno, _("Unable to write %s"), p.fdoutname);
> + break;
> + case -4:
> + virReportSystemError(errno, _("Unable to truncate %s"), p.fdoutname);
> + break;
> + default:
> + virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown runIOCopy error %ld"), total);
> + break;
> + }
> + goto cleanup;
> + }
> +
> /* Ensure all data is written */
> - if (virFileDataSync(fdout) < 0) {
> + if (virFileDataSync(p.fdout) < 0) {
> if (errno != EINVAL && errno != EROFS) {
> /* fdatasync() may fail on some special FDs, e.g. pipes */
> - virReportSystemError(errno, _("unable to fsync %s"), fdoutname);
> + virReportSystemError(errno, _("unable to fsync %s"), p.fdoutname);
> goto cleanup;
> }
> }
>
More information about the libvir-list
mailing list