#include <arpa/inet.h>
#include <ifaddrs.h>
-extern pthread_mutex_t thread_mutex;
-
lxc_log_define(lxc_container, lxc);
/* LOCKING
if (c->numthreads < 1)
return 0;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return 0;
if (c->numthreads < 1) {
// bail without trying to unlock, bc the privlock is now probably
return 0;
}
c->numthreads++;
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return 1;
}
{
if (!c)
return -1;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return -1;
if (--c->numthreads < 1) {
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
lxc_container_free(c);
return 1;
}
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return 0;
}
if (!c)
return false;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return false;
if (!c->configfile)
goto out;
ret = true;
out:
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return ret;
}
if (!c)
return NULL;
- if (lxclock(c->privlock, 0))
+ if (container_disk_lock(c))
return NULL;
- if (lxclock(c->slock, 0))
- goto bad;
s = lxc_getstate(c->name, c->config_path);
ret = lxc_state2str(s);
- lxcunlock(c->slock);
-bad:
- lxcunlock(c->privlock);
+ container_disk_unlock(c);
return ret;
}
if (!c)
return false;
- if (lxclock(c->privlock, 0))
- return false;
- if (lxclock(c->slock, 0)) {
- lxcunlock(c->privlock);
+ if (container_disk_lock(c))
return false;
- }
ret = lxc_freeze(c->name, c->config_path);
- lxcunlock(c->slock);
- lxcunlock(c->privlock);
+ container_disk_unlock(c);
if (ret)
return false;
return true;
if (!c)
return false;
- if (lxclock(c->privlock, 0))
- return false;
- if (lxclock(c->slock, 0)) {
- lxcunlock(c->privlock);
+ if (container_disk_lock(c))
return false;
- }
ret = lxc_unfreeze(c->name, c->config_path);
- lxcunlock(c->slock);
- lxcunlock(c->privlock);
+ container_disk_unlock(c);
if (ret)
return false;
return true;
static pid_t lxcapi_init_pid(struct lxc_container *c)
{
- pid_t ret;
if (!c)
return -1;
- if (lxclock(c->privlock, 0))
- return -1;
- if (lxclock(c->slock, 0)) {
- lxcunlock(c->privlock);
- return -1;
- }
- ret = lxc_cmd_get_init_pid(c->name, c->config_path);
- lxcunlock(c->slock);
- lxcunlock(c->privlock);
- return ret;
+ return lxc_cmd_get_init_pid(c->name, c->config_path);
}
static bool load_config_locked(struct lxc_container *c, const char *fname)
fname = alt_file;
if (!fname)
return false;
- if (lxclock(c->privlock, 0))
- return false;
- if (lxclock(c->slock, 0)) {
- lxcunlock(c->privlock);
+ if (container_disk_lock(c))
return false;
- }
ret = load_config_locked(c, fname);
- lxcunlock(c->slock);
- lxcunlock(c->privlock);
+ container_disk_unlock(c);
return ret;
}
if (useinit && !argv)
return false;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return false;
conf = c->lxc_conf;
daemonize = c->daemonize;
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
if (useinit) {
ret = lxc_execute(c->name, argv, 1, conf, c->config_path);
return false;
lxc_monitord_spawn(c->config_path);
- ret = pthread_mutex_lock(&thread_mutex);
- if (ret != 0) {
- ERROR("pthread_mutex_lock returned:%d %s", ret, strerror(ret));
+ if (process_lock())
return false;
- }
pid_t pid = fork();
if (pid < 0) {
lxc_container_put(c);
- pthread_mutex_unlock(&thread_mutex);
+ process_unlock();
return false;
}
if (pid != 0) {
ret = wait_on_daemonized_start(c);
- pthread_mutex_unlock(&thread_mutex);
+ process_unlock();
return ret;
}
- pthread_mutex_unlock(&thread_mutex);
+ process_unlock();
/* second fork to be reparented by init */
pid = fork();
if (pid < 0) {
/* we're going to fork. but since we'll wait for our child, we
* don't need to lxc_container_get */
- if (lxclock(c->privlock, 0))
+ if (container_disk_lock(c))
goto out;
- if (lxclock(c->slock, 0)) {
- ERROR("failed to grab global container lock for %s\n", c->name);
- lxcunlock(c->privlock);
- goto out_unlock1;
- }
pid = fork();
if (pid < 0) {
bret = load_config_locked(c, c->configfile);
out_unlock:
- lxcunlock(c->slock);
-out_unlock1:
- lxcunlock(c->privlock);
+ container_disk_unlock(c);
out:
if (tpath)
free(tpath);
if (!c || !c->lxc_conf)
return false;
- if (lxclock(c->privlock, 0)) {
+ if (container_mem_lock(c))
return false;
- }
ret = lxc_clear_config_item(c->lxc_conf, key);
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return ret == 0;
}
if (!c || !c->lxc_conf)
return -1;
- if (lxclock(c->privlock, 0)) {
+ if (container_mem_lock(c))
return -1;
- }
ret = lxc_get_config_item(c->lxc_conf, key, retv, inlen);
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return ret;
}
*/
if (!c || !c->lxc_conf)
return -1;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return -1;
int ret = -1;
if (strncmp(key, "lxc.network.", 12) == 0)
ret = lxc_list_nicconfigs(c->lxc_conf, key, retv, inlen);
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return ret;
}
FILE *fout = fopen(alt_file, "w");
if (!fout)
return false;
- if (lxclock(c->privlock, 0)) {
+ if (container_mem_lock(c)) {
fclose(fout);
return false;
}
write_config(fout, c->lxc_conf);
fclose(fout);
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return true;
}
if (!c)
return false;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return false;
if (!c->lxc_conf)
b = true;
err:
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return b;
}
if (!c)
return b;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return b;
p = strdup(path);
err:
if (oldpath)
free(oldpath);
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return b;
}
if (!c)
return false;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return false;
if (is_stopped_nolock(c))
if (!ret)
b = true;
err:
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return b;
}
if (!c || !c->lxc_conf)
return -1;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return -1;
if (is_stopped_nolock(c))
ret = lxc_cgroup_get(c->name, subsys, retv, inlen, c->config_path);
out:
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return ret;
}
if (!c || !c->is_defined(c))
return NULL;
- if (lxclock(c->privlock, 0))
+ if (container_mem_lock(c))
return NULL;
if (c->is_running(c)) {
goto out;
// TODO: update c's lxc.snapshot = count
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
return c2;
out:
- lxcunlock(c->privlock);
+ container_mem_unlock(c);
if (c2) {
c2->destroy(c2);
lxc_container_put(c2);
#include <unistd.h>
#include <lxc/utils.h>
#include <lxc/log.h>
+#include <lxc/lxccontainer.h>
#define OFLAG (O_CREAT | O_RDWR)
#define SEMMODE 0660
free(dest);
return NULL;
}
- if (mkdir_p(dest, 0755) < 0) {
+ process_lock();
+ ret = mkdir_p(dest, 0755);
+ process_unlock();
+ if (ret < 0) {
free(dest);
return NULL;
}
struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name)
{
struct lxc_lock *l;
- int ret = pthread_mutex_lock(&thread_mutex);
- if (ret != 0) {
- ERROR("pthread_mutex_lock returned:%d %s", ret, strerror(ret));
- return NULL;
- }
l = malloc(sizeof(*l));
if (!l)
l->u.f.fd = -1;
out:
- pthread_mutex_unlock(&thread_mutex);
return l;
}
int lxclock(struct lxc_lock *l, int timeout)
{
- int saved_errno = errno;
- int ret = pthread_mutex_lock(&thread_mutex);
- if (ret != 0) {
- ERROR("pthread_mutex_lock returned:%d %s", ret, strerror(ret));
- return ret;
- }
+ int ret = -1, saved_errno = errno;
switch(l->type) {
case LXC_LOCK_ANON_SEM:
ret = -2;
goto out;
}
+ process_lock();
if (l->u.f.fd == -1) {
l->u.f.fd = open(l->u.f.fname, O_RDWR|O_CREAT,
S_IWUSR | S_IRUSR);
if (l->u.f.fd == -1) {
+ process_unlock();
ERROR("Error opening %s", l->u.f.fname);
goto out;
}
}
ret = flock(l->u.f.fd, LOCK_EX);
+ process_unlock();
if (ret == -1)
saved_errno = errno;
break;
}
out:
- pthread_mutex_unlock(&thread_mutex);
errno = saved_errno;
return ret;
}
int lxcunlock(struct lxc_lock *l)
{
- int saved_errno = errno;
- int ret = pthread_mutex_lock(&thread_mutex);
-
- if (ret != 0) {
- ERROR("pthread_mutex_lock returned:%d %s", ret, strerror(ret));
- return ret;
- }
+ int ret = 0, saved_errno = errno;
switch(l->type) {
case LXC_LOCK_ANON_SEM:
saved_errno = errno;
break;
case LXC_LOCK_FLOCK:
+ process_lock();
if (l->u.f.fd != -1) {
if ((ret = flock(l->u.f.fd, LOCK_UN)) < 0)
saved_errno = errno;
l->u.f.fd = -1;
} else
ret = -2;
+ process_unlock();
break;
}
- pthread_mutex_unlock(&thread_mutex);
errno = saved_errno;
return ret;
}
+/*
+ * lxc_putlock() is only called when a container_new() fails,
+ * or during container_put(), which is already guaranteed to
+ * only be done by one task.
+ * So the only exclusion we need to provide here is for regular
+ * thread safety (i.e. file descriptor table changes).
+ */
void lxc_putlock(struct lxc_lock *l)
{
- int ret = pthread_mutex_lock(&thread_mutex);
- if (ret != 0) {
- ERROR("pthread_mutex_lock returned:%d %s", ret, strerror(ret));
- return;
- }
-
if (!l)
- goto out;
+ return;
switch(l->type) {
case LXC_LOCK_ANON_SEM:
if (l->u.sem)
sem_close(l->u.sem);
break;
case LXC_LOCK_FLOCK:
+ process_lock();
if (l->u.f.fd != -1) {
close(l->u.f.fd);
l->u.f.fd = -1;
}
+ process_unlock();
if (l->u.f.fname) {
free(l->u.f.fname);
l->u.f.fname = NULL;
}
break;
}
-out:
+}
+
+int process_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&thread_mutex);
+ if (ret != 0)
+ ERROR("pthread_mutex_lock returned:%d %s", ret, strerror(ret));
+ return ret;
+}
+
+void process_unlock(void)
+{
pthread_mutex_unlock(&thread_mutex);
}
+
+int container_mem_lock(struct lxc_container *c)
+{
+ return lxclock(c->privlock, 0);
+}
+
+void container_mem_unlock(struct lxc_container *c)
+{
+ lxcunlock(c->privlock);
+}
+
+int container_disk_lock(struct lxc_container *c)
+{
+ int ret;
+
+ if ((ret = lxclock(c->privlock, 0)))
+ return ret;
+ if ((ret = lxclock(c->slock, 0))) {
+ lxcunlock(c->privlock);
+ return ret;
+ }
+ return 0;
+}
+
+void container_disk_unlock(struct lxc_container *c)
+{
+ lxcunlock(c->slock);
+ lxcunlock(c->privlock);
+}