[CRIU] [PATCH v2] cr-service: add lazy-pages RPC feature check

Andrei Vagin avagin at virtuozzo.com
Mon Feb 27 10:21:04 PST 2017


On Thu, Feb 23, 2017 at 11:17:42AM +0100, Adrian Reber wrote:
> From: Adrian Reber <areber at redhat.com>
> 
> Extend the RPC feature check functionality to also test for lazy-pages
> support. This does not check for certain UFFD features (yet). Right now
> it only checks if kerndat_uffd() returns non-zero.
> 
> The RPC response is now transmitted from the forked process instead of
> encoding all the results into the return code. The parent RPC process
> now only sends an RPC message in the case of a failure.
> 
> Signed-off-by: Adrian Reber <areber at redhat.com>
> ---
>  criu/cr-service.c | 83 ++++++++++++++++++++++++++++++++++++++-----------------
>  images/rpc.proto  |  1 +
>  2 files changed, 59 insertions(+), 25 deletions(-)
> 
> diff --git a/criu/cr-service.c b/criu/cr-service.c
> index 169d637..d1007e7 100644
> --- a/criu/cr-service.c
> +++ b/criu/cr-service.c
> @@ -823,33 +823,21 @@ static int handle_feature_check(int sk, CriuReq * msg)
>  {
>  	CriuResp resp = CRIU_RESP__INIT;
>  	CriuFeatures feat = CRIU_FEATURES__INIT;
> -	bool success = false;
>  	int pid, status;
>  
>  	/* enable setting of an optional message */
>  	feat.has_mem_track = 1;
>  	feat.mem_track = false;
> +	feat.has_lazy_pages = 1;
> +	feat.lazy_pages = false;
>  
> -	/*
> -	 * Check if the requested feature check can be answered.
> -	 *
> -	 * This function is right now hard-coded to memory
> -	 * tracking detection and needs other/better logic to
> -	 * handle multiple feature checks.
> -	 */
> -	if (msg->features->has_mem_track != 1) {
> +	/* Check if the requested feature check can be answered. */
> +	if ((msg->features->has_mem_track != 1) ||
> +	    (msg->features->has_lazy_pages != 1)) {
>  		pr_warn("Feature checking for unknown feature.\n");
>  		goto out;
>  	}
>  
> -	/*
> -	 * From this point on the function will always
> -	 * 'succeed'. If the requested features are supported
> -	 * can be seen if the requested optional parameters are
> -	 * set in the message 'criu_features'.
> -	 */
> -	success = true;
> -
>  	pid = fork();
>  	if (pid < 0) {
>  		pr_perror("Can't fork");
> @@ -857,27 +845,72 @@ static int handle_feature_check(int sk, CriuReq * msg)
>  	}
>  
>  	if (pid == 0) {
> -		int ret = 1;
> +		int ret;
>  
>  		setproctitle("feature-check --rpc");
>  
> -		kerndat_get_dirty_track();
> +		if ((msg->features->has_mem_track == 1) &&
> +		    (msg->features->mem_track == true)) {
> +
> +			feat.mem_track = true;
> +			ret = kerndat_get_dirty_track();
> +
> +			if (ret)
> +				feat.mem_track = false;
> +
> +			if (!kdat.has_dirty_track)
> +				feat.mem_track = false;
> +		}
> +
> +		if ((msg->features->has_lazy_pages == 1) &&
> +		    (msg->features->lazy_pages == true)) {
> +			ret = kerndat_uffd(true);

offtopic: I like an idea when kerndat_* functions fill kdat and return
errors when they meet an unexpected error.

			if (kerndat_uffd())
				goto err;

			if (kdat.laze_pages)
				feat.lazy_pages = true;

> +
> +			/*
> +			 * Not checking for specific UFFD features yet.
> +			 * If no error is returned it is probably
> +			 * enough for basic UFFD functionality. This can
> +			 * be extended in the future for a more detailed
> +			 * UFFD feature check.
> +			 */
> +			if (ret)
> +				feat.lazy_pages = false;
> +			else
> +				feat.lazy_pages = true;
> +		}
>  
> -		if (kdat.has_dirty_track)
> -			ret = 0;
> +		resp.features = &feat;
> +		resp.type = msg->type;
> +		/* The feature check is working, actual results are in resp.features */
> +		resp.success = true;
> +
> +		/*
> +		 * If this point is reached the information about the features
> +		 * is transmitted from the forked CRIU process (here).
> +		 * If an error occured earlier, the feature check response will be
> +		 * be send from the parent process.
> +		 */
> +		ret = send_criu_msg(sk, &resp);
>  
>  		exit(ret);
>  	}
>  
>  	wait(&status);

You don't check an exit code from wait here, so status may be
uninitialized. I recomend to use waitpid if pid is known.

> -	if (!WIFEXITED(status) || WEXITSTATUS(status))
> -		goto out;
> +	if (WIFEXITED(status) && !WEXITSTATUS(status))
> +		/*
> +		 * The child process exited was able to send the answer.
> +		 * Nothing more to do here.
> +		 */
> +		return 0;
>  
> -	feat.mem_track = true;
> +	/*
> +	 * The child process was not able to send an answer. Tell
> +	 * the RPC client that something did not work as expected.
> +	 */
>  out:
>  	resp.features = &feat;

I think we should not set feat here, should we?

>  	resp.type = msg->type;
> -	resp.success = success;
> +	resp.success = false;
>  
>  	return send_criu_msg(sk, &resp);
>  }
> diff --git a/images/rpc.proto b/images/rpc.proto
> index f924b73..f894ae1 100644
> --- a/images/rpc.proto
> +++ b/images/rpc.proto
> @@ -148,6 +148,7 @@ enum criu_req_type {
>   */
>  message criu_features {
>  	optional bool			mem_track	= 1;
> +	optional bool			lazy_pages	= 2;
>  }
>  
>  /*
> -- 
> 2.9.3
> 


More information about the CRIU mailing list