aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-01-24 14:35:52 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-07 13:37:14 -0500
commitb592fcfe7f06c15ec11774b5be7ce0de3aa86e73 (patch)
tree13f2cb344f8871edd30dc15007534405197d8480
parent2f65168de7d68a5795e945e781d85b313bdc97b9 (diff)
sysfs: Shadow directory support
The problem. When implementing a network namespace I need to be able to have multiple network devices with the same name. Currently this is a problem for /sys/class/net/*. What I want is a separate /sys/class/net directory in sysfs for each network namespace, and I want to name each of them /sys/class/net. I looked and the VFS actually allows that. All that is needed is for /sys/class/net to implement a follow link method to redirect lookups to the real directory you want. Implementing a follow link method that is sensitive to the current network namespace turns out to be 3 lines of code so it looks like a clean approach. Modifying sysfs so it doesn't get in my was is a bit trickier. I am calling the concept of multiple directories all at the same path in the filesystem shadow directories. With the directory entry really at that location the shadow master. The following patch modifies sysfs so it can handle a directory structure slightly different from the kobject tree so I can implement the shadow directories for handling /sys/class/net/. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Maneesh Soni <maneesh@in.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--fs/sysfs/dir.c207
-rw-r--r--fs/sysfs/group.c1
-rw-r--r--fs/sysfs/inode.c10
-rw-r--r--fs/sysfs/mount.c2
-rw-r--r--fs/sysfs/sysfs.h5
-rw-r--r--include/linux/kobject.h4
-rw-r--r--include/linux/sysfs.h23
-rw-r--r--lib/kobject.c42
8 files changed, 249 insertions, 45 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 9ff04491e3ea..9dcdf556c99c 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -33,8 +33,7 @@ static struct dentry_operations sysfs_dentry_ops = {
33/* 33/*
34 * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent 34 * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent
35 */ 35 */
36static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, 36static struct sysfs_dirent * __sysfs_new_dirent(void * element)
37 void * element)
38{ 37{
39 struct sysfs_dirent * sd; 38 struct sysfs_dirent * sd;
40 39
@@ -46,12 +45,28 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
46 atomic_set(&sd->s_count, 1); 45 atomic_set(&sd->s_count, 1);
47 atomic_set(&sd->s_event, 1); 46 atomic_set(&sd->s_event, 1);
48 INIT_LIST_HEAD(&sd->s_children); 47 INIT_LIST_HEAD(&sd->s_children);
49 list_add(&sd->s_sibling, &parent_sd->s_children); 48 INIT_LIST_HEAD(&sd->s_sibling);
50 sd->s_element = element; 49 sd->s_element = element;
51 50
52 return sd; 51 return sd;
53} 52}
54 53
54static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd,
55 struct sysfs_dirent *sd)
56{
57 if (sd)
58 list_add(&sd->s_sibling, &parent_sd->s_children);
59}
60
61static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd,
62 void * element)
63{
64 struct sysfs_dirent *sd;
65 sd = __sysfs_new_dirent(element);
66 __sysfs_list_dirent(parent_sd, sd);
67 return sd;
68}
69
55/* 70/*
56 * 71 *
57 * Return -EEXIST if there is already a sysfs element with the same name for 72 * Return -EEXIST if there is already a sysfs element with the same name for
@@ -78,14 +93,14 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
78} 93}
79 94
80 95
81int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, 96static struct sysfs_dirent *
82 void * element, umode_t mode, int type) 97__sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type)
83{ 98{
84 struct sysfs_dirent * sd; 99 struct sysfs_dirent * sd;
85 100
86 sd = sysfs_new_dirent(parent_sd, element); 101 sd = __sysfs_new_dirent(element);
87 if (!sd) 102 if (!sd)
88 return -ENOMEM; 103 goto out;
89 104
90 sd->s_mode = mode; 105 sd->s_mode = mode;
91 sd->s_type = type; 106 sd->s_type = type;
@@ -95,7 +110,19 @@ int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
95 dentry->d_op = &sysfs_dentry_ops; 110 dentry->d_op = &sysfs_dentry_ops;
96 } 111 }
97 112
98 return 0; 113out:
114 return sd;
115}
116
117int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
118 void * element, umode_t mode, int type)
119{
120 struct sysfs_dirent *sd;
121
122 sd = __sysfs_make_dirent(dentry, element, mode, type);
123 __sysfs_list_dirent(parent_sd, sd);
124
125 return sd ? 0 : -ENOMEM;
99} 126}
100 127
101static int init_dir(struct inode * inode) 128static int init_dir(struct inode * inode)
@@ -166,11 +193,11 @@ int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d)
166 193
167/** 194/**
168 * sysfs_create_dir - create a directory for an object. 195 * sysfs_create_dir - create a directory for an object.
169 * @parent: parent parent object.
170 * @kobj: object we're creating directory for. 196 * @kobj: object we're creating directory for.
197 * @shadow_parent: parent parent object.
171 */ 198 */
172 199
173int sysfs_create_dir(struct kobject * kobj) 200int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
174{ 201{
175 struct dentry * dentry = NULL; 202 struct dentry * dentry = NULL;
176 struct dentry * parent; 203 struct dentry * parent;
@@ -178,7 +205,9 @@ int sysfs_create_dir(struct kobject * kobj)
178 205
179 BUG_ON(!kobj); 206 BUG_ON(!kobj);
180 207
181 if (kobj->parent) 208 if (shadow_parent)
209 parent = shadow_parent;
210 else if (kobj->parent)
182 parent = kobj->parent->dentry; 211 parent = kobj->parent->dentry;
183 else if (sysfs_mount && sysfs_mount->mnt_sb) 212 else if (sysfs_mount && sysfs_mount->mnt_sb)
184 parent = sysfs_mount->mnt_sb->s_root; 213 parent = sysfs_mount->mnt_sb->s_root;
@@ -299,21 +328,12 @@ void sysfs_remove_subdir(struct dentry * d)
299} 328}
300 329
301 330
302/** 331static void __sysfs_remove_dir(struct dentry *dentry)
303 * sysfs_remove_dir - remove an object's directory.
304 * @kobj: object.
305 *
306 * The only thing special about this is that we remove any files in
307 * the directory before we remove the directory, and we've inlined
308 * what used to be sysfs_rmdir() below, instead of calling separately.
309 */
310
311void sysfs_remove_dir(struct kobject * kobj)
312{ 332{
313 struct dentry * dentry = dget(kobj->dentry);
314 struct sysfs_dirent * parent_sd; 333 struct sysfs_dirent * parent_sd;
315 struct sysfs_dirent * sd, * tmp; 334 struct sysfs_dirent * sd, * tmp;
316 335
336 dget(dentry);
317 if (!dentry) 337 if (!dentry)
318 return; 338 return;
319 339
@@ -334,32 +354,60 @@ void sysfs_remove_dir(struct kobject * kobj)
334 * Drop reference from dget() on entrance. 354 * Drop reference from dget() on entrance.
335 */ 355 */
336 dput(dentry); 356 dput(dentry);
357}
358
359/**
360 * sysfs_remove_dir - remove an object's directory.
361 * @kobj: object.
362 *
363 * The only thing special about this is that we remove any files in
364 * the directory before we remove the directory, and we've inlined
365 * what used to be sysfs_rmdir() below, instead of calling separately.
366 */
367
368void sysfs_remove_dir(struct kobject * kobj)
369{
370 __sysfs_remove_dir(kobj->dentry);
337 kobj->dentry = NULL; 371 kobj->dentry = NULL;
338} 372}
339 373
340int sysfs_rename_dir(struct kobject * kobj, const char *new_name) 374int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
375 const char *new_name)
341{ 376{
342 int error = 0; 377 int error = 0;
343 struct dentry * new_dentry, * parent; 378 struct dentry * new_dentry;
344 379
345 if (!strcmp(kobject_name(kobj), new_name)) 380 if (!new_parent)
346 return -EINVAL; 381 return -EFAULT;
347
348 if (!kobj->parent)
349 return -EINVAL;
350 382
351 down_write(&sysfs_rename_sem); 383 down_write(&sysfs_rename_sem);
352 parent = kobj->parent->dentry; 384 mutex_lock(&new_parent->d_inode->i_mutex);
353 385
354 mutex_lock(&parent->d_inode->i_mutex); 386 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
355
356 new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
357 if (!IS_ERR(new_dentry)) { 387 if (!IS_ERR(new_dentry)) {
358 if (!new_dentry->d_inode) { 388 /* By allowing two different directories with the
389 * same d_parent we allow this routine to move
390 * between different shadows of the same directory
391 */
392 if (kobj->dentry->d_parent->d_inode != new_parent->d_inode)
393 return -EINVAL;
394 else if (new_dentry->d_parent->d_inode != new_parent->d_inode)
395 error = -EINVAL;
396 else if (new_dentry == kobj->dentry)
397 error = -EINVAL;
398 else if (!new_dentry->d_inode) {
359 error = kobject_set_name(kobj, "%s", new_name); 399 error = kobject_set_name(kobj, "%s", new_name);
360 if (!error) { 400 if (!error) {
401 struct sysfs_dirent *sd, *parent_sd;
402
361 d_add(new_dentry, NULL); 403 d_add(new_dentry, NULL);
362 d_move(kobj->dentry, new_dentry); 404 d_move(kobj->dentry, new_dentry);
405
406 sd = kobj->dentry->d_fsdata;
407 parent_sd = new_parent->d_fsdata;
408
409 list_del_init(&sd->s_sibling);
410 list_add(&sd->s_sibling, &parent_sd->s_children);
363 } 411 }
364 else 412 else
365 d_drop(new_dentry); 413 d_drop(new_dentry);
@@ -367,7 +415,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
367 error = -EEXIST; 415 error = -EEXIST;
368 dput(new_dentry); 416 dput(new_dentry);
369 } 417 }
370 mutex_unlock(&parent->d_inode->i_mutex); 418 mutex_unlock(&new_parent->d_inode->i_mutex);
371 up_write(&sysfs_rename_sem); 419 up_write(&sysfs_rename_sem);
372 420
373 return error; 421 return error;
@@ -546,6 +594,95 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
546 return offset; 594 return offset;
547} 595}
548 596
597
598/**
599 * sysfs_make_shadowed_dir - Setup so a directory can be shadowed
600 * @kobj: object we're creating shadow of.
601 */
602
603int sysfs_make_shadowed_dir(struct kobject *kobj,
604 void * (*follow_link)(struct dentry *, struct nameidata *))
605{
606 struct inode *inode;
607 struct inode_operations *i_op;
608
609 inode = kobj->dentry->d_inode;
610 if (inode->i_op != &sysfs_dir_inode_operations)
611 return -EINVAL;
612
613 i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
614 if (!i_op)
615 return -ENOMEM;
616
617 memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
618 i_op->follow_link = follow_link;
619
620 /* Locking of inode->i_op?
621 * Since setting i_op is a single word write and they
622 * are atomic we should be ok here.
623 */
624 inode->i_op = i_op;
625 return 0;
626}
627
628/**
629 * sysfs_create_shadow_dir - create a shadow directory for an object.
630 * @kobj: object we're creating directory for.
631 *
632 * sysfs_make_shadowed_dir must already have been called on this
633 * directory.
634 */
635
636struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
637{
638 struct sysfs_dirent *sd;
639 struct dentry *parent, *dir, *shadow;
640 struct inode *inode;
641
642 dir = kobj->dentry;
643 inode = dir->d_inode;
644 parent = dir->d_parent;
645 shadow = ERR_PTR(-EINVAL);
646 if (!sysfs_is_shadowed_inode(inode))
647 goto out;
648
649 shadow = d_alloc(parent, &dir->d_name);
650 if (!shadow)
651 goto nomem;
652
653 sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR);
654 if (!sd)
655 goto nomem;
656
657 d_instantiate(shadow, igrab(inode));
658 inc_nlink(inode);
659 inc_nlink(parent->d_inode);
660 shadow->d_op = &sysfs_dentry_ops;
661
662 dget(shadow); /* Extra count - pin the dentry in core */
663
664out:
665 return shadow;
666nomem:
667 dput(shadow);
668 shadow = ERR_PTR(-ENOMEM);
669 goto out;
670}
671
672/**
673 * sysfs_remove_shadow_dir - remove an object's directory.
674 * @shadow: dentry of shadow directory
675 *
676 * The only thing special about this is that we remove any files in
677 * the directory before we remove the directory, and we've inlined
678 * what used to be sysfs_rmdir() below, instead of calling separately.
679 */
680
681void sysfs_remove_shadow_dir(struct dentry *shadow)
682{
683 __sysfs_remove_dir(shadow);
684}
685
549const struct file_operations sysfs_dir_operations = { 686const struct file_operations sysfs_dir_operations = {
550 .open = sysfs_dir_open, 687 .open = sysfs_dir_open,
551 .release = sysfs_dir_close, 688 .release = sysfs_dir_close,
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 46a277b0838e..b20951c93761 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,6 +13,7 @@
13#include <linux/dcache.h> 13#include <linux/dcache.h>
14#include <linux/namei.h> 14#include <linux/namei.h>
15#include <linux/err.h> 15#include <linux/err.h>
16#include <linux/fs.h>
16#include <asm/semaphore.h> 17#include <asm/semaphore.h>
17#include "sysfs.h" 18#include "sysfs.h"
18 19
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index dbd820f9aeed..542d2bcc73df 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -33,6 +33,16 @@ static struct inode_operations sysfs_inode_operations ={
33 .setattr = sysfs_setattr, 33 .setattr = sysfs_setattr,
34}; 34};
35 35
36void sysfs_delete_inode(struct inode *inode)
37{
38 /* Free the shadowed directory inode operations */
39 if (sysfs_is_shadowed_inode(inode)) {
40 kfree(inode->i_op);
41 inode->i_op = NULL;
42 }
43 return generic_delete_inode(inode);
44}
45
36int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) 46int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
37{ 47{
38 struct inode * inode = dentry->d_inode; 48 struct inode * inode = dentry->d_inode;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index a1a58b97f322..f6a87a824883 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -23,7 +23,7 @@ static void sysfs_clear_inode(struct inode *inode);
23 23
24static struct super_operations sysfs_ops = { 24static struct super_operations sysfs_ops = {
25 .statfs = simple_statfs, 25 .statfs = simple_statfs,
26 .drop_inode = generic_delete_inode, 26 .drop_inode = sysfs_delete_inode,
27 .clear_inode = sysfs_clear_inode, 27 .clear_inode = sysfs_clear_inode,
28}; 28};
29 29
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 39c623fdc277..fe1cbfd208ed 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -2,6 +2,7 @@
2extern struct vfsmount * sysfs_mount; 2extern struct vfsmount * sysfs_mount;
3extern struct kmem_cache *sysfs_dir_cachep; 3extern struct kmem_cache *sysfs_dir_cachep;
4 4
5extern void sysfs_delete_inode(struct inode *inode);
5extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); 6extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
6extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); 7extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
7 8
@@ -112,3 +113,7 @@ static inline void sysfs_put(struct sysfs_dirent * sd)
112 release_sysfs_dirent(sd); 113 release_sysfs_dirent(sd);
113} 114}
114 115
116static inline int sysfs_is_shadowed_inode(struct inode *inode)
117{
118 return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
119}
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 76538fcf2c4e..b850e0310538 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -74,9 +74,13 @@ extern void kobject_init(struct kobject *);
74extern void kobject_cleanup(struct kobject *); 74extern void kobject_cleanup(struct kobject *);
75 75
76extern int __must_check kobject_add(struct kobject *); 76extern int __must_check kobject_add(struct kobject *);
77extern int __must_check kobject_shadow_add(struct kobject *, struct dentry *);
77extern void kobject_del(struct kobject *); 78extern void kobject_del(struct kobject *);
78 79
79extern int __must_check kobject_rename(struct kobject *, const char *new_name); 80extern int __must_check kobject_rename(struct kobject *, const char *new_name);
81extern int __must_check kobject_shadow_rename(struct kobject *kobj,
82 struct dentry *new_parent,
83 const char *new_name);
80extern int __must_check kobject_move(struct kobject *, struct kobject *); 84extern int __must_check kobject_move(struct kobject *, struct kobject *);
81 85
82extern int __must_check kobject_register(struct kobject *); 86extern int __must_check kobject_register(struct kobject *);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index eee485957c0c..192de3afa96b 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -16,6 +16,7 @@
16 16
17struct kobject; 17struct kobject;
18struct module; 18struct module;
19struct nameidata;
19 20
20struct attribute { 21struct attribute {
21 const char * name; 22 const char * name;
@@ -89,13 +90,13 @@ struct sysfs_dirent {
89#ifdef CONFIG_SYSFS 90#ifdef CONFIG_SYSFS
90 91
91extern int __must_check 92extern int __must_check
92sysfs_create_dir(struct kobject *); 93sysfs_create_dir(struct kobject *, struct dentry *);
93 94
94extern void 95extern void
95sysfs_remove_dir(struct kobject *); 96sysfs_remove_dir(struct kobject *);
96 97
97extern int __must_check 98extern int __must_check
98sysfs_rename_dir(struct kobject *, const char *new_name); 99sysfs_rename_dir(struct kobject *, struct dentry *, const char *new_name);
99 100
100extern int __must_check 101extern int __must_check
101sysfs_move_dir(struct kobject *, struct kobject *); 102sysfs_move_dir(struct kobject *, struct kobject *);
@@ -127,11 +128,17 @@ int __must_check sysfs_create_group(struct kobject *,
127void sysfs_remove_group(struct kobject *, const struct attribute_group *); 128void sysfs_remove_group(struct kobject *, const struct attribute_group *);
128void sysfs_notify(struct kobject * k, char *dir, char *attr); 129void sysfs_notify(struct kobject * k, char *dir, char *attr);
129 130
131
132extern int sysfs_make_shadowed_dir(struct kobject *kobj,
133 void * (*follow_link)(struct dentry *, struct nameidata *));
134extern struct dentry *sysfs_create_shadow_dir(struct kobject *kobj);
135extern void sysfs_remove_shadow_dir(struct dentry *dir);
136
130extern int __must_check sysfs_init(void); 137extern int __must_check sysfs_init(void);
131 138
132#else /* CONFIG_SYSFS */ 139#else /* CONFIG_SYSFS */
133 140
134static inline int sysfs_create_dir(struct kobject * k) 141static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow)
135{ 142{
136 return 0; 143 return 0;
137} 144}
@@ -141,7 +148,9 @@ static inline void sysfs_remove_dir(struct kobject * k)
141 ; 148 ;
142} 149}
143 150
144static inline int sysfs_rename_dir(struct kobject * k, const char *new_name) 151static inline int sysfs_rename_dir(struct kobject * k,
152 struct dentry *new_parent,
153 const char *new_name)
145{ 154{
146 return 0; 155 return 0;
147} 156}
@@ -205,6 +214,12 @@ static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
205{ 214{
206} 215}
207 216
217static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
218 void * (*follow_link)(struct dentry *, struct nameidata *))
219{
220 return 0;
221}
222
208static inline int __must_check sysfs_init(void) 223static inline int __must_check sysfs_init(void)
209{ 224{
210 return 0; 225 return 0;
diff --git a/lib/kobject.c b/lib/kobject.c
index 74b8dbca150e..c2917ffe8bf1 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -44,11 +44,11 @@ static int populate_dir(struct kobject * kobj)
44 return error; 44 return error;
45} 45}
46 46
47static int create_dir(struct kobject * kobj) 47static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)
48{ 48{
49 int error = 0; 49 int error = 0;
50 if (kobject_name(kobj)) { 50 if (kobject_name(kobj)) {
51 error = sysfs_create_dir(kobj); 51 error = sysfs_create_dir(kobj, shadow_parent);
52 if (!error) { 52 if (!error) {
53 if ((error = populate_dir(kobj))) 53 if ((error = populate_dir(kobj)))
54 sysfs_remove_dir(kobj); 54 sysfs_remove_dir(kobj);
@@ -158,9 +158,10 @@ static void unlink(struct kobject * kobj)
158/** 158/**
159 * kobject_add - add an object to the hierarchy. 159 * kobject_add - add an object to the hierarchy.
160 * @kobj: object. 160 * @kobj: object.
161 * @shadow_parent: sysfs directory to add to.
161 */ 162 */
162 163
163int kobject_add(struct kobject * kobj) 164int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
164{ 165{
165 int error = 0; 166 int error = 0;
166 struct kobject * parent; 167 struct kobject * parent;
@@ -191,7 +192,7 @@ int kobject_add(struct kobject * kobj)
191 } 192 }
192 kobj->parent = parent; 193 kobj->parent = parent;
193 194
194 error = create_dir(kobj); 195 error = create_dir(kobj, shadow_parent);
195 if (error) { 196 if (error) {
196 /* unlink does the kobject_put() for us */ 197 /* unlink does the kobject_put() for us */
197 unlink(kobj); 198 unlink(kobj);
@@ -212,6 +213,15 @@ int kobject_add(struct kobject * kobj)
212 return error; 213 return error;
213} 214}
214 215
216/**
217 * kobject_add - add an object to the hierarchy.
218 * @kobj: object.
219 */
220int kobject_add(struct kobject * kobj)
221{
222 return kobject_shadow_add(kobj, NULL);
223}
224
215 225
216/** 226/**
217 * kobject_register - initialize and add an object. 227 * kobject_register - initialize and add an object.
@@ -304,7 +314,29 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
304 kobj = kobject_get(kobj); 314 kobj = kobject_get(kobj);
305 if (!kobj) 315 if (!kobj)
306 return -EINVAL; 316 return -EINVAL;
307 error = sysfs_rename_dir(kobj, new_name); 317 if (!kobj->parent)
318 return -EINVAL;
319 error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name);
320 kobject_put(kobj);
321
322 return error;
323}
324
325/**
326 * kobject_rename - change the name of an object
327 * @kobj: object in question.
328 * @new_name: object's new name
329 */
330
331int kobject_shadow_rename(struct kobject * kobj, struct dentry *new_parent,
332 const char *new_name)
333{
334 int error = 0;
335
336 kobj = kobject_get(kobj);
337 if (!kobj)
338 return -EINVAL;
339 error = sysfs_rename_dir(kobj, new_parent, new_name);
308 kobject_put(kobj); 340 kobject_put(kobj);
309 341
310 return error; 342 return error;