aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/symlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs/symlink.c')
-rw-r--r--fs/sysfs/symlink.c58
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 */
134void 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
160out: 203out:
161 sysfs_put(sd); 204 sysfs_put(sd);
@@ -261,3 +304,4 @@ const struct inode_operations sysfs_symlink_inode_operations = {
261 304
262EXPORT_SYMBOL_GPL(sysfs_create_link); 305EXPORT_SYMBOL_GPL(sysfs_create_link);
263EXPORT_SYMBOL_GPL(sysfs_remove_link); 306EXPORT_SYMBOL_GPL(sysfs_remove_link);
307EXPORT_SYMBOL_GPL(sysfs_rename_link);