Subject: [PATCH] nethost sysfs: Refactor the sysfs support so it actually works. From: Eric W. Biederman Date: 1137525766 -0700 The current code introduces helpers that need to move out of net-sysfs but the code works, and it works for all of the right reasons. --- net/core/net-sysfs.c | 88 +++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 76 insertions(+), 12 deletions(-) ccde72a811cba810a5434df676eb8a6513b9d85a diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index aaf0f48..b596d1c 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -18,6 +18,10 @@ #include #include #include +#if 1 +#include +#include "../../fs/sysfs/sysfs.h" +#endif #define to_class_dev(obj) container_of(obj,struct class_device,kobj) #define to_net_dev(class) container_of(class, struct net_device, class_dev) @@ -503,22 +507,82 @@ out: return ret; } -void netdev_move_sysfs(struct net_device *net) +static int sysfs_reparent(struct kobject *kobj) { - struct class_device *class_dev = &(net->class_dev); - struct class *parent; - struct kobject *kobj_parent; + struct dentry *old_dentry = dget(kobj->dentry); + struct dentry *old_dir = dget(old_dentry->d_parent); + struct dentry *new_dir = dget(kobj->parent->dentry); + struct dentry *new_dentry; + struct dentry *trap; + struct sysfs_dirent *sd, *parent_sd; + int error; + + trap = lock_rename(new_dir, old_dir); + + /* source shold not be ancestor of target */ + error = -EINVAL; + if (old_dentry == trap) + goto out; + + new_dentry = lookup_one_len(old_dentry->d_name.name, new_dir, old_dentry->d_name.len); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) + goto out; - parent = class_dev->class; - kobj_parent = class_dev->kobj.parent; + /* Target should not exist */ + error = -ENOTEMPTY; + if (new_dentry->d_inode) + goto out2; + + /* Move the directory entry */ + parent_sd = new_dir->d_fsdata; + sd = old_dentry->d_fsdata; + list_del_init(&sd->s_sibling); + list_add(&sd->s_sibling, &parent_sd->s_children); + + /* Move the dcache entry */ + d_move(old_dentry, new_dentry); +out2: + dput(new_dentry); +out: + unlock_rename(new_dir, old_dir); + dput(old_dentry); + dput(old_dir); + dput(new_dir); + return error; +} + +static void kobject_reparent(struct kobject *kobj, struct kobject *new_parent) +{ + struct kobject *old_parent; + + old_parent = kobj->parent; - class_dev->class = &net->host->net_class; - class_get(class_dev->class); - class_dev->kobj.parent = &class_dev->class->subsys.kset.kobj; - kobject_get(class_dev->kobj.parent); + kobj->parent = new_parent; + kobject_get(kobj->parent); - class_put(parent); - kobject_put(kobj_parent); + sysfs_reparent(kobj); + + kobject_put(old_parent); +} + +static void class_device_reparent(struct class_device *class_dev, struct class *new_parent) +{ + struct class *old_parent; + + old_parent = class_dev->class; + class_dev->class = new_parent; + class_get(new_parent); + + kobject_reparent(&class_dev->kobj, &class_dev->class->subsys.kset.kobj); + + class_put(old_parent); +} + +void netdev_move_sysfs(struct net_device *net) +{ + struct class_device *class_dev = &(net->class_dev); + class_device_reparent(class_dev, &net->host->net_class); } int netdev_sysfs_init(struct nethost *host) -- 1.0.GIT