aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/symlink.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-12-16 05:23:45 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-12-16 05:23:45 -0500
commitc4de673b775e4db48cd2db6277e0c6714332ca0c (patch)
tree84f9e4728e6ccf257236d2ba063b6e784ec8b65d /fs/sysfs/symlink.c
parentbafdc614a1f4f8be8cde41b8ab10ac17e67c1837 (diff)
parent55957fb7a0b61d8ab6ff3f04e279b8fc22b738fa (diff)
Merge remote-tracking branch 'wireless-next/master' into mac80211-next
Diffstat (limited to 'fs/sysfs/symlink.c')
-rw-r--r--fs/sysfs/symlink.c50
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}
181EXPORT_SYMBOL_GPL(sysfs_remove_link); 189EXPORT_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 */
192int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, 201int 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
223out: 229out:
224 sysfs_put(sd); 230 sysfs_put(sd);
225 return result; 231 return result;
226} 232}
227EXPORT_SYMBOL_GPL(sysfs_rename_link); 233EXPORT_SYMBOL_GPL(sysfs_rename_link_ns);
228 234
229static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, 235static 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)