driver core: Fix error handling in driver API device_rename()

[ Upstream commit 6d8249ac29 ]

For class-device, device_rename() failure maybe cause unexpected link name
within its class folder as explained below:

/sys/class/.../old_name -> /sys/devices/.../old_name
device_rename(..., new_name) and failed
/sys/class/.../new_name -> /sys/devices/.../old_name

Fixed by undoing renaming link if renaming kobject failed.

Fixes: f349cf3473 ("driver core: Implement ns directory support for device classes.")
Signed-off-by: Zijun Hu <quic_zijuhu@quicinc.com>
Link: https://lore.kernel.org/r/20240722-device_rename_fix-v2-1-77de1a6c6495@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Zijun Hu 2024-07-22 22:48:10 +08:00 committed by Greg Kroah-Hartman
parent 0f115888ea
commit dd69fb026c

View File

@ -4485,9 +4485,11 @@ EXPORT_SYMBOL_GPL(device_destroy);
*/ */
int device_rename(struct device *dev, const char *new_name) int device_rename(struct device *dev, const char *new_name)
{ {
struct subsys_private *sp = NULL;
struct kobject *kobj = &dev->kobj; struct kobject *kobj = &dev->kobj;
char *old_device_name = NULL; char *old_device_name = NULL;
int error; int error;
bool is_link_renamed = false;
dev = get_device(dev); dev = get_device(dev);
if (!dev) if (!dev)
@ -4502,7 +4504,7 @@ int device_rename(struct device *dev, const char *new_name)
} }
if (dev->class) { if (dev->class) {
struct subsys_private *sp = class_to_subsys(dev->class); sp = class_to_subsys(dev->class);
if (!sp) { if (!sp) {
error = -EINVAL; error = -EINVAL;
@ -4511,16 +4513,19 @@ int device_rename(struct device *dev, const char *new_name)
error = sysfs_rename_link_ns(&sp->subsys.kobj, kobj, old_device_name, error = sysfs_rename_link_ns(&sp->subsys.kobj, kobj, old_device_name,
new_name, kobject_namespace(kobj)); new_name, kobject_namespace(kobj));
subsys_put(sp);
if (error) if (error)
goto out; goto out;
is_link_renamed = true;
} }
error = kobject_rename(kobj, new_name); error = kobject_rename(kobj, new_name);
if (error)
goto out;
out: out:
if (error && is_link_renamed)
sysfs_rename_link_ns(&sp->subsys.kobj, kobj, new_name,
old_device_name, kobject_namespace(kobj));
subsys_put(sp);
put_device(dev); put_device(dev);
kfree(old_device_name); kfree(old_device_name);