diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 123 | ||||
-rw-r--r-- | fs/proc/base.c | 156 | ||||
-rw-r--r-- | fs/proc/generic.c | 52 | ||||
-rw-r--r-- | fs/proc/inode.c | 254 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 7 | ||||
-rw-r--r-- | fs/proc/proc_tty.c | 15 |
6 files changed, 460 insertions, 147 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 74f30e0c0381..965625a0977d 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -62,6 +62,8 @@ | |||
62 | #include <linux/mman.h> | 62 | #include <linux/mman.h> |
63 | #include <linux/proc_fs.h> | 63 | #include <linux/proc_fs.h> |
64 | #include <linux/ioport.h> | 64 | #include <linux/ioport.h> |
65 | #include <linux/uaccess.h> | ||
66 | #include <linux/io.h> | ||
65 | #include <linux/mm.h> | 67 | #include <linux/mm.h> |
66 | #include <linux/hugetlb.h> | 68 | #include <linux/hugetlb.h> |
67 | #include <linux/pagemap.h> | 69 | #include <linux/pagemap.h> |
@@ -76,9 +78,7 @@ | |||
76 | #include <linux/rcupdate.h> | 78 | #include <linux/rcupdate.h> |
77 | #include <linux/delayacct.h> | 79 | #include <linux/delayacct.h> |
78 | 80 | ||
79 | #include <asm/uaccess.h> | ||
80 | #include <asm/pgtable.h> | 81 | #include <asm/pgtable.h> |
81 | #include <asm/io.h> | ||
82 | #include <asm/processor.h> | 82 | #include <asm/processor.h> |
83 | #include "internal.h" | 83 | #include "internal.h" |
84 | 84 | ||
@@ -87,10 +87,10 @@ | |||
87 | do { memcpy(buffer, string, strlen(string)); \ | 87 | do { memcpy(buffer, string, strlen(string)); \ |
88 | buffer += strlen(string); } while (0) | 88 | buffer += strlen(string); } while (0) |
89 | 89 | ||
90 | static inline char * task_name(struct task_struct *p, char * buf) | 90 | static inline char *task_name(struct task_struct *p, char *buf) |
91 | { | 91 | { |
92 | int i; | 92 | int i; |
93 | char * name; | 93 | char *name; |
94 | char tcomm[sizeof(p->comm)]; | 94 | char tcomm[sizeof(p->comm)]; |
95 | 95 | ||
96 | get_task_comm(tcomm, p); | 96 | get_task_comm(tcomm, p); |
@@ -138,7 +138,7 @@ static const char *task_state_array[] = { | |||
138 | "X (dead)" /* 32 */ | 138 | "X (dead)" /* 32 */ |
139 | }; | 139 | }; |
140 | 140 | ||
141 | static inline const char * get_task_state(struct task_struct *tsk) | 141 | static inline const char *get_task_state(struct task_struct *tsk) |
142 | { | 142 | { |
143 | unsigned int state = (tsk->state & (TASK_RUNNING | | 143 | unsigned int state = (tsk->state & (TASK_RUNNING | |
144 | TASK_INTERRUPTIBLE | | 144 | TASK_INTERRUPTIBLE | |
@@ -156,7 +156,7 @@ static inline const char * get_task_state(struct task_struct *tsk) | |||
156 | return *p; | 156 | return *p; |
157 | } | 157 | } |
158 | 158 | ||
159 | static inline char * task_state(struct task_struct *p, char *buffer) | 159 | static inline char *task_state(struct task_struct *p, char *buffer) |
160 | { | 160 | { |
161 | struct group_info *group_info; | 161 | struct group_info *group_info; |
162 | int g; | 162 | int g; |
@@ -165,7 +165,6 @@ static inline char * task_state(struct task_struct *p, char *buffer) | |||
165 | rcu_read_lock(); | 165 | rcu_read_lock(); |
166 | buffer += sprintf(buffer, | 166 | buffer += sprintf(buffer, |
167 | "State:\t%s\n" | 167 | "State:\t%s\n" |
168 | "SleepAVG:\t%lu%%\n" | ||
169 | "Tgid:\t%d\n" | 168 | "Tgid:\t%d\n" |
170 | "Pid:\t%d\n" | 169 | "Pid:\t%d\n" |
171 | "PPid:\t%d\n" | 170 | "PPid:\t%d\n" |
@@ -173,9 +172,8 @@ static inline char * task_state(struct task_struct *p, char *buffer) | |||
173 | "Uid:\t%d\t%d\t%d\t%d\n" | 172 | "Uid:\t%d\t%d\t%d\t%d\n" |
174 | "Gid:\t%d\t%d\t%d\t%d\n", | 173 | "Gid:\t%d\t%d\t%d\t%d\n", |
175 | get_task_state(p), | 174 | get_task_state(p), |
176 | (p->sleep_avg/1024)*100/(1020000000/1024), | 175 | p->tgid, p->pid, |
177 | p->tgid, p->pid, | 176 | pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0, |
178 | pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0, | ||
179 | pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0, | 177 | pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0, |
180 | p->uid, p->euid, p->suid, p->fsuid, | 178 | p->uid, p->euid, p->suid, p->fsuid, |
181 | p->gid, p->egid, p->sgid, p->fsgid); | 179 | p->gid, p->egid, p->sgid, p->fsgid); |
@@ -193,15 +191,15 @@ static inline char * task_state(struct task_struct *p, char *buffer) | |||
193 | get_group_info(group_info); | 191 | get_group_info(group_info); |
194 | task_unlock(p); | 192 | task_unlock(p); |
195 | 193 | ||
196 | for (g = 0; g < min(group_info->ngroups,NGROUPS_SMALL); g++) | 194 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) |
197 | buffer += sprintf(buffer, "%d ", GROUP_AT(group_info,g)); | 195 | buffer += sprintf(buffer, "%d ", GROUP_AT(group_info, g)); |
198 | put_group_info(group_info); | 196 | put_group_info(group_info); |
199 | 197 | ||
200 | buffer += sprintf(buffer, "\n"); | 198 | buffer += sprintf(buffer, "\n"); |
201 | return buffer; | 199 | return buffer; |
202 | } | 200 | } |
203 | 201 | ||
204 | static char * render_sigset_t(const char *header, sigset_t *set, char *buffer) | 202 | static char *render_sigset_t(const char *header, sigset_t *set, char *buffer) |
205 | { | 203 | { |
206 | int i, len; | 204 | int i, len; |
207 | 205 | ||
@@ -241,7 +239,7 @@ static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, | |||
241 | } | 239 | } |
242 | } | 240 | } |
243 | 241 | ||
244 | static inline char * task_sig(struct task_struct *p, char *buffer) | 242 | static inline char *task_sig(struct task_struct *p, char *buffer) |
245 | { | 243 | { |
246 | unsigned long flags; | 244 | unsigned long flags; |
247 | sigset_t pending, shpending, blocked, ignored, caught; | 245 | sigset_t pending, shpending, blocked, ignored, caught; |
@@ -291,14 +289,23 @@ static inline char *task_cap(struct task_struct *p, char *buffer) | |||
291 | cap_t(p->cap_effective)); | 289 | cap_t(p->cap_effective)); |
292 | } | 290 | } |
293 | 291 | ||
294 | int proc_pid_status(struct task_struct *task, char * buffer) | 292 | static inline char *task_context_switch_counts(struct task_struct *p, |
293 | char *buffer) | ||
295 | { | 294 | { |
296 | char * orig = buffer; | 295 | return buffer + sprintf(buffer, "voluntary_ctxt_switches:\t%lu\n" |
296 | "nonvoluntary_ctxt_switches:\t%lu\n", | ||
297 | p->nvcsw, | ||
298 | p->nivcsw); | ||
299 | } | ||
300 | |||
301 | int proc_pid_status(struct task_struct *task, char *buffer) | ||
302 | { | ||
303 | char *orig = buffer; | ||
297 | struct mm_struct *mm = get_task_mm(task); | 304 | struct mm_struct *mm = get_task_mm(task); |
298 | 305 | ||
299 | buffer = task_name(task, buffer); | 306 | buffer = task_name(task, buffer); |
300 | buffer = task_state(task, buffer); | 307 | buffer = task_state(task, buffer); |
301 | 308 | ||
302 | if (mm) { | 309 | if (mm) { |
303 | buffer = task_mem(mm, buffer); | 310 | buffer = task_mem(mm, buffer); |
304 | mmput(mm); | 311 | mmput(mm); |
@@ -309,10 +316,45 @@ int proc_pid_status(struct task_struct *task, char * buffer) | |||
309 | #if defined(CONFIG_S390) | 316 | #if defined(CONFIG_S390) |
310 | buffer = task_show_regs(task, buffer); | 317 | buffer = task_show_regs(task, buffer); |
311 | #endif | 318 | #endif |
319 | buffer = task_context_switch_counts(task, buffer); | ||
312 | return buffer - orig; | 320 | return buffer - orig; |
313 | } | 321 | } |
314 | 322 | ||
315 | static int do_task_stat(struct task_struct *task, char * buffer, int whole) | 323 | static clock_t task_utime(struct task_struct *p) |
324 | { | ||
325 | clock_t utime = cputime_to_clock_t(p->utime), | ||
326 | total = utime + cputime_to_clock_t(p->stime); | ||
327 | u64 temp; | ||
328 | |||
329 | /* | ||
330 | * Use CFS's precise accounting: | ||
331 | */ | ||
332 | temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime); | ||
333 | |||
334 | if (total) { | ||
335 | temp *= utime; | ||
336 | do_div(temp, total); | ||
337 | } | ||
338 | utime = (clock_t)temp; | ||
339 | |||
340 | return utime; | ||
341 | } | ||
342 | |||
343 | static clock_t task_stime(struct task_struct *p) | ||
344 | { | ||
345 | clock_t stime; | ||
346 | |||
347 | /* | ||
348 | * Use CFS's precise accounting. (we subtract utime from | ||
349 | * the total, to make sure the total observed by userspace | ||
350 | * grows monotonically - apps rely on that): | ||
351 | */ | ||
352 | stime = nsec_to_clock_t(p->se.sum_exec_runtime) - task_utime(p); | ||
353 | |||
354 | return stime; | ||
355 | } | ||
356 | |||
357 | static int do_task_stat(struct task_struct *task, char *buffer, int whole) | ||
316 | { | 358 | { |
317 | unsigned long vsize, eip, esp, wchan = ~0UL; | 359 | unsigned long vsize, eip, esp, wchan = ~0UL; |
318 | long priority, nice; | 360 | long priority, nice; |
@@ -320,13 +362,14 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
320 | sigset_t sigign, sigcatch; | 362 | sigset_t sigign, sigcatch; |
321 | char state; | 363 | char state; |
322 | int res; | 364 | int res; |
323 | pid_t ppid = 0, pgid = -1, sid = -1; | 365 | pid_t ppid = 0, pgid = -1, sid = -1; |
324 | int num_threads = 0; | 366 | int num_threads = 0; |
325 | struct mm_struct *mm; | 367 | struct mm_struct *mm; |
326 | unsigned long long start_time; | 368 | unsigned long long start_time; |
327 | unsigned long cmin_flt = 0, cmaj_flt = 0; | 369 | unsigned long cmin_flt = 0, cmaj_flt = 0; |
328 | unsigned long min_flt = 0, maj_flt = 0; | 370 | unsigned long min_flt = 0, maj_flt = 0; |
329 | cputime_t cutime, cstime, utime, stime; | 371 | cputime_t cutime, cstime; |
372 | clock_t utime, stime; | ||
330 | unsigned long rsslim = 0; | 373 | unsigned long rsslim = 0; |
331 | char tcomm[sizeof(task->comm)]; | 374 | char tcomm[sizeof(task->comm)]; |
332 | unsigned long flags; | 375 | unsigned long flags; |
@@ -344,7 +387,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
344 | 387 | ||
345 | sigemptyset(&sigign); | 388 | sigemptyset(&sigign); |
346 | sigemptyset(&sigcatch); | 389 | sigemptyset(&sigcatch); |
347 | cutime = cstime = utime = stime = cputime_zero; | 390 | cutime = cstime = cputime_zero; |
391 | utime = stime = 0; | ||
348 | 392 | ||
349 | rcu_read_lock(); | 393 | rcu_read_lock(); |
350 | if (lock_task_sighand(task, &flags)) { | 394 | if (lock_task_sighand(task, &flags)) { |
@@ -370,15 +414,15 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
370 | do { | 414 | do { |
371 | min_flt += t->min_flt; | 415 | min_flt += t->min_flt; |
372 | maj_flt += t->maj_flt; | 416 | maj_flt += t->maj_flt; |
373 | utime = cputime_add(utime, t->utime); | 417 | utime += task_utime(t); |
374 | stime = cputime_add(stime, t->stime); | 418 | stime += task_stime(t); |
375 | t = next_thread(t); | 419 | t = next_thread(t); |
376 | } while (t != task); | 420 | } while (t != task); |
377 | 421 | ||
378 | min_flt += sig->min_flt; | 422 | min_flt += sig->min_flt; |
379 | maj_flt += sig->maj_flt; | 423 | maj_flt += sig->maj_flt; |
380 | utime = cputime_add(utime, sig->utime); | 424 | utime += cputime_to_clock_t(sig->utime); |
381 | stime = cputime_add(stime, sig->stime); | 425 | stime += cputime_to_clock_t(sig->stime); |
382 | } | 426 | } |
383 | 427 | ||
384 | sid = signal_session(sig); | 428 | sid = signal_session(sig); |
@@ -389,13 +433,13 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
389 | } | 433 | } |
390 | rcu_read_unlock(); | 434 | rcu_read_unlock(); |
391 | 435 | ||
392 | if (!whole || num_threads<2) | 436 | if (!whole || num_threads < 2) |
393 | wchan = get_wchan(task); | 437 | wchan = get_wchan(task); |
394 | if (!whole) { | 438 | if (!whole) { |
395 | min_flt = task->min_flt; | 439 | min_flt = task->min_flt; |
396 | maj_flt = task->maj_flt; | 440 | maj_flt = task->maj_flt; |
397 | utime = task->utime; | 441 | utime = task_utime(task); |
398 | stime = task->stime; | 442 | stime = task_stime(task); |
399 | } | 443 | } |
400 | 444 | ||
401 | /* scale priority and nice values from timeslices to -20..20 */ | 445 | /* scale priority and nice values from timeslices to -20..20 */ |
@@ -405,12 +449,13 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
405 | 449 | ||
406 | /* Temporary variable needed for gcc-2.96 */ | 450 | /* Temporary variable needed for gcc-2.96 */ |
407 | /* convert timespec -> nsec*/ | 451 | /* convert timespec -> nsec*/ |
408 | start_time = (unsigned long long)task->start_time.tv_sec * NSEC_PER_SEC | 452 | start_time = |
409 | + task->start_time.tv_nsec; | 453 | (unsigned long long)task->real_start_time.tv_sec * NSEC_PER_SEC |
454 | + task->real_start_time.tv_nsec; | ||
410 | /* convert nsec -> ticks */ | 455 | /* convert nsec -> ticks */ |
411 | start_time = nsec_to_clock_t(start_time); | 456 | start_time = nsec_to_clock_t(start_time); |
412 | 457 | ||
413 | res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %u %lu \ | 458 | res = sprintf(buffer, "%d (%s) %c %d %d %d %d %d %u %lu \ |
414 | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ | 459 | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ |
415 | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu\n", | 460 | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu\n", |
416 | task->pid, | 461 | task->pid, |
@@ -426,8 +471,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
426 | cmin_flt, | 471 | cmin_flt, |
427 | maj_flt, | 472 | maj_flt, |
428 | cmaj_flt, | 473 | cmaj_flt, |
429 | cputime_to_clock_t(utime), | 474 | utime, |
430 | cputime_to_clock_t(stime), | 475 | stime, |
431 | cputime_to_clock_t(cutime), | 476 | cputime_to_clock_t(cutime), |
432 | cputime_to_clock_t(cstime), | 477 | cputime_to_clock_t(cstime), |
433 | priority, | 478 | priority, |
@@ -436,7 +481,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
436 | start_time, | 481 | start_time, |
437 | vsize, | 482 | vsize, |
438 | mm ? get_mm_rss(mm) : 0, | 483 | mm ? get_mm_rss(mm) : 0, |
439 | rsslim, | 484 | rsslim, |
440 | mm ? mm->start_code : 0, | 485 | mm ? mm->start_code : 0, |
441 | mm ? mm->end_code : 0, | 486 | mm ? mm->end_code : 0, |
442 | mm ? mm->start_stack : 0, | 487 | mm ? mm->start_stack : 0, |
@@ -458,17 +503,17 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
458 | task->rt_priority, | 503 | task->rt_priority, |
459 | task->policy, | 504 | task->policy, |
460 | (unsigned long long)delayacct_blkio_ticks(task)); | 505 | (unsigned long long)delayacct_blkio_ticks(task)); |
461 | if(mm) | 506 | if (mm) |
462 | mmput(mm); | 507 | mmput(mm); |
463 | return res; | 508 | return res; |
464 | } | 509 | } |
465 | 510 | ||
466 | int proc_tid_stat(struct task_struct *task, char * buffer) | 511 | int proc_tid_stat(struct task_struct *task, char *buffer) |
467 | { | 512 | { |
468 | return do_task_stat(task, buffer, 0); | 513 | return do_task_stat(task, buffer, 0); |
469 | } | 514 | } |
470 | 515 | ||
471 | int proc_tgid_stat(struct task_struct *task, char * buffer) | 516 | int proc_tgid_stat(struct task_struct *task, char *buffer) |
472 | { | 517 | { |
473 | return do_task_stat(task, buffer, 1); | 518 | return do_task_stat(task, buffer, 1); |
474 | } | 519 | } |
@@ -477,12 +522,12 @@ int proc_pid_statm(struct task_struct *task, char *buffer) | |||
477 | { | 522 | { |
478 | int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data = 0; | 523 | int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data = 0; |
479 | struct mm_struct *mm = get_task_mm(task); | 524 | struct mm_struct *mm = get_task_mm(task); |
480 | 525 | ||
481 | if (mm) { | 526 | if (mm) { |
482 | size = task_statm(mm, &shared, &text, &data, &resident); | 527 | size = task_statm(mm, &shared, &text, &data, &resident); |
483 | mmput(mm); | 528 | mmput(mm); |
484 | } | 529 | } |
485 | 530 | ||
486 | return sprintf(buffer,"%d %d %d %d %d %d %d\n", | 531 | return sprintf(buffer, "%d %d %d %d %d %d %d\n", |
487 | size, resident, shared, text, lib, data, 0); | 532 | size, resident, shared, text, lib, data, 0); |
488 | } | 533 | } |
diff --git a/fs/proc/base.c b/fs/proc/base.c index a5fa1fdafc4e..42cb4f5613b6 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -67,7 +67,6 @@ | |||
67 | #include <linux/mount.h> | 67 | #include <linux/mount.h> |
68 | #include <linux/security.h> | 68 | #include <linux/security.h> |
69 | #include <linux/ptrace.h> | 69 | #include <linux/ptrace.h> |
70 | #include <linux/seccomp.h> | ||
71 | #include <linux/cpuset.h> | 70 | #include <linux/cpuset.h> |
72 | #include <linux/audit.h> | 71 | #include <linux/audit.h> |
73 | #include <linux/poll.h> | 72 | #include <linux/poll.h> |
@@ -204,12 +203,17 @@ static int proc_pid_environ(struct task_struct *task, char * buffer) | |||
204 | int res = 0; | 203 | int res = 0; |
205 | struct mm_struct *mm = get_task_mm(task); | 204 | struct mm_struct *mm = get_task_mm(task); |
206 | if (mm) { | 205 | if (mm) { |
207 | unsigned int len = mm->env_end - mm->env_start; | 206 | unsigned int len; |
207 | |||
208 | res = -ESRCH; | ||
209 | if (!ptrace_may_attach(task)) | ||
210 | goto out; | ||
211 | |||
212 | len = mm->env_end - mm->env_start; | ||
208 | if (len > PAGE_SIZE) | 213 | if (len > PAGE_SIZE) |
209 | len = PAGE_SIZE; | 214 | len = PAGE_SIZE; |
210 | res = access_process_vm(task, mm->env_start, buffer, len, 0); | 215 | res = access_process_vm(task, mm->env_start, buffer, len, 0); |
211 | if (!ptrace_may_attach(task)) | 216 | out: |
212 | res = -ESRCH; | ||
213 | mmput(mm); | 217 | mmput(mm); |
214 | } | 218 | } |
215 | return res; | 219 | return res; |
@@ -279,7 +283,7 @@ static int proc_pid_auxv(struct task_struct *task, char *buffer) | |||
279 | static int proc_pid_wchan(struct task_struct *task, char *buffer) | 283 | static int proc_pid_wchan(struct task_struct *task, char *buffer) |
280 | { | 284 | { |
281 | unsigned long wchan; | 285 | unsigned long wchan; |
282 | char symname[KSYM_NAME_LEN+1]; | 286 | char symname[KSYM_NAME_LEN]; |
283 | 287 | ||
284 | wchan = get_wchan(task); | 288 | wchan = get_wchan(task); |
285 | 289 | ||
@@ -296,7 +300,7 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer) | |||
296 | */ | 300 | */ |
297 | static int proc_pid_schedstat(struct task_struct *task, char *buffer) | 301 | static int proc_pid_schedstat(struct task_struct *task, char *buffer) |
298 | { | 302 | { |
299 | return sprintf(buffer, "%lu %lu %lu\n", | 303 | return sprintf(buffer, "%llu %llu %lu\n", |
300 | task->sched_info.cpu_time, | 304 | task->sched_info.cpu_time, |
301 | task->sched_info.run_delay, | 305 | task->sched_info.run_delay, |
302 | task->sched_info.pcnt); | 306 | task->sched_info.pcnt); |
@@ -812,71 +816,6 @@ static const struct file_operations proc_loginuid_operations = { | |||
812 | }; | 816 | }; |
813 | #endif | 817 | #endif |
814 | 818 | ||
815 | #ifdef CONFIG_SECCOMP | ||
816 | static ssize_t seccomp_read(struct file *file, char __user *buf, | ||
817 | size_t count, loff_t *ppos) | ||
818 | { | ||
819 | struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode); | ||
820 | char __buf[20]; | ||
821 | size_t len; | ||
822 | |||
823 | if (!tsk) | ||
824 | return -ESRCH; | ||
825 | /* no need to print the trailing zero, so use only len */ | ||
826 | len = sprintf(__buf, "%u\n", tsk->seccomp.mode); | ||
827 | put_task_struct(tsk); | ||
828 | |||
829 | return simple_read_from_buffer(buf, count, ppos, __buf, len); | ||
830 | } | ||
831 | |||
832 | static ssize_t seccomp_write(struct file *file, const char __user *buf, | ||
833 | size_t count, loff_t *ppos) | ||
834 | { | ||
835 | struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode); | ||
836 | char __buf[20], *end; | ||
837 | unsigned int seccomp_mode; | ||
838 | ssize_t result; | ||
839 | |||
840 | result = -ESRCH; | ||
841 | if (!tsk) | ||
842 | goto out_no_task; | ||
843 | |||
844 | /* can set it only once to be even more secure */ | ||
845 | result = -EPERM; | ||
846 | if (unlikely(tsk->seccomp.mode)) | ||
847 | goto out; | ||
848 | |||
849 | result = -EFAULT; | ||
850 | memset(__buf, 0, sizeof(__buf)); | ||
851 | count = min(count, sizeof(__buf) - 1); | ||
852 | if (copy_from_user(__buf, buf, count)) | ||
853 | goto out; | ||
854 | |||
855 | seccomp_mode = simple_strtoul(__buf, &end, 0); | ||
856 | if (*end == '\n') | ||
857 | end++; | ||
858 | result = -EINVAL; | ||
859 | if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) { | ||
860 | tsk->seccomp.mode = seccomp_mode; | ||
861 | set_tsk_thread_flag(tsk, TIF_SECCOMP); | ||
862 | } else | ||
863 | goto out; | ||
864 | result = -EIO; | ||
865 | if (unlikely(!(end - __buf))) | ||
866 | goto out; | ||
867 | result = end - __buf; | ||
868 | out: | ||
869 | put_task_struct(tsk); | ||
870 | out_no_task: | ||
871 | return result; | ||
872 | } | ||
873 | |||
874 | static const struct file_operations proc_seccomp_operations = { | ||
875 | .read = seccomp_read, | ||
876 | .write = seccomp_write, | ||
877 | }; | ||
878 | #endif /* CONFIG_SECCOMP */ | ||
879 | |||
880 | #ifdef CONFIG_FAULT_INJECTION | 819 | #ifdef CONFIG_FAULT_INJECTION |
881 | static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, | 820 | static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, |
882 | size_t count, loff_t *ppos) | 821 | size_t count, loff_t *ppos) |
@@ -929,6 +868,69 @@ static const struct file_operations proc_fault_inject_operations = { | |||
929 | }; | 868 | }; |
930 | #endif | 869 | #endif |
931 | 870 | ||
871 | #ifdef CONFIG_SCHED_DEBUG | ||
872 | /* | ||
873 | * Print out various scheduling related per-task fields: | ||
874 | */ | ||
875 | static int sched_show(struct seq_file *m, void *v) | ||
876 | { | ||
877 | struct inode *inode = m->private; | ||
878 | struct task_struct *p; | ||
879 | |||
880 | WARN_ON(!inode); | ||
881 | |||
882 | p = get_proc_task(inode); | ||
883 | if (!p) | ||
884 | return -ESRCH; | ||
885 | proc_sched_show_task(p, m); | ||
886 | |||
887 | put_task_struct(p); | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static ssize_t | ||
893 | sched_write(struct file *file, const char __user *buf, | ||
894 | size_t count, loff_t *offset) | ||
895 | { | ||
896 | struct inode *inode = file->f_path.dentry->d_inode; | ||
897 | struct task_struct *p; | ||
898 | |||
899 | WARN_ON(!inode); | ||
900 | |||
901 | p = get_proc_task(inode); | ||
902 | if (!p) | ||
903 | return -ESRCH; | ||
904 | proc_sched_set_task(p); | ||
905 | |||
906 | put_task_struct(p); | ||
907 | |||
908 | return count; | ||
909 | } | ||
910 | |||
911 | static int sched_open(struct inode *inode, struct file *filp) | ||
912 | { | ||
913 | int ret; | ||
914 | |||
915 | ret = single_open(filp, sched_show, NULL); | ||
916 | if (!ret) { | ||
917 | struct seq_file *m = filp->private_data; | ||
918 | |||
919 | m->private = inode; | ||
920 | } | ||
921 | return ret; | ||
922 | } | ||
923 | |||
924 | static const struct file_operations proc_pid_sched_operations = { | ||
925 | .open = sched_open, | ||
926 | .read = seq_read, | ||
927 | .write = sched_write, | ||
928 | .llseek = seq_lseek, | ||
929 | .release = seq_release, | ||
930 | }; | ||
931 | |||
932 | #endif | ||
933 | |||
932 | static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | 934 | static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) |
933 | { | 935 | { |
934 | struct inode *inode = dentry->d_inode; | 936 | struct inode *inode = dentry->d_inode; |
@@ -1963,6 +1965,9 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
1963 | INF("environ", S_IRUSR, pid_environ), | 1965 | INF("environ", S_IRUSR, pid_environ), |
1964 | INF("auxv", S_IRUSR, pid_auxv), | 1966 | INF("auxv", S_IRUSR, pid_auxv), |
1965 | INF("status", S_IRUGO, pid_status), | 1967 | INF("status", S_IRUGO, pid_status), |
1968 | #ifdef CONFIG_SCHED_DEBUG | ||
1969 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), | ||
1970 | #endif | ||
1966 | INF("cmdline", S_IRUGO, pid_cmdline), | 1971 | INF("cmdline", S_IRUGO, pid_cmdline), |
1967 | INF("stat", S_IRUGO, tgid_stat), | 1972 | INF("stat", S_IRUGO, tgid_stat), |
1968 | INF("statm", S_IRUGO, pid_statm), | 1973 | INF("statm", S_IRUGO, pid_statm), |
@@ -1971,9 +1976,6 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
1971 | REG("numa_maps", S_IRUGO, numa_maps), | 1976 | REG("numa_maps", S_IRUGO, numa_maps), |
1972 | #endif | 1977 | #endif |
1973 | REG("mem", S_IRUSR|S_IWUSR, mem), | 1978 | REG("mem", S_IRUSR|S_IWUSR, mem), |
1974 | #ifdef CONFIG_SECCOMP | ||
1975 | REG("seccomp", S_IRUSR|S_IWUSR, seccomp), | ||
1976 | #endif | ||
1977 | LNK("cwd", cwd), | 1979 | LNK("cwd", cwd), |
1978 | LNK("root", root), | 1980 | LNK("root", root), |
1979 | LNK("exe", exe), | 1981 | LNK("exe", exe), |
@@ -2247,6 +2249,9 @@ static const struct pid_entry tid_base_stuff[] = { | |||
2247 | INF("environ", S_IRUSR, pid_environ), | 2249 | INF("environ", S_IRUSR, pid_environ), |
2248 | INF("auxv", S_IRUSR, pid_auxv), | 2250 | INF("auxv", S_IRUSR, pid_auxv), |
2249 | INF("status", S_IRUGO, pid_status), | 2251 | INF("status", S_IRUGO, pid_status), |
2252 | #ifdef CONFIG_SCHED_DEBUG | ||
2253 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), | ||
2254 | #endif | ||
2250 | INF("cmdline", S_IRUGO, pid_cmdline), | 2255 | INF("cmdline", S_IRUGO, pid_cmdline), |
2251 | INF("stat", S_IRUGO, tid_stat), | 2256 | INF("stat", S_IRUGO, tid_stat), |
2252 | INF("statm", S_IRUGO, pid_statm), | 2257 | INF("statm", S_IRUGO, pid_statm), |
@@ -2255,9 +2260,6 @@ static const struct pid_entry tid_base_stuff[] = { | |||
2255 | REG("numa_maps", S_IRUGO, numa_maps), | 2260 | REG("numa_maps", S_IRUGO, numa_maps), |
2256 | #endif | 2261 | #endif |
2257 | REG("mem", S_IRUSR|S_IWUSR, mem), | 2262 | REG("mem", S_IRUSR|S_IWUSR, mem), |
2258 | #ifdef CONFIG_SECCOMP | ||
2259 | REG("seccomp", S_IRUSR|S_IWUSR, seccomp), | ||
2260 | #endif | ||
2261 | LNK("cwd", cwd), | 2263 | LNK("cwd", cwd), |
2262 | LNK("root", root), | 2264 | LNK("root", root), |
2263 | LNK("exe", exe), | 2265 | LNK("exe", exe), |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 8a40e15f5ecb..b5e7155d30d8 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/spinlock.h> | 22 | #include <linux/spinlock.h> |
23 | #include <linux/completion.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | 25 | ||
25 | #include "internal.h" | 26 | #include "internal.h" |
@@ -529,12 +530,6 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
529 | return -EAGAIN; | 530 | return -EAGAIN; |
530 | dp->low_ino = i; | 531 | dp->low_ino = i; |
531 | 532 | ||
532 | spin_lock(&proc_subdir_lock); | ||
533 | dp->next = dir->subdir; | ||
534 | dp->parent = dir; | ||
535 | dir->subdir = dp; | ||
536 | spin_unlock(&proc_subdir_lock); | ||
537 | |||
538 | if (S_ISDIR(dp->mode)) { | 533 | if (S_ISDIR(dp->mode)) { |
539 | if (dp->proc_iops == NULL) { | 534 | if (dp->proc_iops == NULL) { |
540 | dp->proc_fops = &proc_dir_operations; | 535 | dp->proc_fops = &proc_dir_operations; |
@@ -550,6 +545,13 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
550 | if (dp->proc_iops == NULL) | 545 | if (dp->proc_iops == NULL) |
551 | dp->proc_iops = &proc_file_inode_operations; | 546 | dp->proc_iops = &proc_file_inode_operations; |
552 | } | 547 | } |
548 | |||
549 | spin_lock(&proc_subdir_lock); | ||
550 | dp->next = dir->subdir; | ||
551 | dp->parent = dir; | ||
552 | dir->subdir = dp; | ||
553 | spin_unlock(&proc_subdir_lock); | ||
554 | |||
553 | return 0; | 555 | return 0; |
554 | } | 556 | } |
555 | 557 | ||
@@ -613,6 +615,9 @@ static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent, | |||
613 | ent->namelen = len; | 615 | ent->namelen = len; |
614 | ent->mode = mode; | 616 | ent->mode = mode; |
615 | ent->nlink = nlink; | 617 | ent->nlink = nlink; |
618 | ent->pde_users = 0; | ||
619 | spin_lock_init(&ent->pde_unload_lock); | ||
620 | ent->pde_unload_completion = NULL; | ||
616 | out: | 621 | out: |
617 | return ent; | 622 | return ent; |
618 | } | 623 | } |
@@ -649,9 +654,6 @@ struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, | |||
649 | 654 | ||
650 | ent = proc_create(&parent, name, S_IFDIR | mode, 2); | 655 | ent = proc_create(&parent, name, S_IFDIR | mode, 2); |
651 | if (ent) { | 656 | if (ent) { |
652 | ent->proc_fops = &proc_dir_operations; | ||
653 | ent->proc_iops = &proc_dir_inode_operations; | ||
654 | |||
655 | if (proc_register(parent, ent) < 0) { | 657 | if (proc_register(parent, ent) < 0) { |
656 | kfree(ent); | 658 | kfree(ent); |
657 | ent = NULL; | 659 | ent = NULL; |
@@ -686,10 +688,6 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, | |||
686 | 688 | ||
687 | ent = proc_create(&parent,name,mode,nlink); | 689 | ent = proc_create(&parent,name,mode,nlink); |
688 | if (ent) { | 690 | if (ent) { |
689 | if (S_ISDIR(mode)) { | ||
690 | ent->proc_fops = &proc_dir_operations; | ||
691 | ent->proc_iops = &proc_dir_inode_operations; | ||
692 | } | ||
693 | if (proc_register(parent, ent) < 0) { | 691 | if (proc_register(parent, ent) < 0) { |
694 | kfree(ent); | 692 | kfree(ent); |
695 | ent = NULL; | 693 | ent = NULL; |
@@ -734,9 +732,35 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
734 | de = *p; | 732 | de = *p; |
735 | *p = de->next; | 733 | *p = de->next; |
736 | de->next = NULL; | 734 | de->next = NULL; |
735 | |||
736 | spin_lock(&de->pde_unload_lock); | ||
737 | /* | ||
738 | * Stop accepting new callers into module. If you're | ||
739 | * dynamically allocating ->proc_fops, save a pointer somewhere. | ||
740 | */ | ||
741 | de->proc_fops = NULL; | ||
742 | /* Wait until all existing callers into module are done. */ | ||
743 | if (de->pde_users > 0) { | ||
744 | DECLARE_COMPLETION_ONSTACK(c); | ||
745 | |||
746 | if (!de->pde_unload_completion) | ||
747 | de->pde_unload_completion = &c; | ||
748 | |||
749 | spin_unlock(&de->pde_unload_lock); | ||
750 | spin_unlock(&proc_subdir_lock); | ||
751 | |||
752 | wait_for_completion(de->pde_unload_completion); | ||
753 | |||
754 | spin_lock(&proc_subdir_lock); | ||
755 | goto continue_removing; | ||
756 | } | ||
757 | spin_unlock(&de->pde_unload_lock); | ||
758 | |||
759 | continue_removing: | ||
737 | if (S_ISDIR(de->mode)) | 760 | if (S_ISDIR(de->mode)) |
738 | parent->nlink--; | 761 | parent->nlink--; |
739 | proc_kill_inodes(de); | 762 | if (!S_ISREG(de->mode)) |
763 | proc_kill_inodes(de); | ||
740 | de->nlink = 0; | 764 | de->nlink = 0; |
741 | WARN_ON(de->subdir); | 765 | WARN_ON(de->subdir); |
742 | if (!atomic_read(&de->count)) | 766 | if (!atomic_read(&de->count)) |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index d5ce65c68d7b..dd28e86ab422 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/string.h> | 11 | #include <linux/string.h> |
12 | #include <linux/stat.h> | 12 | #include <linux/stat.h> |
13 | #include <linux/completion.h> | ||
13 | #include <linux/file.h> | 14 | #include <linux/file.h> |
14 | #include <linux/limits.h> | 15 | #include <linux/limits.h> |
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
@@ -140,6 +141,251 @@ static const struct super_operations proc_sops = { | |||
140 | .remount_fs = proc_remount, | 141 | .remount_fs = proc_remount, |
141 | }; | 142 | }; |
142 | 143 | ||
144 | static void pde_users_dec(struct proc_dir_entry *pde) | ||
145 | { | ||
146 | spin_lock(&pde->pde_unload_lock); | ||
147 | pde->pde_users--; | ||
148 | if (pde->pde_unload_completion && pde->pde_users == 0) | ||
149 | complete(pde->pde_unload_completion); | ||
150 | spin_unlock(&pde->pde_unload_lock); | ||
151 | } | ||
152 | |||
153 | static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence) | ||
154 | { | ||
155 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
156 | loff_t rv = -EINVAL; | ||
157 | loff_t (*llseek)(struct file *, loff_t, int); | ||
158 | |||
159 | spin_lock(&pde->pde_unload_lock); | ||
160 | /* | ||
161 | * remove_proc_entry() is going to delete PDE (as part of module | ||
162 | * cleanup sequence). No new callers into module allowed. | ||
163 | */ | ||
164 | if (!pde->proc_fops) { | ||
165 | spin_unlock(&pde->pde_unload_lock); | ||
166 | return rv; | ||
167 | } | ||
168 | /* | ||
169 | * Bump refcount so that remove_proc_entry will wail for ->llseek to | ||
170 | * complete. | ||
171 | */ | ||
172 | pde->pde_users++; | ||
173 | /* | ||
174 | * Save function pointer under lock, to protect against ->proc_fops | ||
175 | * NULL'ifying right after ->pde_unload_lock is dropped. | ||
176 | */ | ||
177 | llseek = pde->proc_fops->llseek; | ||
178 | spin_unlock(&pde->pde_unload_lock); | ||
179 | |||
180 | if (!llseek) | ||
181 | llseek = default_llseek; | ||
182 | rv = llseek(file, offset, whence); | ||
183 | |||
184 | pde_users_dec(pde); | ||
185 | return rv; | ||
186 | } | ||
187 | |||
188 | static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | ||
189 | { | ||
190 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
191 | ssize_t rv = -EIO; | ||
192 | ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); | ||
193 | |||
194 | spin_lock(&pde->pde_unload_lock); | ||
195 | if (!pde->proc_fops) { | ||
196 | spin_unlock(&pde->pde_unload_lock); | ||
197 | return rv; | ||
198 | } | ||
199 | pde->pde_users++; | ||
200 | read = pde->proc_fops->read; | ||
201 | spin_unlock(&pde->pde_unload_lock); | ||
202 | |||
203 | if (read) | ||
204 | rv = read(file, buf, count, ppos); | ||
205 | |||
206 | pde_users_dec(pde); | ||
207 | return rv; | ||
208 | } | ||
209 | |||
210 | static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | ||
211 | { | ||
212 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
213 | ssize_t rv = -EIO; | ||
214 | ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); | ||
215 | |||
216 | spin_lock(&pde->pde_unload_lock); | ||
217 | if (!pde->proc_fops) { | ||
218 | spin_unlock(&pde->pde_unload_lock); | ||
219 | return rv; | ||
220 | } | ||
221 | pde->pde_users++; | ||
222 | write = pde->proc_fops->write; | ||
223 | spin_unlock(&pde->pde_unload_lock); | ||
224 | |||
225 | if (write) | ||
226 | rv = write(file, buf, count, ppos); | ||
227 | |||
228 | pde_users_dec(pde); | ||
229 | return rv; | ||
230 | } | ||
231 | |||
232 | static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *pts) | ||
233 | { | ||
234 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
235 | unsigned int rv = 0; | ||
236 | unsigned int (*poll)(struct file *, struct poll_table_struct *); | ||
237 | |||
238 | spin_lock(&pde->pde_unload_lock); | ||
239 | if (!pde->proc_fops) { | ||
240 | spin_unlock(&pde->pde_unload_lock); | ||
241 | return rv; | ||
242 | } | ||
243 | pde->pde_users++; | ||
244 | poll = pde->proc_fops->poll; | ||
245 | spin_unlock(&pde->pde_unload_lock); | ||
246 | |||
247 | if (poll) | ||
248 | rv = poll(file, pts); | ||
249 | |||
250 | pde_users_dec(pde); | ||
251 | return rv; | ||
252 | } | ||
253 | |||
254 | static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
255 | { | ||
256 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
257 | long rv = -ENOTTY; | ||
258 | long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); | ||
259 | int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); | ||
260 | |||
261 | spin_lock(&pde->pde_unload_lock); | ||
262 | if (!pde->proc_fops) { | ||
263 | spin_unlock(&pde->pde_unload_lock); | ||
264 | return rv; | ||
265 | } | ||
266 | pde->pde_users++; | ||
267 | unlocked_ioctl = pde->proc_fops->unlocked_ioctl; | ||
268 | ioctl = pde->proc_fops->ioctl; | ||
269 | spin_unlock(&pde->pde_unload_lock); | ||
270 | |||
271 | if (unlocked_ioctl) { | ||
272 | rv = unlocked_ioctl(file, cmd, arg); | ||
273 | if (rv == -ENOIOCTLCMD) | ||
274 | rv = -EINVAL; | ||
275 | } else if (ioctl) { | ||
276 | lock_kernel(); | ||
277 | rv = ioctl(file->f_path.dentry->d_inode, file, cmd, arg); | ||
278 | unlock_kernel(); | ||
279 | } | ||
280 | |||
281 | pde_users_dec(pde); | ||
282 | return rv; | ||
283 | } | ||
284 | |||
285 | #ifdef CONFIG_COMPAT | ||
286 | static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
287 | { | ||
288 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
289 | long rv = -ENOTTY; | ||
290 | long (*compat_ioctl)(struct file *, unsigned int, unsigned long); | ||
291 | |||
292 | spin_lock(&pde->pde_unload_lock); | ||
293 | if (!pde->proc_fops) { | ||
294 | spin_unlock(&pde->pde_unload_lock); | ||
295 | return rv; | ||
296 | } | ||
297 | pde->pde_users++; | ||
298 | compat_ioctl = pde->proc_fops->compat_ioctl; | ||
299 | spin_unlock(&pde->pde_unload_lock); | ||
300 | |||
301 | if (compat_ioctl) | ||
302 | rv = compat_ioctl(file, cmd, arg); | ||
303 | |||
304 | pde_users_dec(pde); | ||
305 | return rv; | ||
306 | } | ||
307 | #endif | ||
308 | |||
309 | static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) | ||
310 | { | ||
311 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
312 | int rv = -EIO; | ||
313 | int (*mmap)(struct file *, struct vm_area_struct *); | ||
314 | |||
315 | spin_lock(&pde->pde_unload_lock); | ||
316 | if (!pde->proc_fops) { | ||
317 | spin_unlock(&pde->pde_unload_lock); | ||
318 | return rv; | ||
319 | } | ||
320 | pde->pde_users++; | ||
321 | mmap = pde->proc_fops->mmap; | ||
322 | spin_unlock(&pde->pde_unload_lock); | ||
323 | |||
324 | if (mmap) | ||
325 | rv = mmap(file, vma); | ||
326 | |||
327 | pde_users_dec(pde); | ||
328 | return rv; | ||
329 | } | ||
330 | |||
331 | static int proc_reg_open(struct inode *inode, struct file *file) | ||
332 | { | ||
333 | struct proc_dir_entry *pde = PDE(inode); | ||
334 | int rv = 0; | ||
335 | int (*open)(struct inode *, struct file *); | ||
336 | |||
337 | spin_lock(&pde->pde_unload_lock); | ||
338 | if (!pde->proc_fops) { | ||
339 | spin_unlock(&pde->pde_unload_lock); | ||
340 | return rv; | ||
341 | } | ||
342 | pde->pde_users++; | ||
343 | open = pde->proc_fops->open; | ||
344 | spin_unlock(&pde->pde_unload_lock); | ||
345 | |||
346 | if (open) | ||
347 | rv = open(inode, file); | ||
348 | |||
349 | pde_users_dec(pde); | ||
350 | return rv; | ||
351 | } | ||
352 | |||
353 | static int proc_reg_release(struct inode *inode, struct file *file) | ||
354 | { | ||
355 | struct proc_dir_entry *pde = PDE(inode); | ||
356 | int rv = 0; | ||
357 | int (*release)(struct inode *, struct file *); | ||
358 | |||
359 | spin_lock(&pde->pde_unload_lock); | ||
360 | if (!pde->proc_fops) { | ||
361 | spin_unlock(&pde->pde_unload_lock); | ||
362 | return rv; | ||
363 | } | ||
364 | pde->pde_users++; | ||
365 | release = pde->proc_fops->release; | ||
366 | spin_unlock(&pde->pde_unload_lock); | ||
367 | |||
368 | if (release) | ||
369 | rv = release(inode, file); | ||
370 | |||
371 | pde_users_dec(pde); | ||
372 | return rv; | ||
373 | } | ||
374 | |||
375 | static const struct file_operations proc_reg_file_ops = { | ||
376 | .llseek = proc_reg_llseek, | ||
377 | .read = proc_reg_read, | ||
378 | .write = proc_reg_write, | ||
379 | .poll = proc_reg_poll, | ||
380 | .unlocked_ioctl = proc_reg_unlocked_ioctl, | ||
381 | #ifdef CONFIG_COMPAT | ||
382 | .compat_ioctl = proc_reg_compat_ioctl, | ||
383 | #endif | ||
384 | .mmap = proc_reg_mmap, | ||
385 | .open = proc_reg_open, | ||
386 | .release = proc_reg_release, | ||
387 | }; | ||
388 | |||
143 | struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | 389 | struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, |
144 | struct proc_dir_entry *de) | 390 | struct proc_dir_entry *de) |
145 | { | 391 | { |
@@ -166,8 +412,12 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
166 | inode->i_nlink = de->nlink; | 412 | inode->i_nlink = de->nlink; |
167 | if (de->proc_iops) | 413 | if (de->proc_iops) |
168 | inode->i_op = de->proc_iops; | 414 | inode->i_op = de->proc_iops; |
169 | if (de->proc_fops) | 415 | if (de->proc_fops) { |
170 | inode->i_fop = de->proc_fops; | 416 | if (S_ISREG(inode->i_mode)) |
417 | inode->i_fop = &proc_reg_file_ops; | ||
418 | else | ||
419 | inode->i_fop = de->proc_fops; | ||
420 | } | ||
171 | } | 421 | } |
172 | 422 | ||
173 | return inode; | 423 | return inode; |
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 5fd49e47f83a..d24b8d46059a 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -105,6 +105,7 @@ static int uptime_read_proc(char *page, char **start, off_t off, | |||
105 | cputime_t idletime = cputime_add(init_task.utime, init_task.stime); | 105 | cputime_t idletime = cputime_add(init_task.utime, init_task.stime); |
106 | 106 | ||
107 | do_posix_clock_monotonic_gettime(&uptime); | 107 | do_posix_clock_monotonic_gettime(&uptime); |
108 | monotonic_to_bootbased(&uptime); | ||
108 | cputime_to_timespec(idletime, &idle); | 109 | cputime_to_timespec(idletime, &idle); |
109 | len = sprintf(page,"%lu.%02lu %lu.%02lu\n", | 110 | len = sprintf(page,"%lu.%02lu %lu.%02lu\n", |
110 | (unsigned long) uptime.tv_sec, | 111 | (unsigned long) uptime.tv_sec, |
@@ -443,12 +444,12 @@ static int show_stat(struct seq_file *p, void *v) | |||
443 | unsigned long jif; | 444 | unsigned long jif; |
444 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; | 445 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; |
445 | u64 sum = 0; | 446 | u64 sum = 0; |
447 | struct timespec boottime; | ||
446 | 448 | ||
447 | user = nice = system = idle = iowait = | 449 | user = nice = system = idle = iowait = |
448 | irq = softirq = steal = cputime64_zero; | 450 | irq = softirq = steal = cputime64_zero; |
449 | jif = - wall_to_monotonic.tv_sec; | 451 | getboottime(&boottime); |
450 | if (wall_to_monotonic.tv_nsec) | 452 | jif = boottime.tv_sec; |
451 | --jif; | ||
452 | 453 | ||
453 | for_each_possible_cpu(i) { | 454 | for_each_possible_cpu(i) { |
454 | int j; | 455 | int j; |
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index b3a473b0a191..22846225acfa 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c | |||
@@ -69,7 +69,7 @@ static void show_tty_range(struct seq_file *m, struct tty_driver *p, | |||
69 | 69 | ||
70 | static int show_tty_driver(struct seq_file *m, void *v) | 70 | static int show_tty_driver(struct seq_file *m, void *v) |
71 | { | 71 | { |
72 | struct tty_driver *p = v; | 72 | struct tty_driver *p = list_entry(v, struct tty_driver, tty_drivers); |
73 | dev_t from = MKDEV(p->major, p->minor_start); | 73 | dev_t from = MKDEV(p->major, p->minor_start); |
74 | dev_t to = from + p->num; | 74 | dev_t to = from + p->num; |
75 | 75 | ||
@@ -106,22 +106,13 @@ static int show_tty_driver(struct seq_file *m, void *v) | |||
106 | /* iterator */ | 106 | /* iterator */ |
107 | static void *t_start(struct seq_file *m, loff_t *pos) | 107 | static void *t_start(struct seq_file *m, loff_t *pos) |
108 | { | 108 | { |
109 | struct list_head *p; | ||
110 | loff_t l = *pos; | ||
111 | |||
112 | mutex_lock(&tty_mutex); | 109 | mutex_lock(&tty_mutex); |
113 | list_for_each(p, &tty_drivers) | 110 | return seq_list_start(&tty_drivers, *pos); |
114 | if (!l--) | ||
115 | return list_entry(p, struct tty_driver, tty_drivers); | ||
116 | return NULL; | ||
117 | } | 111 | } |
118 | 112 | ||
119 | static void *t_next(struct seq_file *m, void *v, loff_t *pos) | 113 | static void *t_next(struct seq_file *m, void *v, loff_t *pos) |
120 | { | 114 | { |
121 | struct list_head *p = ((struct tty_driver *)v)->tty_drivers.next; | 115 | return seq_list_next(v, &tty_drivers, pos); |
122 | (*pos)++; | ||
123 | return p==&tty_drivers ? NULL : | ||
124 | list_entry(p, struct tty_driver, tty_drivers); | ||
125 | } | 116 | } |
126 | 117 | ||
127 | static void t_stop(struct seq_file *m, void *v) | 118 | static void t_stop(struct seq_file *m, void *v) |