diff options
-rw-r--r-- | fs/sysfs/symlink.c | 76 | ||||
-rw-r--r-- | include/linux/kernfs.h | 9 |
2 files changed, 55 insertions, 30 deletions
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 71583fc8100a..41138e91947a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -21,14 +21,48 @@ | |||
21 | 21 | ||
22 | #include "sysfs.h" | 22 | #include "sysfs.h" |
23 | 23 | ||
24 | /** | ||
25 | * kernfs_create_link - create a symlink | ||
26 | * @parent: directory to create the symlink in | ||
27 | * @name: name of the symlink | ||
28 | * @target: target node for the symlink to point to | ||
29 | * | ||
30 | * Returns the created node on success, ERR_PTR() value on error. | ||
31 | */ | ||
32 | struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, | ||
33 | const char *name, | ||
34 | struct sysfs_dirent *target) | ||
35 | { | ||
36 | struct sysfs_dirent *sd; | ||
37 | struct sysfs_addrm_cxt acxt; | ||
38 | int error; | ||
39 | |||
40 | sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK); | ||
41 | if (!sd) | ||
42 | return ERR_PTR(-ENOMEM); | ||
43 | |||
44 | if (parent->s_flags & SYSFS_FLAG_NS) | ||
45 | sd->s_ns = target->s_ns; | ||
46 | sd->s_symlink.target_sd = target; | ||
47 | sysfs_get(target); /* ref owned by symlink */ | ||
48 | |||
49 | sysfs_addrm_start(&acxt); | ||
50 | error = __sysfs_add_one(&acxt, sd, parent); | ||
51 | sysfs_addrm_finish(&acxt); | ||
52 | |||
53 | if (!error) | ||
54 | return sd; | ||
55 | |||
56 | sysfs_put(sd); | ||
57 | return ERR_PTR(error); | ||
58 | } | ||
59 | |||
60 | |||
24 | static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, | 61 | static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, |
25 | struct kobject *target, | 62 | struct kobject *target, |
26 | const char *name, int warn) | 63 | const char *name, int warn) |
27 | { | 64 | { |
28 | struct sysfs_dirent *target_sd = NULL; | 65 | struct sysfs_dirent *sd, *target_sd = NULL; |
29 | struct sysfs_dirent *sd = NULL; | ||
30 | struct sysfs_addrm_cxt acxt; | ||
31 | int error; | ||
32 | 66 | ||
33 | BUG_ON(!name || !parent_sd); | 67 | BUG_ON(!name || !parent_sd); |
34 | 68 | ||
@@ -42,36 +76,18 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, | |||
42 | target_sd = sysfs_get(target->sd); | 76 | target_sd = sysfs_get(target->sd); |
43 | spin_unlock(&sysfs_symlink_target_lock); | 77 | spin_unlock(&sysfs_symlink_target_lock); |
44 | 78 | ||
45 | error = -ENOENT; | ||
46 | if (!target_sd) | 79 | if (!target_sd) |
47 | goto out_put; | 80 | return -ENOENT; |
48 | 81 | ||
49 | error = -ENOMEM; | 82 | sd = kernfs_create_link(parent_sd, name, target_sd); |
50 | sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK); | 83 | sysfs_put(target_sd); |
51 | if (!sd) | ||
52 | goto out_put; | ||
53 | |||
54 | if (parent_sd->s_flags & SYSFS_FLAG_NS) | ||
55 | sd->s_ns = target_sd->s_ns; | ||
56 | sd->s_symlink.target_sd = target_sd; | ||
57 | target_sd = NULL; /* reference is now owned by the symlink */ | ||
58 | |||
59 | sysfs_addrm_start(&acxt); | ||
60 | if (warn) | ||
61 | error = sysfs_add_one(&acxt, sd, parent_sd); | ||
62 | else | ||
63 | error = __sysfs_add_one(&acxt, sd, parent_sd); | ||
64 | sysfs_addrm_finish(&acxt); | ||
65 | |||
66 | if (error) | ||
67 | goto out_put; | ||
68 | 84 | ||
69 | return 0; | 85 | if (!IS_ERR(sd)) |
86 | return 0; | ||
70 | 87 | ||
71 | out_put: | 88 | if (warn && PTR_ERR(sd) == -EEXIST) |
72 | sysfs_put(target_sd); | 89 | sysfs_warn_dup(parent_sd, name); |
73 | sysfs_put(sd); | 90 | return PTR_ERR(sd); |
74 | return error; | ||
75 | } | 91 | } |
76 | 92 | ||
77 | /** | 93 | /** |
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 83e151ad0619..fe6290d41776 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h | |||
@@ -8,17 +8,26 @@ | |||
8 | #define __LINUX_KERNFS_H | 8 | #define __LINUX_KERNFS_H |
9 | 9 | ||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/err.h> | ||
11 | 12 | ||
12 | struct sysfs_dirent; | 13 | struct sysfs_dirent; |
13 | 14 | ||
14 | #ifdef CONFIG_SYSFS | 15 | #ifdef CONFIG_SYSFS |
15 | 16 | ||
17 | struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, | ||
18 | const char *name, | ||
19 | struct sysfs_dirent *target); | ||
16 | void kernfs_remove(struct sysfs_dirent *sd); | 20 | void kernfs_remove(struct sysfs_dirent *sd); |
17 | int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, | 21 | int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, |
18 | const void *ns); | 22 | const void *ns); |
19 | 23 | ||
20 | #else /* CONFIG_SYSFS */ | 24 | #else /* CONFIG_SYSFS */ |
21 | 25 | ||
26 | static inline struct sysfs_dirent * | ||
27 | kernfs_create_link(struct sysfs_dirent *parent, const char *name, | ||
28 | struct sysfs_dirent *target) | ||
29 | { return ERR_PTR(-ENOSYS); } | ||
30 | |||
22 | static inline void kernfs_remove(struct sysfs_dirent *sd) { } | 31 | static inline void kernfs_remove(struct sysfs_dirent *sd) { } |
23 | 32 | ||
24 | static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, | 33 | static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, |