diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/Makefile | 2 | ||||
| -rw-r--r-- | kernel/module.c | 5 | ||||
| -rw-r--r-- | kernel/slow-work-debugfs.c (renamed from kernel/slow-work-proc.c) | 4 | ||||
| -rw-r--r-- | kernel/slow-work.c | 64 | ||||
| -rw-r--r-- | kernel/slow-work.h | 6 |
5 files changed, 51 insertions, 30 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index 776ffed1556d..d7c13d249b2d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
| @@ -94,7 +94,7 @@ obj-$(CONFIG_X86_DS) += trace/ | |||
| 94 | obj-$(CONFIG_RING_BUFFER) += trace/ | 94 | obj-$(CONFIG_RING_BUFFER) += trace/ |
| 95 | obj-$(CONFIG_SMP) += sched_cpupri.o | 95 | obj-$(CONFIG_SMP) += sched_cpupri.o |
| 96 | obj-$(CONFIG_SLOW_WORK) += slow-work.o | 96 | obj-$(CONFIG_SLOW_WORK) += slow-work.o |
| 97 | obj-$(CONFIG_SLOW_WORK_PROC) += slow-work-proc.o | 97 | obj-$(CONFIG_SLOW_WORK_DEBUG) += slow-work-debugfs.o |
| 98 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o | 98 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o |
| 99 | 99 | ||
| 100 | ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) | 100 | ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) |
diff --git a/kernel/module.c b/kernel/module.c index 8b7d8805819d..5842a71cf052 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -1187,7 +1187,8 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, | |||
| 1187 | 1187 | ||
| 1188 | /* Count loaded sections and allocate structures */ | 1188 | /* Count loaded sections and allocate structures */ |
| 1189 | for (i = 0; i < nsect; i++) | 1189 | for (i = 0; i < nsect; i++) |
| 1190 | if (sechdrs[i].sh_flags & SHF_ALLOC) | 1190 | if (sechdrs[i].sh_flags & SHF_ALLOC |
| 1191 | && sechdrs[i].sh_size) | ||
| 1191 | nloaded++; | 1192 | nloaded++; |
| 1192 | size[0] = ALIGN(sizeof(*sect_attrs) | 1193 | size[0] = ALIGN(sizeof(*sect_attrs) |
| 1193 | + nloaded * sizeof(sect_attrs->attrs[0]), | 1194 | + nloaded * sizeof(sect_attrs->attrs[0]), |
| @@ -1207,6 +1208,8 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, | |||
| 1207 | for (i = 0; i < nsect; i++) { | 1208 | for (i = 0; i < nsect; i++) { |
| 1208 | if (! (sechdrs[i].sh_flags & SHF_ALLOC)) | 1209 | if (! (sechdrs[i].sh_flags & SHF_ALLOC)) |
| 1209 | continue; | 1210 | continue; |
| 1211 | if (!sechdrs[i].sh_size) | ||
| 1212 | continue; | ||
| 1210 | sattr->address = sechdrs[i].sh_addr; | 1213 | sattr->address = sechdrs[i].sh_addr; |
| 1211 | sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, | 1214 | sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, |
| 1212 | GFP_KERNEL); | 1215 | GFP_KERNEL); |
diff --git a/kernel/slow-work-proc.c b/kernel/slow-work-debugfs.c index 3988032571f5..e45c43645298 100644 --- a/kernel/slow-work-proc.c +++ b/kernel/slow-work-debugfs.c | |||
| @@ -57,7 +57,7 @@ static void slow_work_print_mark(struct seq_file *m, struct slow_work *work) | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | /* | 59 | /* |
| 60 | * Describe a slow work item for /proc | 60 | * Describe a slow work item for debugfs |
| 61 | */ | 61 | */ |
| 62 | static int slow_work_runqueue_show(struct seq_file *m, void *v) | 62 | static int slow_work_runqueue_show(struct seq_file *m, void *v) |
| 63 | { | 63 | { |
| @@ -211,7 +211,7 @@ static const struct seq_operations slow_work_runqueue_ops = { | |||
| 211 | }; | 211 | }; |
| 212 | 212 | ||
| 213 | /* | 213 | /* |
| 214 | * open "/proc/slow_work_rq" to list queue contents | 214 | * open "/sys/kernel/debug/slow_work/runqueue" to list queue contents |
| 215 | */ | 215 | */ |
| 216 | static int slow_work_runqueue_open(struct inode *inode, struct file *file) | 216 | static int slow_work_runqueue_open(struct inode *inode, struct file *file) |
| 217 | { | 217 | { |
diff --git a/kernel/slow-work.c b/kernel/slow-work.c index da94f3c101af..00889bd3c590 100644 --- a/kernel/slow-work.c +++ b/kernel/slow-work.c | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | #include <linux/kthread.h> | 16 | #include <linux/kthread.h> |
| 17 | #include <linux/freezer.h> | 17 | #include <linux/freezer.h> |
| 18 | #include <linux/wait.h> | 18 | #include <linux/wait.h> |
| 19 | #include <linux/proc_fs.h> | 19 | #include <linux/debugfs.h> |
| 20 | #include "slow-work.h" | 20 | #include "slow-work.h" |
| 21 | 21 | ||
| 22 | static void slow_work_cull_timeout(unsigned long); | 22 | static void slow_work_cull_timeout(unsigned long); |
| @@ -109,12 +109,36 @@ static struct module *slow_work_unreg_module; | |||
| 109 | static struct slow_work *slow_work_unreg_work_item; | 109 | static struct slow_work *slow_work_unreg_work_item; |
| 110 | static DECLARE_WAIT_QUEUE_HEAD(slow_work_unreg_wq); | 110 | static DECLARE_WAIT_QUEUE_HEAD(slow_work_unreg_wq); |
| 111 | static DEFINE_MUTEX(slow_work_unreg_sync_lock); | 111 | static DEFINE_MUTEX(slow_work_unreg_sync_lock); |
| 112 | |||
| 113 | static void slow_work_set_thread_processing(int id, struct slow_work *work) | ||
| 114 | { | ||
| 115 | if (work) | ||
| 116 | slow_work_thread_processing[id] = work->owner; | ||
| 117 | } | ||
| 118 | static void slow_work_done_thread_processing(int id, struct slow_work *work) | ||
| 119 | { | ||
| 120 | struct module *module = slow_work_thread_processing[id]; | ||
| 121 | |||
| 122 | slow_work_thread_processing[id] = NULL; | ||
| 123 | smp_mb(); | ||
| 124 | if (slow_work_unreg_work_item == work || | ||
| 125 | slow_work_unreg_module == module) | ||
| 126 | wake_up_all(&slow_work_unreg_wq); | ||
| 127 | } | ||
| 128 | static void slow_work_clear_thread_processing(int id) | ||
| 129 | { | ||
| 130 | slow_work_thread_processing[id] = NULL; | ||
| 131 | } | ||
| 132 | #else | ||
| 133 | static void slow_work_set_thread_processing(int id, struct slow_work *work) {} | ||
| 134 | static void slow_work_done_thread_processing(int id, struct slow_work *work) {} | ||
| 135 | static void slow_work_clear_thread_processing(int id) {} | ||
| 112 | #endif | 136 | #endif |
| 113 | 137 | ||
| 114 | /* | 138 | /* |
| 115 | * Data for tracking currently executing items for indication through /proc | 139 | * Data for tracking currently executing items for indication through /proc |
| 116 | */ | 140 | */ |
| 117 | #ifdef CONFIG_SLOW_WORK_PROC | 141 | #ifdef CONFIG_SLOW_WORK_DEBUG |
| 118 | struct slow_work *slow_work_execs[SLOW_WORK_THREAD_LIMIT]; | 142 | struct slow_work *slow_work_execs[SLOW_WORK_THREAD_LIMIT]; |
| 119 | pid_t slow_work_pids[SLOW_WORK_THREAD_LIMIT]; | 143 | pid_t slow_work_pids[SLOW_WORK_THREAD_LIMIT]; |
| 120 | DEFINE_RWLOCK(slow_work_execs_lock); | 144 | DEFINE_RWLOCK(slow_work_execs_lock); |
| @@ -197,9 +221,6 @@ static unsigned slow_work_calc_vsmax(void) | |||
| 197 | */ | 221 | */ |
| 198 | static noinline bool slow_work_execute(int id) | 222 | static noinline bool slow_work_execute(int id) |
| 199 | { | 223 | { |
| 200 | #ifdef CONFIG_MODULES | ||
| 201 | struct module *module; | ||
| 202 | #endif | ||
| 203 | struct slow_work *work = NULL; | 224 | struct slow_work *work = NULL; |
| 204 | unsigned vsmax; | 225 | unsigned vsmax; |
| 205 | bool very_slow; | 226 | bool very_slow; |
| @@ -236,10 +257,7 @@ static noinline bool slow_work_execute(int id) | |||
| 236 | very_slow = false; /* avoid the compiler warning */ | 257 | very_slow = false; /* avoid the compiler warning */ |
| 237 | } | 258 | } |
| 238 | 259 | ||
| 239 | #ifdef CONFIG_MODULES | 260 | slow_work_set_thread_processing(id, work); |
| 240 | if (work) | ||
| 241 | slow_work_thread_processing[id] = work->owner; | ||
| 242 | #endif | ||
| 243 | if (work) { | 261 | if (work) { |
| 244 | slow_work_mark_time(work); | 262 | slow_work_mark_time(work); |
| 245 | slow_work_begin_exec(id, work); | 263 | slow_work_begin_exec(id, work); |
| @@ -287,15 +305,7 @@ static noinline bool slow_work_execute(int id) | |||
| 287 | 305 | ||
| 288 | /* sort out the race between module unloading and put_ref() */ | 306 | /* sort out the race between module unloading and put_ref() */ |
| 289 | slow_work_put_ref(work); | 307 | slow_work_put_ref(work); |
| 290 | 308 | slow_work_done_thread_processing(id, work); | |
| 291 | #ifdef CONFIG_MODULES | ||
| 292 | module = slow_work_thread_processing[id]; | ||
| 293 | slow_work_thread_processing[id] = NULL; | ||
| 294 | smp_mb(); | ||
| 295 | if (slow_work_unreg_work_item == work || | ||
| 296 | slow_work_unreg_module == module) | ||
| 297 | wake_up_all(&slow_work_unreg_wq); | ||
| 298 | #endif | ||
| 299 | 309 | ||
| 300 | return true; | 310 | return true; |
| 301 | 311 | ||
| @@ -310,7 +320,7 @@ auto_requeue: | |||
| 310 | else | 320 | else |
| 311 | list_add_tail(&work->link, &slow_work_queue); | 321 | list_add_tail(&work->link, &slow_work_queue); |
| 312 | spin_unlock_irq(&slow_work_queue_lock); | 322 | spin_unlock_irq(&slow_work_queue_lock); |
| 313 | slow_work_thread_processing[id] = NULL; | 323 | slow_work_clear_thread_processing(id); |
| 314 | return true; | 324 | return true; |
| 315 | } | 325 | } |
| 316 | 326 | ||
| @@ -813,7 +823,7 @@ static void slow_work_new_thread_execute(struct slow_work *work) | |||
| 813 | static const struct slow_work_ops slow_work_new_thread_ops = { | 823 | static const struct slow_work_ops slow_work_new_thread_ops = { |
| 814 | .owner = THIS_MODULE, | 824 | .owner = THIS_MODULE, |
| 815 | .execute = slow_work_new_thread_execute, | 825 | .execute = slow_work_new_thread_execute, |
| 816 | #ifdef CONFIG_SLOW_WORK_PROC | 826 | #ifdef CONFIG_SLOW_WORK_DEBUG |
| 817 | .desc = slow_work_new_thread_desc, | 827 | .desc = slow_work_new_thread_desc, |
| 818 | #endif | 828 | #endif |
| 819 | }; | 829 | }; |
| @@ -943,6 +953,7 @@ EXPORT_SYMBOL(slow_work_register_user); | |||
| 943 | */ | 953 | */ |
| 944 | static void slow_work_wait_for_items(struct module *module) | 954 | static void slow_work_wait_for_items(struct module *module) |
| 945 | { | 955 | { |
| 956 | #ifdef CONFIG_MODULES | ||
| 946 | DECLARE_WAITQUEUE(myself, current); | 957 | DECLARE_WAITQUEUE(myself, current); |
| 947 | struct slow_work *work; | 958 | struct slow_work *work; |
| 948 | int loop; | 959 | int loop; |
| @@ -989,6 +1000,7 @@ static void slow_work_wait_for_items(struct module *module) | |||
| 989 | 1000 | ||
| 990 | remove_wait_queue(&slow_work_unreg_wq, &myself); | 1001 | remove_wait_queue(&slow_work_unreg_wq, &myself); |
| 991 | mutex_unlock(&slow_work_unreg_sync_lock); | 1002 | mutex_unlock(&slow_work_unreg_sync_lock); |
| 1003 | #endif /* CONFIG_MODULES */ | ||
| 992 | } | 1004 | } |
| 993 | 1005 | ||
| 994 | /** | 1006 | /** |
| @@ -1043,9 +1055,15 @@ static int __init init_slow_work(void) | |||
| 1043 | if (slow_work_max_max_threads < nr_cpus * 2) | 1055 | if (slow_work_max_max_threads < nr_cpus * 2) |
| 1044 | slow_work_max_max_threads = nr_cpus * 2; | 1056 | slow_work_max_max_threads = nr_cpus * 2; |
| 1045 | #endif | 1057 | #endif |
| 1046 | #ifdef CONFIG_SLOW_WORK_PROC | 1058 | #ifdef CONFIG_SLOW_WORK_DEBUG |
| 1047 | proc_create("slow_work_rq", S_IFREG | 0400, NULL, | 1059 | { |
| 1048 | &slow_work_runqueue_fops); | 1060 | struct dentry *dbdir; |
| 1061 | |||
| 1062 | dbdir = debugfs_create_dir("slow_work", NULL); | ||
| 1063 | if (dbdir && !IS_ERR(dbdir)) | ||
| 1064 | debugfs_create_file("runqueue", S_IFREG | 0400, dbdir, | ||
| 1065 | NULL, &slow_work_runqueue_fops); | ||
| 1066 | } | ||
| 1049 | #endif | 1067 | #endif |
| 1050 | return 0; | 1068 | return 0; |
| 1051 | } | 1069 | } |
diff --git a/kernel/slow-work.h b/kernel/slow-work.h index 3c2f007f3ad6..321f3c59d732 100644 --- a/kernel/slow-work.h +++ b/kernel/slow-work.h | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | /* | 19 | /* |
| 20 | * slow-work.c | 20 | * slow-work.c |
| 21 | */ | 21 | */ |
| 22 | #ifdef CONFIG_SLOW_WORK_PROC | 22 | #ifdef CONFIG_SLOW_WORK_DEBUG |
| 23 | extern struct slow_work *slow_work_execs[]; | 23 | extern struct slow_work *slow_work_execs[]; |
| 24 | extern pid_t slow_work_pids[]; | 24 | extern pid_t slow_work_pids[]; |
| 25 | extern rwlock_t slow_work_execs_lock; | 25 | extern rwlock_t slow_work_execs_lock; |
| @@ -30,9 +30,9 @@ extern struct list_head vslow_work_queue; | |||
| 30 | extern spinlock_t slow_work_queue_lock; | 30 | extern spinlock_t slow_work_queue_lock; |
| 31 | 31 | ||
| 32 | /* | 32 | /* |
| 33 | * slow-work-proc.c | 33 | * slow-work-debugfs.c |
| 34 | */ | 34 | */ |
| 35 | #ifdef CONFIG_SLOW_WORK_PROC | 35 | #ifdef CONFIG_SLOW_WORK_DEBUG |
| 36 | extern const struct file_operations slow_work_runqueue_fops; | 36 | extern const struct file_operations slow_work_runqueue_fops; |
| 37 | 37 | ||
| 38 | extern void slow_work_new_thread_desc(struct slow_work *, struct seq_file *); | 38 | extern void slow_work_new_thread_desc(struct slow_work *, struct seq_file *); |
