diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/Kconfig | 1 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 44 | ||||
-rw-r--r-- | fs/sysfs/file.c | 115 | ||||
-rw-r--r-- | fs/sysfs/group.c | 7 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 2 |
5 files changed, 43 insertions, 126 deletions
diff --git a/fs/sysfs/Kconfig b/fs/sysfs/Kconfig index 8c41feacbac5..b2756014508c 100644 --- a/fs/sysfs/Kconfig +++ b/fs/sysfs/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config SYSFS | 1 | config SYSFS |
2 | bool "sysfs file system support" if EXPERT | 2 | bool "sysfs file system support" if EXPERT |
3 | default y | 3 | default y |
4 | select KERNFS | ||
4 | help | 5 | help |
5 | The sysfs filesystem is a virtual filesystem that the kernel uses to | 6 | The sysfs filesystem is a virtual filesystem that the kernel uses to |
6 | export internal kernel objects, their attributes, and their | 7 | export internal kernel objects, their attributes, and their |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index ee0d761c3179..0b45ff42f374 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -19,39 +19,18 @@ | |||
19 | 19 | ||
20 | DEFINE_SPINLOCK(sysfs_symlink_target_lock); | 20 | DEFINE_SPINLOCK(sysfs_symlink_target_lock); |
21 | 21 | ||
22 | /** | ||
23 | * sysfs_pathname - return full path to sysfs dirent | ||
24 | * @kn: kernfs_node whose path we want | ||
25 | * @path: caller allocated buffer of size PATH_MAX | ||
26 | * | ||
27 | * Gives the name "/" to the sysfs_root entry; any path returned | ||
28 | * is relative to wherever sysfs is mounted. | ||
29 | */ | ||
30 | static char *sysfs_pathname(struct kernfs_node *kn, char *path) | ||
31 | { | ||
32 | if (kn->parent) { | ||
33 | sysfs_pathname(kn->parent, path); | ||
34 | strlcat(path, "/", PATH_MAX); | ||
35 | } | ||
36 | strlcat(path, kn->name, PATH_MAX); | ||
37 | return path; | ||
38 | } | ||
39 | |||
40 | void sysfs_warn_dup(struct kernfs_node *parent, const char *name) | 22 | void sysfs_warn_dup(struct kernfs_node *parent, const char *name) |
41 | { | 23 | { |
42 | char *path; | 24 | char *buf, *path = NULL; |
43 | 25 | ||
44 | path = kzalloc(PATH_MAX, GFP_KERNEL); | 26 | buf = kzalloc(PATH_MAX, GFP_KERNEL); |
45 | if (path) { | 27 | if (buf) |
46 | sysfs_pathname(parent, path); | 28 | path = kernfs_path(parent, buf, PATH_MAX); |
47 | strlcat(path, "/", PATH_MAX); | ||
48 | strlcat(path, name, PATH_MAX); | ||
49 | } | ||
50 | 29 | ||
51 | WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n", | 30 | WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s/%s'\n", |
52 | path ? path : name); | 31 | path, name); |
53 | 32 | ||
54 | kfree(path); | 33 | kfree(buf); |
55 | } | 34 | } |
56 | 35 | ||
57 | /** | 36 | /** |
@@ -122,9 +101,13 @@ void sysfs_remove_dir(struct kobject *kobj) | |||
122 | int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, | 101 | int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, |
123 | const void *new_ns) | 102 | const void *new_ns) |
124 | { | 103 | { |
125 | struct kernfs_node *parent = kobj->sd->parent; | 104 | struct kernfs_node *parent; |
105 | int ret; | ||
126 | 106 | ||
127 | return kernfs_rename_ns(kobj->sd, parent, new_name, new_ns); | 107 | parent = kernfs_get_parent(kobj->sd); |
108 | ret = kernfs_rename_ns(kobj->sd, parent, new_name, new_ns); | ||
109 | kernfs_put(parent); | ||
110 | return ret; | ||
128 | } | 111 | } |
129 | 112 | ||
130 | int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, | 113 | int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, |
@@ -133,7 +116,6 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, | |||
133 | struct kernfs_node *kn = kobj->sd; | 116 | struct kernfs_node *kn = kobj->sd; |
134 | struct kernfs_node *new_parent; | 117 | struct kernfs_node *new_parent; |
135 | 118 | ||
136 | BUG_ON(!kn->parent); | ||
137 | new_parent = new_parent_kobj && new_parent_kobj->sd ? | 119 | new_parent = new_parent_kobj && new_parent_kobj->sd ? |
138 | new_parent_kobj->sd : sysfs_root_kn; | 120 | new_parent_kobj->sd : sysfs_root_kn; |
139 | 121 | ||
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 810cf6e613e5..28cc1acd5439 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -372,6 +372,29 @@ void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, | |||
372 | } | 372 | } |
373 | EXPORT_SYMBOL_GPL(sysfs_remove_file_ns); | 373 | EXPORT_SYMBOL_GPL(sysfs_remove_file_ns); |
374 | 374 | ||
375 | /** | ||
376 | * sysfs_remove_file_self - remove an object attribute from its own method | ||
377 | * @kobj: object we're acting for | ||
378 | * @attr: attribute descriptor | ||
379 | * | ||
380 | * See kernfs_remove_self() for details. | ||
381 | */ | ||
382 | bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr) | ||
383 | { | ||
384 | struct kernfs_node *parent = kobj->sd; | ||
385 | struct kernfs_node *kn; | ||
386 | bool ret; | ||
387 | |||
388 | kn = kernfs_find_and_get(parent, attr->name); | ||
389 | if (WARN_ON_ONCE(!kn)) | ||
390 | return false; | ||
391 | |||
392 | ret = kernfs_remove_self(kn); | ||
393 | |||
394 | kernfs_put(kn); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
375 | void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr) | 398 | void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr) |
376 | { | 399 | { |
377 | int i; | 400 | int i; |
@@ -430,95 +453,3 @@ void sysfs_remove_bin_file(struct kobject *kobj, | |||
430 | kernfs_remove_by_name(kobj->sd, attr->attr.name); | 453 | kernfs_remove_by_name(kobj->sd, attr->attr.name); |
431 | } | 454 | } |
432 | EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); | 455 | EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); |
433 | |||
434 | struct sysfs_schedule_callback_struct { | ||
435 | struct list_head workq_list; | ||
436 | struct kobject *kobj; | ||
437 | void (*func)(void *); | ||
438 | void *data; | ||
439 | struct module *owner; | ||
440 | struct work_struct work; | ||
441 | }; | ||
442 | |||
443 | static struct workqueue_struct *sysfs_workqueue; | ||
444 | static DEFINE_MUTEX(sysfs_workq_mutex); | ||
445 | static LIST_HEAD(sysfs_workq); | ||
446 | static void sysfs_schedule_callback_work(struct work_struct *work) | ||
447 | { | ||
448 | struct sysfs_schedule_callback_struct *ss = container_of(work, | ||
449 | struct sysfs_schedule_callback_struct, work); | ||
450 | |||
451 | (ss->func)(ss->data); | ||
452 | kobject_put(ss->kobj); | ||
453 | module_put(ss->owner); | ||
454 | mutex_lock(&sysfs_workq_mutex); | ||
455 | list_del(&ss->workq_list); | ||
456 | mutex_unlock(&sysfs_workq_mutex); | ||
457 | kfree(ss); | ||
458 | } | ||
459 | |||
460 | /** | ||
461 | * sysfs_schedule_callback - helper to schedule a callback for a kobject | ||
462 | * @kobj: object we're acting for. | ||
463 | * @func: callback function to invoke later. | ||
464 | * @data: argument to pass to @func. | ||
465 | * @owner: module owning the callback code | ||
466 | * | ||
467 | * sysfs attribute methods must not unregister themselves or their parent | ||
468 | * kobject (which would amount to the same thing). Attempts to do so will | ||
469 | * deadlock, since unregistration is mutually exclusive with driver | ||
470 | * callbacks. | ||
471 | * | ||
472 | * Instead methods can call this routine, which will attempt to allocate | ||
473 | * and schedule a workqueue request to call back @func with @data as its | ||
474 | * argument in the workqueue's process context. @kobj will be pinned | ||
475 | * until @func returns. | ||
476 | * | ||
477 | * Returns 0 if the request was submitted, -ENOMEM if storage could not | ||
478 | * be allocated, -ENODEV if a reference to @owner isn't available, | ||
479 | * -EAGAIN if a callback has already been scheduled for @kobj. | ||
480 | */ | ||
481 | int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), | ||
482 | void *data, struct module *owner) | ||
483 | { | ||
484 | struct sysfs_schedule_callback_struct *ss, *tmp; | ||
485 | |||
486 | if (!try_module_get(owner)) | ||
487 | return -ENODEV; | ||
488 | |||
489 | mutex_lock(&sysfs_workq_mutex); | ||
490 | list_for_each_entry_safe(ss, tmp, &sysfs_workq, workq_list) | ||
491 | if (ss->kobj == kobj) { | ||
492 | module_put(owner); | ||
493 | mutex_unlock(&sysfs_workq_mutex); | ||
494 | return -EAGAIN; | ||
495 | } | ||
496 | mutex_unlock(&sysfs_workq_mutex); | ||
497 | |||
498 | if (sysfs_workqueue == NULL) { | ||
499 | sysfs_workqueue = create_singlethread_workqueue("sysfsd"); | ||
500 | if (sysfs_workqueue == NULL) { | ||
501 | module_put(owner); | ||
502 | return -ENOMEM; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | ss = kmalloc(sizeof(*ss), GFP_KERNEL); | ||
507 | if (!ss) { | ||
508 | module_put(owner); | ||
509 | return -ENOMEM; | ||
510 | } | ||
511 | kobject_get(kobj); | ||
512 | ss->kobj = kobj; | ||
513 | ss->func = func; | ||
514 | ss->data = data; | ||
515 | ss->owner = owner; | ||
516 | INIT_WORK(&ss->work, sysfs_schedule_callback_work); | ||
517 | INIT_LIST_HEAD(&ss->workq_list); | ||
518 | mutex_lock(&sysfs_workq_mutex); | ||
519 | list_add_tail(&ss->workq_list, &sysfs_workq); | ||
520 | mutex_unlock(&sysfs_workq_mutex); | ||
521 | queue_work(sysfs_workqueue, &ss->work); | ||
522 | return 0; | ||
523 | } | ||
524 | EXPORT_SYMBOL_GPL(sysfs_schedule_callback); | ||
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 6b579387c67a..aa0406895b53 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
@@ -70,8 +70,11 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj, | |||
70 | if (grp->bin_attrs) { | 70 | if (grp->bin_attrs) { |
71 | for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) { | 71 | for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) { |
72 | if (update) | 72 | if (update) |
73 | sysfs_remove_bin_file(kobj, *bin_attr); | 73 | kernfs_remove_by_name(parent, |
74 | error = sysfs_create_bin_file(kobj, *bin_attr); | 74 | (*bin_attr)->attr.name); |
75 | error = sysfs_add_file_mode_ns(parent, | ||
76 | &(*bin_attr)->attr, true, | ||
77 | (*bin_attr)->attr.mode, NULL); | ||
75 | if (error) | 78 | if (error) |
76 | break; | 79 | break; |
77 | } | 80 | } |
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 3eaf5c6622eb..a66ad6196f59 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -63,7 +63,7 @@ int __init sysfs_init(void) | |||
63 | { | 63 | { |
64 | int err; | 64 | int err; |
65 | 65 | ||
66 | sysfs_root = kernfs_create_root(NULL, NULL); | 66 | sysfs_root = kernfs_create_root(NULL, 0, NULL); |
67 | if (IS_ERR(sysfs_root)) | 67 | if (IS_ERR(sysfs_root)) |
68 | return PTR_ERR(sysfs_root); | 68 | return PTR_ERR(sysfs_root); |
69 | 69 | ||