]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
lxccontainer: don't lock around getstate and freeze/unfreeze (v2)
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Wed, 29 May 2013 17:26:25 +0000 (12:26 -0500)
committerSerge Hallyn <serge.hallyn@ubuntu.com>
Wed, 29 May 2013 18:54:11 +0000 (13:54 -0500)
Those go through commands.c and are already mutex'ed that way.

Also remove a unmatched container_disk_unlock in lxcapi_create.

Since is_stopped uses getstate which is no longer locked, rename
it to drop the _locked suffix.

And convert save_config to taking the disk lock.  This way the
save_ and load_config are mutexing each other, as they should.

Changelog: May 29:
   Per Dwight's comment, take the lock before opening the config
      FILE *.
   Only take disklock at load and save_config when we're using the
   container's config file, not when read/writing from/to another
   file.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Dwight Engen <dwight.engen@oracle.com>
src/lxc/lxccontainer.c

index 5a9cdf127365eeb1676d67914df364183ed2ee8f..9bc1caf56fe20ca2f28cf2576e0fcede087617e1 100644 (file)
@@ -287,21 +287,15 @@ out:
 
 static const char *lxcapi_state(struct lxc_container *c)
 {
-       const char *ret;
        lxc_state_t s;
 
        if (!c)
                return NULL;
-       if (container_disk_lock(c))
-               return NULL;
        s = lxc_getstate(c->name, c->config_path);
-       ret = lxc_state2str(s);
-       container_disk_unlock(c);
-
-       return ret;
+       return lxc_state2str(s);
 }
 
-static bool is_stopped_locked(struct lxc_container *c)
+static bool is_stopped(struct lxc_container *c)
 {
        lxc_state_t s;
        s = lxc_getstate(c->name, c->config_path);
@@ -326,10 +320,7 @@ static bool lxcapi_freeze(struct lxc_container *c)
        if (!c)
                return false;
 
-       if (container_disk_lock(c))
-               return false;
        ret = lxc_freeze(c->name, c->config_path);
-       container_disk_unlock(c);
        if (ret)
                return false;
        return true;
@@ -341,10 +332,7 @@ static bool lxcapi_unfreeze(struct lxc_container *c)
        if (!c)
                return false;
 
-       if (container_disk_lock(c))
-               return false;
        ret = lxc_unfreeze(c->name, c->config_path);
-       container_disk_unlock(c);
        if (ret)
                return false;
        return true;
@@ -379,7 +367,8 @@ static bool load_config_locked(struct lxc_container *c, const char *fname)
 
 static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file)
 {
-       bool ret = false;
+       bool ret = false, need_disklock = false;
+       int lret;
        const char *fname;
        if (!c)
                return false;
@@ -389,10 +378,27 @@ static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file)
                fname = alt_file;
        if (!fname)
                return false;
-       if (container_disk_lock(c))
+       /*
+        * If we're reading something other than the container's config,
+        * we only need to lock the in-memory container.  If loading the
+        * container's config file, take the disk lock.
+        */
+       if (strcmp(fname, c->configfile) == 0)
+               need_disklock = true;
+
+       if (need_disklock)
+               lret = container_disk_lock(c);
+       else
+               lret = container_mem_lock(c);
+       if (lret)
                return false;
+
        ret = load_config_locked(c, fname);
-       container_disk_unlock(c);
+
+       if (need_disklock)
+               container_disk_unlock(c);
+       else
+               container_mem_unlock(c);
        return ret;
 }
 
@@ -898,7 +904,6 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
 out_unlock:
        if (partial_fd >= 0)
                remove_partial(c, partial_fd);
-       container_disk_unlock(c);
 out:
        if (tpath)
                free(tpath);
@@ -1153,30 +1158,55 @@ static int lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv,
 #define LXC_DEFAULT_CONFIG "/etc/lxc/default.conf"
 static bool lxcapi_save_config(struct lxc_container *c, const char *alt_file)
 {
+       FILE *fout;
+       bool ret = false, need_disklock = false;
+       int lret;
+
        if (!alt_file)
                alt_file = c->configfile;
        if (!alt_file)
                return false;  // should we write to stdout if no file is specified?
-       if (!c->lxc_conf)
+
+       // If we haven't yet loaded a config, load the stock config
+       if (!c->lxc_conf) {
                if (!c->load_config(c, LXC_DEFAULT_CONFIG)) {
                        ERROR("Error loading default configuration file %s while saving %s\n", LXC_DEFAULT_CONFIG, c->name);
                        return false;
                }
+       }
 
        if (!create_container_dir(c))
                return false;
 
-       FILE *fout = fopen(alt_file, "w");
-       if (!fout)
-               return false;
-       if (container_mem_lock(c)) {
-               fclose(fout);
+       /*
+        * If we're writing to the container's config file, take the
+        * disk lock.  Otherwise just take the memlock to protect the
+        * struct lxc_container while we're traversing it.
+        */
+       if (strcmp(c->configfile, alt_file) == 0)
+               need_disklock = true;
+
+       if (need_disklock)
+               lret = container_disk_lock(c);
+       else
+               lret = container_mem_lock(c);
+
+       if (lret)
                return false;
-       }
+
+       fout = fopen(alt_file, "w");
+       if (!fout)
+               goto out;
        write_config(fout, c->lxc_conf);
        fclose(fout);
-       container_mem_unlock(c);
-       return true;
+       ret = true;
+
+out:
+       if (need_disklock)
+               container_disk_unlock(c);
+       else
+               container_mem_unlock(c);
+       return ret;
 }
 
 // do we want the api to support --force, or leave that to the caller?
@@ -1195,7 +1225,7 @@ static bool lxcapi_destroy(struct lxc_container *c)
                return false;
        }
 
-       if (!is_stopped_locked(c)) {
+       if (!is_stopped(c)) {
                // we should queue some sort of error - in c->error_string?
                ERROR("container %s is not stopped", c->name);
                goto out;
@@ -1352,7 +1382,7 @@ static bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys,
        if (container_mem_lock(c))
                return false;
 
-       if (is_stopped_locked(c))
+       if (is_stopped(c))
                goto err;
 
        ret = lxc_cgroup_set(c->name, subsys, value, c->config_path);
@@ -1373,7 +1403,7 @@ static int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, c
        if (container_mem_lock(c))
                return -1;
 
-       if (is_stopped_locked(c))
+       if (is_stopped(c))
                goto out;
 
        ret = lxc_cgroup_get(c->name, subsys, retv, inlen, c->config_path);
@@ -1837,7 +1867,7 @@ struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname,
        if (container_mem_lock(c))
                return NULL;
 
-       if (!is_stopped_locked(c)) {
+       if (!is_stopped(c)) {
                ERROR("error: Original container (%s) is running", c->name);
                goto out;
        }