diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-12-16 05:23:45 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-12-16 05:23:45 -0500 |
commit | c4de673b775e4db48cd2db6277e0c6714332ca0c (patch) | |
tree | 84f9e4728e6ccf257236d2ba063b6e784ec8b65d /fs/sysfs/symlink.c | |
parent | bafdc614a1f4f8be8cde41b8ab10ac17e67c1837 (diff) | |
parent | 55957fb7a0b61d8ab6ff3f04e279b8fc22b738fa (diff) |
Merge remote-tracking branch 'wireless-next/master' into mac80211-next
Diffstat (limited to 'fs/sysfs/symlink.c')
-rw-r--r-- | fs/sysfs/symlink.c | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 2dd4507d9edd..3ae3f1bf1a09 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -33,13 +33,15 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, | |||
33 | 33 | ||
34 | BUG_ON(!name || !parent_sd); | 34 | BUG_ON(!name || !parent_sd); |
35 | 35 | ||
36 | /* target->sd can go away beneath us but is protected with | 36 | /* |
37 | * sysfs_assoc_lock. Fetch target_sd from it. | 37 | * We don't own @target and it may be removed at any time. |
38 | * Synchronize using sysfs_symlink_target_lock. See | ||
39 | * sysfs_remove_dir() for details. | ||
38 | */ | 40 | */ |
39 | spin_lock(&sysfs_assoc_lock); | 41 | spin_lock(&sysfs_symlink_target_lock); |
40 | if (target->sd) | 42 | if (target->sd) |
41 | target_sd = sysfs_get(target->sd); | 43 | target_sd = sysfs_get(target->sd); |
42 | spin_unlock(&sysfs_assoc_lock); | 44 | spin_unlock(&sysfs_symlink_target_lock); |
43 | 45 | ||
44 | error = -ENOENT; | 46 | error = -ENOENT; |
45 | if (!target_sd) | 47 | if (!target_sd) |
@@ -52,18 +54,18 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, | |||
52 | 54 | ||
53 | ns_type = sysfs_ns_type(parent_sd); | 55 | ns_type = sysfs_ns_type(parent_sd); |
54 | if (ns_type) | 56 | if (ns_type) |
55 | sd->s_ns = target->ktype->namespace(target); | 57 | sd->s_ns = target_sd->s_ns; |
56 | sd->s_symlink.target_sd = target_sd; | 58 | sd->s_symlink.target_sd = target_sd; |
57 | target_sd = NULL; /* reference is now owned by the symlink */ | 59 | target_sd = NULL; /* reference is now owned by the symlink */ |
58 | 60 | ||
59 | sysfs_addrm_start(&acxt, parent_sd); | 61 | sysfs_addrm_start(&acxt); |
60 | /* Symlinks must be between directories with the same ns_type */ | 62 | /* Symlinks must be between directories with the same ns_type */ |
61 | if (!ns_type || | 63 | if (!ns_type || |
62 | (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { | 64 | (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { |
63 | if (warn) | 65 | if (warn) |
64 | error = sysfs_add_one(&acxt, sd); | 66 | error = sysfs_add_one(&acxt, sd, parent_sd); |
65 | else | 67 | else |
66 | error = __sysfs_add_one(&acxt, sd); | 68 | error = __sysfs_add_one(&acxt, sd, parent_sd); |
67 | } else { | 69 | } else { |
68 | error = -EINVAL; | 70 | error = -EINVAL; |
69 | WARN(1, KERN_WARNING | 71 | WARN(1, KERN_WARNING |
@@ -155,11 +157,17 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, | |||
155 | const char *name) | 157 | const char *name) |
156 | { | 158 | { |
157 | const void *ns = NULL; | 159 | const void *ns = NULL; |
158 | spin_lock(&sysfs_assoc_lock); | 160 | |
161 | /* | ||
162 | * We don't own @target and it may be removed at any time. | ||
163 | * Synchronize using sysfs_symlink_target_lock. See | ||
164 | * sysfs_remove_dir() for details. | ||
165 | */ | ||
166 | spin_lock(&sysfs_symlink_target_lock); | ||
159 | if (targ->sd && sysfs_ns_type(kobj->sd)) | 167 | if (targ->sd && sysfs_ns_type(kobj->sd)) |
160 | ns = targ->sd->s_ns; | 168 | ns = targ->sd->s_ns; |
161 | spin_unlock(&sysfs_assoc_lock); | 169 | spin_unlock(&sysfs_symlink_target_lock); |
162 | sysfs_hash_and_remove(kobj->sd, ns, name); | 170 | sysfs_hash_and_remove(kobj->sd, name, ns); |
163 | } | 171 | } |
164 | 172 | ||
165 | /** | 173 | /** |
@@ -176,24 +184,25 @@ void sysfs_remove_link(struct kobject *kobj, const char *name) | |||
176 | else | 184 | else |
177 | parent_sd = kobj->sd; | 185 | parent_sd = kobj->sd; |
178 | 186 | ||
179 | sysfs_hash_and_remove(parent_sd, NULL, name); | 187 | sysfs_hash_and_remove(parent_sd, name, NULL); |
180 | } | 188 | } |
181 | EXPORT_SYMBOL_GPL(sysfs_remove_link); | 189 | EXPORT_SYMBOL_GPL(sysfs_remove_link); |
182 | 190 | ||
183 | /** | 191 | /** |
184 | * sysfs_rename_link - rename symlink in object's directory. | 192 | * sysfs_rename_link_ns - rename symlink in object's directory. |
185 | * @kobj: object we're acting for. | 193 | * @kobj: object we're acting for. |
186 | * @targ: object we're pointing to. | 194 | * @targ: object we're pointing to. |
187 | * @old: previous name of the symlink. | 195 | * @old: previous name of the symlink. |
188 | * @new: new name of the symlink. | 196 | * @new: new name of the symlink. |
197 | * @new_ns: new namespace of the symlink. | ||
189 | * | 198 | * |
190 | * A helper function for the common rename symlink idiom. | 199 | * A helper function for the common rename symlink idiom. |
191 | */ | 200 | */ |
192 | int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | 201 | int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, |
193 | const char *old, const char *new) | 202 | const char *old, const char *new, const void *new_ns) |
194 | { | 203 | { |
195 | struct sysfs_dirent *parent_sd, *sd = NULL; | 204 | struct sysfs_dirent *parent_sd, *sd = NULL; |
196 | const void *old_ns = NULL, *new_ns = NULL; | 205 | const void *old_ns = NULL; |
197 | int result; | 206 | int result; |
198 | 207 | ||
199 | if (!kobj) | 208 | if (!kobj) |
@@ -205,7 +214,7 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | |||
205 | old_ns = targ->sd->s_ns; | 214 | old_ns = targ->sd->s_ns; |
206 | 215 | ||
207 | result = -ENOENT; | 216 | result = -ENOENT; |
208 | sd = sysfs_get_dirent(parent_sd, old_ns, old); | 217 | sd = sysfs_get_dirent_ns(parent_sd, old, old_ns); |
209 | if (!sd) | 218 | if (!sd) |
210 | goto out; | 219 | goto out; |
211 | 220 | ||
@@ -215,16 +224,13 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | |||
215 | if (sd->s_symlink.target_sd->s_dir.kobj != targ) | 224 | if (sd->s_symlink.target_sd->s_dir.kobj != targ) |
216 | goto out; | 225 | goto out; |
217 | 226 | ||
218 | if (sysfs_ns_type(parent_sd)) | 227 | result = sysfs_rename(sd, parent_sd, new, new_ns); |
219 | new_ns = targ->ktype->namespace(targ); | ||
220 | |||
221 | result = sysfs_rename(sd, parent_sd, new_ns, new); | ||
222 | 228 | ||
223 | out: | 229 | out: |
224 | sysfs_put(sd); | 230 | sysfs_put(sd); |
225 | return result; | 231 | return result; |
226 | } | 232 | } |
227 | EXPORT_SYMBOL_GPL(sysfs_rename_link); | 233 | EXPORT_SYMBOL_GPL(sysfs_rename_link_ns); |
228 | 234 | ||
229 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, | 235 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, |
230 | struct sysfs_dirent *target_sd, char *path) | 236 | struct sysfs_dirent *target_sd, char *path) |