From nobody Mon Sep 28 02:56:52 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6321C3C456F; Thu, 27 Aug 2026 10:22:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787826183; cv=none; b=EgVFicwuWdIK9I0JK0N/6StVRkv1Ll1SiWjKgx4gY1SpP5Ys1c9yaBozPxHsDkGiNWg8ekS29cn4W3a+WEFe81P712knNeCQ9Zr6enKaUfj+FCWpKmzy9Y6oW/FI0te8qwoO2gyUWRO0b4ajZ4nrXEZWmYJRw+YybIvw8It5hnc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787826183; c=relaxed/simple; bh=gUppXHTdEj1kYYCABbev3ayBSZcA0PFUMCztre2Jszg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hoccX5FPEDzwpNE8SiUrFH3/S2+1yGLRyGj4EmkV1mkvJZEHLm7dcnXDV4kBJhl3noxW68rdq7Kgm1lVkx+d7Df9M/7qnkpPd59PbdnXKhX2wlNx8MfwlDlwhVzcG5bWPR96CIjcSKr9fLu4eccbVqBctbM+Sfqam8/MUnsTiOQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=izR9bRx9; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="izR9bRx9" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A79941F00A3E; Thu, 27 Aug 2026 10:22:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787826178; bh=ktjeE9kyUjXdIJfec6DZ8GRyHL+s78itx2hMV0y6Mgk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=izR9bRx9kovnKCveIORRbatQizYPls3j/u6fMgUFoCKZWP0I4cpioQMJtNJwgUI/R ZzzI4MtFoZCYDTCkj9lI8ipLQzCADrhPR8lYS5kmoHuNeWToxvkezrU/gPWNQ7duHY QueiZhAOO02Fg8yxK6cIUH+QlV11zVGFAUjtauZJq8RdlFVG6oc9aQsd/vhu7dWZ+k 04YCUwfRvw8GJQ30u9pgWXbynlFbiyOTZAk+ZqIzL6R8y+r14sr+O9pZv3fb5TmV+G pJLLhaQyTuROziCgXvVJsa6vnwTwb3K2Urz8RC6hiu3w3MtluqahupXJyl/4DZui8u kMvNeYrRO6o6A== Received: from johan by xi.lan with local (Exim 4.99.4) (envelope-from ) id 1wzXG4-00000002pC1-16Lk; Thu, 27 Aug 2026 12:22:56 +0200 From: Johan Hovold To: Andi Shyti Cc: Wolfram Sang , linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, Johan Hovold , stable@vger.kernel.org Subject: [PATCH v2 1/3] i2c: dev: fix blocked adapter deregistration Date: Thu, 27 Aug 2026 12:20:41 +0200 Message-ID: <20260827102043.673273-2-johan@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260827102043.673273-1-johan@kernel.org> References: <20260827102043.673273-1-johan@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The I2C subsystem allows controllers to be used by non-child devices that may remain registered after an adapter goes away. To handle this, adapter deregistration blocks until the last reference to the adapter is released. Albeit unorthodox, this is mostly fine for the vast majority of controllers but can cause some trouble when controllers reside on hotpluggable buses. Specifically, userspace can prevent an adapter from being deregistered indefinitely by holding an i2c-dev character device file open. And with USB attached controllers this prevents further hub events from being processed by the parent hub until the file is closed. Fix the i2c-dev implementation by dropping the additional reference taken at open() and using an rwsem to make sure the adapter is only accessed while registered. Note that before commit 611e12ea0f12 ("i2c: core: manage i2c bus device refcount in i2c_[get|put]_adapter") an adapter going away would instead have resulted in a use-after-free. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/i2c/i2c-dev.c | 95 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 19 deletions(-) diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index ccaac5e29f90..0940070c0317 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include =20 @@ -41,11 +42,17 @@ */ struct i2c_dev { struct list_head list; + struct rw_semaphore rwsem; struct i2c_adapter *adap; struct device dev; struct cdev cdev; }; =20 +struct i2c_dev_data { + struct i2c_dev *i2c_dev; + struct i2c_client client; +}; + #define I2C_MINORS (MINORMASK + 1) static LIST_HEAD(i2c_dev_list); static DEFINE_SPINLOCK(i2c_dev_list_lock); @@ -92,6 +99,11 @@ static void put_i2c_dev(struct i2c_dev *i2c_dev, bool de= l_cdev) spin_unlock(&i2c_dev_list_lock); if (del_cdev) cdev_device_del(&i2c_dev->cdev, &i2c_dev->dev); + + scoped_guard(rwsem_write, &i2c_dev->rwsem) { + i2c_dev->adap =3D NULL; + } + put_device(&i2c_dev->dev); } =20 @@ -134,10 +146,16 @@ ATTRIBUTE_GROUPS(i2c); static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t cou= nt, loff_t *offset) { + struct i2c_dev_data *data =3D file->private_data; + struct i2c_client *client =3D &data->client; + struct i2c_dev *i2c_dev =3D data->i2c_dev; char *tmp; int ret; =20 - struct i2c_client *client =3D file->private_data; + guard(rwsem_read)(&i2c_dev->rwsem); + + if (!i2c_dev->adap) + return -ENODEV; =20 /* Adapter must support I2C transfers */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) @@ -163,9 +181,16 @@ static ssize_t i2cdev_read(struct file *file, char __u= ser *buf, size_t count, static ssize_t i2cdev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) { + struct i2c_dev_data *data =3D file->private_data; + struct i2c_client *client =3D &data->client; + struct i2c_dev *i2c_dev =3D data->i2c_dev; int ret; char *tmp; - struct i2c_client *client =3D file->private_data; + + guard(rwsem_read)(&i2c_dev->rwsem); + + if (!i2c_dev->adap) + return -ENODEV; =20 /* Adapter must support I2C transfers */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) @@ -397,11 +422,15 @@ static noinline int i2cdev_ioctl_smbus(struct i2c_cli= ent *client, return res; } =20 -static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lon= g arg) +static long i2cdev_ioctl_locked(struct file *file, unsigned int cmd, unsig= ned long arg) { - struct i2c_client *client =3D file->private_data; + struct i2c_dev_data *data =3D file->private_data; + struct i2c_client *client =3D &data->client; + struct i2c_dev *i2c_dev =3D data->i2c_dev; unsigned long funcs; =20 + lockdep_assert_held(&i2c_dev->rwsem); + dev_dbg(&client->adapter->dev, "ioctl, cmd=3D0x%02x, arg=3D0x%02lx\n", cmd, arg); =20 @@ -507,6 +536,19 @@ 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_data *data =3D file->private_data; + struct i2c_dev *i2c_dev =3D data->i2c_dev; + + guard(rwsem_read)(&i2c_dev->rwsem); + + if (!i2c_dev->adap) + return -ENODEV; + + return i2cdev_ioctl_locked(file, cmd, arg); +} + #ifdef CONFIG_COMPAT =20 struct i2c_smbus_ioctl_data32 { @@ -530,8 +572,16 @@ struct i2c_rdwr_ioctl_data32 { =20 static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsig= ned long arg) { - struct i2c_client *client =3D file->private_data; + struct i2c_dev_data *data =3D file->private_data; + struct i2c_client *client =3D &data->client; + struct i2c_dev *i2c_dev =3D data->i2c_dev; unsigned long funcs; + + guard(rwsem_read)(&i2c_dev->rwsem); + + if (!i2c_dev->adap) + return -ENODEV; + switch (cmd) { case I2C_FUNCS: funcs =3D i2c_get_functionality(client->adapter); @@ -588,7 +638,7 @@ static long compat_i2cdev_ioctl(struct file *file, unsi= gned int cmd, unsigned lo compat_ptr(data32.data)); } default: - return i2cdev_ioctl(file, cmd, arg); + return i2cdev_ioctl_locked(file, cmd, arg); } } #else @@ -597,14 +647,18 @@ static long compat_i2cdev_ioctl(struct file *file, un= signed int cmd, unsigned lo =20 static int i2cdev_open(struct inode *inode, struct file *file) { - unsigned int minor =3D iminor(inode); + struct i2c_dev *i2c_dev =3D container_of(inode->i_cdev, struct i2c_dev, c= dev); + struct i2c_dev_data *data; struct i2c_client *client; struct i2c_adapter *adap; =20 - adap =3D i2c_get_adapter(minor); - if (!adap) + guard(rwsem_read)(&i2c_dev->rwsem); + + if (!i2c_dev->adap) return -ENODEV; =20 + adap =3D i2c_dev->adap; + /* This creates an anonymous i2c_client, which may later be * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE. * @@ -612,26 +666,27 @@ static int i2cdev_open(struct inode *inode, struct fi= le *file) * or I2C core code!! It just holds private copies of addressing * information and maybe a PEC flag. */ - client =3D kzalloc_obj(*client); - if (!client) { - i2c_put_adapter(adap); + data =3D kzalloc_obj(*data); + if (!data) return -ENOMEM; - } + + data->i2c_dev =3D i2c_dev; + + client =3D &data->client; + snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr); =20 client->adapter =3D adap; - file->private_data =3D client; + file->private_data =3D data; =20 return 0; } =20 static int i2cdev_release(struct inode *inode, struct file *file) { - struct i2c_client *client =3D file->private_data; + struct i2c_dev_data *data =3D file->private_data; =20 - i2c_put_adapter(client->adapter); - kfree(client); - file->private_data =3D NULL; + kfree(data); =20 return 0; } @@ -675,8 +730,10 @@ static int i2cdev_attach_adapter(struct device *dev) if (IS_ERR(i2c_dev)) return NOTIFY_DONE; =20 + init_rwsem(&i2c_dev->rwsem); + cdev_init(&i2c_dev->cdev, &i2cdev_fops); - i2c_dev->cdev.owner =3D THIS_MODULE; + i2c_dev->cdev.owner =3D adap->owner; =20 device_initialize(&i2c_dev->dev); i2c_dev->dev.devt =3D MKDEV(I2C_MAJOR, adap->nr); --=20 2.54.0 From nobody Mon Sep 28 02:56:52 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 29BC142BEAA; Thu, 27 Aug 2026 10:22:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787826181; cv=none; b=NmjQnuO9EQEpE40l2d8kj/DRXEGqktNCvpC85F6/hSPl2aeR8JTNc0PV9I+Tkl3V7VNRAbfH/uky/HSOemdtsmAhCFqRWFZT9t2BJ7Q1fUjXRhsJifZNHThciv+agqx4BtY5DUDYTmQchp05M3XFn18XtvIwWZnJXf3PJBS+Ubo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787826181; c=relaxed/simple; bh=cr8GUHc33pCoSQQViyf2cxw4PqqMGDnkCl9gUsZ8L+k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uFbkWZiQTA7inedARbCINr2GkjRpP4IIL4psjz6QFWHbr1n2G6Ed4xMs4+i2vwFvW8xmFNviK2POBw7RQZPYCF/nRIOtELv/PPigKJSK81H79D8fddmLm6M55ns8k5Wz0mZpIBRfaQCUftM9cypxo8IvyIRFa3LysvLTO1ur6NU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dVCpAKQi; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dVCpAKQi" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A15041F000E9; Thu, 27 Aug 2026 10:22:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787826178; bh=znfXMecyUVlNTcrDh+JBz4l6+Y6OUdvjsSRBHXtwkVw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=dVCpAKQiYJLNj3FL5QmAeokJmvKt8o4kEKVzah6/HXdxiSElyd3CDMh1YXMeHPzI9 UgKZlHurAAFIJmu7yi7BbFPr6TJoBoKut1upOdyDyTV4DXm4I6/jnHBL1xMCMudTSO hqSHltY7p3Vth5mzVNRcgq8+gjeG4LgnTUCH5FzaRUIIoFfHJW6mncSabVd4m/voDM YMLRpnFaEg81w5AdLYHMgJj4j8E/jOSD/frgnnhxzLuW5LKcSwTEPvP34WB93eaOZ2 Mp3J6qjxSOvGbaBfXH4+lUW6IBxyUrB+8f9Lw+geHSKgA7vhtoknHMvmfh/RHNmPBt Xfs3w2S/CPU3A== Received: from johan by xi.lan with local (Exim 4.99.4) (envelope-from ) id 1wzXG4-00000002pC3-18fh; Thu, 27 Aug 2026 12:22:56 +0200 From: Johan Hovold To: Andi Shyti Cc: Wolfram Sang , linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, Johan Hovold Subject: [PATCH v2 2/3] i2c: dev: drop unnecessary sysfs device lookup Date: Thu, 27 Aug 2026 12:20:42 +0200 Message-ID: <20260827102043.673273-3-johan@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260827102043.673273-1-johan@kernel.org> References: <20260827102043.673273-1-johan@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The sysfs lifetime rules guarantees that the i2c-dev class device is still valid while its attribute callbacks are executing so drop the unnecessary reverse lookup. Signed-off-by: Johan Hovold --- drivers/i2c/i2c-dev.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 0940070c0317..49c05f2eb223 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -47,6 +47,7 @@ struct i2c_dev { struct device dev; struct cdev cdev; }; +#define to_i2c_dev(d) container_of((d), struct i2c_dev, dev) =20 struct i2c_dev_data { struct i2c_dev *i2c_dev; @@ -110,10 +111,8 @@ static void put_i2c_dev(struct i2c_dev *i2c_dev, bool = del_cdev) static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_dev *i2c_dev =3D i2c_dev_get_by_minor(MINOR(dev->devt)); + struct i2c_dev *i2c_dev =3D to_i2c_dev(dev); =20 - if (!i2c_dev) - return -ENODEV; return sysfs_emit(buf, "%s\n", i2c_dev->adap->name); } static DEVICE_ATTR_RO(name); @@ -710,9 +709,8 @@ static const struct class i2c_dev_class =3D { =20 static void i2cdev_dev_release(struct device *dev) { - struct i2c_dev *i2c_dev; + struct i2c_dev *i2c_dev =3D to_i2c_dev(dev); =20 - i2c_dev =3D container_of(dev, struct i2c_dev, dev); kfree(i2c_dev); } =20 --=20 2.54.0 From nobody Mon Sep 28 02:56:52 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9CBD83DC4AF; Thu, 27 Aug 2026 10:22:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787826183; cv=none; b=fetCZRqD6EyyvfrmrX+Q497T98e0nPeuw9WndQLtyG+PTUTO4xLXLwhr3Zk0SPN+fRXnsTgVEMyaPkAbqdiIOj8Sj9zom1dbhzvmdLDCoCM+8lE8okdSWygAF3NbRkWbGDBR6p9fIGGFm4qEkkK8kPgG7qTfeDOIH9oOE+iPYbk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787826183; c=relaxed/simple; bh=SbEvIrfZf0UM1Km9jUjL31vDdWKBp9XUP6wj9P4kcoU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W5J+8WU5FdQFfFLO0Y8sJwG2xfd+JpjoQ7pn/Gcn6xraUY8ZGsKvu2sngfU+phPIwypFDo6UMjn7B481csNxs/HV/mX0WSBgnZ4RpQj6D8N5XPBL7w6hpSJJClo6AT/RpeGXxcaaQ6gfCNk8wyLUGz+k5OXZr6skKkta53/NDnQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HzxAGBPG; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="HzxAGBPG" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A34FA1F00A3A; Thu, 27 Aug 2026 10:22:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787826178; bh=seBf3gc5LIy9dpRjrgrmfv7aes/dCe59oN23kOG8nm8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=HzxAGBPGbCgNCagWCQgEJMoRUiAo9VJ1U4OnVX7Yaq3TJDanly+LFQGK/Zmvvi8wr OvvSWuf+T7YVedf/oYKcYD199YdsTIBvHyY+V1zywu7f2N82yyxyK9P8laG8NUnf0W 8mlJYY6Li0DI2c9Pw4hrXKxUaX7NbvK3io6IlhHuXr2Pb0Iuo3wH7YMuozeg5FRwXq Ce/PRS1RjlpOFoz+IQ0a/jrzusJnxkqFmVKDfnZO/wZPaub9hJ06xZvXRXNC7GDGCr qCnxerjUT2RMUIb300gCzd6IPeYgNJHQo91wVNml0rNHV2dtwtQ4DV8NILWujRPGaM lx38PYkF/g0kw== Received: from johan by xi.lan with local (Exim 4.99.4) (envelope-from ) id 1wzXG4-00000002pC5-1B2g; Thu, 27 Aug 2026 12:22:56 +0200 From: Johan Hovold To: Andi Shyti Cc: Wolfram Sang , linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, Johan Hovold Subject: [PATCH v2 3/3] i2c: dev: clean up registration Date: Thu, 27 Aug 2026 12:20:43 +0200 Message-ID: <20260827102043.673273-4-johan@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260827102043.673273-1-johan@kernel.org> References: <20260827102043.673273-1-johan@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Drop the get_free_i2c_dev() and put_i2c_dev() helpers and do all setup and teardown directly in i2cdev_attach_adapter() and i2cdev_detach_adapter() for consistency and to make the logic clearer. Note that the device list is only used at detach so the i2c-dev can be added after registering the class device. Signed-off-by: Johan Hovold --- drivers/i2c/i2c-dev.c | 69 ++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 49c05f2eb223..9ad145f67fc1 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -73,41 +73,6 @@ static struct i2c_dev *i2c_dev_get_by_minor(unsigned ind= ex) return i2c_dev; } =20 -static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap) -{ - struct i2c_dev *i2c_dev; - - if (adap->nr >=3D I2C_MINORS) { - pr_err("Out of device minors (%d)\n", adap->nr); - return ERR_PTR(-ENODEV); - } - - i2c_dev =3D kzalloc_obj(*i2c_dev); - if (!i2c_dev) - return ERR_PTR(-ENOMEM); - i2c_dev->adap =3D adap; - - spin_lock(&i2c_dev_list_lock); - list_add_tail(&i2c_dev->list, &i2c_dev_list); - spin_unlock(&i2c_dev_list_lock); - return i2c_dev; -} - -static void put_i2c_dev(struct i2c_dev *i2c_dev, bool del_cdev) -{ - spin_lock(&i2c_dev_list_lock); - list_del(&i2c_dev->list); - spin_unlock(&i2c_dev_list_lock); - if (del_cdev) - cdev_device_del(&i2c_dev->cdev, &i2c_dev->dev); - - scoped_guard(rwsem_write, &i2c_dev->rwsem) { - i2c_dev->adap =3D NULL; - } - - put_device(&i2c_dev->dev); -} - static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -724,11 +689,17 @@ static int i2cdev_attach_adapter(struct device *dev) return NOTIFY_DONE; adap =3D to_i2c_adapter(dev); =20 - i2c_dev =3D get_free_i2c_dev(adap); - if (IS_ERR(i2c_dev)) + if (adap->nr >=3D I2C_MINORS) { + pr_err("Out of device minors (%d)\n", adap->nr); + return NOTIFY_DONE; + } + + i2c_dev =3D kzalloc_obj(*i2c_dev); + if (!i2c_dev) return NOTIFY_DONE; =20 init_rwsem(&i2c_dev->rwsem); + i2c_dev->adap =3D adap; =20 cdev_init(&i2c_dev->cdev, &i2cdev_fops); i2c_dev->cdev.owner =3D adap->owner; @@ -745,13 +716,21 @@ static int i2cdev_attach_adapter(struct device *dev) =20 res =3D cdev_device_add(&i2c_dev->cdev, &i2c_dev->dev); if (res) - goto err_put_i2c_dev; + goto err_clear_adap; + + spin_lock(&i2c_dev_list_lock); + list_add_tail(&i2c_dev->list, &i2c_dev_list); + spin_unlock(&i2c_dev_list_lock); =20 pr_debug("adapter [%s] registered as minor %d\n", adap->name, adap->nr); return NOTIFY_OK; =20 +err_clear_adap: + scoped_guard(rwsem_write, &i2c_dev->rwsem) { + i2c_dev->adap =3D NULL; + } err_put_i2c_dev: - put_i2c_dev(i2c_dev, false); + put_device(&i2c_dev->dev); return NOTIFY_DONE; } =20 @@ -768,7 +747,17 @@ static int i2cdev_detach_adapter(struct device *dev) if (!i2c_dev) /* attach_adapter must have failed */ return NOTIFY_DONE; =20 - put_i2c_dev(i2c_dev, true); + spin_lock(&i2c_dev_list_lock); + list_del(&i2c_dev->list); + spin_unlock(&i2c_dev_list_lock); + + cdev_device_del(&i2c_dev->cdev, &i2c_dev->dev); + + scoped_guard(rwsem_write, &i2c_dev->rwsem) { + i2c_dev->adap =3D NULL; + } + + put_device(&i2c_dev->dev); =20 pr_debug("adapter [%s] unregistered\n", adap->name); return NOTIFY_OK; --=20 2.54.0