From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 81158C433F5 for ; Wed, 20 Apr 2022 17:14:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:Subject:Message-ID:Date:From: In-Reply-To:References:MIME-Version:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=pxmQA073ubij6/deDTktUnMYpdKmBQPWcGOS54hwXFg=; b=1DOCN9+LSYM+mV ahfIuvIy4FMDLHo/0+Mqj/qw0+zUwR/G4gyjFteoo/w0w3JHMinNwBAJHdj9VUbpZb5QRdAy0BfBh cwQtIKE51UI9EU2tY9UPQw/WHi88Fv0S7Iws1S6kyRLSZUDDub0e59Hm5pQe+mHKU/Mox0I9zbXeX dFx/6HJv0Azkz1UURMWJRxe/bKOdd8dzxzIgdxuzNd4ApTbXUQneZeqymcamX8kc+/E6WqlH1p0EY UzJAEZdpJClIgtyqoT0UIVObIsvMu2EsTNu4G6pKMSYa4nIbIVEX7BKvBwjihDdT7PpBP6c8zuUPl 1RxuEPmIsLjzCAe6qKzw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nhDt2-009ruI-7p; Wed, 20 Apr 2022 17:13:04 +0000 Received: from mail-yb1-f169.google.com ([209.85.219.169]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nhDsy-009rsu-IA for linux-arm-kernel@lists.infradead.org; Wed, 20 Apr 2022 17:13:02 +0000 Received: by mail-yb1-f169.google.com with SMTP id b95so4087937ybi.1 for ; Wed, 20 Apr 2022 10:12:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=/ASIWAo0HytBTKR5fLcMLGJJVl7MsnssiA8AeEXSjEM=; b=JyTmustYuMgJ6cjOQiSXg/DYvDjod+9iPhbkJpYNF9/Z345MrdncLY+QBFO3Cuc3Df MWMIzuOtA5dH1xD8PkivNpR8XAiQnnydjE5vcXUg7lqujSxDqzr0SbrJzr7VxEhUEwQ6 KXsqPEAEeqfV4NwxHGUrUgv0iiGc3DnQkXRCyCJg8UD0Md3mNsoP/2quTszSbHwdhpTP TvdtTsc8o7st0Xr/bZgLsOyznbRA3UreJ3q/ieypwzbHnAfvuvfPrcr9TS0eBxsDfRT6 RODtghTEMf7OxbJHBTnc4mTEfb5BY8f5LvRnK6WiQ3JXbLu+3Td9wqjTZ4IIyQIOiCEo XDGw== X-Gm-Message-State: AOAM533hau7s8WwA8+JjWVPlDgDQPQYKgVlMRFoEFFbfzOKDBaJCaNi+ EJX+a05gp9H4PU4kljYJZFcAt46q69QIv/Mv8+U= X-Google-Smtp-Source: ABdhPJygxTqwH/fYP8f9/TOx3wegsu6FxX5O1kN/quLL9EMh/cabSnVGqayxP5pVJxnDK33VgIW6Cm39TvZfF3wMYBU= X-Received: by 2002:a25:e082:0:b0:641:cf5:b91f with SMTP id x124-20020a25e082000000b006410cf5b91fmr20887561ybg.482.1650474779115; Wed, 20 Apr 2022 10:12:59 -0700 (PDT) MIME-Version: 1.0 References: <20220419113435.246203-1-krzysztof.kozlowski@linaro.org> <20220419113435.246203-2-krzysztof.kozlowski@linaro.org> In-Reply-To: <20220419113435.246203-2-krzysztof.kozlowski@linaro.org> From: "Rafael J. Wysocki" Date: Wed, 20 Apr 2022 19:12:48 +0200 Message-ID: Subject: Re: [PATCH v7 01/12] driver: platform: Add helper for safer setting of driver_override To: Krzysztof Kozlowski Cc: Greg Kroah-Hartman , "Rafael J. Wysocki" , Stuart Yoder , "K. Y. Srinivasan" , Haiyang Zhang , Stephen Hemminger , Wei Liu , Dexuan Cui , Bjorn Helgaas , Bjorn Andersson , Mathieu Poirier , Vineeth Vijayan , Peter Oberparleiter , Heiko Carstens , Vasily Gorbik , Alexander Gordeev , Christian Borntraeger , Sven Schnelle , Andy Gross , Linux Kernel Mailing List , linux-clk , NXP Linux Team , Linux ARM , Linux on Hyper-V List , Linux PCI , linux-remoteproc@vger.kernel.org, linux-s390@vger.kernel.org, linux-arm-msm , "moderated list:SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEM..." , linux-spi , virtualization@lists.linux-foundation.org, Linus Torvalds , Rasmus Villemoes , Andy Shevchenko X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220420_101300_641357_657C8DAC X-CRM114-Status: GOOD ( 41.02 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On Tue, Apr 19, 2022 at 1:34 PM Krzysztof Kozlowski wrote: > > Several core drivers and buses expect that driver_override is a > dynamically allocated memory thus later they can kfree() it. > > However such assumption is not documented, there were in the past and > there are already users setting it to a string literal. This leads to > kfree() of static memory during device release (e.g. in error paths or > during unbind): > > kernel BUG at ../mm/slub.c:3960! > Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM > ... > (kfree) from [] (platform_device_release+0x88/0xb4) > (platform_device_release) from [] (device_release+0x2c/0x90) > (device_release) from [] (kobject_put+0xec/0x20c) > (kobject_put) from [] (exynos5_clk_probe+0x154/0x18c) > (exynos5_clk_probe) from [] (platform_drv_probe+0x6c/0xa4) > (platform_drv_probe) from [] (really_probe+0x280/0x414) > (really_probe) from [] (driver_probe_device+0x78/0x1c4) > (driver_probe_device) from [] (bus_for_each_drv+0x74/0xb8) > (bus_for_each_drv) from [] (__device_attach+0xd4/0x16c) > (__device_attach) from [] (bus_probe_device+0x88/0x90) > (bus_probe_device) from [] (device_add+0x3dc/0x62c) > (device_add) from [] (of_platform_device_create_pdata+0x94/0xbc) > (of_platform_device_create_pdata) from [] (of_platform_bus_create+0x1a8/0x4fc) > (of_platform_bus_create) from [] (of_platform_bus_create+0x20c/0x4fc) > (of_platform_bus_create) from [] (of_platform_populate+0x84/0x118) > (of_platform_populate) from [] (of_platform_default_populate_init+0xa0/0xb8) > (of_platform_default_populate_init) from [] (do_one_initcall+0x8c/0x404) > > Provide a helper which clearly documents the usage of driver_override. > This will allow later to reuse the helper and reduce the amount of > duplicated code. > > Convert the platform driver to use a new helper and make the > driver_override field const char (it is not modified by the core). > > Signed-off-by: Krzysztof Kozlowski > --- > drivers/base/driver.c | 69 +++++++++++++++++++++++++++++++++ > drivers/base/platform.c | 28 ++----------- > include/linux/device/driver.h | 2 + > include/linux/platform_device.h | 6 ++- > 4 files changed, 80 insertions(+), 25 deletions(-) > > diff --git a/drivers/base/driver.c b/drivers/base/driver.c > index 8c0d33e182fd..1b9d47b10bd0 100644 > --- a/drivers/base/driver.c > +++ b/drivers/base/driver.c > @@ -30,6 +30,75 @@ static struct device *next_device(struct klist_iter *i) > return dev; > } > > +/** > + * driver_set_override() - Helper to set or clear driver override. > + * @dev: Device to change > + * @override: Address of string to change (e.g. &device->driver_override); > + * The contents will be freed and hold newly allocated override. I would stick to one-line description here and possibly expand them in the body of the comment. Regardless, I think that the series is an improvement, so please feel free to add Reviewed-by: Rafael J. Wysocki to this patch and Acked-by: Rafael J. Wysocki to the other patches in the series. > + * @s: NUL-terminated string, new driver name to force a match, pass empty > + * string to clear it ("" or "\n", where the latter is only for sysfs > + * interface). > + * @len: length of @s > + * > + * Helper to set or clear driver override in a device, intended for the cases > + * when the driver_override field is allocated by driver/bus code. > + * > + * Returns: 0 on success or a negative error code on failure. > + */ > +int driver_set_override(struct device *dev, const char **override, > + const char *s, size_t len) > +{ > + const char *new, *old; > + char *cp; > + > + if (!override || !s) > + return -EINVAL; > + > + /* > + * The stored value will be used in sysfs show callback (sysfs_emit()), > + * which has a length limit of PAGE_SIZE and adds a trailing newline. > + * Thus we can store one character less to avoid truncation during sysfs > + * show. > + */ > + if (len >= (PAGE_SIZE - 1)) > + return -EINVAL; > + > + if (!len) { > + /* Empty string passed - clear override */ > + device_lock(dev); > + old = *override; > + *override = NULL; > + device_unlock(dev); > + kfree(old); > + > + return 0; > + } > + > + cp = strnchr(s, len, '\n'); > + if (cp) > + len = cp - s; > + > + new = kstrndup(s, len, GFP_KERNEL); > + if (!new) > + return -ENOMEM; > + > + device_lock(dev); > + old = *override; > + if (cp != s) { > + *override = new; > + } else { > + /* "\n" passed - clear override */ > + kfree(new); > + *override = NULL; > + } > + device_unlock(dev); > + > + kfree(old); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(driver_set_override); > + > /** > * driver_for_each_device - Iterator for devices bound to a driver. > * @drv: Driver we're iterating. > diff --git a/drivers/base/platform.c b/drivers/base/platform.c > index 8cc272fd5c99..b684157b7f2f 100644 > --- a/drivers/base/platform.c > +++ b/drivers/base/platform.c > @@ -1275,31 +1275,11 @@ static ssize_t driver_override_store(struct device *dev, > const char *buf, size_t count) > { > struct platform_device *pdev = to_platform_device(dev); > - char *driver_override, *old, *cp; > - > - /* We need to keep extra room for a newline */ > - if (count >= (PAGE_SIZE - 1)) > - return -EINVAL; > - > - driver_override = kstrndup(buf, count, GFP_KERNEL); > - if (!driver_override) > - return -ENOMEM; > - > - cp = strchr(driver_override, '\n'); > - if (cp) > - *cp = '\0'; > - > - device_lock(dev); > - old = pdev->driver_override; > - if (strlen(driver_override)) { > - pdev->driver_override = driver_override; > - } else { > - kfree(driver_override); > - pdev->driver_override = NULL; > - } > - device_unlock(dev); > + int ret; > > - kfree(old); > + ret = driver_set_override(dev, &pdev->driver_override, buf, count); > + if (ret) > + return ret; > > return count; > } > diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h > index 15e7c5e15d62..700453017e1c 100644 > --- a/include/linux/device/driver.h > +++ b/include/linux/device/driver.h > @@ -151,6 +151,8 @@ extern int __must_check driver_create_file(struct device_driver *driver, > extern void driver_remove_file(struct device_driver *driver, > const struct driver_attribute *attr); > > +int driver_set_override(struct device *dev, const char **override, > + const char *s, size_t len); > extern int __must_check driver_for_each_device(struct device_driver *drv, > struct device *start, > void *data, > diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h > index 7c96f169d274..582d83ed9a91 100644 > --- a/include/linux/platform_device.h > +++ b/include/linux/platform_device.h > @@ -31,7 +31,11 @@ struct platform_device { > struct resource *resource; > > const struct platform_device_id *id_entry; > - char *driver_override; /* Driver name to force a match */ > + /* > + * Driver name to force a match. Do not set directly, because core > + * frees it. Use driver_set_override() to set or clear it. > + */ > + const char *driver_override; > > /* MFD cell pointer */ > struct mfd_cell *mfd_cell; > -- > 2.32.0 > _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel