From nobody Tue Sep 16 21:19:21 2025 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 048DFC4332F for ; Thu, 29 Dec 2022 16:01:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233676AbiL2QA6 (ORCPT ); Thu, 29 Dec 2022 11:00:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48040 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233548AbiL2QAw (ORCPT ); Thu, 29 Dec 2022 11:00:52 -0500 Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 27D46C2A for ; Thu, 29 Dec 2022 08:00:51 -0800 (PST) Received: by mail-wm1-x334.google.com with SMTP id k26-20020a05600c1c9a00b003d972646a7dso10342462wms.5 for ; Thu, 29 Dec 2022 08:00:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=rU7sDwiy4wxWca9BJshy+agHeUQnApN7sCu5RKlRtdM=; b=QMG0v/1nbi8hZ9k+X70DoEIE//b9nhmqplfikAPHlsmTZe0xNR2l8nbm2O0DqduQEp d5uEnccRjQpPn3ruyZ1t7DEuKhwxuQGVmpJoUtDbHF61PKSy+MNX7c3QaSS+LmKGA9h4 Cj7SCwh1kzAWFjTGnCER9W7spZKATQR/wfjGZu4qOTBL9sb4RSfPgcSfaqJlUmO2m/B1 nXpNroyIn3zjqGtPwPHUuHorNkwTKe5uP1L+hCqPFNrDZcYkJY/XrIWqmJL25pad4GC/ rW2CJyVUI4dw/irPK1J2hAwnjnc7rDGMxWBHAQ045TexoC72zdqEADUK9FdApcoCtbGO d5Xg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rU7sDwiy4wxWca9BJshy+agHeUQnApN7sCu5RKlRtdM=; b=qaAL/1MqcFNQm2Z89IsWi+Ob7YELrZxp8nCSKzinQ6r29LKiHxmDY9lDl6CblIfApY D3nWjAd1wxcHPmJaz/a0d/jhyhJ2ychl54cYu+cDa3sZRJiQV2tHq3e2+2ZGf2fb5eHU FhwpZGMXX5dPrxdwP84cLmRz9B2b8D3w6zafdbeKy4TGhUYTXHghbvjPri7uhJKBTGVL 3qrloaJPXza0Ef6aCJ8oxuPVW4hOchHCunTCxdABX1HSVL65joJNSOtm+Htp2T0ab2p1 pHRwKwDyRiIJTz1yXZhr1eNggEy5cLEmR7tshRXHzKytNZJV+Y7Ev75Jv/YNcDokzqP4 T1og== X-Gm-Message-State: AFqh2kobRPaZjtZqg4zC8ft9NWqPWJXgGuphuae1103f8gtSzh4VvMuu IumObFUmGyMQUYo+e5zaNnkD27RSM7s99SuX X-Google-Smtp-Source: AMrXdXuoZ2vTu1bXeKBH+OFEFAhnLg5FXTl0GNGp1V2KuPzwTzzms+/8kk/xRMOp+MadsofE8cxzzA== X-Received: by 2002:a05:600c:4995:b0:3d3:4f43:fbc2 with SMTP id h21-20020a05600c499500b003d34f43fbc2mr20646046wmp.41.1672329649761; Thu, 29 Dec 2022 08:00:49 -0800 (PST) Received: from brgl-uxlite.home ([2a01:cb1d:334:ac00:8f7a:98d8:9d8d:ced8]) by smtp.gmail.com with ESMTPSA id c12-20020a05600c0a4c00b003cfa3a12660sm42511593wmq.1.2022.12.29.08.00.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Dec 2022 08:00:49 -0800 (PST) From: Bartosz Golaszewski To: Wolfram Sang Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, Bartosz Golaszewski Subject: [PATCH v2 1/2] i2c: dev: fix notifier return values Date: Thu, 29 Dec 2022 17:00:44 +0100 Message-Id: <20221229160045.535778-2-brgl@bgdev.pl> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221229160045.535778-1-brgl@bgdev.pl> References: <20221229160045.535778-1-brgl@bgdev.pl> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Bartosz Golaszewski We have a set of return values that notifier callbacks can return. They should not return 0, error codes or anything other than those predefined values. Make the i2c character device's callback return NOTIFY_DONE or NOTIFY_OK depending on the situation. Signed-off-by: Bartosz Golaszewski --- drivers/i2c/i2c-dev.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index ab0adaa130da..107623c4cc14 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -653,12 +653,12 @@ static int i2cdev_attach_adapter(struct device *dev, = void *dummy) int res; =20 if (dev->type !=3D &i2c_adapter_type) - return 0; + return NOTIFY_DONE; adap =3D to_i2c_adapter(dev); =20 i2c_dev =3D get_free_i2c_dev(adap); if (IS_ERR(i2c_dev)) - return PTR_ERR(i2c_dev); + return NOTIFY_DONE; =20 cdev_init(&i2c_dev->cdev, &i2cdev_fops); i2c_dev->cdev.owner =3D THIS_MODULE; @@ -678,11 +678,11 @@ static int i2cdev_attach_adapter(struct device *dev, = void *dummy) goto err_put_i2c_dev; =20 pr_debug("adapter [%s] registered as minor %d\n", adap->name, adap->nr); - return 0; + return NOTIFY_OK; =20 err_put_i2c_dev: put_i2c_dev(i2c_dev, false); - return res; + return NOTIFY_DONE; } =20 static int i2cdev_detach_adapter(struct device *dev, void *dummy) @@ -691,17 +691,17 @@ static int i2cdev_detach_adapter(struct device *dev, = void *dummy) struct i2c_dev *i2c_dev; =20 if (dev->type !=3D &i2c_adapter_type) - return 0; + return NOTIFY_DONE; adap =3D to_i2c_adapter(dev); =20 i2c_dev =3D i2c_dev_get_by_minor(adap->nr); if (!i2c_dev) /* attach_adapter must have failed */ - return 0; + return NOTIFY_DONE; =20 put_i2c_dev(i2c_dev, true); =20 pr_debug("adapter [%s] unregistered\n", adap->name); - return 0; + return NOTIFY_OK; } =20 static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long a= ction, @@ -716,7 +716,7 @@ static int i2cdev_notifier_call(struct notifier_block *= nb, unsigned long action, return i2cdev_detach_adapter(dev, NULL); } =20 - return 0; + return NOTIFY_DONE; } =20 static struct notifier_block i2cdev_notifier =3D { --=20 2.37.2 From nobody Tue Sep 16 21:19:21 2025 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 41E6CC4332F for ; Thu, 29 Dec 2022 16:01:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229721AbiL2QBB (ORCPT ); Thu, 29 Dec 2022 11:01:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48052 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229871AbiL2QAx (ORCPT ); Thu, 29 Dec 2022 11:00:53 -0500 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1662410A4 for ; Thu, 29 Dec 2022 08:00:52 -0800 (PST) Received: by mail-wm1-x32d.google.com with SMTP id c65-20020a1c3544000000b003cfffd00fc0so16637958wma.1 for ; Thu, 29 Dec 2022 08:00:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RijxwWVbFkgEBf5aHju3Exr6WeKQXc2Z1r2PJmBjhNQ=; b=8C5GY2+pcJlRd/VllT2QxHtdEAxwqt9L3RTzWYdZF6ISZabF6Ve/KYDzc1ZogWak5p HcPVFZSpNFvj74QQTAu66NumhgKBg23HP6RmmZUb8Ky2IopRfWWbpjZHl8Kl/atEevff djhfMxm/vVv+GA+01dCm9gEKI5PGqCwMY8IClUHASxXfnq6E3o/kPw3NtLNe2sYMrlHR ENbZQwD0MD8vjn/ESyhW0QfscC8X8Rc9DXPoQ1+YhJybFV9vc1cVaNc2yWTI0Srxl/WY tOsGkSOCIMdp+uo1P64dL/gHVvc/ZydMmNdjVQTL+E6Zhw4gaY1fBZOdv/qUDcoV6I8H FXdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RijxwWVbFkgEBf5aHju3Exr6WeKQXc2Z1r2PJmBjhNQ=; b=vjoz+0T+n5AnDGEH1TDAEC8BnXsp+zPb6B3ea5CXInCobdUYMoRfH84gN3eRYB9TRY YeC4l88BBtUybDt0P/kWrwZAjdScQyrF69CTpuwaGibC8Gr0nSsEE1lXSocvn7BH3Fq6 f6NkLys2S4M/mzFVJec2fQbGJa1ge7fEu7ARJeO/MHcc6BKWe1G2nyyNfpXX4FeEPL5K 0Erz6+JkiZR8IO8uurt28ShYY0/tk79lLbDFA7EslTZxWfsvc9IM/8FNb9QGWyzgHQTq bUA4srhaET+2SnTlvijiJq1IZgjLIA/T+nJ4Mbo4/TJm5t+XJiNvW83Icth6On7pUnef tSqA== X-Gm-Message-State: AFqh2kolzt+T971ETOHHvktxdqREGqKi9ZSy8RjxUebrxqQod3/c1Oya E5mt1JsUddRBZ+/8YQ8NcZhihQICioSmF0TN X-Google-Smtp-Source: AMrXdXtzyQyyl4NEjo2WIs/VrOWIlAeMS8bb7f7rjety531zTnGrM7EDp6nL510upy2K/HIIXq4C/Q== X-Received: by 2002:a05:600c:4255:b0:3d3:3d34:5d63 with SMTP id r21-20020a05600c425500b003d33d345d63mr21116648wmm.8.1672329650623; Thu, 29 Dec 2022 08:00:50 -0800 (PST) Received: from brgl-uxlite.home ([2a01:cb1d:334:ac00:8f7a:98d8:9d8d:ced8]) by smtp.gmail.com with ESMTPSA id c12-20020a05600c0a4c00b003cfa3a12660sm42511593wmq.1.2022.12.29.08.00.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Dec 2022 08:00:50 -0800 (PST) From: Bartosz Golaszewski To: Wolfram Sang Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, Bartosz Golaszewski Subject: [PATCH v2 2/2] i2c: dev: don't allow user-space to deadlock the kernel Date: Thu, 29 Dec 2022 17:00:45 +0100 Message-Id: <20221229160045.535778-3-brgl@bgdev.pl> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221229160045.535778-1-brgl@bgdev.pl> References: <20221229160045.535778-1-brgl@bgdev.pl> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Bartosz Golaszewski If we open an i2c character device and then unbind the underlying i2c adapter (either by unbinding it manually via sysfs or - for a real-life example - when unplugging a USB device with an i2c adaper), the kernel thread calling i2c_del_adapter() will become blocked waiting for the completion that only completes once all references to the character device get dropped. In order to fix that, we introduce a couple changes. They need to be part of a single commit in order to preserve bisectability. First, drop the dev_release completion. That removes the risk of a deadlock but we now need to protect the character device structures against NULL pointer dereferences. To that end introduce an rw semaphore. It will protect the dummy i2c_client structure against dropping the adapter from under it. It will be taken for reading by all file_operations callbacks and for writing by the notifier's unbind handler. This way we don't prohibit the syscalls that don't get in each other's way from running concurrently but the adapter will not be unbound before all syscalls return. Finally: upon being notified about an unbind event for the i2c adapter, we take the lock for writing and set the adapter pointer in the character device's structure to NULL. This "numbs down" the device - it still exists but is no longer functional. Meanwhile every syscall callback checks that pointer after taking the lock but before executing any code that requires it. If it's NULL, we return an error to user-space. This way we can safely open an i2c device from user-space, unbind the device without triggering a deadlock and any subsequent system-call for the file descriptor associated with the removed adapter will gracefully fail. Signed-off-by: Bartosz Golaszewski --- drivers/i2c/i2c-core-base.c | 26 ++-------- drivers/i2c/i2c-dev.c | 96 ++++++++++++++++++++++++++++++++----- include/linux/i2c.h | 2 - 3 files changed, 88 insertions(+), 36 deletions(-) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 087e480b624c..9ce63d513f72 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1139,7 +1139,11 @@ EXPORT_SYMBOL_GPL(i2c_new_ancillary_device); static void i2c_adapter_dev_release(struct device *dev) { struct i2c_adapter *adap =3D to_i2c_adapter(dev); - complete(&adap->dev_released); + + /* free bus id */ + mutex_lock(&core_lock); + idr_remove(&i2c_adapter_idr, adap->nr); + mutex_unlock(&core_lock); } =20 unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) @@ -1512,9 +1516,7 @@ static int i2c_register_adapter(struct i2c_adapter *a= dap) return 0; =20 out_reg: - init_completion(&adap->dev_released); device_unregister(&adap->dev); - wait_for_completion(&adap->dev_released); out_list: mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); @@ -1713,25 +1715,7 @@ void i2c_del_adapter(struct i2c_adapter *adap) =20 i2c_host_notify_irq_teardown(adap); =20 - /* wait until all references to the device are gone - * - * FIXME: This is old code and should ideally be replaced by an - * alternative which results in decoupling the lifetime of the struct - * device from the i2c_adapter, like spi or netdev do. Any solution - * should be thoroughly tested with DEBUG_KOBJECT_RELEASE enabled! - */ - init_completion(&adap->dev_released); device_unregister(&adap->dev); - wait_for_completion(&adap->dev_released); - - /* free bus id */ - mutex_lock(&core_lock); - idr_remove(&i2c_adapter_idr, adap->nr); - mutex_unlock(&core_lock); - - /* Clear the device structure in case this adapter is ever going to be - added again */ - memset(&adap->dev, 0, sizeof(adap->dev)); } EXPORT_SYMBOL(i2c_del_adapter); =20 diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 107623c4cc14..305b64a5d4d4 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include =20 @@ -44,8 +45,14 @@ struct i2c_dev { struct i2c_adapter *adap; struct device dev; struct cdev cdev; + struct rw_semaphore sem; }; =20 +static inline struct i2c_dev *to_i2c_dev(struct inode *ino) +{ + return container_of(ino->i_cdev, struct i2c_dev, cdev); +} + #define I2C_MINORS (MINORMASK + 1) static LIST_HEAD(i2c_dev_list); static DEFINE_SPINLOCK(i2c_dev_list_lock); @@ -136,15 +143,23 @@ static ssize_t i2cdev_read(struct file *file, char __= user *buf, size_t count, { char *tmp; int ret; - + struct i2c_dev *i2c_dev =3D to_i2c_dev(file_inode(file)); struct i2c_client *client =3D file->private_data; =20 if (count > 8192) count =3D 8192; =20 + down_read(&i2c_dev->sem); + if (!i2c_dev->adap) { + up_read(&i2c_dev->sem); + return -ENODEV; + } + tmp =3D kzalloc(count, GFP_KERNEL); - if (tmp =3D=3D NULL) + if (tmp =3D=3D NULL) { + up_read(&i2c_dev->sem); return -ENOMEM; + } =20 pr_debug("i2c-%d reading %zu bytes.\n", iminor(file_inode(file)), count); =20 @@ -152,6 +167,7 @@ static ssize_t i2cdev_read(struct file *file, char __us= er *buf, size_t count, if (ret >=3D 0) if (copy_to_user(buf, tmp, ret)) ret =3D -EFAULT; + up_read(&i2c_dev->sem); kfree(tmp); return ret; } @@ -161,18 +177,28 @@ static ssize_t i2cdev_write(struct file *file, const = char __user *buf, { int ret; char *tmp; + struct i2c_dev *i2c_dev =3D to_i2c_dev(file_inode(file)); struct i2c_client *client =3D file->private_data; =20 if (count > 8192) count =3D 8192; =20 + down_read(&i2c_dev->sem); + if (!i2c_dev->adap) { + up_read(&i2c_dev->sem); + return -ENODEV; + } + tmp =3D memdup_user(buf, count); - if (IS_ERR(tmp)) + if (IS_ERR(tmp)) { + up_read(&i2c_dev->sem); return PTR_ERR(tmp); + } =20 pr_debug("i2c-%d writing %zu bytes.\n", iminor(file_inode(file)), count); =20 ret =3D i2c_master_send(client, tmp, count); + up_read(&i2c_dev->sem); kfree(tmp); return ret; } @@ -389,7 +415,8 @@ static noinline int i2cdev_ioctl_smbus(struct i2c_clien= t *client, return res; } =20 -static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lon= g arg) +static long i2cdev_ioctl_unlocked(struct file *file, unsigned int cmd, + unsigned long arg) { struct i2c_client *client =3D file->private_data; unsigned long funcs; @@ -495,6 +522,20 @@ static long i2cdev_ioctl(struct file *file, unsigned i= nt cmd, unsigned long arg) return 0; } =20 +static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lon= g arg) +{ + struct i2c_dev *i2c_dev =3D to_i2c_dev(file_inode(file)); + long ret; + + down_read(&i2c_dev->sem); + if (!i2c_dev->adap) + ret =3D -ENODEV; + else + ret =3D i2cdev_ioctl_unlocked(file, cmd, arg); + up_read(&i2c_dev->sem); + + return ret; +} #ifdef CONFIG_COMPAT =20 struct i2c_smbus_ioctl_data32 { @@ -516,10 +557,12 @@ struct i2c_rdwr_ioctl_data32 { u32 nmsgs; }; =20 -static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsig= ned long arg) +static long compat_i2cdev_ioctl_unlocked(struct file *file, unsigned int c= md, + unsigned long arg) { struct i2c_client *client =3D file->private_data; unsigned long funcs; + switch (cmd) { case I2C_FUNCS: funcs =3D i2c_get_functionality(client->adapter); @@ -578,19 +621,39 @@ static long compat_i2cdev_ioctl(struct file *file, un= signed int cmd, unsigned lo return i2cdev_ioctl(file, cmd, arg); } } + +static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct i2c_dev *i2c_dev =3D to_i2c_dev(file_inode(file)); + long ret; + + down_read(&i2c_dev->sem); + if (!i2c_dev->adap) + ret =3D -ENODEV; + else + ret =3D compat_i2cdev_ioctl_unlocked(file, cmd, arg); + up_read(&i2c_dev->sem); + + return ret; +} #else #define compat_i2cdev_ioctl NULL #endif =20 static int i2cdev_open(struct inode *inode, struct file *file) { - unsigned int minor =3D iminor(inode); + struct i2c_dev *i2c_dev =3D to_i2c_dev(inode); struct i2c_client *client; struct i2c_adapter *adap; + int ret =3D 0; =20 - adap =3D i2c_get_adapter(minor); - if (!adap) - return -ENODEV; + down_read(&i2c_dev->sem); + adap =3D i2c_dev->adap; + if (!adap) { + ret =3D -ENODEV; + goto out_unlock; + } =20 /* This creates an anonymous i2c_client, which may later be * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE. @@ -601,22 +664,23 @@ static int i2cdev_open(struct inode *inode, struct fi= le *file) */ client =3D kzalloc(sizeof(*client), GFP_KERNEL); if (!client) { - i2c_put_adapter(adap); - return -ENOMEM; + ret =3D -ENOMEM; + goto out_unlock; } snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr); =20 client->adapter =3D adap; file->private_data =3D client; =20 - return 0; +out_unlock: + up_read(&i2c_dev->sem); + return ret; } =20 static int i2cdev_release(struct inode *inode, struct file *file) { struct i2c_client *client =3D file->private_data; =20 - i2c_put_adapter(client->adapter); kfree(client); file->private_data =3D NULL; =20 @@ -669,6 +733,8 @@ static int i2cdev_attach_adapter(struct device *dev, vo= id *dummy) i2c_dev->dev.parent =3D &adap->dev; i2c_dev->dev.release =3D i2cdev_dev_release; =20 + init_rwsem(&i2c_dev->sem); + res =3D dev_set_name(&i2c_dev->dev, "i2c-%d", adap->nr); if (res) goto err_put_i2c_dev; @@ -698,6 +764,10 @@ static int i2cdev_detach_adapter(struct device *dev, v= oid *dummy) if (!i2c_dev) /* attach_adapter must have failed */ return NOTIFY_DONE; =20 + down_write(&i2c_dev->sem); + i2c_dev->adap =3D NULL; + up_write(&i2c_dev->sem); + put_i2c_dev(i2c_dev, true); =20 pr_debug("adapter [%s] unregistered\n", adap->name); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index d84e0e99f084..3f31e4032044 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -14,7 +14,6 @@ #include #include #include /* for struct device */ -#include /* for completion */ #include #include #include @@ -739,7 +738,6 @@ struct i2c_adapter { =20 int nr; char name[48]; - struct completion dev_released; =20 struct mutex userspace_clients_lock; struct list_head userspace_clients; --=20 2.37.2