Received: by 2002:ac0:a5a6:0:0:0:0:0 with SMTP id m35-v6csp422628imm; Fri, 31 Aug 2018 04:12:15 -0700 (PDT) X-Google-Smtp-Source: ANB0VdbiYGAXLXW70dZPOkQ4PjGExYF8wOOn5yDvGf798vBJWrTzyg9RTfxBWscYL2TjQ/lPLP+G X-Received: by 2002:a63:8f05:: with SMTP id n5-v6mr13913161pgd.131.1535713935302; Fri, 31 Aug 2018 04:12:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1535713935; cv=none; d=google.com; s=arc-20160816; b=0PLCFWdnjx6qjF4PMyoabXBCBTkNYtfaCi1C9YWjRtwYIAnEAtC5P2p+KrsZWM9MJc ArZuS82Q0c9ffHZiSowY1lhvmCLdE4TCEIh4GD0TjkrlelV8t8Te5qQorx/OWjKXueFO eg/jVyrzP8uKU/po4QQkdjR2BAJ+qPCrDmzMdCKT5AjtU/S5AZSTtxySVU+5l0ZbxDI2 E5O25emG8OU4fQkRKCHWv9WzP4VRDoQcr+D7dShRPt2MxDCEd2bSuSmoOEG41fSdbgAa JDsRRXOIF3kf1hHyV21x6YzBYEvWwXu96Fq4o0Uix1M2SgeRqhE41fn4Q0k2P1sCmYfb ++xA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :message-id:in-reply-to:subject:cc:to:from:date :arc-authentication-results; bh=kri46vHXVP8Dq9sc4ZcXZT+4sC30OWvgXPvkQl15hwM=; b=NlWG5PE67gAJTkfzKw9nAeh1S40exxRBg/hMLeLVAYLn4EbQ5yqoUlNRCMYCGC/S/R KeWFZB3esCHGPaxTuULlFyY/JYLkVkeB0u8f2iFJv5p3owQhCxuX3urz0KAm41EjSFJ+ AO5fGvzHG/sC30qzPl0i8BczNSxP2UjwI8oM4/Xk4RxBlJ34/a2UWSHXBdXiAAA0I3iU 7rgGD/a2qrdYFhYqhtBsl6W3MRsnQ7SJ+FY3kG5mcfSqC6By3g+VG4BUM2i61elRKfRq N99YLGaNR4syscX3nqehCyoMjQouxk1UzY34jcyXzOmvomaBVthpTlPLCL22msRI05Kp 2qiA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e4-v6si8815777pfn.340.2018.08.31.04.12.00; Fri, 31 Aug 2018 04:12:15 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727545AbeHaOqT (ORCPT + 99 others); Fri, 31 Aug 2018 10:46:19 -0400 Received: from mx2.suse.de ([195.135.220.15]:47770 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727191AbeHaOqT (ORCPT ); Fri, 31 Aug 2018 10:46:19 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id A9B77AF60; Fri, 31 Aug 2018 10:39:24 +0000 (UTC) Date: Fri, 31 Aug 2018 12:39:23 +0200 (CEST) From: Miroslav Benes To: Petr Mladek cc: Jiri Kosina , Josh Poimboeuf , Jason Baron , Joe Lawrence , Jessica Yu , Evgenii Shatokhin , live-patching@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH v12 04/12] livepatch: Consolidate klp_free functions In-Reply-To: <20180828143603.4442-5-pmladek@suse.com> Message-ID: References: <20180828143603.4442-1-pmladek@suse.com> <20180828143603.4442-5-pmladek@suse.com> User-Agent: Alpine 2.21 (LSU 202 2017-01-01) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, 28 Aug 2018, Petr Mladek wrote: > The code for freeing livepatch structures is a bit scattered and tricky: > > + direct calls to klp_free_*_limited() and kobject_put() are > used to release partially initialized objects > > + klp_free_patch() removes the patch from the public list > and releases all objects except for patch->kobj > > + object_put(&patch->kobj) and the related wait_for_completion() > are called directly outside klp_mutex; this code is duplicated; > > Now, we are going to remove the registration stage to simplify the API > and the code. This would require handling more situations in > klp_enable_patch() error paths. > > More importantly, we are going to add a feature called atomic replace. > It will need to dynamically create func and object structures. We will > want to reuse the existing init() and free() functions. This would > create even more error path scenarios. > > This patch implements a more clever free functions: > > + checks kobj.state_initialized instead of @limit > > + initializes patch->list early so that the check for empty list > always works > > + The action(s) that has to be done outside klp_mutex are done > in separate klp_free_patch_end() function. It waits only > when patch->kobj was really released via the _begin() part. > > Note that it is safe to put patch->kobj under klp_mutex. It calls > the release callback only when the reference count reaches zero. > Therefore it does not block any related sysfs operation that took > a reference and might eventually wait for klp_mutex. This seems to be the reason of the issue which lockdep reported. The patch moved kobject_put(&patch->kobj) under klp_mutex. Perhaps I cannot read kernfs code properly today, but I fail to understand why it is supposed to be safe. Indeed, if it is safe, lockdep report is false positive. > Note that __klp_free_patch() is split because it will be later > used in a _nowait() variant. Also klp_free_patch_end() makes > sense because it will later get more complicated. There are no _begin() and _end() functions in the patch. > This patch does not change the existing behavior. > > Signed-off-by: Petr Mladek > Cc: Josh Poimboeuf > Cc: Jessica Yu > Cc: Jiri Kosina > Cc: Jason Baron > Acked-by: Miroslav Benes My Acked-by here is a bit premature. > --- > include/linux/livepatch.h | 2 ++ > kernel/livepatch/core.c | 92 +++++++++++++++++++++++++++++------------------ > 2 files changed, 59 insertions(+), 35 deletions(-) > > diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h > index 1163742b27c0..22e0767d64b0 100644 > --- a/include/linux/livepatch.h > +++ b/include/linux/livepatch.h > @@ -138,6 +138,7 @@ struct klp_object { > * @list: list node for global list of registered patches > * @kobj: kobject for sysfs resources > * @enabled: the patch is enabled (but operation may be incomplete) > + * @wait_free: wait until the patch is freed > * @finish: for waiting till it is safe to remove the patch module > */ > struct klp_patch { > @@ -149,6 +150,7 @@ struct klp_patch { > struct list_head list; > struct kobject kobj; > bool enabled; > + bool wait_free; > struct completion finish; > }; > > diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c > index b3956cce239e..3ca404545150 100644 > --- a/kernel/livepatch/core.c > +++ b/kernel/livepatch/core.c > @@ -465,17 +465,15 @@ static struct kobj_type klp_ktype_func = { > .sysfs_ops = &kobj_sysfs_ops, > }; > > -/* > - * Free all functions' kobjects in the array up to some limit. When limit is > - * NULL, all kobjects are freed. > - */ > -static void klp_free_funcs_limited(struct klp_object *obj, > - struct klp_func *limit) > +static void klp_free_funcs(struct klp_object *obj) > { > struct klp_func *func; > > - for (func = obj->funcs; func->old_name && func != limit; func++) > - kobject_put(&func->kobj); > + klp_for_each_func(obj, func) { > + /* Might be called from klp_init_patch() error path. */ > + if (func->kobj.state_initialized) > + kobject_put(&func->kobj); > + } > } Just for the record, it is a slightly suboptimal because now we iterate through the whole list. We could add break to else branch, I think, but it's not necessary. > /* Clean up when a patched object is unloaded */ > @@ -489,26 +487,59 @@ static void klp_free_object_loaded(struct klp_object *obj) > func->old_addr = 0; > } > > -/* > - * Free all objects' kobjects in the array up to some limit. When limit is > - * NULL, all kobjects are freed. > - */ > -static void klp_free_objects_limited(struct klp_patch *patch, > - struct klp_object *limit) > +static void klp_free_objects(struct klp_patch *patch) > { > struct klp_object *obj; > > - for (obj = patch->objs; obj->funcs && obj != limit; obj++) { > - klp_free_funcs_limited(obj, NULL); > - kobject_put(&obj->kobj); > + klp_for_each_object(patch, obj) { > + klp_free_funcs(obj); > + > + /* Might be called from klp_init_patch() error path. */ > + if (obj->kobj.state_initialized) > + kobject_put(&obj->kobj); > } > } Same here, of course. Regards, Miroslav