linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Tejun Heo <tj@kernel.org>
To: Aristeu Rozanski <aris@redhat.com>
Cc: linux-kernel@vger.kernel.org,
	Serge Hallyn <serge.hallyn@canonical.com>,
	cgroups@vger.kernel.org
Subject: Re: [PATCH 5/5] device_cgroup: propagate local changes down the hierarchy
Date: Mon, 3 Dec 2012 10:01:45 -0800	[thread overview]
Message-ID: <20121203180145.GJ19802@htj.dyndns.org> (raw)
In-Reply-To: <20121127193503.114004167@napanee.usersys.redhat.com>

Hello, Aristeu.

On Tue, Nov 27, 2012 at 02:35:06PM -0500, Aristeu Rozanski wrote:
> This patch makes all changes propagate down in hierarchy respecting when
> possible local configurations.
> 
> Behavior changes will clean up exceptions in all the children except when the
> parent changes the behavior from allow to deny and the child's behavior was
> already deny, in which case the local exceptions will be reused. The inverse
> is not possible: you can't have a parent with behavior deny and a child with
> behavior accept.
> 
> New exceptions allowing additional access to devices won't be propagated, but
> it'll be possible to add an exception to access all of part of the newly
> allowed device(s).
> 
> New exceptions disallowing access to devices will be propagated down and the
> local group's exceptions will be revalidated for the new situation.

I think the inheritance policy needs to be documented in detail
listing the possible cases and the implemented behavior preferably
with rationale.  Can you please do that?

> +/**
> + * __revalidate_exceptions - walks through the exception list and revalidates
> + *			     the exceptions based on parents' behavior and
> + *			     exceptions. Called with devcgroup_mutex held.

new line

> + * @devcg: cgroup which exceptions will be checked
> + * returns: 0 in success, -ENOMEM in case of out of memory
> + */
> +static int __revalidate_exceptions(struct dev_cgroup *devcg)

Why __?

> +{
> +	struct dev_exception_item *ex;
> +	struct list_head *this, *tmp;
> +
> +	list_for_each_safe(this, tmp, &devcg->local.exceptions) {
> +		ex = container_of(this, struct dev_exception_item, list);
> +		if (parent_has_perm(devcg, ex)) {
> +			if (dev_exception_copy(&devcg->exceptions, ex))
> +				goto error;
> +		}
> +	}
> +	return 0;
> +
> +error:
> +	__dev_exception_clean(&devcg->exceptions);

Ditto.

> +	return -ENOMEM;
> +}
> +
> +/**
> + * propagate_behavior - propagates a change in the behavior to the children
> + * @devcg: device cgroup that changed behavior
> + *
> + * returns: 0 in case of success, != 0 in case of error
> + */
> +static int propagate_behavior(struct dev_cgroup *devcg)
> +{
> +	struct cgroup *root = devcg->css.cgroup, *pos, *saved = NULL,
> +			*prev = NULL;
> +	struct dev_cgroup *parent;
> +	int rc = 0;
> +
> +	while (1) {
> +		rcu_read_lock();
> +		cgroup_for_each_descendant_pre(pos, root) {
> +			if (saved && prev != saved) {
> +				prev = pos;
> +				continue;
> +			}
> +			break;
> +		}
> +		rcu_read_unlock();

Hmmm... this can race with new cgroup creation and a new child can
escape propagation.  devcg currently inherits from css_alloc() at
which it isn't visible to cgroup_for_each_*() iteration.  The
inheriting step should be moved to css_online() with explicit online
marking.  Please take a look at the recently posted cpuset for an
example.

> +
> +		if (!pos)
> +			break;
> +
> +		devcg = cgroup_to_devcgroup(pos);
> +		parent = cgroup_to_devcgroup(pos->parent);
> +
> +		/* first copy parent's state */
> +		devcg->behavior = parent->behavior;
> +		__dev_exception_clean(&devcg->exceptions);
> +		rc = dev_exceptions_copy(&devcg->exceptions, &parent->exceptions);
> +		if (rc) {
> +			devcg->behavior = DEVCG_DEFAULT_DENY;
> +			break;
> +		}
> +
> +		if (devcg->local.behavior == DEVCG_DEFAULT_DENY &&
> +		    devcg->behavior == DEVCG_DEFAULT_ALLOW) {
> +			devcg->behavior = DEVCG_DEFAULT_DENY;
> +		}
> +		if (devcg->local.behavior == devcg->behavior)
> +			rc = __revalidate_exceptions(devcg);
> +		if (rc)
> +			break;
> +		saved = pos;
> +	}
> +
> +	return rc;
> +}
> +
> +/**
> + * propagate_exception - propagates a new exception to the children
> + * @devcg: device cgroup that added a new exception
> + *
> + * returns: 0 in case of success, != 0 in case of error
> + */
> +static int propagate_exception(struct dev_cgroup *devcg)
> +{
> +	struct cgroup *root = devcg->css.cgroup, *pos, *saved = NULL,
> +			*prev = NULL;
> +	struct dev_cgroup *parent;
> +	int rc = 0;
> +
> +	while(1) {
> +		rcu_read_lock();
> +		cgroup_for_each_descendant_pre(pos, root) {
> +			if (saved && prev != saved) {
> +				prev = pos;
> +				continue;
> +			}
> +			break;
> +		}
> +		rcu_read_unlock();

Ditto.  Racy.

> +		if (!pos)
> +			break;
> +
> +		devcg = cgroup_to_devcgroup(pos);
> +		parent = cgroup_to_devcgroup(pos->parent);
> +
> +		__dev_exception_clean(&devcg->exceptions);
> +		if (devcg->behavior == parent->behavior) {
> +			rc = dev_exceptions_copy(&devcg->exceptions, &parent->exceptions);
> +			if (rc) {
> +				devcg->behavior = DEVCG_DEFAULT_DENY;
> +				break;
> +			}
> +			rc = __revalidate_exceptions(devcg);
> +			if (rc)
> +				break;
> +		} else {
> +			/* we never give more permissions to the child */
> +			WARN_ONCE(devcg->behavior == DEVCG_DEFAULT_ALLOW,
> +				  "devcg: parent/child behavior is inconsistent");
> +			rc = __revalidate_exceptions(devcg);
> +			if (rc)
> +				break;
> +		}
> +		saved = pos;
> +	}
> +	return rc;
> +}

Maybe I'm misunderstanding something but the behavior seems a bit
inconsistent.  So, you can't add an exception which isn't allowed by
your parent, right?  But, if your parent disallows an existing
exception, you get to keep it?  I think it would be more consistent to
go either

* Allow all settings but apply only as allowed by the parent.

* Deny settings disallowed by the parent.  If parent's config changes,
  delete configs which fall outside the new config.

It seems the implemented behavior is something inbetween which can be
quite confusing.

Thanks.

-- 
tejun

  reply	other threads:[~2012-12-03 18:01 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-27 19:35 [PATCH 0/5] devcg: introduce proper hierarchy support Aristeu Rozanski
2012-11-27 19:35 ` [PATCH 1/5] device_cgroup: fix locking in devcgroup_destroy() Aristeu Rozanski
2012-11-29 19:06   ` Serge E. Hallyn
2012-12-03 17:29   ` Tejun Heo
2012-11-27 19:35 ` [PATCH 2/5] device_cgroup: prepare exception list handling functions for two lists Aristeu Rozanski
2012-11-29 19:07   ` Serge E. Hallyn
2012-12-03 17:31   ` Tejun Heo
2012-11-27 19:35 ` [PATCH 3/5] device_cgroup: keep track of local group settings Aristeu Rozanski
2012-11-29 19:29   ` Serge E. Hallyn
2012-11-29 19:59     ` Aristeu Rozanski
2012-11-29 20:26       ` Serge E. Hallyn
2012-11-29 22:31         ` Aristeu Rozanski
2012-12-03 18:01           ` Serge E. Hallyn
2012-12-03 19:06             ` Aristeu Rozanski
2012-12-06  4:31               ` Serge E. Hallyn
2012-11-29 20:11     ` Aristeu Rozanski
2012-11-27 19:35 ` [PATCH 4/5] device_cgroup: make may_access() stronger Aristeu Rozanski
2012-12-03 17:44   ` Tejun Heo
2012-12-03 19:01     ` Aristeu Rozanski
2012-11-27 19:35 ` [PATCH 5/5] device_cgroup: propagate local changes down the hierarchy Aristeu Rozanski
2012-12-03 18:01   ` Tejun Heo [this message]
2012-12-03 19:14     ` Aristeu Rozanski
2012-12-03 21:36       ` Tejun Heo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20121203180145.GJ19802@htj.dyndns.org \
    --to=tj@kernel.org \
    --cc=aris@redhat.com \
    --cc=cgroups@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=serge.hallyn@canonical.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).