Blame view
fs/sysfs/symlink.c
4.79 KB
1da177e4c
|
1 |
/* |
6d66f5cd2
|
2 3 4 5 6 7 8 9 10 |
* fs/sysfs/symlink.c - sysfs symlink implementation * * Copyright (c) 2001-3 Patrick Mochel * Copyright (c) 2007 SUSE Linux Products GmbH * Copyright (c) 2007 Tejun Heo <teheo@suse.de> * * This file is released under the GPLv2. * * Please see Documentation/filesystems/sysfs.txt for more information. |
1da177e4c
|
11 12 13 14 15 |
*/ #include <linux/fs.h> #include <linux/module.h> #include <linux/kobject.h> |
869512ab5
|
16 |
#include <linux/mutex.h> |
ddd29ec65
|
17 |
#include <linux/security.h> |
1da177e4c
|
18 19 |
#include "sysfs.h" |
324a56e16
|
20 21 |
static int sysfs_do_create_link_sd(struct kernfs_node *parent, struct kobject *target_kobj, |
0bb8f3d6a
|
22 |
const char *name, int warn) |
1da177e4c
|
23 |
{ |
324a56e16
|
24 |
struct kernfs_node *kn, *target = NULL; |
1da177e4c
|
25 |
|
324a56e16
|
26 |
BUG_ON(!name || !parent); |
2b29ac252
|
27 |
|
0cae60f91
|
28 |
/* |
324a56e16
|
29 |
* We don't own @target_kobj and it may be removed at any time. |
0cae60f91
|
30 31 |
* Synchronize using sysfs_symlink_target_lock. See * sysfs_remove_dir() for details. |
2b29ac252
|
32 |
*/ |
0cae60f91
|
33 |
spin_lock(&sysfs_symlink_target_lock); |
324a56e16
|
34 35 36 |
if (target_kobj->sd) { target = target_kobj->sd; kernfs_get(target); |
ccf73cf33
|
37 |
} |
0cae60f91
|
38 |
spin_unlock(&sysfs_symlink_target_lock); |
2b29ac252
|
39 |
|
324a56e16
|
40 |
if (!target) |
5d0e26bb5
|
41 |
return -ENOENT; |
a1da4dfe3
|
42 |
|
324a56e16
|
43 44 |
kn = kernfs_create_link(parent, name, target); kernfs_put(target); |
967e35dcc
|
45 |
|
324a56e16
|
46 |
if (!IS_ERR(kn)) |
5d0e26bb5
|
47 |
return 0; |
fb6896da3
|
48 |
|
324a56e16
|
49 50 51 |
if (warn && PTR_ERR(kn) == -EEXIST) sysfs_warn_dup(parent, name); return PTR_ERR(kn); |
1da177e4c
|
52 |
} |
1da177e4c
|
53 |
/** |
0bb8f3d6a
|
54 |
* sysfs_create_link_sd - create symlink to a given object. |
324a56e16
|
55 |
* @kn: directory we're creating the link in. |
0bb8f3d6a
|
56 57 58 |
* @target: object we're pointing to. * @name: name of the symlink. */ |
324a56e16
|
59 |
int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target, |
0bb8f3d6a
|
60 61 |
const char *name) { |
324a56e16
|
62 |
return sysfs_do_create_link_sd(kn, target, name, 1); |
0bb8f3d6a
|
63 64 65 66 67 |
} static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, const char *name, int warn) { |
324a56e16
|
68 |
struct kernfs_node *parent = NULL; |
0bb8f3d6a
|
69 70 |
if (!kobj) |
324a56e16
|
71 |
parent = sysfs_root_kn; |
0bb8f3d6a
|
72 |
else |
324a56e16
|
73 |
parent = kobj->sd; |
0bb8f3d6a
|
74 |
|
324a56e16
|
75 |
if (!parent) |
0bb8f3d6a
|
76 |
return -EFAULT; |
324a56e16
|
77 |
return sysfs_do_create_link_sd(parent, target, name, warn); |
0bb8f3d6a
|
78 79 80 |
} /** |
36ce6dad6
|
81 82 83 84 85 86 87 88 89 90 |
* sysfs_create_link - create symlink between two objects. * @kobj: object whose directory we're creating the link in. * @target: object we're pointing to. * @name: name of the symlink. */ int sysfs_create_link(struct kobject *kobj, struct kobject *target, const char *name) { return sysfs_do_create_link(kobj, target, name, 1); } |
1b866757f
|
91 |
EXPORT_SYMBOL_GPL(sysfs_create_link); |
36ce6dad6
|
92 93 94 95 96 97 98 |
/** * sysfs_create_link_nowarn - create symlink between two objects. * @kobj: object whose directory we're creating the link in. * @target: object we're pointing to. * @name: name of the symlink. * |
6f1cbd4a2
|
99 |
* This function does the same as sysfs_create_link(), but it |
36ce6dad6
|
100 101 102 103 104 105 106 107 108 |
* doesn't warn if the link already exists. */ int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target, const char *name) { return sysfs_do_create_link(kobj, target, name, 0); } /** |
746edb7ae
|
109 110 111 112 113 114 115 116 117 118 119 120 |
* sysfs_delete_link - remove symlink in object's directory. * @kobj: object we're acting for. * @targ: object we're pointing to. * @name: name of the symlink to remove. * * Unlike sysfs_remove_link sysfs_delete_link has enough information * to successfully delete symlinks in tagged directories. */ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, const char *name) { const void *ns = NULL; |
0cae60f91
|
121 122 123 124 125 126 127 |
/* * We don't own @target and it may be removed at any time. * Synchronize using sysfs_symlink_target_lock. See * sysfs_remove_dir() for details. */ spin_lock(&sysfs_symlink_target_lock); |
ac9bba031
|
128 |
if (targ->sd && kernfs_ns_enabled(kobj->sd)) |
adc5e8b58
|
129 |
ns = targ->sd->ns; |
0cae60f91
|
130 |
spin_unlock(&sysfs_symlink_target_lock); |
879f40d19
|
131 |
kernfs_remove_by_name_ns(kobj->sd, name, ns); |
746edb7ae
|
132 133 134 |
} /** |
1da177e4c
|
135 136 137 138 |
* sysfs_remove_link - remove symlink in object's directory. * @kobj: object we're acting for. * @name: name of the symlink to remove. */ |
1b18dc2be
|
139 |
void sysfs_remove_link(struct kobject *kobj, const char *name) |
1da177e4c
|
140 |
{ |
324a56e16
|
141 |
struct kernfs_node *parent = NULL; |
a839c5afc
|
142 143 |
if (!kobj) |
324a56e16
|
144 |
parent = sysfs_root_kn; |
a839c5afc
|
145 |
else |
324a56e16
|
146 |
parent = kobj->sd; |
a839c5afc
|
147 |
|
324a56e16
|
148 |
kernfs_remove_by_name(parent, name); |
1da177e4c
|
149 |
} |
1b866757f
|
150 |
EXPORT_SYMBOL_GPL(sysfs_remove_link); |
1da177e4c
|
151 |
|
7cb32942d
|
152 |
/** |
4b30ee58e
|
153 |
* sysfs_rename_link_ns - rename symlink in object's directory. |
7cb32942d
|
154 155 156 157 |
* @kobj: object we're acting for. * @targ: object we're pointing to. * @old: previous name of the symlink. * @new: new name of the symlink. |
4b30ee58e
|
158 |
* @new_ns: new namespace of the symlink. |
7cb32942d
|
159 160 161 |
* * A helper function for the common rename symlink idiom. */ |
4b30ee58e
|
162 163 |
int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, const char *old, const char *new, const void *new_ns) |
7cb32942d
|
164 |
{ |
324a56e16
|
165 |
struct kernfs_node *parent, *kn = NULL; |
4b30ee58e
|
166 |
const void *old_ns = NULL; |
7cb32942d
|
167 168 169 |
int result; if (!kobj) |
324a56e16
|
170 |
parent = sysfs_root_kn; |
7cb32942d
|
171 |
else |
324a56e16
|
172 |
parent = kobj->sd; |
7cb32942d
|
173 |
|
3ff195b01
|
174 |
if (targ->sd) |
adc5e8b58
|
175 |
old_ns = targ->sd->ns; |
3ff195b01
|
176 |
|
7cb32942d
|
177 |
result = -ENOENT; |
324a56e16
|
178 179 |
kn = kernfs_find_and_get_ns(parent, old, old_ns); if (!kn) |
7cb32942d
|
180 181 182 |
goto out; result = -EINVAL; |
df23fc39b
|
183 |
if (kernfs_type(kn) != KERNFS_LINK) |
7cb32942d
|
184 |
goto out; |
adc5e8b58
|
185 |
if (kn->symlink.target_kn->priv != targ) |
7cb32942d
|
186 |
goto out; |
324a56e16
|
187 |
result = kernfs_rename_ns(kn, parent, new, new_ns); |
7cb32942d
|
188 189 |
out: |
324a56e16
|
190 |
kernfs_put(kn); |
7cb32942d
|
191 192 |
return result; } |
4b30ee58e
|
193 |
EXPORT_SYMBOL_GPL(sysfs_rename_link_ns); |