[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v3 02/15] libxl: functions to lock / unlock libxl userdata store



This lock is used to protect all userdata files related to a particular
domain, which include but are not limited to domain configuration.  A
new "domain-userdata-lock" entry is introduced in libxl registry.

This lock works among different processes and different threads within
the same process.

Locking protocol inspired by Ian Jackson's chiark-utils with-lock-ex. A
file lock is taken with flock(2). If that succeeds that thread fstat the
fd and stat the lock file path. If the device and inode match then the
lock has been successfully acquired. This lock remains acquired until
the lock file gets deleted or released by flock(2). If device and inode
don't match then another thread acquired the lock and deleted the file
in the meantime; lock procedure should restart.

Portability note: this lock utilises flock(2) so a proper implementation
of flock(2) is required -- that is, it should not be implemented with
fcntl(2).

Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx>
Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>

---
change in v3:
rename functions to libxl__{un,}lock_domain_userdata
rename registry entry to "domain-userdata-lock"
---
 tools/libxl/libxl.h          |    3 ++
 tools/libxl/libxl_internal.c |   69 ++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_internal.h |    5 +++
 3 files changed, 77 insertions(+)

diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 460207b..1ca25ae 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 b880c89..edf864b 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 7244473..0cedd30 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -43,6 +43,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/socket.h>
+#include <sys/file.h>
 
 #include <xenstore.h>
 #include <xenctrl.h>
@@ -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
 
 /*
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.