[Devel] [PATCH rh7] ub: sync exec_ub on fork

Kirill Tkhai ktkhai at odin.com
Tue Jun 16 09:26:36 PDT 2015


В Вт, 16/06/2015 в 19:02 +0300, Vladimir Davydov пишет:
> Since we want to be able to get/set current's exec_ub, when attaching a
> task to a ub cgroup we change its exec_ub in a task_work (i.e. from its
> own context, when it returns to userspace). This design works perfectly
> well, but we have to be careful with forking tasks while currently we
> are not.
> 
> The problem is that if a forking task is moved between cgroups, the
> child will have exec_ub set to the source cgroup while being attached to
> the destination cgroup. To avoid this discrepancy, we have to
> synchronize the child's exec_ub with its cgroup on cgroup_post_fork.
> This patch does the trick. It is safe to change exec_ub there, because
> the task is not allowed to run yet and therefore cannot get/set its
> exec_ub.
> 
> Reported-by: Kirill Tkhai <ktkhai at odin.com>
> Signed-off-by: Vladimir Davydov <vdavydov at parallels.com>

Reviewed-by: Kirill Tkhai <ktkhai at odin.com>

> ---
>  kernel/bc/beancounter.c | 26 ++++++++++++++++++++++++--
>  1 file changed, 24 insertions(+), 2 deletions(-)
> 
> diff --git a/kernel/bc/beancounter.c b/kernel/bc/beancounter.c
> index ecc5a96c1a5e..6bb3d3951262 100644
> --- a/kernel/bc/beancounter.c
> +++ b/kernel/bc/beancounter.c
> @@ -570,20 +570,27 @@ static void ub_cgroup_css_free(struct cgroup *cg)
>  	free_ub(ub);
>  }
>  
> -static void ub_cgroup_attach_work_fn(struct callback_head *ch)
> +static void __ub_cgroup_attach(struct task_struct *tsk)
>  {
> -	struct task_struct *tsk = current;
>  	struct user_beancounter *ub;
>  
>  	rcu_read_lock();
>  	do {
>  		ub = cgroup_ub(task_cgroup(current, ub_subsys_id));
> +		if (tsk->task_bc.exec_ub == ub)
> +			goto out;
>  	} while (!get_beancounter_rcu(ub));
>  	put_beancounter(tsk->task_bc.exec_ub);
>  	tsk->task_bc.exec_ub = ub;
> +out:
>  	rcu_read_unlock();
>  }
>  
> +static void ub_cgroup_attach_work_fn(struct callback_head *ch)
> +{
> +	__ub_cgroup_attach(current);
> +}
> +
>  static void ub_cgroup_attach(struct cgroup *cg, struct cgroup_taskset *tset)
>  {
>  	struct task_struct *p;
> @@ -607,6 +614,20 @@ static void ub_cgroup_attach(struct cgroup *cg, struct cgroup_taskset *tset)
>  	}
>  }
>  
> +static void ub_cgroup_fork(struct task_struct *tsk)
> +{
> +	/*
> +	 * If a forking task is moved between cgroups, the child will have
> +	 * exec_ub set to the source cgroup while being attached to the
> +	 * destination cgroup, because the parent's exec_ub will only change
> +	 * when it returns to userspace (see ub_cgroup_attach). To avoid this
> +	 * discrepancy, here we synchronize the child's exec_ub with its
> +	 * cgroup. It is safe, because the task is not allowed to run yet and
> +	 * therefore cannot get/set its exec_ub.
> +	 */
> +	__ub_cgroup_attach(tsk);
> +}
> +
>  static ssize_t ub_cgroup_read(struct cgroup *cg, struct cftype *cft,
>  			      struct file *file, char __user *buf,
>  			      size_t nbytes, loff_t *ppos)
> @@ -831,6 +852,7 @@ struct cgroup_subsys ub_subsys = {
>  	.css_offline = ub_cgroup_css_offline,
>  	.css_free = ub_cgroup_css_free,
>  	.attach = ub_cgroup_attach,
> +	.fork = ub_cgroup_fork,
>  	.base_cftypes = ub_cgroup_files,
>  	.use_id = true,
>  };





More information about the Devel mailing list