diff options
Diffstat (limited to 'fs/sysfs/symlink.c')
-rw-r--r-- | fs/sysfs/symlink.c | 58 |
1 files changed, 51 insertions, 7 deletions
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index b93ec51fa7ac..a7ac78f8e67a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -28,6 +28,7 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, | |||
28 | struct sysfs_dirent *target_sd = NULL; | 28 | struct sysfs_dirent *target_sd = NULL; |
29 | struct sysfs_dirent *sd = NULL; | 29 | struct sysfs_dirent *sd = NULL; |
30 | struct sysfs_addrm_cxt acxt; | 30 | struct sysfs_addrm_cxt acxt; |
31 | enum kobj_ns_type ns_type; | ||
31 | int error; | 32 | int error; |
32 | 33 | ||
33 | BUG_ON(!name); | 34 | BUG_ON(!name); |
@@ -58,14 +59,29 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, | |||
58 | if (!sd) | 59 | if (!sd) |
59 | goto out_put; | 60 | goto out_put; |
60 | 61 | ||
62 | ns_type = sysfs_ns_type(parent_sd); | ||
63 | if (ns_type) | ||
64 | sd->s_ns = target->ktype->namespace(target); | ||
61 | sd->s_symlink.target_sd = target_sd; | 65 | sd->s_symlink.target_sd = target_sd; |
62 | target_sd = NULL; /* reference is now owned by the symlink */ | 66 | target_sd = NULL; /* reference is now owned by the symlink */ |
63 | 67 | ||
64 | sysfs_addrm_start(&acxt, parent_sd); | 68 | sysfs_addrm_start(&acxt, parent_sd); |
65 | if (warn) | 69 | /* Symlinks must be between directories with the same ns_type */ |
66 | error = sysfs_add_one(&acxt, sd); | 70 | if (!ns_type || |
67 | else | 71 | (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { |
68 | error = __sysfs_add_one(&acxt, sd); | 72 | if (warn) |
73 | error = sysfs_add_one(&acxt, sd); | ||
74 | else | ||
75 | error = __sysfs_add_one(&acxt, sd); | ||
76 | } else { | ||
77 | error = -EINVAL; | ||
78 | WARN(1, KERN_WARNING | ||
79 | "sysfs: symlink across ns_types %s/%s -> %s/%s\n", | ||
80 | parent_sd->s_name, | ||
81 | sd->s_name, | ||
82 | sd->s_symlink.target_sd->s_parent->s_name, | ||
83 | sd->s_symlink.target_sd->s_name); | ||
84 | } | ||
69 | sysfs_addrm_finish(&acxt); | 85 | sysfs_addrm_finish(&acxt); |
70 | 86 | ||
71 | if (error) | 87 | if (error) |
@@ -107,6 +123,26 @@ int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target, | |||
107 | } | 123 | } |
108 | 124 | ||
109 | /** | 125 | /** |
126 | * sysfs_delete_link - remove symlink in object's directory. | ||
127 | * @kobj: object we're acting for. | ||
128 | * @targ: object we're pointing to. | ||
129 | * @name: name of the symlink to remove. | ||
130 | * | ||
131 | * Unlike sysfs_remove_link sysfs_delete_link has enough information | ||
132 | * to successfully delete symlinks in tagged directories. | ||
133 | */ | ||
134 | void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, | ||
135 | const char *name) | ||
136 | { | ||
137 | const void *ns = NULL; | ||
138 | spin_lock(&sysfs_assoc_lock); | ||
139 | if (targ->sd && sysfs_ns_type(kobj->sd)) | ||
140 | ns = targ->sd->s_ns; | ||
141 | spin_unlock(&sysfs_assoc_lock); | ||
142 | sysfs_hash_and_remove(kobj->sd, ns, name); | ||
143 | } | ||
144 | |||
145 | /** | ||
110 | * sysfs_remove_link - remove symlink in object's directory. | 146 | * sysfs_remove_link - remove symlink in object's directory. |
111 | * @kobj: object we're acting for. | 147 | * @kobj: object we're acting for. |
112 | * @name: name of the symlink to remove. | 148 | * @name: name of the symlink to remove. |
@@ -121,7 +157,7 @@ void sysfs_remove_link(struct kobject * kobj, const char * name) | |||
121 | else | 157 | else |
122 | parent_sd = kobj->sd; | 158 | parent_sd = kobj->sd; |
123 | 159 | ||
124 | sysfs_hash_and_remove(parent_sd, name); | 160 | sysfs_hash_and_remove(parent_sd, NULL, name); |
125 | } | 161 | } |
126 | 162 | ||
127 | /** | 163 | /** |
@@ -137,6 +173,7 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | |||
137 | const char *old, const char *new) | 173 | const char *old, const char *new) |
138 | { | 174 | { |
139 | struct sysfs_dirent *parent_sd, *sd = NULL; | 175 | struct sysfs_dirent *parent_sd, *sd = NULL; |
176 | const void *old_ns = NULL, *new_ns = NULL; | ||
140 | int result; | 177 | int result; |
141 | 178 | ||
142 | if (!kobj) | 179 | if (!kobj) |
@@ -144,8 +181,11 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | |||
144 | else | 181 | else |
145 | parent_sd = kobj->sd; | 182 | parent_sd = kobj->sd; |
146 | 183 | ||
184 | if (targ->sd) | ||
185 | old_ns = targ->sd->s_ns; | ||
186 | |||
147 | result = -ENOENT; | 187 | result = -ENOENT; |
148 | sd = sysfs_get_dirent(parent_sd, old); | 188 | sd = sysfs_get_dirent(parent_sd, old_ns, old); |
149 | if (!sd) | 189 | if (!sd) |
150 | goto out; | 190 | goto out; |
151 | 191 | ||
@@ -155,7 +195,10 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | |||
155 | if (sd->s_symlink.target_sd->s_dir.kobj != targ) | 195 | if (sd->s_symlink.target_sd->s_dir.kobj != targ) |
156 | goto out; | 196 | goto out; |
157 | 197 | ||
158 | result = sysfs_rename(sd, parent_sd, new); | 198 | if (sysfs_ns_type(parent_sd)) |
199 | new_ns = targ->ktype->namespace(targ); | ||
200 | |||
201 | result = sysfs_rename(sd, parent_sd, new_ns, new); | ||
159 | 202 | ||
160 | out: | 203 | out: |
161 | sysfs_put(sd); | 204 | sysfs_put(sd); |
@@ -261,3 +304,4 @@ const struct inode_operations sysfs_symlink_inode_operations = { | |||
261 | 304 | ||
262 | EXPORT_SYMBOL_GPL(sysfs_create_link); | 305 | EXPORT_SYMBOL_GPL(sysfs_create_link); |
263 | EXPORT_SYMBOL_GPL(sysfs_remove_link); | 306 | EXPORT_SYMBOL_GPL(sysfs_remove_link); |
307 | EXPORT_SYMBOL_GPL(sysfs_rename_link); | ||