diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/bin.c | 76 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 224 | ||||
-rw-r--r-- | fs/sysfs/file.c | 64 | ||||
-rw-r--r-- | fs/sysfs/group.c | 6 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 63 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 100 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 93 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 51 |
8 files changed, 485 insertions, 192 deletions
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index a0a500af24a1..4e321f7353fa 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
@@ -46,22 +46,22 @@ struct bin_buffer { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | static int | 48 | static int |
49 | fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) | 49 | fill_read(struct file *file, char *buffer, loff_t off, size_t count) |
50 | { | 50 | { |
51 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 51 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
52 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; | 52 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; |
53 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 53 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
54 | int rc; | 54 | int rc; |
55 | 55 | ||
56 | /* need attr_sd for attr, its parent for kobj */ | 56 | /* need attr_sd for attr, its parent for kobj */ |
57 | if (!sysfs_get_active_two(attr_sd)) | 57 | if (!sysfs_get_active(attr_sd)) |
58 | return -ENODEV; | 58 | return -ENODEV; |
59 | 59 | ||
60 | rc = -EIO; | 60 | rc = -EIO; |
61 | if (attr->read) | 61 | if (attr->read) |
62 | rc = attr->read(kobj, attr, buffer, off, count); | 62 | rc = attr->read(file, kobj, attr, buffer, off, count); |
63 | 63 | ||
64 | sysfs_put_active_two(attr_sd); | 64 | sysfs_put_active(attr_sd); |
65 | 65 | ||
66 | return rc; | 66 | return rc; |
67 | } | 67 | } |
@@ -70,8 +70,7 @@ static ssize_t | |||
70 | read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) | 70 | read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) |
71 | { | 71 | { |
72 | struct bin_buffer *bb = file->private_data; | 72 | struct bin_buffer *bb = file->private_data; |
73 | struct dentry *dentry = file->f_path.dentry; | 73 | int size = file->f_path.dentry->d_inode->i_size; |
74 | int size = dentry->d_inode->i_size; | ||
75 | loff_t offs = *off; | 74 | loff_t offs = *off; |
76 | int count = min_t(size_t, bytes, PAGE_SIZE); | 75 | int count = min_t(size_t, bytes, PAGE_SIZE); |
77 | char *temp; | 76 | char *temp; |
@@ -92,7 +91,7 @@ read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) | |||
92 | 91 | ||
93 | mutex_lock(&bb->mutex); | 92 | mutex_lock(&bb->mutex); |
94 | 93 | ||
95 | count = fill_read(dentry, bb->buffer, offs, count); | 94 | count = fill_read(file, bb->buffer, offs, count); |
96 | if (count < 0) { | 95 | if (count < 0) { |
97 | mutex_unlock(&bb->mutex); | 96 | mutex_unlock(&bb->mutex); |
98 | goto out_free; | 97 | goto out_free; |
@@ -117,22 +116,22 @@ read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) | |||
117 | } | 116 | } |
118 | 117 | ||
119 | static int | 118 | static int |
120 | flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) | 119 | flush_write(struct file *file, char *buffer, loff_t offset, size_t count) |
121 | { | 120 | { |
122 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 121 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
123 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; | 122 | struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; |
124 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 123 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
125 | int rc; | 124 | int rc; |
126 | 125 | ||
127 | /* need attr_sd for attr, its parent for kobj */ | 126 | /* need attr_sd for attr, its parent for kobj */ |
128 | if (!sysfs_get_active_two(attr_sd)) | 127 | if (!sysfs_get_active(attr_sd)) |
129 | return -ENODEV; | 128 | return -ENODEV; |
130 | 129 | ||
131 | rc = -EIO; | 130 | rc = -EIO; |
132 | if (attr->write) | 131 | if (attr->write) |
133 | rc = attr->write(kobj, attr, buffer, offset, count); | 132 | rc = attr->write(file, kobj, attr, buffer, offset, count); |
134 | 133 | ||
135 | sysfs_put_active_two(attr_sd); | 134 | sysfs_put_active(attr_sd); |
136 | 135 | ||
137 | return rc; | 136 | return rc; |
138 | } | 137 | } |
@@ -141,8 +140,7 @@ static ssize_t write(struct file *file, const char __user *userbuf, | |||
141 | size_t bytes, loff_t *off) | 140 | size_t bytes, loff_t *off) |
142 | { | 141 | { |
143 | struct bin_buffer *bb = file->private_data; | 142 | struct bin_buffer *bb = file->private_data; |
144 | struct dentry *dentry = file->f_path.dentry; | 143 | int size = file->f_path.dentry->d_inode->i_size; |
145 | int size = dentry->d_inode->i_size; | ||
146 | loff_t offs = *off; | 144 | loff_t offs = *off; |
147 | int count = min_t(size_t, bytes, PAGE_SIZE); | 145 | int count = min_t(size_t, bytes, PAGE_SIZE); |
148 | char *temp; | 146 | char *temp; |
@@ -165,7 +163,7 @@ static ssize_t write(struct file *file, const char __user *userbuf, | |||
165 | 163 | ||
166 | memcpy(bb->buffer, temp, count); | 164 | memcpy(bb->buffer, temp, count); |
167 | 165 | ||
168 | count = flush_write(dentry, bb->buffer, offs, count); | 166 | count = flush_write(file, bb->buffer, offs, count); |
169 | mutex_unlock(&bb->mutex); | 167 | mutex_unlock(&bb->mutex); |
170 | 168 | ||
171 | if (count > 0) | 169 | if (count > 0) |
@@ -184,12 +182,12 @@ static void bin_vma_open(struct vm_area_struct *vma) | |||
184 | if (!bb->vm_ops || !bb->vm_ops->open) | 182 | if (!bb->vm_ops || !bb->vm_ops->open) |
185 | return; | 183 | return; |
186 | 184 | ||
187 | if (!sysfs_get_active_two(attr_sd)) | 185 | if (!sysfs_get_active(attr_sd)) |
188 | return; | 186 | return; |
189 | 187 | ||
190 | bb->vm_ops->open(vma); | 188 | bb->vm_ops->open(vma); |
191 | 189 | ||
192 | sysfs_put_active_two(attr_sd); | 190 | sysfs_put_active(attr_sd); |
193 | } | 191 | } |
194 | 192 | ||
195 | static void bin_vma_close(struct vm_area_struct *vma) | 193 | static void bin_vma_close(struct vm_area_struct *vma) |
@@ -201,12 +199,12 @@ static void bin_vma_close(struct vm_area_struct *vma) | |||
201 | if (!bb->vm_ops || !bb->vm_ops->close) | 199 | if (!bb->vm_ops || !bb->vm_ops->close) |
202 | return; | 200 | return; |
203 | 201 | ||
204 | if (!sysfs_get_active_two(attr_sd)) | 202 | if (!sysfs_get_active(attr_sd)) |
205 | return; | 203 | return; |
206 | 204 | ||
207 | bb->vm_ops->close(vma); | 205 | bb->vm_ops->close(vma); |
208 | 206 | ||
209 | sysfs_put_active_two(attr_sd); | 207 | sysfs_put_active(attr_sd); |
210 | } | 208 | } |
211 | 209 | ||
212 | static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 210 | static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
@@ -219,12 +217,12 @@ static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
219 | if (!bb->vm_ops || !bb->vm_ops->fault) | 217 | if (!bb->vm_ops || !bb->vm_ops->fault) |
220 | return VM_FAULT_SIGBUS; | 218 | return VM_FAULT_SIGBUS; |
221 | 219 | ||
222 | if (!sysfs_get_active_two(attr_sd)) | 220 | if (!sysfs_get_active(attr_sd)) |
223 | return VM_FAULT_SIGBUS; | 221 | return VM_FAULT_SIGBUS; |
224 | 222 | ||
225 | ret = bb->vm_ops->fault(vma, vmf); | 223 | ret = bb->vm_ops->fault(vma, vmf); |
226 | 224 | ||
227 | sysfs_put_active_two(attr_sd); | 225 | sysfs_put_active(attr_sd); |
228 | return ret; | 226 | return ret; |
229 | } | 227 | } |
230 | 228 | ||
@@ -241,12 +239,12 @@ static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
241 | if (!bb->vm_ops->page_mkwrite) | 239 | if (!bb->vm_ops->page_mkwrite) |
242 | return 0; | 240 | return 0; |
243 | 241 | ||
244 | if (!sysfs_get_active_two(attr_sd)) | 242 | if (!sysfs_get_active(attr_sd)) |
245 | return VM_FAULT_SIGBUS; | 243 | return VM_FAULT_SIGBUS; |
246 | 244 | ||
247 | ret = bb->vm_ops->page_mkwrite(vma, vmf); | 245 | ret = bb->vm_ops->page_mkwrite(vma, vmf); |
248 | 246 | ||
249 | sysfs_put_active_two(attr_sd); | 247 | sysfs_put_active(attr_sd); |
250 | return ret; | 248 | return ret; |
251 | } | 249 | } |
252 | 250 | ||
@@ -261,12 +259,12 @@ static int bin_access(struct vm_area_struct *vma, unsigned long addr, | |||
261 | if (!bb->vm_ops || !bb->vm_ops->access) | 259 | if (!bb->vm_ops || !bb->vm_ops->access) |
262 | return -EINVAL; | 260 | return -EINVAL; |
263 | 261 | ||
264 | if (!sysfs_get_active_two(attr_sd)) | 262 | if (!sysfs_get_active(attr_sd)) |
265 | return -EINVAL; | 263 | return -EINVAL; |
266 | 264 | ||
267 | ret = bb->vm_ops->access(vma, addr, buf, len, write); | 265 | ret = bb->vm_ops->access(vma, addr, buf, len, write); |
268 | 266 | ||
269 | sysfs_put_active_two(attr_sd); | 267 | sysfs_put_active(attr_sd); |
270 | return ret; | 268 | return ret; |
271 | } | 269 | } |
272 | 270 | ||
@@ -281,12 +279,12 @@ static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new) | |||
281 | if (!bb->vm_ops || !bb->vm_ops->set_policy) | 279 | if (!bb->vm_ops || !bb->vm_ops->set_policy) |
282 | return 0; | 280 | return 0; |
283 | 281 | ||
284 | if (!sysfs_get_active_two(attr_sd)) | 282 | if (!sysfs_get_active(attr_sd)) |
285 | return -EINVAL; | 283 | return -EINVAL; |
286 | 284 | ||
287 | ret = bb->vm_ops->set_policy(vma, new); | 285 | ret = bb->vm_ops->set_policy(vma, new); |
288 | 286 | ||
289 | sysfs_put_active_two(attr_sd); | 287 | sysfs_put_active(attr_sd); |
290 | return ret; | 288 | return ret; |
291 | } | 289 | } |
292 | 290 | ||
@@ -301,12 +299,12 @@ static struct mempolicy *bin_get_policy(struct vm_area_struct *vma, | |||
301 | if (!bb->vm_ops || !bb->vm_ops->get_policy) | 299 | if (!bb->vm_ops || !bb->vm_ops->get_policy) |
302 | return vma->vm_policy; | 300 | return vma->vm_policy; |
303 | 301 | ||
304 | if (!sysfs_get_active_two(attr_sd)) | 302 | if (!sysfs_get_active(attr_sd)) |
305 | return vma->vm_policy; | 303 | return vma->vm_policy; |
306 | 304 | ||
307 | pol = bb->vm_ops->get_policy(vma, addr); | 305 | pol = bb->vm_ops->get_policy(vma, addr); |
308 | 306 | ||
309 | sysfs_put_active_two(attr_sd); | 307 | sysfs_put_active(attr_sd); |
310 | return pol; | 308 | return pol; |
311 | } | 309 | } |
312 | 310 | ||
@@ -321,12 +319,12 @@ static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from, | |||
321 | if (!bb->vm_ops || !bb->vm_ops->migrate) | 319 | if (!bb->vm_ops || !bb->vm_ops->migrate) |
322 | return 0; | 320 | return 0; |
323 | 321 | ||
324 | if (!sysfs_get_active_two(attr_sd)) | 322 | if (!sysfs_get_active(attr_sd)) |
325 | return 0; | 323 | return 0; |
326 | 324 | ||
327 | ret = bb->vm_ops->migrate(vma, from, to, flags); | 325 | ret = bb->vm_ops->migrate(vma, from, to, flags); |
328 | 326 | ||
329 | sysfs_put_active_two(attr_sd); | 327 | sysfs_put_active(attr_sd); |
330 | return ret; | 328 | return ret; |
331 | } | 329 | } |
332 | #endif | 330 | #endif |
@@ -356,14 +354,14 @@ static int mmap(struct file *file, struct vm_area_struct *vma) | |||
356 | 354 | ||
357 | /* need attr_sd for attr, its parent for kobj */ | 355 | /* need attr_sd for attr, its parent for kobj */ |
358 | rc = -ENODEV; | 356 | rc = -ENODEV; |
359 | if (!sysfs_get_active_two(attr_sd)) | 357 | if (!sysfs_get_active(attr_sd)) |
360 | goto out_unlock; | 358 | goto out_unlock; |
361 | 359 | ||
362 | rc = -EINVAL; | 360 | rc = -EINVAL; |
363 | if (!attr->mmap) | 361 | if (!attr->mmap) |
364 | goto out_put; | 362 | goto out_put; |
365 | 363 | ||
366 | rc = attr->mmap(kobj, attr, vma); | 364 | rc = attr->mmap(file, kobj, attr, vma); |
367 | if (rc) | 365 | if (rc) |
368 | goto out_put; | 366 | goto out_put; |
369 | 367 | ||
@@ -384,7 +382,7 @@ static int mmap(struct file *file, struct vm_area_struct *vma) | |||
384 | bb->vm_ops = vma->vm_ops; | 382 | bb->vm_ops = vma->vm_ops; |
385 | vma->vm_ops = &bin_vm_ops; | 383 | vma->vm_ops = &bin_vm_ops; |
386 | out_put: | 384 | out_put: |
387 | sysfs_put_active_two(attr_sd); | 385 | sysfs_put_active(attr_sd); |
388 | out_unlock: | 386 | out_unlock: |
389 | mutex_unlock(&bb->mutex); | 387 | mutex_unlock(&bb->mutex); |
390 | 388 | ||
@@ -399,7 +397,7 @@ static int open(struct inode * inode, struct file * file) | |||
399 | int error; | 397 | int error; |
400 | 398 | ||
401 | /* binary file operations requires both @sd and its parent */ | 399 | /* binary file operations requires both @sd and its parent */ |
402 | if (!sysfs_get_active_two(attr_sd)) | 400 | if (!sysfs_get_active(attr_sd)) |
403 | return -ENODEV; | 401 | return -ENODEV; |
404 | 402 | ||
405 | error = -EACCES; | 403 | error = -EACCES; |
@@ -426,11 +424,11 @@ static int open(struct inode * inode, struct file * file) | |||
426 | mutex_unlock(&sysfs_bin_lock); | 424 | mutex_unlock(&sysfs_bin_lock); |
427 | 425 | ||
428 | /* open succeeded, put active references */ | 426 | /* open succeeded, put active references */ |
429 | sysfs_put_active_two(attr_sd); | 427 | sysfs_put_active(attr_sd); |
430 | return 0; | 428 | return 0; |
431 | 429 | ||
432 | err_out: | 430 | err_out: |
433 | sysfs_put_active_two(attr_sd); | 431 | sysfs_put_active(attr_sd); |
434 | kfree(bb); | 432 | kfree(bb); |
435 | return error; | 433 | return error; |
436 | } | 434 | } |
@@ -501,7 +499,7 @@ int sysfs_create_bin_file(struct kobject *kobj, | |||
501 | void sysfs_remove_bin_file(struct kobject *kobj, | 499 | void sysfs_remove_bin_file(struct kobject *kobj, |
502 | const struct bin_attribute *attr) | 500 | const struct bin_attribute *attr) |
503 | { | 501 | { |
504 | sysfs_hash_and_remove(kobj->sd, attr->attr.name); | 502 | sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name); |
505 | } | 503 | } |
506 | 504 | ||
507 | EXPORT_SYMBOL_GPL(sysfs_create_bin_file); | 505 | EXPORT_SYMBOL_GPL(sysfs_create_bin_file); |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 699f371b9f12..7e54bac8c4b0 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -93,7 +93,7 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
93 | * RETURNS: | 93 | * RETURNS: |
94 | * Pointer to @sd on success, NULL on failure. | 94 | * Pointer to @sd on success, NULL on failure. |
95 | */ | 95 | */ |
96 | static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | 96 | struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) |
97 | { | 97 | { |
98 | if (unlikely(!sd)) | 98 | if (unlikely(!sd)) |
99 | return NULL; | 99 | return NULL; |
@@ -124,7 +124,7 @@ static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | |||
124 | * Put an active reference to @sd. This function is noop if @sd | 124 | * Put an active reference to @sd. This function is noop if @sd |
125 | * is NULL. | 125 | * is NULL. |
126 | */ | 126 | */ |
127 | static void sysfs_put_active(struct sysfs_dirent *sd) | 127 | void sysfs_put_active(struct sysfs_dirent *sd) |
128 | { | 128 | { |
129 | struct completion *cmpl; | 129 | struct completion *cmpl; |
130 | int v; | 130 | int v; |
@@ -145,45 +145,6 @@ static void sysfs_put_active(struct sysfs_dirent *sd) | |||
145 | } | 145 | } |
146 | 146 | ||
147 | /** | 147 | /** |
148 | * sysfs_get_active_two - get active references to sysfs_dirent and parent | ||
149 | * @sd: sysfs_dirent of interest | ||
150 | * | ||
151 | * Get active reference to @sd and its parent. Parent's active | ||
152 | * reference is grabbed first. This function is noop if @sd is | ||
153 | * NULL. | ||
154 | * | ||
155 | * RETURNS: | ||
156 | * Pointer to @sd on success, NULL on failure. | ||
157 | */ | ||
158 | struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd) | ||
159 | { | ||
160 | if (sd) { | ||
161 | if (sd->s_parent && unlikely(!sysfs_get_active(sd->s_parent))) | ||
162 | return NULL; | ||
163 | if (unlikely(!sysfs_get_active(sd))) { | ||
164 | sysfs_put_active(sd->s_parent); | ||
165 | return NULL; | ||
166 | } | ||
167 | } | ||
168 | return sd; | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * sysfs_put_active_two - put active references to sysfs_dirent and parent | ||
173 | * @sd: sysfs_dirent of interest | ||
174 | * | ||
175 | * Put active references to @sd and its parent. This function is | ||
176 | * noop if @sd is NULL. | ||
177 | */ | ||
178 | void sysfs_put_active_two(struct sysfs_dirent *sd) | ||
179 | { | ||
180 | if (sd) { | ||
181 | sysfs_put_active(sd); | ||
182 | sysfs_put_active(sd->s_parent); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * sysfs_deactivate - deactivate sysfs_dirent | 148 | * sysfs_deactivate - deactivate sysfs_dirent |
188 | * @sd: sysfs_dirent to deactivate | 149 | * @sd: sysfs_dirent to deactivate |
189 | * | 150 | * |
@@ -195,6 +156,10 @@ static void sysfs_deactivate(struct sysfs_dirent *sd) | |||
195 | int v; | 156 | int v; |
196 | 157 | ||
197 | BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED)); | 158 | BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED)); |
159 | |||
160 | if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF)) | ||
161 | return; | ||
162 | |||
198 | sd->s_sibling = (void *)&wait; | 163 | sd->s_sibling = (void *)&wait; |
199 | 164 | ||
200 | rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); | 165 | rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); |
@@ -354,7 +319,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
354 | 319 | ||
355 | atomic_set(&sd->s_count, 1); | 320 | atomic_set(&sd->s_count, 1); |
356 | atomic_set(&sd->s_active, 0); | 321 | atomic_set(&sd->s_active, 0); |
357 | sysfs_dirent_init_lockdep(sd); | ||
358 | 322 | ||
359 | sd->s_name = name; | 323 | sd->s_name = name; |
360 | sd->s_mode = mode; | 324 | sd->s_mode = mode; |
@@ -416,7 +380,7 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
416 | { | 380 | { |
417 | struct sysfs_inode_attrs *ps_iattr; | 381 | struct sysfs_inode_attrs *ps_iattr; |
418 | 382 | ||
419 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) | 383 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name)) |
420 | return -EEXIST; | 384 | return -EEXIST; |
421 | 385 | ||
422 | sd->s_parent = sysfs_get(acxt->parent_sd); | 386 | sd->s_parent = sysfs_get(acxt->parent_sd); |
@@ -569,13 +533,17 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
569 | * Pointer to sysfs_dirent if found, NULL if not. | 533 | * Pointer to sysfs_dirent if found, NULL if not. |
570 | */ | 534 | */ |
571 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | 535 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, |
536 | const void *ns, | ||
572 | const unsigned char *name) | 537 | const unsigned char *name) |
573 | { | 538 | { |
574 | struct sysfs_dirent *sd; | 539 | struct sysfs_dirent *sd; |
575 | 540 | ||
576 | for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) | 541 | for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) { |
542 | if (ns && sd->s_ns && (sd->s_ns != ns)) | ||
543 | continue; | ||
577 | if (!strcmp(sd->s_name, name)) | 544 | if (!strcmp(sd->s_name, name)) |
578 | return sd; | 545 | return sd; |
546 | } | ||
579 | return NULL; | 547 | return NULL; |
580 | } | 548 | } |
581 | 549 | ||
@@ -594,12 +562,13 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
594 | * Pointer to sysfs_dirent if found, NULL if not. | 562 | * Pointer to sysfs_dirent if found, NULL if not. |
595 | */ | 563 | */ |
596 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | 564 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, |
565 | const void *ns, | ||
597 | const unsigned char *name) | 566 | const unsigned char *name) |
598 | { | 567 | { |
599 | struct sysfs_dirent *sd; | 568 | struct sysfs_dirent *sd; |
600 | 569 | ||
601 | mutex_lock(&sysfs_mutex); | 570 | mutex_lock(&sysfs_mutex); |
602 | sd = sysfs_find_dirent(parent_sd, name); | 571 | sd = sysfs_find_dirent(parent_sd, ns, name); |
603 | sysfs_get(sd); | 572 | sysfs_get(sd); |
604 | mutex_unlock(&sysfs_mutex); | 573 | mutex_unlock(&sysfs_mutex); |
605 | 574 | ||
@@ -608,7 +577,8 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | |||
608 | EXPORT_SYMBOL_GPL(sysfs_get_dirent); | 577 | EXPORT_SYMBOL_GPL(sysfs_get_dirent); |
609 | 578 | ||
610 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | 579 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, |
611 | const char *name, struct sysfs_dirent **p_sd) | 580 | enum kobj_ns_type type, const void *ns, const char *name, |
581 | struct sysfs_dirent **p_sd) | ||
612 | { | 582 | { |
613 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; | 583 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; |
614 | struct sysfs_addrm_cxt acxt; | 584 | struct sysfs_addrm_cxt acxt; |
@@ -619,6 +589,9 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
619 | sd = sysfs_new_dirent(name, mode, SYSFS_DIR); | 589 | sd = sysfs_new_dirent(name, mode, SYSFS_DIR); |
620 | if (!sd) | 590 | if (!sd) |
621 | return -ENOMEM; | 591 | return -ENOMEM; |
592 | |||
593 | sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT); | ||
594 | sd->s_ns = ns; | ||
622 | sd->s_dir.kobj = kobj; | 595 | sd->s_dir.kobj = kobj; |
623 | 596 | ||
624 | /* link in */ | 597 | /* link in */ |
@@ -637,7 +610,33 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
637 | int sysfs_create_subdir(struct kobject *kobj, const char *name, | 610 | int sysfs_create_subdir(struct kobject *kobj, const char *name, |
638 | struct sysfs_dirent **p_sd) | 611 | struct sysfs_dirent **p_sd) |
639 | { | 612 | { |
640 | return create_dir(kobj, kobj->sd, name, p_sd); | 613 | return create_dir(kobj, kobj->sd, |
614 | KOBJ_NS_TYPE_NONE, NULL, name, p_sd); | ||
615 | } | ||
616 | |||
617 | /** | ||
618 | * sysfs_read_ns_type: return associated ns_type | ||
619 | * @kobj: the kobject being queried | ||
620 | * | ||
621 | * Each kobject can be tagged with exactly one namespace type | ||
622 | * (i.e. network or user). Return the ns_type associated with | ||
623 | * this object if any | ||
624 | */ | ||
625 | static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj) | ||
626 | { | ||
627 | const struct kobj_ns_type_operations *ops; | ||
628 | enum kobj_ns_type type; | ||
629 | |||
630 | ops = kobj_child_ns_ops(kobj); | ||
631 | if (!ops) | ||
632 | return KOBJ_NS_TYPE_NONE; | ||
633 | |||
634 | type = ops->type; | ||
635 | BUG_ON(type <= KOBJ_NS_TYPE_NONE); | ||
636 | BUG_ON(type >= KOBJ_NS_TYPES); | ||
637 | BUG_ON(!kobj_ns_type_registered(type)); | ||
638 | |||
639 | return type; | ||
641 | } | 640 | } |
642 | 641 | ||
643 | /** | 642 | /** |
@@ -646,7 +645,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, | |||
646 | */ | 645 | */ |
647 | int sysfs_create_dir(struct kobject * kobj) | 646 | int sysfs_create_dir(struct kobject * kobj) |
648 | { | 647 | { |
648 | enum kobj_ns_type type; | ||
649 | struct sysfs_dirent *parent_sd, *sd; | 649 | struct sysfs_dirent *parent_sd, *sd; |
650 | const void *ns = NULL; | ||
650 | int error = 0; | 651 | int error = 0; |
651 | 652 | ||
652 | BUG_ON(!kobj); | 653 | BUG_ON(!kobj); |
@@ -656,7 +657,11 @@ int sysfs_create_dir(struct kobject * kobj) | |||
656 | else | 657 | else |
657 | parent_sd = &sysfs_root; | 658 | parent_sd = &sysfs_root; |
658 | 659 | ||
659 | error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); | 660 | if (sysfs_ns_type(parent_sd)) |
661 | ns = kobj->ktype->namespace(kobj); | ||
662 | type = sysfs_read_ns_type(kobj); | ||
663 | |||
664 | error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd); | ||
660 | if (!error) | 665 | if (!error) |
661 | kobj->sd = sd; | 666 | kobj->sd = sd; |
662 | return error; | 667 | return error; |
@@ -666,13 +671,19 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
666 | struct nameidata *nd) | 671 | struct nameidata *nd) |
667 | { | 672 | { |
668 | struct dentry *ret = NULL; | 673 | struct dentry *ret = NULL; |
669 | struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; | 674 | struct dentry *parent = dentry->d_parent; |
675 | struct sysfs_dirent *parent_sd = parent->d_fsdata; | ||
670 | struct sysfs_dirent *sd; | 676 | struct sysfs_dirent *sd; |
671 | struct inode *inode; | 677 | struct inode *inode; |
678 | enum kobj_ns_type type; | ||
679 | const void *ns; | ||
672 | 680 | ||
673 | mutex_lock(&sysfs_mutex); | 681 | mutex_lock(&sysfs_mutex); |
674 | 682 | ||
675 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); | 683 | type = sysfs_ns_type(parent_sd); |
684 | ns = sysfs_info(dir->i_sb)->ns[type]; | ||
685 | |||
686 | sd = sysfs_find_dirent(parent_sd, ns, dentry->d_name.name); | ||
676 | 687 | ||
677 | /* no such entry */ | 688 | /* no such entry */ |
678 | if (!sd) { | 689 | if (!sd) { |
@@ -681,7 +692,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
681 | } | 692 | } |
682 | 693 | ||
683 | /* attach dentry and inode */ | 694 | /* attach dentry and inode */ |
684 | inode = sysfs_get_inode(sd); | 695 | inode = sysfs_get_inode(dir->i_sb, sd); |
685 | if (!inode) { | 696 | if (!inode) { |
686 | ret = ERR_PTR(-ENOMEM); | 697 | ret = ERR_PTR(-ENOMEM); |
687 | goto out_unlock; | 698 | goto out_unlock; |
@@ -771,7 +782,8 @@ void sysfs_remove_dir(struct kobject * kobj) | |||
771 | } | 782 | } |
772 | 783 | ||
773 | int sysfs_rename(struct sysfs_dirent *sd, | 784 | int sysfs_rename(struct sysfs_dirent *sd, |
774 | struct sysfs_dirent *new_parent_sd, const char *new_name) | 785 | struct sysfs_dirent *new_parent_sd, const void *new_ns, |
786 | const char *new_name) | ||
775 | { | 787 | { |
776 | const char *dup_name = NULL; | 788 | const char *dup_name = NULL; |
777 | int error; | 789 | int error; |
@@ -779,12 +791,12 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
779 | mutex_lock(&sysfs_mutex); | 791 | mutex_lock(&sysfs_mutex); |
780 | 792 | ||
781 | error = 0; | 793 | error = 0; |
782 | if ((sd->s_parent == new_parent_sd) && | 794 | if ((sd->s_parent == new_parent_sd) && (sd->s_ns == new_ns) && |
783 | (strcmp(sd->s_name, new_name) == 0)) | 795 | (strcmp(sd->s_name, new_name) == 0)) |
784 | goto out; /* nothing to rename */ | 796 | goto out; /* nothing to rename */ |
785 | 797 | ||
786 | error = -EEXIST; | 798 | error = -EEXIST; |
787 | if (sysfs_find_dirent(new_parent_sd, new_name)) | 799 | if (sysfs_find_dirent(new_parent_sd, new_ns, new_name)) |
788 | goto out; | 800 | goto out; |
789 | 801 | ||
790 | /* rename sysfs_dirent */ | 802 | /* rename sysfs_dirent */ |
@@ -806,6 +818,7 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
806 | sd->s_parent = new_parent_sd; | 818 | sd->s_parent = new_parent_sd; |
807 | sysfs_link_sibling(sd); | 819 | sysfs_link_sibling(sd); |
808 | } | 820 | } |
821 | sd->s_ns = new_ns; | ||
809 | 822 | ||
810 | error = 0; | 823 | error = 0; |
811 | out: | 824 | out: |
@@ -816,19 +829,28 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
816 | 829 | ||
817 | int sysfs_rename_dir(struct kobject *kobj, const char *new_name) | 830 | int sysfs_rename_dir(struct kobject *kobj, const char *new_name) |
818 | { | 831 | { |
819 | return sysfs_rename(kobj->sd, kobj->sd->s_parent, new_name); | 832 | struct sysfs_dirent *parent_sd = kobj->sd->s_parent; |
833 | const void *new_ns = NULL; | ||
834 | |||
835 | if (sysfs_ns_type(parent_sd)) | ||
836 | new_ns = kobj->ktype->namespace(kobj); | ||
837 | |||
838 | return sysfs_rename(kobj->sd, parent_sd, new_ns, new_name); | ||
820 | } | 839 | } |
821 | 840 | ||
822 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | 841 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) |
823 | { | 842 | { |
824 | struct sysfs_dirent *sd = kobj->sd; | 843 | struct sysfs_dirent *sd = kobj->sd; |
825 | struct sysfs_dirent *new_parent_sd; | 844 | struct sysfs_dirent *new_parent_sd; |
845 | const void *new_ns = NULL; | ||
826 | 846 | ||
827 | BUG_ON(!sd->s_parent); | 847 | BUG_ON(!sd->s_parent); |
848 | if (sysfs_ns_type(sd->s_parent)) | ||
849 | new_ns = kobj->ktype->namespace(kobj); | ||
828 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? | 850 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? |
829 | new_parent_kobj->sd : &sysfs_root; | 851 | new_parent_kobj->sd : &sysfs_root; |
830 | 852 | ||
831 | return sysfs_rename(sd, new_parent_sd, sd->s_name); | 853 | return sysfs_rename(sd, new_parent_sd, new_ns, sd->s_name); |
832 | } | 854 | } |
833 | 855 | ||
834 | /* Relationship between s_mode and the DT_xxx types */ | 856 | /* Relationship between s_mode and the DT_xxx types */ |
@@ -837,13 +859,56 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd) | |||
837 | return (sd->s_mode >> 12) & 15; | 859 | return (sd->s_mode >> 12) & 15; |
838 | } | 860 | } |
839 | 861 | ||
862 | static int sysfs_dir_release(struct inode *inode, struct file *filp) | ||
863 | { | ||
864 | sysfs_put(filp->private_data); | ||
865 | return 0; | ||
866 | } | ||
867 | |||
868 | static struct sysfs_dirent *sysfs_dir_pos(const void *ns, | ||
869 | struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) | ||
870 | { | ||
871 | if (pos) { | ||
872 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && | ||
873 | pos->s_parent == parent_sd && | ||
874 | ino == pos->s_ino; | ||
875 | sysfs_put(pos); | ||
876 | if (!valid) | ||
877 | pos = NULL; | ||
878 | } | ||
879 | if (!pos && (ino > 1) && (ino < INT_MAX)) { | ||
880 | pos = parent_sd->s_dir.children; | ||
881 | while (pos && (ino > pos->s_ino)) | ||
882 | pos = pos->s_sibling; | ||
883 | } | ||
884 | while (pos && pos->s_ns && pos->s_ns != ns) | ||
885 | pos = pos->s_sibling; | ||
886 | return pos; | ||
887 | } | ||
888 | |||
889 | static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns, | ||
890 | struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) | ||
891 | { | ||
892 | pos = sysfs_dir_pos(ns, parent_sd, ino, pos); | ||
893 | if (pos) | ||
894 | pos = pos->s_sibling; | ||
895 | while (pos && pos->s_ns && pos->s_ns != ns) | ||
896 | pos = pos->s_sibling; | ||
897 | return pos; | ||
898 | } | ||
899 | |||
840 | static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | 900 | static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) |
841 | { | 901 | { |
842 | struct dentry *dentry = filp->f_path.dentry; | 902 | struct dentry *dentry = filp->f_path.dentry; |
843 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | 903 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; |
844 | struct sysfs_dirent *pos; | 904 | struct sysfs_dirent *pos = filp->private_data; |
905 | enum kobj_ns_type type; | ||
906 | const void *ns; | ||
845 | ino_t ino; | 907 | ino_t ino; |
846 | 908 | ||
909 | type = sysfs_ns_type(parent_sd); | ||
910 | ns = sysfs_info(dentry->d_sb)->ns[type]; | ||
911 | |||
847 | if (filp->f_pos == 0) { | 912 | if (filp->f_pos == 0) { |
848 | ino = parent_sd->s_ino; | 913 | ino = parent_sd->s_ino; |
849 | if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) | 914 | if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) |
@@ -857,29 +922,31 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
857 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) | 922 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) |
858 | filp->f_pos++; | 923 | filp->f_pos++; |
859 | } | 924 | } |
860 | if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { | 925 | mutex_lock(&sysfs_mutex); |
861 | mutex_lock(&sysfs_mutex); | 926 | for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos); |
862 | 927 | pos; | |
863 | /* Skip the dentries we have already reported */ | 928 | pos = sysfs_dir_next_pos(ns, parent_sd, filp->f_pos, pos)) { |
864 | pos = parent_sd->s_dir.children; | 929 | const char * name; |
865 | while (pos && (filp->f_pos > pos->s_ino)) | 930 | unsigned int type; |
866 | pos = pos->s_sibling; | 931 | int len, ret; |
867 | 932 | ||
868 | for ( ; pos; pos = pos->s_sibling) { | 933 | name = pos->s_name; |
869 | const char * name; | 934 | len = strlen(name); |
870 | int len; | 935 | ino = pos->s_ino; |
871 | 936 | type = dt_type(pos); | |
872 | name = pos->s_name; | 937 | filp->f_pos = ino; |
873 | len = strlen(name); | 938 | filp->private_data = sysfs_get(pos); |
874 | filp->f_pos = ino = pos->s_ino; | ||
875 | 939 | ||
876 | if (filldir(dirent, name, len, filp->f_pos, ino, | ||
877 | dt_type(pos)) < 0) | ||
878 | break; | ||
879 | } | ||
880 | if (!pos) | ||
881 | filp->f_pos = INT_MAX; | ||
882 | mutex_unlock(&sysfs_mutex); | 940 | mutex_unlock(&sysfs_mutex); |
941 | ret = filldir(dirent, name, len, filp->f_pos, ino, type); | ||
942 | mutex_lock(&sysfs_mutex); | ||
943 | if (ret < 0) | ||
944 | break; | ||
945 | } | ||
946 | mutex_unlock(&sysfs_mutex); | ||
947 | if ((filp->f_pos > 1) && !pos) { /* EOF */ | ||
948 | filp->f_pos = INT_MAX; | ||
949 | filp->private_data = NULL; | ||
883 | } | 950 | } |
884 | return 0; | 951 | return 0; |
885 | } | 952 | } |
@@ -888,5 +955,6 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
888 | const struct file_operations sysfs_dir_operations = { | 955 | const struct file_operations sysfs_dir_operations = { |
889 | .read = generic_read_dir, | 956 | .read = generic_read_dir, |
890 | .readdir = sysfs_readdir, | 957 | .readdir = sysfs_readdir, |
958 | .release = sysfs_dir_release, | ||
891 | .llseek = generic_file_llseek, | 959 | .llseek = generic_file_llseek, |
892 | }; | 960 | }; |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index dc30d9e31683..1beaa739d0a6 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -53,7 +53,7 @@ struct sysfs_buffer { | |||
53 | size_t count; | 53 | size_t count; |
54 | loff_t pos; | 54 | loff_t pos; |
55 | char * page; | 55 | char * page; |
56 | struct sysfs_ops * ops; | 56 | const struct sysfs_ops * ops; |
57 | struct mutex mutex; | 57 | struct mutex mutex; |
58 | int needs_read_fill; | 58 | int needs_read_fill; |
59 | int event; | 59 | int event; |
@@ -75,7 +75,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
75 | { | 75 | { |
76 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 76 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
77 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 77 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
78 | struct sysfs_ops * ops = buffer->ops; | 78 | const struct sysfs_ops * ops = buffer->ops; |
79 | int ret = 0; | 79 | int ret = 0; |
80 | ssize_t count; | 80 | ssize_t count; |
81 | 81 | ||
@@ -85,13 +85,13 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
85 | return -ENOMEM; | 85 | return -ENOMEM; |
86 | 86 | ||
87 | /* need attr_sd for attr and ops, its parent for kobj */ | 87 | /* need attr_sd for attr and ops, its parent for kobj */ |
88 | if (!sysfs_get_active_two(attr_sd)) | 88 | if (!sysfs_get_active(attr_sd)) |
89 | return -ENODEV; | 89 | return -ENODEV; |
90 | 90 | ||
91 | buffer->event = atomic_read(&attr_sd->s_attr.open->event); | 91 | buffer->event = atomic_read(&attr_sd->s_attr.open->event); |
92 | count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); | 92 | count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); |
93 | 93 | ||
94 | sysfs_put_active_two(attr_sd); | 94 | sysfs_put_active(attr_sd); |
95 | 95 | ||
96 | /* | 96 | /* |
97 | * The code works fine with PAGE_SIZE return but it's likely to | 97 | * The code works fine with PAGE_SIZE return but it's likely to |
@@ -199,16 +199,16 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t | |||
199 | { | 199 | { |
200 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; | 200 | struct sysfs_dirent *attr_sd = dentry->d_fsdata; |
201 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 201 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
202 | struct sysfs_ops * ops = buffer->ops; | 202 | const struct sysfs_ops * ops = buffer->ops; |
203 | int rc; | 203 | int rc; |
204 | 204 | ||
205 | /* need attr_sd for attr and ops, its parent for kobj */ | 205 | /* need attr_sd for attr and ops, its parent for kobj */ |
206 | if (!sysfs_get_active_two(attr_sd)) | 206 | if (!sysfs_get_active(attr_sd)) |
207 | return -ENODEV; | 207 | return -ENODEV; |
208 | 208 | ||
209 | rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); | 209 | rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); |
210 | 210 | ||
211 | sysfs_put_active_two(attr_sd); | 211 | sysfs_put_active(attr_sd); |
212 | 212 | ||
213 | return rc; | 213 | return rc; |
214 | } | 214 | } |
@@ -335,7 +335,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
335 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 335 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
336 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 336 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
337 | struct sysfs_buffer *buffer; | 337 | struct sysfs_buffer *buffer; |
338 | struct sysfs_ops *ops; | 338 | const struct sysfs_ops *ops; |
339 | int error = -EACCES; | 339 | int error = -EACCES; |
340 | char *p; | 340 | char *p; |
341 | 341 | ||
@@ -344,7 +344,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
344 | memmove(last_sysfs_file, p, strlen(p) + 1); | 344 | memmove(last_sysfs_file, p, strlen(p) + 1); |
345 | 345 | ||
346 | /* need attr_sd for attr and ops, its parent for kobj */ | 346 | /* need attr_sd for attr and ops, its parent for kobj */ |
347 | if (!sysfs_get_active_two(attr_sd)) | 347 | if (!sysfs_get_active(attr_sd)) |
348 | return -ENODEV; | 348 | return -ENODEV; |
349 | 349 | ||
350 | /* every kobject with an attribute needs a ktype assigned */ | 350 | /* every kobject with an attribute needs a ktype assigned */ |
@@ -393,13 +393,13 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
393 | goto err_free; | 393 | goto err_free; |
394 | 394 | ||
395 | /* open succeeded, put active references */ | 395 | /* open succeeded, put active references */ |
396 | sysfs_put_active_two(attr_sd); | 396 | sysfs_put_active(attr_sd); |
397 | return 0; | 397 | return 0; |
398 | 398 | ||
399 | err_free: | 399 | err_free: |
400 | kfree(buffer); | 400 | kfree(buffer); |
401 | err_out: | 401 | err_out: |
402 | sysfs_put_active_two(attr_sd); | 402 | sysfs_put_active(attr_sd); |
403 | return error; | 403 | return error; |
404 | } | 404 | } |
405 | 405 | ||
@@ -437,12 +437,12 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | |||
437 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; | 437 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; |
438 | 438 | ||
439 | /* need parent for the kobj, grab both */ | 439 | /* need parent for the kobj, grab both */ |
440 | if (!sysfs_get_active_two(attr_sd)) | 440 | if (!sysfs_get_active(attr_sd)) |
441 | goto trigger; | 441 | goto trigger; |
442 | 442 | ||
443 | poll_wait(filp, &od->poll, wait); | 443 | poll_wait(filp, &od->poll, wait); |
444 | 444 | ||
445 | sysfs_put_active_two(attr_sd); | 445 | sysfs_put_active(attr_sd); |
446 | 446 | ||
447 | if (buffer->event != atomic_read(&od->event)) | 447 | if (buffer->event != atomic_read(&od->event)) |
448 | goto trigger; | 448 | goto trigger; |
@@ -478,9 +478,12 @@ void sysfs_notify(struct kobject *k, const char *dir, const char *attr) | |||
478 | mutex_lock(&sysfs_mutex); | 478 | mutex_lock(&sysfs_mutex); |
479 | 479 | ||
480 | if (sd && dir) | 480 | if (sd && dir) |
481 | sd = sysfs_find_dirent(sd, dir); | 481 | /* Only directories are tagged, so no need to pass |
482 | * a tag explicitly. | ||
483 | */ | ||
484 | sd = sysfs_find_dirent(sd, NULL, dir); | ||
482 | if (sd && attr) | 485 | if (sd && attr) |
483 | sd = sysfs_find_dirent(sd, attr); | 486 | sd = sysfs_find_dirent(sd, NULL, attr); |
484 | if (sd) | 487 | if (sd) |
485 | sysfs_notify_dirent(sd); | 488 | sysfs_notify_dirent(sd); |
486 | 489 | ||
@@ -509,6 +512,7 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | |||
509 | if (!sd) | 512 | if (!sd) |
510 | return -ENOMEM; | 513 | return -ENOMEM; |
511 | sd->s_attr.attr = (void *)attr; | 514 | sd->s_attr.attr = (void *)attr; |
515 | sysfs_dirent_init_lockdep(sd); | ||
512 | 516 | ||
513 | sysfs_addrm_start(&acxt, dir_sd); | 517 | sysfs_addrm_start(&acxt, dir_sd); |
514 | rc = sysfs_add_one(&acxt, sd); | 518 | rc = sysfs_add_one(&acxt, sd); |
@@ -542,6 +546,18 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) | |||
542 | 546 | ||
543 | } | 547 | } |
544 | 548 | ||
549 | int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) | ||
550 | { | ||
551 | int err = 0; | ||
552 | int i; | ||
553 | |||
554 | for (i = 0; ptr[i] && !err; i++) | ||
555 | err = sysfs_create_file(kobj, ptr[i]); | ||
556 | if (err) | ||
557 | while (--i >= 0) | ||
558 | sysfs_remove_file(kobj, ptr[i]); | ||
559 | return err; | ||
560 | } | ||
545 | 561 | ||
546 | /** | 562 | /** |
547 | * sysfs_add_file_to_group - add an attribute file to a pre-existing group. | 563 | * sysfs_add_file_to_group - add an attribute file to a pre-existing group. |
@@ -556,7 +572,7 @@ int sysfs_add_file_to_group(struct kobject *kobj, | |||
556 | int error; | 572 | int error; |
557 | 573 | ||
558 | if (group) | 574 | if (group) |
559 | dir_sd = sysfs_get_dirent(kobj->sd, group); | 575 | dir_sd = sysfs_get_dirent(kobj->sd, NULL, group); |
560 | else | 576 | else |
561 | dir_sd = sysfs_get(kobj->sd); | 577 | dir_sd = sysfs_get(kobj->sd); |
562 | 578 | ||
@@ -586,7 +602,7 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) | |||
586 | mutex_lock(&sysfs_mutex); | 602 | mutex_lock(&sysfs_mutex); |
587 | 603 | ||
588 | rc = -ENOENT; | 604 | rc = -ENOENT; |
589 | sd = sysfs_find_dirent(kobj->sd, attr->name); | 605 | sd = sysfs_find_dirent(kobj->sd, NULL, attr->name); |
590 | if (!sd) | 606 | if (!sd) |
591 | goto out; | 607 | goto out; |
592 | 608 | ||
@@ -611,9 +627,15 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); | |||
611 | 627 | ||
612 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | 628 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) |
613 | { | 629 | { |
614 | sysfs_hash_and_remove(kobj->sd, attr->name); | 630 | sysfs_hash_and_remove(kobj->sd, NULL, attr->name); |
615 | } | 631 | } |
616 | 632 | ||
633 | void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr) | ||
634 | { | ||
635 | int i; | ||
636 | for (i = 0; ptr[i]; i++) | ||
637 | sysfs_remove_file(kobj, ptr[i]); | ||
638 | } | ||
617 | 639 | ||
618 | /** | 640 | /** |
619 | * sysfs_remove_file_from_group - remove an attribute file from a group. | 641 | * sysfs_remove_file_from_group - remove an attribute file from a group. |
@@ -627,11 +649,11 @@ void sysfs_remove_file_from_group(struct kobject *kobj, | |||
627 | struct sysfs_dirent *dir_sd; | 649 | struct sysfs_dirent *dir_sd; |
628 | 650 | ||
629 | if (group) | 651 | if (group) |
630 | dir_sd = sysfs_get_dirent(kobj->sd, group); | 652 | dir_sd = sysfs_get_dirent(kobj->sd, NULL, group); |
631 | else | 653 | else |
632 | dir_sd = sysfs_get(kobj->sd); | 654 | dir_sd = sysfs_get(kobj->sd); |
633 | if (dir_sd) { | 655 | if (dir_sd) { |
634 | sysfs_hash_and_remove(dir_sd, attr->name); | 656 | sysfs_hash_and_remove(dir_sd, NULL, attr->name); |
635 | sysfs_put(dir_sd); | 657 | sysfs_put(dir_sd); |
636 | } | 658 | } |
637 | } | 659 | } |
@@ -732,3 +754,5 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback); | |||
732 | 754 | ||
733 | EXPORT_SYMBOL_GPL(sysfs_create_file); | 755 | EXPORT_SYMBOL_GPL(sysfs_create_file); |
734 | EXPORT_SYMBOL_GPL(sysfs_remove_file); | 756 | EXPORT_SYMBOL_GPL(sysfs_remove_file); |
757 | EXPORT_SYMBOL_GPL(sysfs_remove_files); | ||
758 | EXPORT_SYMBOL_GPL(sysfs_create_files); | ||
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index fe611949a7f7..23c1e598792a 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
@@ -23,7 +23,7 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | |||
23 | int i; | 23 | int i; |
24 | 24 | ||
25 | for (i = 0, attr = grp->attrs; *attr; i++, attr++) | 25 | for (i = 0, attr = grp->attrs; *attr; i++, attr++) |
26 | sysfs_hash_and_remove(dir_sd, (*attr)->name); | 26 | sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name); |
27 | } | 27 | } |
28 | 28 | ||
29 | static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | 29 | static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, |
@@ -39,7 +39,7 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | |||
39 | * visibility. Do this by first removing then | 39 | * visibility. Do this by first removing then |
40 | * re-adding (if required) the file */ | 40 | * re-adding (if required) the file */ |
41 | if (update) | 41 | if (update) |
42 | sysfs_hash_and_remove(dir_sd, (*attr)->name); | 42 | sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name); |
43 | if (grp->is_visible) { | 43 | if (grp->is_visible) { |
44 | mode = grp->is_visible(kobj, *attr, i); | 44 | mode = grp->is_visible(kobj, *attr, i); |
45 | if (!mode) | 45 | if (!mode) |
@@ -132,7 +132,7 @@ void sysfs_remove_group(struct kobject * kobj, | |||
132 | struct sysfs_dirent *sd; | 132 | struct sysfs_dirent *sd; |
133 | 133 | ||
134 | if (grp->name) { | 134 | if (grp->name) { |
135 | sd = sysfs_get_dirent(dir_sd, grp->name); | 135 | sd = sysfs_get_dirent(dir_sd, NULL, grp->name); |
136 | if (!sd) { | 136 | if (!sd) { |
137 | WARN(!sd, KERN_WARNING "sysfs group %p not found for " | 137 | WARN(!sd, KERN_WARNING "sysfs group %p not found for " |
138 | "kobject '%s'\n", grp, kobject_name(kobj)); | 138 | "kobject '%s'\n", grp, kobject_name(kobj)); |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 220b758523ae..0835a3b70e03 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/slab.h> | ||
21 | #include <linux/xattr.h> | 22 | #include <linux/xattr.h> |
22 | #include <linux/security.h> | 23 | #include <linux/security.h> |
23 | #include "sysfs.h" | 24 | #include "sysfs.h" |
@@ -81,24 +82,23 @@ int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr) | |||
81 | if (!sd_attrs) | 82 | if (!sd_attrs) |
82 | return -ENOMEM; | 83 | return -ENOMEM; |
83 | sd->s_iattr = sd_attrs; | 84 | sd->s_iattr = sd_attrs; |
84 | } else { | 85 | } |
85 | /* attributes were changed at least once in past */ | 86 | /* attributes were changed at least once in past */ |
86 | iattrs = &sd_attrs->ia_iattr; | 87 | iattrs = &sd_attrs->ia_iattr; |
87 | 88 | ||
88 | if (ia_valid & ATTR_UID) | 89 | if (ia_valid & ATTR_UID) |
89 | iattrs->ia_uid = iattr->ia_uid; | 90 | iattrs->ia_uid = iattr->ia_uid; |
90 | if (ia_valid & ATTR_GID) | 91 | if (ia_valid & ATTR_GID) |
91 | iattrs->ia_gid = iattr->ia_gid; | 92 | iattrs->ia_gid = iattr->ia_gid; |
92 | if (ia_valid & ATTR_ATIME) | 93 | if (ia_valid & ATTR_ATIME) |
93 | iattrs->ia_atime = iattr->ia_atime; | 94 | iattrs->ia_atime = iattr->ia_atime; |
94 | if (ia_valid & ATTR_MTIME) | 95 | if (ia_valid & ATTR_MTIME) |
95 | iattrs->ia_mtime = iattr->ia_mtime; | 96 | iattrs->ia_mtime = iattr->ia_mtime; |
96 | if (ia_valid & ATTR_CTIME) | 97 | if (ia_valid & ATTR_CTIME) |
97 | iattrs->ia_ctime = iattr->ia_ctime; | 98 | iattrs->ia_ctime = iattr->ia_ctime; |
98 | if (ia_valid & ATTR_MODE) { | 99 | if (ia_valid & ATTR_MODE) { |
99 | umode_t mode = iattr->ia_mode; | 100 | umode_t mode = iattr->ia_mode; |
100 | iattrs->ia_mode = sd->s_mode = mode; | 101 | iattrs->ia_mode = sd->s_mode = mode; |
101 | } | ||
102 | } | 102 | } |
103 | return 0; | 103 | return 0; |
104 | } | 104 | } |
@@ -112,20 +112,20 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
112 | if (!sd) | 112 | if (!sd) |
113 | return -EINVAL; | 113 | return -EINVAL; |
114 | 114 | ||
115 | mutex_lock(&sysfs_mutex); | ||
115 | error = inode_change_ok(inode, iattr); | 116 | error = inode_change_ok(inode, iattr); |
116 | if (error) | 117 | if (error) |
117 | return error; | 118 | goto out; |
118 | |||
119 | iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */ | ||
120 | 119 | ||
121 | error = inode_setattr(inode, iattr); | 120 | error = sysfs_sd_setattr(sd, iattr); |
122 | if (error) | 121 | if (error) |
123 | return error; | 122 | goto out; |
124 | 123 | ||
125 | mutex_lock(&sysfs_mutex); | 124 | /* this ignores size changes */ |
126 | error = sysfs_sd_setattr(sd, iattr); | 125 | generic_setattr(inode, iattr); |
127 | mutex_unlock(&sysfs_mutex); | ||
128 | 126 | ||
127 | out: | ||
128 | mutex_unlock(&sysfs_mutex); | ||
129 | return error; | 129 | return error; |
130 | } | 130 | } |
131 | 131 | ||
@@ -284,6 +284,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
284 | 284 | ||
285 | /** | 285 | /** |
286 | * sysfs_get_inode - get inode for sysfs_dirent | 286 | * sysfs_get_inode - get inode for sysfs_dirent |
287 | * @sb: super block | ||
287 | * @sd: sysfs_dirent to allocate inode for | 288 | * @sd: sysfs_dirent to allocate inode for |
288 | * | 289 | * |
289 | * Get inode for @sd. If such inode doesn't exist, a new inode | 290 | * Get inode for @sd. If such inode doesn't exist, a new inode |
@@ -296,11 +297,11 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
296 | * RETURNS: | 297 | * RETURNS: |
297 | * Pointer to allocated inode on success, NULL on failure. | 298 | * Pointer to allocated inode on success, NULL on failure. |
298 | */ | 299 | */ |
299 | struct inode * sysfs_get_inode(struct sysfs_dirent *sd) | 300 | struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd) |
300 | { | 301 | { |
301 | struct inode *inode; | 302 | struct inode *inode; |
302 | 303 | ||
303 | inode = iget_locked(sysfs_sb, sd->s_ino); | 304 | inode = iget_locked(sb, sd->s_ino); |
304 | if (inode && (inode->i_state & I_NEW)) | 305 | if (inode && (inode->i_state & I_NEW)) |
305 | sysfs_init_inode(sd, inode); | 306 | sysfs_init_inode(sd, inode); |
306 | 307 | ||
@@ -323,7 +324,7 @@ void sysfs_delete_inode(struct inode *inode) | |||
323 | sysfs_put(sd); | 324 | sysfs_put(sd); |
324 | } | 325 | } |
325 | 326 | ||
326 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | 327 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name) |
327 | { | 328 | { |
328 | struct sysfs_addrm_cxt acxt; | 329 | struct sysfs_addrm_cxt acxt; |
329 | struct sysfs_dirent *sd; | 330 | struct sysfs_dirent *sd; |
@@ -333,7 +334,9 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | |||
333 | 334 | ||
334 | sysfs_addrm_start(&acxt, dir_sd); | 335 | sysfs_addrm_start(&acxt, dir_sd); |
335 | 336 | ||
336 | sd = sysfs_find_dirent(dir_sd, name); | 337 | sd = sysfs_find_dirent(dir_sd, ns, name); |
338 | if (sd && (sd->s_ns != ns)) | ||
339 | sd = NULL; | ||
337 | if (sd) | 340 | if (sd) |
338 | sysfs_remove_one(&acxt, sd); | 341 | sysfs_remove_one(&acxt, sd); |
339 | 342 | ||
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 49749955ccaf..281c0c9bc39f 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -18,12 +18,12 @@ | |||
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/magic.h> | 20 | #include <linux/magic.h> |
21 | #include <linux/slab.h> | ||
21 | 22 | ||
22 | #include "sysfs.h" | 23 | #include "sysfs.h" |
23 | 24 | ||
24 | 25 | ||
25 | static struct vfsmount *sysfs_mount; | 26 | static struct vfsmount *sysfs_mount; |
26 | struct super_block * sysfs_sb = NULL; | ||
27 | struct kmem_cache *sysfs_dir_cachep; | 27 | struct kmem_cache *sysfs_dir_cachep; |
28 | 28 | ||
29 | static const struct super_operations sysfs_ops = { | 29 | static const struct super_operations sysfs_ops = { |
@@ -35,7 +35,7 @@ static const struct super_operations sysfs_ops = { | |||
35 | struct sysfs_dirent sysfs_root = { | 35 | struct sysfs_dirent sysfs_root = { |
36 | .s_name = "", | 36 | .s_name = "", |
37 | .s_count = ATOMIC_INIT(1), | 37 | .s_count = ATOMIC_INIT(1), |
38 | .s_flags = SYSFS_DIR, | 38 | .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), |
39 | .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | 39 | .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, |
40 | .s_ino = 1, | 40 | .s_ino = 1, |
41 | }; | 41 | }; |
@@ -50,11 +50,10 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | |||
50 | sb->s_magic = SYSFS_MAGIC; | 50 | sb->s_magic = SYSFS_MAGIC; |
51 | sb->s_op = &sysfs_ops; | 51 | sb->s_op = &sysfs_ops; |
52 | sb->s_time_gran = 1; | 52 | sb->s_time_gran = 1; |
53 | sysfs_sb = sb; | ||
54 | 53 | ||
55 | /* get root inode, initialize and unlock it */ | 54 | /* get root inode, initialize and unlock it */ |
56 | mutex_lock(&sysfs_mutex); | 55 | mutex_lock(&sysfs_mutex); |
57 | inode = sysfs_get_inode(&sysfs_root); | 56 | inode = sysfs_get_inode(sb, &sysfs_root); |
58 | mutex_unlock(&sysfs_mutex); | 57 | mutex_unlock(&sysfs_mutex); |
59 | if (!inode) { | 58 | if (!inode) { |
60 | pr_debug("sysfs: could not get root inode\n"); | 59 | pr_debug("sysfs: could not get root inode\n"); |
@@ -73,18 +72,107 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | |||
73 | return 0; | 72 | return 0; |
74 | } | 73 | } |
75 | 74 | ||
75 | static int sysfs_test_super(struct super_block *sb, void *data) | ||
76 | { | ||
77 | struct sysfs_super_info *sb_info = sysfs_info(sb); | ||
78 | struct sysfs_super_info *info = data; | ||
79 | enum kobj_ns_type type; | ||
80 | int found = 1; | ||
81 | |||
82 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { | ||
83 | if (sb_info->ns[type] != info->ns[type]) | ||
84 | found = 0; | ||
85 | } | ||
86 | return found; | ||
87 | } | ||
88 | |||
89 | static int sysfs_set_super(struct super_block *sb, void *data) | ||
90 | { | ||
91 | int error; | ||
92 | error = set_anon_super(sb, data); | ||
93 | if (!error) | ||
94 | sb->s_fs_info = data; | ||
95 | return error; | ||
96 | } | ||
97 | |||
76 | static int sysfs_get_sb(struct file_system_type *fs_type, | 98 | static int sysfs_get_sb(struct file_system_type *fs_type, |
77 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 99 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) |
78 | { | 100 | { |
79 | return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt); | 101 | struct sysfs_super_info *info; |
102 | enum kobj_ns_type type; | ||
103 | struct super_block *sb; | ||
104 | int error; | ||
105 | |||
106 | error = -ENOMEM; | ||
107 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
108 | if (!info) | ||
109 | goto out; | ||
110 | |||
111 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) | ||
112 | info->ns[type] = kobj_ns_current(type); | ||
113 | |||
114 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info); | ||
115 | if (IS_ERR(sb) || sb->s_fs_info != info) | ||
116 | kfree(info); | ||
117 | if (IS_ERR(sb)) { | ||
118 | error = PTR_ERR(sb); | ||
119 | goto out; | ||
120 | } | ||
121 | if (!sb->s_root) { | ||
122 | sb->s_flags = flags; | ||
123 | error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); | ||
124 | if (error) { | ||
125 | deactivate_locked_super(sb); | ||
126 | goto out; | ||
127 | } | ||
128 | sb->s_flags |= MS_ACTIVE; | ||
129 | } | ||
130 | |||
131 | simple_set_mnt(mnt, sb); | ||
132 | error = 0; | ||
133 | out: | ||
134 | return error; | ||
135 | } | ||
136 | |||
137 | static void sysfs_kill_sb(struct super_block *sb) | ||
138 | { | ||
139 | struct sysfs_super_info *info = sysfs_info(sb); | ||
140 | |||
141 | /* Remove the superblock from fs_supers/s_instances | ||
142 | * so we can't find it, before freeing sysfs_super_info. | ||
143 | */ | ||
144 | kill_anon_super(sb); | ||
145 | kfree(info); | ||
80 | } | 146 | } |
81 | 147 | ||
82 | static struct file_system_type sysfs_fs_type = { | 148 | static struct file_system_type sysfs_fs_type = { |
83 | .name = "sysfs", | 149 | .name = "sysfs", |
84 | .get_sb = sysfs_get_sb, | 150 | .get_sb = sysfs_get_sb, |
85 | .kill_sb = kill_anon_super, | 151 | .kill_sb = sysfs_kill_sb, |
86 | }; | 152 | }; |
87 | 153 | ||
154 | void sysfs_exit_ns(enum kobj_ns_type type, const void *ns) | ||
155 | { | ||
156 | struct super_block *sb; | ||
157 | |||
158 | mutex_lock(&sysfs_mutex); | ||
159 | spin_lock(&sb_lock); | ||
160 | list_for_each_entry(sb, &sysfs_fs_type.fs_supers, s_instances) { | ||
161 | struct sysfs_super_info *info = sysfs_info(sb); | ||
162 | /* | ||
163 | * If we see a superblock on the fs_supers/s_instances | ||
164 | * list the unmount has not completed and sb->s_fs_info | ||
165 | * points to a valid struct sysfs_super_info. | ||
166 | */ | ||
167 | /* Ignore superblocks with the wrong ns */ | ||
168 | if (info->ns[type] != ns) | ||
169 | continue; | ||
170 | info->ns[type] = NULL; | ||
171 | } | ||
172 | spin_unlock(&sb_lock); | ||
173 | mutex_unlock(&sysfs_mutex); | ||
174 | } | ||
175 | |||
88 | int __init sysfs_init(void) | 176 | int __init sysfs_init(void) |
89 | { | 177 | { |
90 | int err = -ENOMEM; | 178 | int err = -ENOMEM; |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index c5eff49fa41b..a7ac78f8e67a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/gfp.h> | ||
14 | #include <linux/mount.h> | 15 | #include <linux/mount.h> |
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/kobject.h> | 17 | #include <linux/kobject.h> |
@@ -27,6 +28,7 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, | |||
27 | struct sysfs_dirent *target_sd = NULL; | 28 | struct sysfs_dirent *target_sd = NULL; |
28 | struct sysfs_dirent *sd = NULL; | 29 | struct sysfs_dirent *sd = NULL; |
29 | struct sysfs_addrm_cxt acxt; | 30 | struct sysfs_addrm_cxt acxt; |
31 | enum kobj_ns_type ns_type; | ||
30 | int error; | 32 | int error; |
31 | 33 | ||
32 | BUG_ON(!name); | 34 | BUG_ON(!name); |
@@ -57,14 +59,29 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, | |||
57 | if (!sd) | 59 | if (!sd) |
58 | goto out_put; | 60 | goto out_put; |
59 | 61 | ||
62 | ns_type = sysfs_ns_type(parent_sd); | ||
63 | if (ns_type) | ||
64 | sd->s_ns = target->ktype->namespace(target); | ||
60 | sd->s_symlink.target_sd = target_sd; | 65 | sd->s_symlink.target_sd = target_sd; |
61 | target_sd = NULL; /* reference is now owned by the symlink */ | 66 | target_sd = NULL; /* reference is now owned by the symlink */ |
62 | 67 | ||
63 | sysfs_addrm_start(&acxt, parent_sd); | 68 | sysfs_addrm_start(&acxt, parent_sd); |
64 | if (warn) | 69 | /* Symlinks must be between directories with the same ns_type */ |
65 | error = sysfs_add_one(&acxt, sd); | 70 | if (!ns_type || |
66 | else | 71 | (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { |
67 | 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 | } | ||
68 | sysfs_addrm_finish(&acxt); | 85 | sysfs_addrm_finish(&acxt); |
69 | 86 | ||
70 | if (error) | 87 | if (error) |
@@ -106,6 +123,26 @@ int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target, | |||
106 | } | 123 | } |
107 | 124 | ||
108 | /** | 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 | /** | ||
109 | * sysfs_remove_link - remove symlink in object's directory. | 146 | * sysfs_remove_link - remove symlink in object's directory. |
110 | * @kobj: object we're acting for. | 147 | * @kobj: object we're acting for. |
111 | * @name: name of the symlink to remove. | 148 | * @name: name of the symlink to remove. |
@@ -120,7 +157,52 @@ void sysfs_remove_link(struct kobject * kobj, const char * name) | |||
120 | else | 157 | else |
121 | parent_sd = kobj->sd; | 158 | parent_sd = kobj->sd; |
122 | 159 | ||
123 | sysfs_hash_and_remove(parent_sd, name); | 160 | sysfs_hash_and_remove(parent_sd, NULL, name); |
161 | } | ||
162 | |||
163 | /** | ||
164 | * sysfs_rename_link - rename symlink in object's directory. | ||
165 | * @kobj: object we're acting for. | ||
166 | * @targ: object we're pointing to. | ||
167 | * @old: previous name of the symlink. | ||
168 | * @new: new name of the symlink. | ||
169 | * | ||
170 | * A helper function for the common rename symlink idiom. | ||
171 | */ | ||
172 | int sysfs_rename_link(struct kobject *kobj, struct kobject *targ, | ||
173 | const char *old, const char *new) | ||
174 | { | ||
175 | struct sysfs_dirent *parent_sd, *sd = NULL; | ||
176 | const void *old_ns = NULL, *new_ns = NULL; | ||
177 | int result; | ||
178 | |||
179 | if (!kobj) | ||
180 | parent_sd = &sysfs_root; | ||
181 | else | ||
182 | parent_sd = kobj->sd; | ||
183 | |||
184 | if (targ->sd) | ||
185 | old_ns = targ->sd->s_ns; | ||
186 | |||
187 | result = -ENOENT; | ||
188 | sd = sysfs_get_dirent(parent_sd, old_ns, old); | ||
189 | if (!sd) | ||
190 | goto out; | ||
191 | |||
192 | result = -EINVAL; | ||
193 | if (sysfs_type(sd) != SYSFS_KOBJ_LINK) | ||
194 | goto out; | ||
195 | if (sd->s_symlink.target_sd->s_dir.kobj != targ) | ||
196 | goto out; | ||
197 | |||
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); | ||
202 | |||
203 | out: | ||
204 | sysfs_put(sd); | ||
205 | return result; | ||
124 | } | 206 | } |
125 | 207 | ||
126 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, | 208 | static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, |
@@ -222,3 +304,4 @@ const struct inode_operations sysfs_symlink_inode_operations = { | |||
222 | 304 | ||
223 | EXPORT_SYMBOL_GPL(sysfs_create_link); | 305 | EXPORT_SYMBOL_GPL(sysfs_create_link); |
224 | EXPORT_SYMBOL_GPL(sysfs_remove_link); | 306 | EXPORT_SYMBOL_GPL(sysfs_remove_link); |
307 | EXPORT_SYMBOL_GPL(sysfs_rename_link); | ||
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index cdd9377a6e06..6a13105b5594 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -58,6 +58,7 @@ struct sysfs_dirent { | |||
58 | struct sysfs_dirent *s_sibling; | 58 | struct sysfs_dirent *s_sibling; |
59 | const char *s_name; | 59 | const char *s_name; |
60 | 60 | ||
61 | const void *s_ns; /* namespace tag */ | ||
61 | union { | 62 | union { |
62 | struct sysfs_elem_dir s_dir; | 63 | struct sysfs_elem_dir s_dir; |
63 | struct sysfs_elem_symlink s_symlink; | 64 | struct sysfs_elem_symlink s_symlink; |
@@ -66,8 +67,8 @@ struct sysfs_dirent { | |||
66 | }; | 67 | }; |
67 | 68 | ||
68 | unsigned int s_flags; | 69 | unsigned int s_flags; |
70 | unsigned short s_mode; | ||
69 | ino_t s_ino; | 71 | ino_t s_ino; |
70 | umode_t s_mode; | ||
71 | struct sysfs_inode_attrs *s_iattr; | 72 | struct sysfs_inode_attrs *s_iattr; |
72 | }; | 73 | }; |
73 | 74 | ||
@@ -79,21 +80,38 @@ struct sysfs_dirent { | |||
79 | #define SYSFS_KOBJ_BIN_ATTR 0x0004 | 80 | #define SYSFS_KOBJ_BIN_ATTR 0x0004 |
80 | #define SYSFS_KOBJ_LINK 0x0008 | 81 | #define SYSFS_KOBJ_LINK 0x0008 |
81 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) | 82 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) |
83 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) | ||
82 | 84 | ||
83 | #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK | 85 | /* identify any namespace tag on sysfs_dirents */ |
84 | #define SYSFS_FLAG_REMOVED 0x0200 | 86 | #define SYSFS_NS_TYPE_MASK 0xff00 |
87 | #define SYSFS_NS_TYPE_SHIFT 8 | ||
88 | |||
89 | #define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK) | ||
90 | #define SYSFS_FLAG_REMOVED 0x020000 | ||
85 | 91 | ||
86 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | 92 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) |
87 | { | 93 | { |
88 | return sd->s_flags & SYSFS_TYPE_MASK; | 94 | return sd->s_flags & SYSFS_TYPE_MASK; |
89 | } | 95 | } |
90 | 96 | ||
97 | /* | ||
98 | * Return any namespace tags on this dirent. | ||
99 | * enum kobj_ns_type is defined in linux/kobject.h | ||
100 | */ | ||
101 | static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd) | ||
102 | { | ||
103 | return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT; | ||
104 | } | ||
105 | |||
91 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 106 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
92 | #define sysfs_dirent_init_lockdep(sd) \ | 107 | #define sysfs_dirent_init_lockdep(sd) \ |
93 | do { \ | 108 | do { \ |
94 | static struct lock_class_key __key; \ | 109 | struct attribute *attr = sd->s_attr.attr; \ |
110 | struct lock_class_key *key = attr->key; \ | ||
111 | if (!key) \ | ||
112 | key = &attr->skey; \ | ||
95 | \ | 113 | \ |
96 | lockdep_init_map(&sd->dep_map, "s_active", &__key, 0); \ | 114 | lockdep_init_map(&sd->dep_map, "s_active", key, 0); \ |
97 | } while(0) | 115 | } while(0) |
98 | #else | 116 | #else |
99 | #define sysfs_dirent_init_lockdep(sd) do {} while(0) | 117 | #define sysfs_dirent_init_lockdep(sd) do {} while(0) |
@@ -110,8 +128,17 @@ struct sysfs_addrm_cxt { | |||
110 | /* | 128 | /* |
111 | * mount.c | 129 | * mount.c |
112 | */ | 130 | */ |
131 | |||
132 | /* | ||
133 | * Each sb is associated with a set of namespace tags (i.e. | ||
134 | * the network namespace of the task which mounted this sysfs | ||
135 | * instance). | ||
136 | */ | ||
137 | struct sysfs_super_info { | ||
138 | const void *ns[KOBJ_NS_TYPES]; | ||
139 | }; | ||
140 | #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) | ||
113 | extern struct sysfs_dirent sysfs_root; | 141 | extern struct sysfs_dirent sysfs_root; |
114 | extern struct super_block *sysfs_sb; | ||
115 | extern struct kmem_cache *sysfs_dir_cachep; | 142 | extern struct kmem_cache *sysfs_dir_cachep; |
116 | 143 | ||
117 | /* | 144 | /* |
@@ -124,8 +151,8 @@ extern const struct file_operations sysfs_dir_operations; | |||
124 | extern const struct inode_operations sysfs_dir_inode_operations; | 151 | extern const struct inode_operations sysfs_dir_inode_operations; |
125 | 152 | ||
126 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); | 153 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); |
127 | struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); | 154 | struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); |
128 | void sysfs_put_active_two(struct sysfs_dirent *sd); | 155 | void sysfs_put_active(struct sysfs_dirent *sd); |
129 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | 156 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, |
130 | struct sysfs_dirent *parent_sd); | 157 | struct sysfs_dirent *parent_sd); |
131 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); | 158 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); |
@@ -134,8 +161,10 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); | |||
134 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); | 161 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); |
135 | 162 | ||
136 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | 163 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, |
164 | const void *ns, | ||
137 | const unsigned char *name); | 165 | const unsigned char *name); |
138 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | 166 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, |
167 | const void *ns, | ||
139 | const unsigned char *name); | 168 | const unsigned char *name); |
140 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); | 169 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); |
141 | 170 | ||
@@ -146,7 +175,7 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, | |||
146 | void sysfs_remove_subdir(struct sysfs_dirent *sd); | 175 | void sysfs_remove_subdir(struct sysfs_dirent *sd); |
147 | 176 | ||
148 | int sysfs_rename(struct sysfs_dirent *sd, | 177 | int sysfs_rename(struct sysfs_dirent *sd, |
149 | struct sysfs_dirent *new_parent_sd, const char *new_name); | 178 | struct sysfs_dirent *new_parent_sd, const void *ns, const char *new_name); |
150 | 179 | ||
151 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) | 180 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) |
152 | { | 181 | { |
@@ -168,7 +197,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) | |||
168 | /* | 197 | /* |
169 | * inode.c | 198 | * inode.c |
170 | */ | 199 | */ |
171 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); | 200 | struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); |
172 | void sysfs_delete_inode(struct inode *inode); | 201 | void sysfs_delete_inode(struct inode *inode); |
173 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); | 202 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); |
174 | int sysfs_permission(struct inode *inode, int mask); | 203 | int sysfs_permission(struct inode *inode, int mask); |
@@ -176,7 +205,7 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | |||
176 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); | 205 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); |
177 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 206 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
178 | size_t size, int flags); | 207 | size_t size, int flags); |
179 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | 208 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name); |
180 | int sysfs_inode_init(void); | 209 | int sysfs_inode_init(void); |
181 | 210 | ||
182 | /* | 211 | /* |