All of lore.kernel.org
 help / color / mirror / Atom feed
From: Petr Mladek <pmladek@suse.com>
To: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Jessica Yu <jeyu@redhat.com>, Jiri Kosina <jikos@kernel.org>,
	Miroslav Benes <mbenes@suse.cz>,
	linux-kernel@vger.kernel.org, live-patching@vger.kernel.org,
	Michael Ellerman <mpe@ellerman.id.au>,
	Heiko Carstens <heiko.carstens@de.ibm.com>,
	x86@kernel.org, linuxppc-dev@lists.ozlabs.org,
	linux-s390@vger.kernel.org, Vojtech Pavlik <vojtech@suse.com>,
	Jiri Slaby <jslaby@suse.cz>,
	Chris J Arges <chris.j.arges@canonical.com>,
	Andy Lutomirski <luto@kernel.org>, Ingo Molnar <mingo@kernel.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>,
	Balbir Singh <bsingharora@gmail.com>
Subject: Re: [PATCH v4 13/15] livepatch: change to a per-task consistency model
Date: Thu, 9 Feb 2017 11:24:10 +0100	[thread overview]
Message-ID: <20170209102410.GA2349@linux.suse> (raw)
In-Reply-To: <20170208164636.moddpqpwppozk5v3@treble>

On Wed 2017-02-08 10:46:36, Josh Poimboeuf wrote:
> On Wed, Feb 08, 2017 at 04:47:50PM +0100, Petr Mladek wrote:
> > > Notice in this case that klp_target_state is KLP_PATCHED.  Which means
> > > that klp_complete_transition() would not call synchronize_rcu() at the
> > > right time, nor would it call module_put().  It can be fixed with:
> > >
> > > @@ -387,7 +389,7 @@ static int __klp_enable_patch(struct klp_patch *patch)
> > >  			pr_warn("failed to enable patch '%s'\n",
> > >  				patch->mod->name);
> > >  
> > > -			klp_unpatch_objects(patch);
> > > +			klp_target_state = KLP_UNPATCHED;
> > >  			klp_complete_transition();
> > >  
> > >  			return ret;
> > 
> > Great catch! Looks good to me.
> 
> As it turns out, klp_target_state isn't accessible from this file, so
> I'll make a klp_cancel_transition() helper function which reverses
> klp_target_state and calls klp_complete_transition().

Sound good to me.

> > > This assumes that the 'if (klp_target_state == KLP_UNPATCHED)' clause in
> > > klp_try_complete_transition() gets moved to klp_complete_transition() as
> > > you suggested.
> > > 
> > > > > > > diff --git a/kernel/livepatch/patch.c b/kernel/livepatch/patch.c
> > > > > > > index 5efa262..1a77f05 100644
> > > > > > > --- a/kernel/livepatch/patch.c
> > > > > > > +++ b/kernel/livepatch/patch.c
> > > > > > > @@ -29,6 +29,7 @@
> > > > > > >  #include <linux/bug.h>
> > > > > > >  #include <linux/printk.h>
> > > > > > >  #include "patch.h"
> > > > > > > +#include "transition.h"
> > > > > > >  
> > > > > > >  static LIST_HEAD(klp_ops);
> > > > > > >  
> > > > > > > @@ -54,15 +55,58 @@ static void notrace klp_ftrace_handler(unsigned long ip,
> > > > > > >  {
> > > > > > >  	struct klp_ops *ops;
> > > > > > >  	struct klp_func *func;
> > > > > > > +	int patch_state;
> > > > > > >  
> > > > > > >  	ops = container_of(fops, struct klp_ops, fops);
> > > > > > >  
> > > > > > >  	rcu_read_lock();
> > > > > > > +
> > > > > > >  	func = list_first_or_null_rcu(&ops->func_stack, struct klp_func,
> > > > > > >  				      stack_node);
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * func should never be NULL because preemption should be disabled here
> > > > > > > +	 * and unregister_ftrace_function() does the equivalent of a
> > > > > > > +	 * synchronize_sched() before the func_stack removal.
> > > > > > > +	 */
> > > > > > > +	if (WARN_ON_ONCE(!func))
> > > > > > > +		goto unlock;
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * Enforce the order of the ops->func_stack and func->transition reads.
> > > > > > > +	 * The corresponding write barrier is in __klp_enable_patch().
> > > > > > > +	 */
> > > > > > > +	smp_rmb();
> > > > > > 
> > > > > > I was curious why the comment did not mention __klp_disable_patch().
> > > > > > It was related to the hours of thinking. I would like to avoid this
> > > > > > in the future and add a comment like.
> > > > > > 
> > > > > > 	 * This barrier probably is not needed when the patch is being
> > > > > > 	 * disabled. The patch is removed from the stack in
> > > > > > 	 * klp_try_complete_transition() and there we need to call
> > > > > > 	 * rcu_synchronize() to prevent seeing the patch on the stack
> > > > > > 	 * at all.
> > > > > > 	 *
> > > > > > 	 * Well, it still might be needed to see func->transition
> > > > > > 	 * when the patch is removed and the task is migrated. See
> > > > > > 	 * the write barrier in __klp_disable_patch().
> > > > > 
> > > > > Agreed, though as you mentioned earlier, there's also the implicit
> > > > > barrier in klp_update_patch_state(), which would execute first in such a
> > > > > scenario.  So I think I'll update the barrier comments in
> > > > > klp_update_patch_state().
> > > > 
> > > > You inspired me to a scenario with 3 CPUs:
> > > > 
> > > > CPU0			CPU1			CPU2
> > > > 
> > > > __klp_disable_patch()
> > > > 
> > > >   klp_init_transition()
> > > > 
> > > >     func->transition = true
> > > > 
> > > >   smp_wmb()
> > > > 
> > > >   klp_start_transition()
> > > > 
> > > >     set TIF_PATCH_PATCHPENDING
> > > > 
> > > > 			klp_update_patch_state()
> > > > 
> > > > 			  task->patch_state
> > > > 			     = KLP_UNPATCHED
> > > > 
> > > > 			  smp_mb()
> > > > 
> > > > 						klp_ftrace_handler()
> > > > 						  func = list_...
> > > > 
> > > > 						  smp_rmb() /*needed?*/
> > > > 
> > > > 						  if (func->transition)
> > > > 
> > > 
> > > I think this isn't possible.  Remember the comment I added to
> > > klp_update_patch_state():
> > > 
> > >  * NOTE: If task is not 'current', the caller must ensure the task is inactive.
> > >  * Otherwise klp_ftrace_handler() might read the wrong 'patch_state' value.
> > > 
> > > Right now klp_update_patch_state() is only called for current.
> > > klp_ftrace_handler() on CPU2 would be running in the context of a
> > > different task.
> > 
> > I agree that it is impossible with the current code. In fact, I cannot
> > imagine a way to migrate the task where the barrier would be needed.
> > The question if we could/should somehow document it. Something like
> > 
> > 	* The barrier is not really needed when the patch is being
> > 	* disabled. The value of func->transition would change
> > 	* the result of this handled only after the task is migrated.
> > 	* But the conditions for the migration are very limited
> > 	* and practically include a full barrier, see
> > 	* klp_update_patch_state().
> 
> Well, I'd like to avoid over-commenting this issue.  For v5 I've added
> the following comment to klp_update_patch_state() -- see #2:
> 
> 	/*
> 	 * This test_and_clear_tsk_thread_flag() call also serves as a read
> 	 * barrier (smp_rmb) for two cases:
> 	 *
> 	 * 1) Enforce the order of the TIF_PATCH_PENDING read and the
> 	 *    klp_target_state read.  The corresponding write barrier is in
> 	 *    klp_init_transition().
> 	 *
> 	 * 2) Enforce the order of the TIF_PATCH_PENDING read and a future read
> 	 *    of func->transition, if klp_ftrace_handler() is called later on
> 	 *    the same CPU.  See __klp_disable_patch().
> 	 */

Sounds good.

> Is that sufficient?  If not, I could maybe add another related comment
> in klp_ftrace_handler() which refers to this comment.

It would be nice. I do not want over-commenting either. On the other
hand, the code is really complex and it is not easy to understand
all the relations. The comments should safe us a lot of pain in
the long term.

Thanks a lot for working on it

Best Regards,
Petr

  reply	other threads:[~2017-02-09 10:24 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-19 15:46 [PATCH v4 00/15] livepatch: hybrid consistency model Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 01/15] stacktrace/x86: add function for detecting reliable stack traces Josh Poimboeuf
2017-01-26 13:56   ` Petr Mladek
2017-01-26 17:57     ` Josh Poimboeuf
2017-01-27  8:47   ` Miroslav Benes
2017-01-27 17:13     ` Josh Poimboeuf
2017-02-01 19:57   ` [PATCH v4.1 " Josh Poimboeuf
2017-02-02 14:39     ` Miroslav Benes
2017-01-19 15:46 ` [PATCH v4 02/15] x86/entry: define _TIF_ALLWORK_MASK flags explicitly Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 03/15] livepatch: create temporary klp_update_patch_state() stub Josh Poimboeuf
2017-01-27  8:52   ` Miroslav Benes
2017-01-19 15:46 ` [PATCH v4 04/15] livepatch/x86: add TIF_PATCH_PENDING thread flag Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 05/15] livepatch/powerpc: " Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 06/15] livepatch/s390: reorganize TIF thread flag bits Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 07/15] livepatch/s390: add TIF_PATCH_PENDING thread flag Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 08/15] livepatch: separate enabled and patched states Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 09/15] livepatch: remove unnecessary object loaded check Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 10/15] livepatch: move patching functions into patch.c Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 11/15] livepatch: use kstrtobool() in enabled_store() Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 12/15] livepatch: store function sizes Josh Poimboeuf
2017-01-19 15:46 ` [PATCH v4 13/15] livepatch: change to a per-task consistency model Josh Poimboeuf
2017-02-02 11:45   ` Petr Mladek
2017-02-02 11:47     ` Petr Mladek
2017-02-02 11:51   ` Petr Mladek
2017-02-03 16:21     ` Miroslav Benes
2017-02-03 20:39     ` Josh Poimboeuf
2017-02-06 16:44       ` Petr Mladek
2017-02-06 19:51         ` Josh Poimboeuf
2017-02-08 15:47           ` Petr Mladek
2017-02-08 16:46             ` Josh Poimboeuf
2017-02-09 10:24               ` Petr Mladek [this message]
2017-02-03 16:41   ` Miroslav Benes
2017-02-06 15:58     ` Josh Poimboeuf
2017-02-07  8:21       ` Miroslav Benes
2017-01-19 15:46 ` [PATCH v4 14/15] livepatch: add /proc/<pid>/patch_state Josh Poimboeuf
2017-01-31 14:31   ` Miroslav Benes
2017-01-31 14:56     ` Josh Poimboeuf
2017-02-01  8:54       ` Miroslav Benes
2017-01-19 15:46 ` [PATCH v4 15/15] livepatch: allow removal of a disabled patch Josh Poimboeuf
2017-02-03 16:48   ` Miroslav Benes
2017-02-01 20:02 ` [PATCH v4 00/15] livepatch: hybrid consistency model Josh Poimboeuf
2017-02-01 20:52   ` Miroslav Benes
2017-02-01 21:01   ` Jiri Kosina
2017-02-02 14:37   ` Petr Mladek

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=20170209102410.GA2349@linux.suse \
    --to=pmladek@suse.com \
    --cc=bsingharora@gmail.com \
    --cc=chris.j.arges@canonical.com \
    --cc=heiko.carstens@de.ibm.com \
    --cc=jeyu@redhat.com \
    --cc=jikos@kernel.org \
    --cc=jpoimboe@redhat.com \
    --cc=jslaby@suse.cz \
    --cc=kamalesh@linux.vnet.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=live-patching@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=mbenes@suse.cz \
    --cc=mingo@kernel.org \
    --cc=mpe@ellerman.id.au \
    --cc=peterz@infradead.org \
    --cc=vojtech@suse.com \
    --cc=x86@kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.