diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 460207bf59..1ca25ae3ff 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -1220,6 +1220,9 @@ void libxl_cpuid_set(libxl_ctx *ctx, uint32_t domid, * "xl" domain config file in xl format, Unix line endings * "libvirt-xml" domain config file in libvirt XML format. See * http://libvirt.org/formatdomain.html + * "domain-userdata-lock" lock file to protect domain userdata in libxl. + * It's a per-domain lock. Applications should + * not touch this file. * * libxl does not enforce the registration of userdata userids or the * semantics of the data. For specifications of the data formats diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c index b880c898b5..edf864b7d2 100644 --- a/tools/libxl/libxl_internal.c +++ b/tools/libxl/libxl_internal.c @@ -381,6 +381,75 @@ out: return rc; } +/* Portability note: this lock utilises flock(2) so a proper implementation of + * flock(2) is required. + */ +libxl__carefd *libxl__lock_domain_userdata(libxl__gc *gc, uint32_t domid) +{ + libxl__carefd *carefd = NULL; + const char *lockfile; + int fd; + struct stat stab, fstab; + + lockfile = libxl__userdata_path(gc, domid, "domain-userdata-lock", "l"); + if (!lockfile) goto out; + + while (true) { + libxl__carefd_begin(); + fd = open(lockfile, O_RDWR|O_CREAT, 0666); + if (fd < 0) + LOGE(ERROR, "cannot open lockfile %s, errno=%d", lockfile, errno); + carefd = libxl__carefd_opened(CTX, fd); + if (fd < 0) goto out; + + /* Lock the file in exclusive mode, wait indefinitely to + * acquire the lock + */ + while (flock(fd, LOCK_EX)) { + switch (errno) { + case EINTR: + /* Signal received, retry */ + continue; + default: + /* All other errno: EBADF, EINVAL, ENOLCK, EWOULDBLOCK */ + LOGE(ERROR, + "unexpected error while trying to lock %s, fd=%d, errno=%d", + lockfile, fd, errno); + goto out; + } + } + + if (fstat(fd, &fstab)) { + LOGE(ERROR, "cannot fstat %s, fd=%d, errno=%d", + lockfile, fd, errno); + goto out; + } + if (stat(lockfile, &stab)) { + if (errno != ENOENT) { + LOGE(ERROR, "cannot stat %s, errno=%d", lockfile, errno); + goto out; + } + } else { + if (stab.st_dev == fstab.st_dev && stab.st_ino == fstab.st_ino) + break; + } + + libxl__carefd_close(carefd); + } + + return carefd; + +out: + if (carefd) libxl__carefd_close(carefd); + return NULL; +} + +void libxl__unlock_domain_userdata(libxl__carefd *lock_carefd) +{ + /* Simply closing the file descriptor releases the lock */ + libxl__carefd_close(lock_carefd); +} + /* * Local variables: * mode: C diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 7244473d88..0cedd3092c 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -3223,6 +3224,10 @@ static inline int libxl__key_value_list_is_empty(libxl_key_value_list *pkvl) int libxl__cpuid_policy_is_empty(libxl_cpuid_policy_list *pl); +/* Portability note: a proper flock(2) implementation is required */ +libxl__carefd *libxl__lock_domain_userdata(libxl__gc *gc, uint32_t domid); +void libxl__unlock_domain_userdata(libxl__carefd *lock_carefd); + #endif /*