From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> Add a virFileNBDDeviceAssociate method, which given a filename will setup a NBD device, using qemu-nbd as the server. Signed-off-by: Daniel P. Berrange <berrange@xxxxxxxxxx> --- src/libvirt_private.syms | 1 + src/util/virfile.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++- src/util/virfile.h | 6 ++ 3 files changed, 155 insertions(+), 3 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f778e9c..a857a0b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1272,6 +1272,7 @@ virFileDirectFdFlag; virFileFclose; virFileFdopen; virFileLoopDeviceAssociate; +virFileNBDDeviceAssociate; virFileRewrite; virFileTouch; virFileUpdatePerm; diff --git a/src/util/virfile.c b/src/util/virfile.c index fbaeedd..034648b 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -530,6 +530,7 @@ static int virFileLoopDeviceOpen(char **dev_name) goto cleanup; } + errno = 0; while ((de = readdir(dh)) != NULL) { if (!STRPREFIX(de->d_name, "loop")) continue; @@ -561,10 +562,15 @@ static int virFileLoopDeviceOpen(char **dev_name) /* Oh well, try the next device */ VIR_FORCE_CLOSE(fd); VIR_FREE(looppath); + errno = 0; } - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find a free loop device in /dev")); + if (errno != 0) + virReportSystemError(errno, "%s", + _("Unable to iterate over loop devices")); + else + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find a free loop device in /dev")); cleanup: if (fd != -1) { @@ -631,10 +637,138 @@ cleanup: return lofd; } + +# define SYSFS_BLOCK_DIR "/sys/block" + + +static int +virFileNBDDeviceIsBusy(const char *devname) +{ + char *path; + int ret = -1; + + if (virAsprintf(&path, SYSFS_BLOCK_DIR "/%s/pid", + devname) < 0) { + virReportOOMError(); + return -1; + } + + if (access(path, F_OK) < 0) { + if (errno == ENOENT) + ret = 0; + else + virReportSystemError(errno, + _("Cannot check NBD device %s pid"), + devname); + goto cleanup; + } + ret = 1; + +cleanup: + VIR_FREE(path); + return ret; +} + + +static char * +virFileNBDDeviceFindUnused(void) +{ + DIR *dh; + char *ret = NULL; + struct dirent *de; + + if (!(dh = opendir(SYSFS_BLOCK_DIR))) { + virReportSystemError(errno, + _("Cannot read directory %s"), + SYSFS_BLOCK_DIR); + return NULL; + } + + while ((de = readdir(dh)) != NULL) { + if (STRPREFIX(de->d_name, "nbd")) { + int rv = virFileNBDDeviceIsBusy(de->d_name); + if (rv < 0) + goto cleanup; + if (rv == 0) { + if (virAsprintf(&ret, "/dev/%s", de->d_name) < 0) { + virReportOOMError(); + goto cleanup; + } + goto cleanup; + } + } + } + + virReportSystemError(EBUSY, "%s", + _("No free NBD devices")); + +cleanup: + closedir(dh); + return ret; +} + + +int virFileNBDDeviceAssociate(const char *file, + enum virStorageFileFormat fmt, + bool readonly, + char **dev) +{ + char *nbddev; + char *qemunbd; + virCommandPtr cmd = NULL; + int ret = -1; + const char *fmtstr = NULL; + + if (!(nbddev = virFileNBDDeviceFindUnused())) + goto cleanup; + + if (!(qemunbd = virFindFileInPath("qemu-nbd"))) { + virReportSystemError(ENOENT, "%s", + _("Unable to find 'qemu-nbd' binary in $PATH")); + goto cleanup; + } + + if (fmt > 0) + fmtstr = virStorageFileFormatTypeToString(fmt); + + cmd = virCommandNew(qemunbd); + + /* Explicitly not trying to cope with old qemu-nbd which + * lacked --format. We want to see a fatal error in that + * case since it would be security flaw to continue */ + if (fmtstr) { + virCommandAddArg(cmd, "--format"); + virCommandAddArg(cmd, fmtstr); + } + + if (readonly) + virCommandAddArg(cmd, "-r"); + + virCommandAddArgList(cmd, + "-n", /* Don't cache in qemu-nbd layer */ + "-c", nbddev, + file, NULL); + + /* qemu-nbd will daemonize itself */ + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + *dev = nbddev; + nbddev = NULL; + ret = 0; + +cleanup: + VIR_FREE(nbddev); + VIR_FREE(qemunbd); + virCommandFree(cmd); + return ret; +} + #else /* __linux__ */ int virFileLoopDeviceAssociate(const char *file, - char **dev ATTRIBUTE_UNUSED) + char **dev ATTRIBUTE) { virReportSystemError(ENOSYS, _("Unable to associate file %s with loop device"), @@ -643,6 +777,17 @@ int virFileLoopDeviceAssociate(const char *file, return -1; } +int virFileNBDDeviceAssociate(const char *file, + enum virStorageFileFormat fmt ATTRIBUTE_UNUSED, + bool readonly ATTRIBUTE_UNUSED, + char **dev ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, + _("Unable to associate file %s with NBD device"), + file); + return -1; +} + #endif /* __linux__ */ diff --git a/src/util/virfile.h b/src/util/virfile.h index 5f0dd2b..9bd8ea5 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -29,6 +29,7 @@ # include <stdio.h> # include "internal.h" +# include "virstoragefile.h" typedef enum virFileCloseFlags { VIR_FILE_CLOSE_PRESERVE_ERRNO = 1 << 0, @@ -108,6 +109,11 @@ int virFileUpdatePerm(const char *path, int virFileLoopDeviceAssociate(const char *file, char **dev); +int virFileNBDDeviceAssociate(const char *file, + enum virStorageFileFormat fmt, + bool readonly, + char **dev); + int virFileDeleteTree(const char *dir); #endif /* __VIR_FILES_H */ -- 1.7.11.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list