[lxc-devel] [RFC 1/2] lxc-start: added --start-frozen

Serge Hallyn serge.hallyn at ubuntu.com
Mon Jan 18 23:18:32 UTC 2016


Quoting Wolfgang Bumiller (w.bumiller at proxmox.com):
> Add the possibility to start a container in a frozen state.
> 
> Signed-off-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
> ---
>  doc/lxc-start.sgml.in  | 12 ++++++++++++
>  src/lxc/arguments.h    |  3 +++
>  src/lxc/conf.h         |  1 +
>  src/lxc/lxc_start.c    |  7 +++++++
>  src/lxc/lxccontainer.c | 16 ++++++++++++++++
>  src/lxc/lxccontainer.h | 10 ++++++++++
>  src/lxc/start.c        | 17 +++++++++++++++++
>  7 files changed, 66 insertions(+)
> 
> diff --git a/doc/lxc-start.sgml.in b/doc/lxc-start.sgml.in
> index 1770ac2..46bfcc7 100644
> --- a/doc/lxc-start.sgml.in
> +++ b/doc/lxc-start.sgml.in
> @@ -59,6 +59,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>        <arg choice="opt">-s KEY=VAL</arg>
>        <arg choice="opt">-C</arg>
>        <arg choice="opt">--share-[net|ipc|uts] <replaceable>name|pid</replaceable></arg>
> +      <arg choice="opt">--start-frozen</arg>
>        <arg choice="opt">command</arg>
>      </cmdsynopsis>
>    </refsynopsisdiv>
> @@ -245,6 +246,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>  	</listitem>
>        </varlistentry>
>  
> +      <varlistentry>
> +	<term>
> +	  <option>--start-frozen</option>
> +	</term>
> +	<listitem>
> +	  <para>
> +	    Freeze the container before starting its init process.
> +	  </para>
> +	</listitem>
> +      </varlistentry>
> +
>      </variablelist>
>  
>    </refsect1>
> diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h
> index 38cb0da..79a4758 100644
> --- a/src/lxc/arguments.h
> +++ b/src/lxc/arguments.h
> @@ -81,6 +81,9 @@ struct lxc_arguments {
>  	/* close fds from parent? */
>  	int close_all_fds;
>  
> +	/* freeze before starting init */
> +	int start_frozen;
> +
>  	/* lxc-create */
>  	char *bdevtype, *configfile, *template;
>  	char *fstype;
> diff --git a/src/lxc/conf.h b/src/lxc/conf.h
> index b0274ec..5c84f5f 100644
> --- a/src/lxc/conf.h
> +++ b/src/lxc/conf.h
> @@ -312,6 +312,7 @@ struct lxc_conf {
>  	struct lxc_rootfs rootfs;
>  	char *ttydir;
>  	int close_all_fds;
> +	int start_frozen;
>  	struct lxc_list hooks[NUM_LXC_HOOKS];
>  
>  	char *lsm_aa_profile;
> diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c
> index 6b942ac..73e27e3 100644
> --- a/src/lxc/lxc_start.c
> +++ b/src/lxc/lxc_start.c
> @@ -53,6 +53,7 @@
>  #define OPT_SHARE_NET OPT_USAGE+1
>  #define OPT_SHARE_IPC OPT_USAGE+2
>  #define OPT_SHARE_UTS OPT_USAGE+3
> +#define OPT_START_FROZEN OPT_USAGE+4
>  
>  lxc_log_define(lxc_start_ui, lxc);
>  
> @@ -154,6 +155,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
>  	case OPT_SHARE_NET: args->share_ns[LXC_NS_NET] = arg; break;
>  	case OPT_SHARE_IPC: args->share_ns[LXC_NS_IPC] = arg; break;
>  	case OPT_SHARE_UTS: args->share_ns[LXC_NS_UTS] = arg; break;
> +	case OPT_START_FROZEN: args->start_frozen = 1; break;
>  	}
>  	return 0;
>  }
> @@ -170,6 +172,7 @@ static const struct option my_longopts[] = {
>  	{"share-net", required_argument, 0, OPT_SHARE_NET},
>  	{"share-ipc", required_argument, 0, OPT_SHARE_IPC},
>  	{"share-uts", required_argument, 0, OPT_SHARE_UTS},
> +	{"start-frozen", no_argument, 0, OPT_START_FROZEN},
>  	LXC_COMMON_OPTIONS
>  };
>  
> @@ -193,6 +196,7 @@ Options :\n\
>                           Note: --daemon implies --close-all-fds\n\
>    -s, --define KEY=VAL   Assign VAL to configuration variable KEY\n\
>        --share-[net|ipc|uts]=NAME Share a namespace with another container or pid\n\
> +      --start-frozen     Freeze the container before starting its init\n\
>  ",
>  	.options   = my_longopts,
>  	.parser    = my_parser,
> @@ -335,6 +339,9 @@ int main(int argc, char *argv[])
>  	if (my_args.close_all_fds)
>  		c->want_close_all_fds(c, true);
>  
> +	if (my_args.start_frozen)
> +		c->set_start_frozen(c, true);
> +
>  	if (args == default_args)
>  		err = c->start(c, 0, NULL) ? 0 : 1;
>  	else
> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> index 802a930..166f507 100644
> --- a/src/lxc/lxccontainer.c
> +++ b/src/lxc/lxccontainer.c
> @@ -590,6 +590,21 @@ static bool do_lxcapi_want_close_all_fds(struct lxc_container *c, bool state)
>  
>  WRAP_API_1(bool, lxcapi_want_close_all_fds, bool)
>  
> +static bool do_lxcapi_set_start_frozen(struct lxc_container *c, bool state)
> +{
> +	if (!c || !c->lxc_conf)
> +		return false;
> +	if (container_mem_lock(c)) {
> +		ERROR("Error getting mem lock");
> +		return false;
> +	}
> +	c->lxc_conf->start_frozen = state;
> +	container_mem_unlock(c);
> +	return true;
> +}
> +
> +WRAP_API_1(bool, lxcapi_set_start_frozen, bool)
> +
>  static bool do_lxcapi_wait(struct lxc_container *c, const char *state, int timeout)
>  {
>  	int ret;
> @@ -4074,6 +4089,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
>  	c->load_config = lxcapi_load_config;
>  	c->want_daemonize = lxcapi_want_daemonize;
>  	c->want_close_all_fds = lxcapi_want_close_all_fds;
> +	c->set_start_frozen = lxcapi_set_start_frozen;
>  	c->start = lxcapi_start;
>  	c->startl = lxcapi_startl;
>  	c->stop = lxcapi_stop;
> diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
> index 6d155a1..454f029 100644
> --- a/src/lxc/lxccontainer.h
> +++ b/src/lxc/lxccontainer.h
> @@ -245,6 +245,16 @@ struct lxc_container {
>  	bool (*want_close_all_fds)(struct lxc_container *c, bool state);
>  
>  	/*!
> +	 * \brief Specify whether the container wishes start in a frozen state.
> +	 *
> +	 * \param c Container.
> +	 * \param state Value for the start_frozen bit (0 or 1).
> +	 *
> +	 * \return \c true on success, else \c false.
> +	 */
> +	bool (*set_start_frozen)(struct lxc_container *c, bool state);

Hi,

new functions must go at the end so as not to force linked applications
to be relinked.

> +
> +	/*!
>  	 * \brief Return current config file name.
>  	 *
>  	 * \param c Container.
> diff --git a/src/lxc/start.c b/src/lxc/start.c
> index 79dbe33..84a05f9 100644
> --- a/src/lxc/start.c
> +++ b/src/lxc/start.c
> @@ -1343,6 +1343,23 @@ static int start(struct lxc_handler *handler, void* data)
>  {
>  	struct start_args *arg = data;
>  
> +	if (handler->conf->start_frozen) {
> +		char *cgfile = NULL;
> +		NOTICE("freezing '%s'", arg->argv[0]);
> +		/* Let the monitor know we reached this point. */
> +		lxc_sync_fini_child(handler);
> +		if (asprintf(&cgfile, "/sys/fs/cgroup/freezer/lxc/%s/freezer.state", handler->name) == -1) {
> +			ERROR("failed to allocate memory trying to freezed container '%s'", handler->name);
> +			return -1;
> +		}

Hm, so this is done fromthe container's namespaces, and makes
assumptions about the cgroup layout.  Won't work for unprivileged
or nested containers (without cgroup namespace).

Depending on how important this is for you, it might be worth
putting a sync point here to have the parent move the child.
Except how will the child get to executing init?  Can you use
ptrace somehow, have the parent step through until the child's
exec() and then freeze it and release the ptrace?

> +		if (lxc_write_to_file(cgfile, "FROZEN", sizeof("FROZEN")-1, false) == -1) {
> +			ERROR("error freezing container '%s' at startup", handler->name);
> +			free(cgfile);
> +			return -1;
> +		}
> +		free(cgfile);
> +	}
> +
>  	NOTICE("exec'ing '%s'", arg->argv[0]);
>  
>  	execvp(arg->argv[0], arg->argv);
> -- 
> 2.1.4
> 
> 
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel


More information about the lxc-devel mailing list