aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2007-01-08 14:16:44 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-07 13:37:11 -0500
commitc744aeae9d173a953b771a7ad5c872f91fa99dec (patch)
tree83d36e211ff6d0109f3aeb29d4fd1bb2dbb2a9b3
parent717e48c29d9a58f4d31c1651bec364212da5f6b2 (diff)
driver core: Allow device_move(dev, NULL).
If we allow NULL as the new parent in device_move(), we need to make sure that the device is placed into the same place as it would if it was newly registered: - Consider the device virtual tree. In order to be able to reuse code, setup_parent() has been tweaked a bit. - kobject_move() can fall back to the kset's kobject. - sysfs_move_dir() uses the sysfs root dir as fallback. Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Cc: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/base/core.c76
-rw-r--r--fs/sysfs/dir.c6
-rw-r--r--lib/kobject.c6
3 files changed, 52 insertions, 36 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 36eedfdeb547..c60114dbe5f5 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -390,22 +390,23 @@ void device_initialize(struct device *dev)
390} 390}
391 391
392#ifdef CONFIG_SYSFS_DEPRECATED 392#ifdef CONFIG_SYSFS_DEPRECATED
393static int setup_parent(struct device *dev, struct device *parent) 393static struct kobject * get_device_parent(struct device *dev,
394 struct device *parent)
394{ 395{
395 /* Set the parent to the class, not the parent device */ 396 /* Set the parent to the class, not the parent device */
396 /* this keeps sysfs from having a symlink to make old udevs happy */ 397 /* this keeps sysfs from having a symlink to make old udevs happy */
397 if (dev->class) 398 if (dev->class)
398 dev->kobj.parent = &dev->class->subsys.kset.kobj; 399 return &dev->class->subsys.kset.kobj;
399 else if (parent) 400 else if (parent)
400 dev->kobj.parent = &parent->kobj; 401 return &parent->kobj;
401 402
402 return 0; 403 return NULL;
403} 404}
404#else 405#else
405static int virtual_device_parent(struct device *dev) 406static struct kobject * virtual_device_parent(struct device *dev)
406{ 407{
407 if (!dev->class) 408 if (!dev->class)
408 return -ENODEV; 409 return ERR_PTR(-ENODEV);
409 410
410 if (!dev->class->virtual_dir) { 411 if (!dev->class->virtual_dir) {
411 static struct kobject *virtual_dir = NULL; 412 static struct kobject *virtual_dir = NULL;
@@ -415,25 +416,31 @@ static int virtual_device_parent(struct device *dev)
415 dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); 416 dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
416 } 417 }
417 418
418 dev->kobj.parent = dev->class->virtual_dir; 419 return dev->class->virtual_dir;
419 return 0;
420} 420}
421 421
422static int setup_parent(struct device *dev, struct device *parent) 422static struct kobject * get_device_parent(struct device *dev,
423 struct device *parent)
423{ 424{
424 int error;
425
426 /* if this is a class device, and has no parent, create one */ 425 /* if this is a class device, and has no parent, create one */
427 if ((dev->class) && (parent == NULL)) { 426 if ((dev->class) && (parent == NULL)) {
428 error = virtual_device_parent(dev); 427 return virtual_device_parent(dev);
429 if (error)
430 return error;
431 } else if (parent) 428 } else if (parent)
432 dev->kobj.parent = &parent->kobj; 429 return &parent->kobj;
430 return NULL;
431}
433 432
433#endif
434static int setup_parent(struct device *dev, struct device *parent)
435{
436 struct kobject *kobj;
437 kobj = get_device_parent(dev, parent);
438 if (IS_ERR(kobj))
439 return PTR_ERR(kobj);
440 if (kobj)
441 dev->kobj.parent = kobj;
434 return 0; 442 return 0;
435} 443}
436#endif
437 444
438/** 445/**
439 * device_add - add device to device hierarchy. 446 * device_add - add device to device hierarchy.
@@ -976,12 +983,18 @@ static int device_move_class_links(struct device *dev,
976 sysfs_remove_link(&dev->kobj, "device"); 983 sysfs_remove_link(&dev->kobj, "device");
977 sysfs_remove_link(&old_parent->kobj, class_name); 984 sysfs_remove_link(&old_parent->kobj, class_name);
978 } 985 }
979 error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); 986 if (new_parent) {
980 if (error) 987 error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
981 goto out; 988 "device");
982 error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name); 989 if (error)
983 if (error) 990 goto out;
984 sysfs_remove_link(&dev->kobj, "device"); 991 error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
992 class_name);
993 if (error)
994 sysfs_remove_link(&dev->kobj, "device");
995 }
996 else
997 error = 0;
985out: 998out:
986 kfree(class_name); 999 kfree(class_name);
987 return error; 1000 return error;
@@ -993,25 +1006,28 @@ out:
993/** 1006/**
994 * device_move - moves a device to a new parent 1007 * device_move - moves a device to a new parent
995 * @dev: the pointer to the struct device to be moved 1008 * @dev: the pointer to the struct device to be moved
996 * @new_parent: the new parent of the device 1009 * @new_parent: the new parent of the device (can by NULL)
997 */ 1010 */
998int device_move(struct device *dev, struct device *new_parent) 1011int device_move(struct device *dev, struct device *new_parent)
999{ 1012{
1000 int error; 1013 int error;
1001 struct device *old_parent; 1014 struct device *old_parent;
1015 struct kobject *new_parent_kobj;
1002 1016
1003 dev = get_device(dev); 1017 dev = get_device(dev);
1004 if (!dev) 1018 if (!dev)
1005 return -EINVAL; 1019 return -EINVAL;
1006 1020
1007 new_parent = get_device(new_parent); 1021 new_parent = get_device(new_parent);
1008 if (!new_parent) { 1022 new_parent_kobj = get_device_parent (dev, new_parent);
1009 error = -EINVAL; 1023 if (IS_ERR(new_parent_kobj)) {
1024 error = PTR_ERR(new_parent_kobj);
1025 put_device(new_parent);
1010 goto out; 1026 goto out;
1011 } 1027 }
1012 pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, 1028 pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
1013 new_parent->bus_id); 1029 new_parent ? new_parent->bus_id : "<NULL>");
1014 error = kobject_move(&dev->kobj, &new_parent->kobj); 1030 error = kobject_move(&dev->kobj, new_parent_kobj);
1015 if (error) { 1031 if (error) {
1016 put_device(new_parent); 1032 put_device(new_parent);
1017 goto out; 1033 goto out;
@@ -1020,7 +1036,8 @@ int device_move(struct device *dev, struct device *new_parent)
1020 dev->parent = new_parent; 1036 dev->parent = new_parent;
1021 if (old_parent) 1037 if (old_parent)
1022 klist_remove(&dev->knode_parent); 1038 klist_remove(&dev->knode_parent);
1023 klist_add_tail(&dev->knode_parent, &new_parent->klist_children); 1039 if (new_parent)
1040 klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
1024 if (!dev->class) 1041 if (!dev->class)
1025 goto out_put; 1042 goto out_put;
1026 error = device_move_class_links(dev, old_parent, new_parent); 1043 error = device_move_class_links(dev, old_parent, new_parent);
@@ -1028,7 +1045,8 @@ int device_move(struct device *dev, struct device *new_parent)
1028 /* We ignore errors on cleanup since we're hosed anyway... */ 1045 /* We ignore errors on cleanup since we're hosed anyway... */
1029 device_move_class_links(dev, new_parent, old_parent); 1046 device_move_class_links(dev, new_parent, old_parent);
1030 if (!kobject_move(&dev->kobj, &old_parent->kobj)) { 1047 if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
1031 klist_remove(&dev->knode_parent); 1048 if (new_parent)
1049 klist_remove(&dev->knode_parent);
1032 if (old_parent) 1050 if (old_parent)
1033 klist_add_tail(&dev->knode_parent, 1051 klist_add_tail(&dev->knode_parent,
1034 &old_parent->klist_children); 1052 &old_parent->klist_children);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 511edef8b321..2bab1b4ddf5a 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -378,12 +378,10 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
378 struct sysfs_dirent *new_parent_sd, *sd; 378 struct sysfs_dirent *new_parent_sd, *sd;
379 int error; 379 int error;
380 380
381 if (!new_parent)
382 return -EINVAL;
383
384 old_parent_dentry = kobj->parent ? 381 old_parent_dentry = kobj->parent ?
385 kobj->parent->dentry : sysfs_mount->mnt_sb->s_root; 382 kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
386 new_parent_dentry = new_parent->dentry; 383 new_parent_dentry = new_parent ?
384 new_parent->dentry : sysfs_mount->mnt_sb->s_root;
387 385
388again: 386again:
389 mutex_lock(&old_parent_dentry->d_inode->i_mutex); 387 mutex_lock(&old_parent_dentry->d_inode->i_mutex);
diff --git a/lib/kobject.c b/lib/kobject.c
index 9aed594bfcac..c033dc8fa9af 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -314,7 +314,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
314/** 314/**
315 * kobject_move - move object to another parent 315 * kobject_move - move object to another parent
316 * @kobj: object in question. 316 * @kobj: object in question.
317 * @new_parent: object's new parent 317 * @new_parent: object's new parent (can be NULL)
318 */ 318 */
319 319
320int kobject_move(struct kobject *kobj, struct kobject *new_parent) 320int kobject_move(struct kobject *kobj, struct kobject *new_parent)
@@ -330,8 +330,8 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent)
330 return -EINVAL; 330 return -EINVAL;
331 new_parent = kobject_get(new_parent); 331 new_parent = kobject_get(new_parent);
332 if (!new_parent) { 332 if (!new_parent) {
333 error = -EINVAL; 333 if (kobj->kset)
334 goto out; 334 new_parent = kobject_get(&kobj->kset->kobj);
335 } 335 }
336 /* old object path */ 336 /* old object path */
337 devpath = kobject_get_path(kobj, GFP_KERNEL); 337 devpath = kobject_get_path(kobj, GFP_KERNEL);