Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp6969587yba; Thu, 2 May 2019 01:36:18 -0700 (PDT) X-Google-Smtp-Source: APXvYqymWewyVW6/KqEG9OmQRFHMMkxCdpD7aGqTIJKggHqxoaDhblsTFz+twCs/QePGayTZOs9Y X-Received: by 2002:a62:2b43:: with SMTP id r64mr2812005pfr.210.1556786178855; Thu, 02 May 2019 01:36:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1556786178; cv=none; d=google.com; s=arc-20160816; b=rJimh2GoI1JTNbTrug/LghXNgusuHGPy2Ue3BPkkcs4zz7AEweQQcQISWiw51EnLFo mEnM1QQlRVx+FUPMxdRa70c9K00TNQRuYKWXvPHxvKlYZyyQJ/+P7wWMymwVDE9BY57y adqPxmbPnqFXJLiMPPU57Ki0aPfPjWmeuEJZk+gugwKJYYnsL2LQYpdnUTJh7tylgRjK KkSJ7FANPVxabfJwE/FnVTx51gsy50yPK+CmdANy7DYm0aPSqfCrkLdWYF+50UhGsnno To9Ru9955pcyog7wEu/sV87KeBYf0q7MvUK98896OM1JSTE2/mgWCJ0gUVGK/lw9oGys LHhw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date; bh=QWrmz82moyYujvBQdOvDWQscJyoyNhE8EVCkXmcLbTg=; b=VOZCOclBpY1D90ik6MItycQpYHFF0suqfUBcjxUo8qW8BFMrzHA3Qjm5IQ7uu0tkiM y9kP9SLGTmepEqivOTMesiV4ZWMbksuIWmbRWUBNYLptLc4Lks7bKitnCc4py7/vt30n Bj5sqpMbMMRVBaJTDBtwxxeUoj3pLagMBy6Nj4sYSYNoJ5PWcqqp9Y7dHThv7iy0wlNs N+FRZ2l8mY8gbG9/iaH/95kxnOopksIu7NagndXP5yk5piCrsx3QI77s+A0LLyBVlv24 5EtaUaVhcJHqQ0erIpOKebsggxJ+NA/zRkqz2UbkHBAu0/O2m4vPmLhYUSWt2gTZcHwd dtgA== 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 s20si41440875pgs.509.2019.05.02.01.36.03; Thu, 02 May 2019 01:36:18 -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 S1726427AbfEBIeP (ORCPT + 99 others); Thu, 2 May 2019 04:34:15 -0400 Received: from mx2.suse.de ([195.135.220.15]:60130 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725905AbfEBIeO (ORCPT ); Thu, 2 May 2019 04:34:14 -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 56E9EABE7; Thu, 2 May 2019 08:34:13 +0000 (UTC) Date: Thu, 2 May 2019 10:34:12 +0200 From: Petr Mladek To: "Tobin C. Harding" Cc: "Rafael J. Wysocki" , Greg Kroah-Hartman , Tyrel Datwyler , Andy Shevchenko , Miroslav Benes , Viresh Kumar , Linux Kernel Mailing List Subject: Re: kobject_init_and_add() confusion Message-ID: <20190502083412.dhqw35juhm42wgmk@pathway.suse.cz> References: <20190430233803.GB10777@eros.localdomain> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20190430233803.GB10777@eros.localdomain> User-Agent: NeoMutt/20170912 (1.9.0) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed 2019-05-01 09:38:03, Tobin C. Harding wrote: > Hi, > > Looks like I've created a bit of confusion trying to fix memleaks in > calls to kobject_init_and_add(). Its spread over various patches and > mailing lists so I'm starting a new thread and CC'ing anyone that > commented on one of those patches. > > If there is a better way to go about this discussion please do tell me. > > The problem > ----------- > > Calls to kobject_init_and_add() are leaking memory throughout the kernel > because of how the error paths are handled. > > The solution > ------------ > > Write the error path code correctly. > > Example > ------- > > We have samples/kobject/kobject-example.c but it uses > kobject_create_and_add(). I thought of adding another example file here > but could not think of how to do it off the top of my head without being > super contrived. Can add this to the TODO list if it will help. > > Here is an attempted canonical usage of kobject_init_and_add() typical > of the code that currently is getting it wrong. This is the second time > I've written this and the first time it was wrong even after review (you > know who you are, you are definitely buying the next round of drinks :) > > > Assumes we have an object in memory already that has the kobject > embedded in it. Variable 'kobj' below would typically be &ptr->kobj > > > void fn(void) > { > int ret; > > ret = kobject_init_and_add(kobj, ktype, NULL, "foo"); > if (ret) { > /* > * This means kobject_init() has succeeded > * but kobject_add() failed. > */ > goto err_put; > } It is strange to make the structure visible in sysfs before we initialize it. > ret = some_init_fn(); > if (ret) { > /* > * We need to wind back kobject_add() AND kobject_put(). > * kobject_add() incremented the refcount in > * kobj->parent, that needs to be decremented THEN we need > * the call to kobject_put() to decrement the > * refcount of kobj. */ > goto err_del; > } > > ret = some_other_init_fn(); > if (ret) > goto other_err; > > kobject_uevent(kobj, KOBJ_ADD); > return 0; > > other_err: > other_clean_up_fn(); > err_del: > kobject_del(kobj); > err_put: > kobject_put(kobj); IMHO, separate kobject_del() makes only sense when the sysfs interface must be destroyed before some other actions. I guess that we need two examples. I currently understand it the following way: 1. sysfs interface and the structure can be freed anytime: struct A { struct kobject kobj; ... }; void fn(void) { struct A *a; int ret; a = kzalloc(sizeof(*a), GFP_KERNEL); if (!a) return; /* * Initialize structure before we make it accessible via * sysfs. */ ret = some_init_fn(); if (ret) { goto init_err; } ret = kobject_init_and_add(&a->kobj, ktype, NULL, "foo"); if (ret) goto kobj_err; return 0; kobj_err: /* kobject_init() always succeds and take reference. */ kobject_put(kobj); return ret; init_err: /* kobject was not initialized, simple free is enough */ kfree(a); return ret; } 2. Structure must be registered into the subsystem before it can be made visible via sysfs: struct A { struct kobject kobj; ... }; void fn(void) { struct A *a; int ret; a = kzalloc(sizeof(*a), GFP_KERNEL); if (!a) return; ret = some_init_fn(); if (ret) { goto init_err; } /* * Structure is in a reasonable state and can be freed * via the kobject release callback. */ kobject_init(&a->kobj); /* * Register the structure so that it can cooperate * with the rest of the system. */ ret = register_fn(a); ` if (ret) goto register_err; /* Make it visible via sysfs */ ret = kobject_add(&a->kobj, ktype, NULL, "foo"); if (ret) { goto kobj_add_err; } /* Manipulate the structure somehow */ ret = action_fn(a); if (ret) goto action_err; mutex_unlock(&my_mutex); return 0; action_err: /* * Destroy sysfs interface but the structure * is still needed. */ kobject_del(&a->kboject); kobject_add_err: /* Make it invisible to the system. */ unregister_fn(a); register_err: /* Release the structure unsing the kobject callback */ kobject_put(&a->kobj); return; init_err: /* * Custom init failed. Kobject release callback would do * a double free or so. Simple free is enough. */ kfree(a); } I would really prefer if we clearly understand where each variant makes sense before we start modifying the code and documentation. Best Regards, Petr