diff options
Diffstat (limited to 'fs/proc')
| -rw-r--r-- | fs/proc/array.c | 129 | ||||
| -rw-r--r-- | fs/proc/base.c | 106 | ||||
| -rw-r--r-- | fs/proc/generic.c | 21 | ||||
| -rw-r--r-- | fs/proc/inode.c | 31 | ||||
| -rw-r--r-- | fs/proc/internal.h | 10 | ||||
| -rw-r--r-- | fs/proc/page.c | 45 | ||||
| -rw-r--r-- | fs/proc/proc_devtree.c | 48 | ||||
| -rw-r--r-- | fs/proc/proc_sysctl.c | 4 | ||||
| -rw-r--r-- | fs/proc/stat.c | 19 | ||||
| -rw-r--r-- | fs/proc/task_mmu.c | 48 | ||||
| -rw-r--r-- | fs/proc/task_nommu.c | 8 |
11 files changed, 241 insertions, 228 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 07f77a7945c3..18e20feee251 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -134,13 +134,16 @@ static inline void task_name(struct seq_file *m, struct task_struct *p) | |||
| 134 | * simple bit tests. | 134 | * simple bit tests. |
| 135 | */ | 135 | */ |
| 136 | static const char *task_state_array[] = { | 136 | static const char *task_state_array[] = { |
| 137 | "R (running)", /* 0 */ | 137 | "R (running)", /* 0 */ |
| 138 | "S (sleeping)", /* 1 */ | 138 | "S (sleeping)", /* 1 */ |
| 139 | "D (disk sleep)", /* 2 */ | 139 | "D (disk sleep)", /* 2 */ |
| 140 | "T (stopped)", /* 4 */ | 140 | "T (stopped)", /* 4 */ |
| 141 | "T (tracing stop)", /* 8 */ | 141 | "t (tracing stop)", /* 8 */ |
| 142 | "Z (zombie)", /* 16 */ | 142 | "Z (zombie)", /* 16 */ |
| 143 | "X (dead)" /* 32 */ | 143 | "X (dead)", /* 32 */ |
| 144 | "x (dead)", /* 64 */ | ||
| 145 | "K (wakekill)", /* 128 */ | ||
| 146 | "W (waking)", /* 256 */ | ||
| 144 | }; | 147 | }; |
| 145 | 148 | ||
| 146 | static inline const char *get_task_state(struct task_struct *tsk) | 149 | static inline const char *get_task_state(struct task_struct *tsk) |
| @@ -148,6 +151,8 @@ static inline const char *get_task_state(struct task_struct *tsk) | |||
| 148 | unsigned int state = (tsk->state & TASK_REPORT) | tsk->exit_state; | 151 | unsigned int state = (tsk->state & TASK_REPORT) | tsk->exit_state; |
| 149 | const char **p = &task_state_array[0]; | 152 | const char **p = &task_state_array[0]; |
| 150 | 153 | ||
| 154 | BUILD_BUG_ON(1 + ilog2(TASK_STATE_MAX) != ARRAY_SIZE(task_state_array)); | ||
| 155 | |||
| 151 | while (state) { | 156 | while (state) { |
| 152 | p++; | 157 | p++; |
| 153 | state >>= 1; | 158 | state >>= 1; |
| @@ -265,7 +270,9 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) | |||
| 265 | blocked = p->blocked; | 270 | blocked = p->blocked; |
| 266 | collect_sigign_sigcatch(p, &ignored, &caught); | 271 | collect_sigign_sigcatch(p, &ignored, &caught); |
| 267 | num_threads = atomic_read(&p->signal->count); | 272 | num_threads = atomic_read(&p->signal->count); |
| 273 | rcu_read_lock(); /* FIXME: is this correct? */ | ||
| 268 | qsize = atomic_read(&__task_cred(p)->user->sigpending); | 274 | qsize = atomic_read(&__task_cred(p)->user->sigpending); |
| 275 | rcu_read_unlock(); | ||
| 269 | qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur; | 276 | qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur; |
| 270 | unlock_task_sighand(p, &flags); | 277 | unlock_task_sighand(p, &flags); |
| 271 | } | 278 | } |
| @@ -322,93 +329,15 @@ static inline void task_context_switch_counts(struct seq_file *m, | |||
| 322 | p->nivcsw); | 329 | p->nivcsw); |
| 323 | } | 330 | } |
| 324 | 331 | ||
| 325 | #ifdef CONFIG_MMU | 332 | static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) |
| 326 | |||
| 327 | struct stack_stats { | ||
| 328 | struct vm_area_struct *vma; | ||
| 329 | unsigned long startpage; | ||
| 330 | unsigned long usage; | ||
| 331 | }; | ||
| 332 | |||
| 333 | static int stack_usage_pte_range(pmd_t *pmd, unsigned long addr, | ||
| 334 | unsigned long end, struct mm_walk *walk) | ||
| 335 | { | ||
| 336 | struct stack_stats *ss = walk->private; | ||
| 337 | struct vm_area_struct *vma = ss->vma; | ||
| 338 | pte_t *pte, ptent; | ||
| 339 | spinlock_t *ptl; | ||
| 340 | int ret = 0; | ||
| 341 | |||
| 342 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); | ||
| 343 | for (; addr != end; pte++, addr += PAGE_SIZE) { | ||
| 344 | ptent = *pte; | ||
| 345 | |||
| 346 | #ifdef CONFIG_STACK_GROWSUP | ||
| 347 | if (pte_present(ptent) || is_swap_pte(ptent)) | ||
| 348 | ss->usage = addr - ss->startpage + PAGE_SIZE; | ||
| 349 | #else | ||
| 350 | if (pte_present(ptent) || is_swap_pte(ptent)) { | ||
| 351 | ss->usage = ss->startpage - addr + PAGE_SIZE; | ||
| 352 | pte++; | ||
| 353 | ret = 1; | ||
| 354 | break; | ||
| 355 | } | ||
| 356 | #endif | ||
| 357 | } | ||
| 358 | pte_unmap_unlock(pte - 1, ptl); | ||
| 359 | cond_resched(); | ||
| 360 | return ret; | ||
| 361 | } | ||
| 362 | |||
| 363 | static inline unsigned long get_stack_usage_in_bytes(struct vm_area_struct *vma, | ||
| 364 | struct task_struct *task) | ||
| 365 | { | ||
| 366 | struct stack_stats ss; | ||
| 367 | struct mm_walk stack_walk = { | ||
| 368 | .pmd_entry = stack_usage_pte_range, | ||
| 369 | .mm = vma->vm_mm, | ||
| 370 | .private = &ss, | ||
| 371 | }; | ||
| 372 | |||
| 373 | if (!vma->vm_mm || is_vm_hugetlb_page(vma)) | ||
| 374 | return 0; | ||
| 375 | |||
| 376 | ss.vma = vma; | ||
| 377 | ss.startpage = task->stack_start & PAGE_MASK; | ||
| 378 | ss.usage = 0; | ||
| 379 | |||
| 380 | #ifdef CONFIG_STACK_GROWSUP | ||
| 381 | walk_page_range(KSTK_ESP(task) & PAGE_MASK, vma->vm_end, | ||
| 382 | &stack_walk); | ||
| 383 | #else | ||
| 384 | walk_page_range(vma->vm_start, (KSTK_ESP(task) & PAGE_MASK) + PAGE_SIZE, | ||
| 385 | &stack_walk); | ||
| 386 | #endif | ||
| 387 | return ss.usage; | ||
| 388 | } | ||
| 389 | |||
| 390 | static inline void task_show_stack_usage(struct seq_file *m, | ||
| 391 | struct task_struct *task) | ||
| 392 | { | ||
| 393 | struct vm_area_struct *vma; | ||
| 394 | struct mm_struct *mm = get_task_mm(task); | ||
| 395 | |||
| 396 | if (mm) { | ||
| 397 | down_read(&mm->mmap_sem); | ||
| 398 | vma = find_vma(mm, task->stack_start); | ||
| 399 | if (vma) | ||
| 400 | seq_printf(m, "Stack usage:\t%lu kB\n", | ||
| 401 | get_stack_usage_in_bytes(vma, task) >> 10); | ||
| 402 | |||
| 403 | up_read(&mm->mmap_sem); | ||
| 404 | mmput(mm); | ||
| 405 | } | ||
| 406 | } | ||
| 407 | #else | ||
| 408 | static void task_show_stack_usage(struct seq_file *m, struct task_struct *task) | ||
| 409 | { | 333 | { |
| 334 | seq_printf(m, "Cpus_allowed:\t"); | ||
| 335 | seq_cpumask(m, &task->cpus_allowed); | ||
| 336 | seq_printf(m, "\n"); | ||
| 337 | seq_printf(m, "Cpus_allowed_list:\t"); | ||
| 338 | seq_cpumask_list(m, &task->cpus_allowed); | ||
| 339 | seq_printf(m, "\n"); | ||
| 410 | } | 340 | } |
| 411 | #endif /* CONFIG_MMU */ | ||
| 412 | 341 | ||
| 413 | int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | 342 | int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, |
| 414 | struct pid *pid, struct task_struct *task) | 343 | struct pid *pid, struct task_struct *task) |
| @@ -424,12 +353,12 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | |||
| 424 | } | 353 | } |
| 425 | task_sig(m, task); | 354 | task_sig(m, task); |
| 426 | task_cap(m, task); | 355 | task_cap(m, task); |
| 356 | task_cpus_allowed(m, task); | ||
| 427 | cpuset_task_status_allowed(m, task); | 357 | cpuset_task_status_allowed(m, task); |
| 428 | #if defined(CONFIG_S390) | 358 | #if defined(CONFIG_S390) |
| 429 | task_show_regs(m, task); | 359 | task_show_regs(m, task); |
| 430 | #endif | 360 | #endif |
| 431 | task_context_switch_counts(m, task); | 361 | task_context_switch_counts(m, task); |
| 432 | task_show_stack_usage(m, task); | ||
| 433 | return 0; | 362 | return 0; |
| 434 | } | 363 | } |
| 435 | 364 | ||
| @@ -495,20 +424,17 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
| 495 | 424 | ||
| 496 | /* add up live thread stats at the group level */ | 425 | /* add up live thread stats at the group level */ |
| 497 | if (whole) { | 426 | if (whole) { |
| 498 | struct task_cputime cputime; | ||
| 499 | struct task_struct *t = task; | 427 | struct task_struct *t = task; |
| 500 | do { | 428 | do { |
| 501 | min_flt += t->min_flt; | 429 | min_flt += t->min_flt; |
| 502 | maj_flt += t->maj_flt; | 430 | maj_flt += t->maj_flt; |
| 503 | gtime = cputime_add(gtime, task_gtime(t)); | 431 | gtime = cputime_add(gtime, t->gtime); |
| 504 | t = next_thread(t); | 432 | t = next_thread(t); |
| 505 | } while (t != task); | 433 | } while (t != task); |
| 506 | 434 | ||
| 507 | min_flt += sig->min_flt; | 435 | min_flt += sig->min_flt; |
| 508 | maj_flt += sig->maj_flt; | 436 | maj_flt += sig->maj_flt; |
| 509 | thread_group_cputime(task, &cputime); | 437 | thread_group_times(task, &utime, &stime); |
| 510 | utime = cputime.utime; | ||
| 511 | stime = cputime.stime; | ||
| 512 | gtime = cputime_add(gtime, sig->gtime); | 438 | gtime = cputime_add(gtime, sig->gtime); |
| 513 | } | 439 | } |
| 514 | 440 | ||
| @@ -524,9 +450,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
| 524 | if (!whole) { | 450 | if (!whole) { |
| 525 | min_flt = task->min_flt; | 451 | min_flt = task->min_flt; |
| 526 | maj_flt = task->maj_flt; | 452 | maj_flt = task->maj_flt; |
| 527 | utime = task_utime(task); | 453 | task_times(task, &utime, &stime); |
| 528 | stime = task_stime(task); | 454 | gtime = task->gtime; |
| 529 | gtime = task_gtime(task); | ||
| 530 | } | 455 | } |
| 531 | 456 | ||
| 532 | /* scale priority and nice values from timeslices to -20..20 */ | 457 | /* scale priority and nice values from timeslices to -20..20 */ |
| @@ -571,7 +496,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
| 571 | rsslim, | 496 | rsslim, |
| 572 | mm ? mm->start_code : 0, | 497 | mm ? mm->start_code : 0, |
| 573 | mm ? mm->end_code : 0, | 498 | mm ? mm->end_code : 0, |
| 574 | (permitted) ? task->stack_start : 0, | 499 | (permitted && mm) ? task->stack_start : 0, |
| 575 | esp, | 500 | esp, |
| 576 | eip, | 501 | eip, |
| 577 | /* The signal information here is obsolete. | 502 | /* The signal information here is obsolete. |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 837469a96598..623e2ffb5d2b 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -1095,8 +1095,12 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, | |||
| 1095 | if (!capable(CAP_AUDIT_CONTROL)) | 1095 | if (!capable(CAP_AUDIT_CONTROL)) |
| 1096 | return -EPERM; | 1096 | return -EPERM; |
| 1097 | 1097 | ||
| 1098 | if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) | 1098 | rcu_read_lock(); |
| 1099 | if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { | ||
| 1100 | rcu_read_unlock(); | ||
| 1099 | return -EPERM; | 1101 | return -EPERM; |
| 1102 | } | ||
| 1103 | rcu_read_unlock(); | ||
| 1100 | 1104 | ||
| 1101 | if (count >= PAGE_SIZE) | 1105 | if (count >= PAGE_SIZE) |
| 1102 | count = PAGE_SIZE - 1; | 1106 | count = PAGE_SIZE - 1; |
| @@ -1265,6 +1269,72 @@ static const struct file_operations proc_pid_sched_operations = { | |||
| 1265 | 1269 | ||
| 1266 | #endif | 1270 | #endif |
| 1267 | 1271 | ||
| 1272 | static ssize_t comm_write(struct file *file, const char __user *buf, | ||
| 1273 | size_t count, loff_t *offset) | ||
| 1274 | { | ||
| 1275 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 1276 | struct task_struct *p; | ||
| 1277 | char buffer[TASK_COMM_LEN]; | ||
| 1278 | |||
| 1279 | memset(buffer, 0, sizeof(buffer)); | ||
| 1280 | if (count > sizeof(buffer) - 1) | ||
| 1281 | count = sizeof(buffer) - 1; | ||
| 1282 | if (copy_from_user(buffer, buf, count)) | ||
| 1283 | return -EFAULT; | ||
| 1284 | |||
| 1285 | p = get_proc_task(inode); | ||
| 1286 | if (!p) | ||
| 1287 | return -ESRCH; | ||
| 1288 | |||
| 1289 | if (same_thread_group(current, p)) | ||
| 1290 | set_task_comm(p, buffer); | ||
| 1291 | else | ||
| 1292 | count = -EINVAL; | ||
| 1293 | |||
| 1294 | put_task_struct(p); | ||
| 1295 | |||
| 1296 | return count; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | static int comm_show(struct seq_file *m, void *v) | ||
| 1300 | { | ||
| 1301 | struct inode *inode = m->private; | ||
| 1302 | struct task_struct *p; | ||
| 1303 | |||
| 1304 | p = get_proc_task(inode); | ||
| 1305 | if (!p) | ||
| 1306 | return -ESRCH; | ||
| 1307 | |||
| 1308 | task_lock(p); | ||
| 1309 | seq_printf(m, "%s\n", p->comm); | ||
| 1310 | task_unlock(p); | ||
| 1311 | |||
| 1312 | put_task_struct(p); | ||
| 1313 | |||
| 1314 | return 0; | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | static int comm_open(struct inode *inode, struct file *filp) | ||
| 1318 | { | ||
| 1319 | int ret; | ||
| 1320 | |||
| 1321 | ret = single_open(filp, comm_show, NULL); | ||
| 1322 | if (!ret) { | ||
| 1323 | struct seq_file *m = filp->private_data; | ||
| 1324 | |||
| 1325 | m->private = inode; | ||
| 1326 | } | ||
| 1327 | return ret; | ||
| 1328 | } | ||
| 1329 | |||
| 1330 | static const struct file_operations proc_pid_set_comm_operations = { | ||
| 1331 | .open = comm_open, | ||
| 1332 | .read = seq_read, | ||
| 1333 | .write = comm_write, | ||
| 1334 | .llseek = seq_lseek, | ||
| 1335 | .release = single_release, | ||
| 1336 | }; | ||
| 1337 | |||
| 1268 | /* | 1338 | /* |
| 1269 | * We added or removed a vma mapping the executable. The vmas are only mapped | 1339 | * We added or removed a vma mapping the executable. The vmas are only mapped |
| 1270 | * during exec and are not mapped with the mmap system call. | 1340 | * during exec and are not mapped with the mmap system call. |
| @@ -1353,7 +1423,6 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 1353 | goto out; | 1423 | goto out; |
| 1354 | 1424 | ||
| 1355 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->path); | 1425 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->path); |
| 1356 | nd->last_type = LAST_BIND; | ||
| 1357 | out: | 1426 | out: |
| 1358 | return ERR_PTR(error); | 1427 | return ERR_PTR(error); |
| 1359 | } | 1428 | } |
| @@ -2200,7 +2269,7 @@ static const struct inode_operations proc_attr_dir_inode_operations = { | |||
| 2200 | 2269 | ||
| 2201 | #endif | 2270 | #endif |
| 2202 | 2271 | ||
| 2203 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 2272 | #ifdef CONFIG_ELF_CORE |
| 2204 | static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, | 2273 | static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, |
| 2205 | size_t count, loff_t *ppos) | 2274 | size_t count, loff_t *ppos) |
| 2206 | { | 2275 | { |
| @@ -2304,16 +2373,30 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 2304 | { | 2373 | { |
| 2305 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | 2374 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; |
| 2306 | pid_t tgid = task_tgid_nr_ns(current, ns); | 2375 | pid_t tgid = task_tgid_nr_ns(current, ns); |
| 2307 | char tmp[PROC_NUMBUF]; | 2376 | char *name = ERR_PTR(-ENOENT); |
| 2308 | if (!tgid) | 2377 | if (tgid) { |
| 2309 | return ERR_PTR(-ENOENT); | 2378 | name = __getname(); |
| 2310 | sprintf(tmp, "%d", task_tgid_nr_ns(current, ns)); | 2379 | if (!name) |
| 2311 | return ERR_PTR(vfs_follow_link(nd,tmp)); | 2380 | name = ERR_PTR(-ENOMEM); |
| 2381 | else | ||
| 2382 | sprintf(name, "%d", tgid); | ||
| 2383 | } | ||
| 2384 | nd_set_link(nd, name); | ||
| 2385 | return NULL; | ||
| 2386 | } | ||
| 2387 | |||
| 2388 | static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, | ||
| 2389 | void *cookie) | ||
| 2390 | { | ||
| 2391 | char *s = nd_get_link(nd); | ||
| 2392 | if (!IS_ERR(s)) | ||
| 2393 | __putname(s); | ||
| 2312 | } | 2394 | } |
| 2313 | 2395 | ||
| 2314 | static const struct inode_operations proc_self_inode_operations = { | 2396 | static const struct inode_operations proc_self_inode_operations = { |
| 2315 | .readlink = proc_self_readlink, | 2397 | .readlink = proc_self_readlink, |
| 2316 | .follow_link = proc_self_follow_link, | 2398 | .follow_link = proc_self_follow_link, |
| 2399 | .put_link = proc_self_put_link, | ||
| 2317 | }; | 2400 | }; |
| 2318 | 2401 | ||
| 2319 | /* | 2402 | /* |
| @@ -2504,6 +2587,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
| 2504 | #ifdef CONFIG_SCHED_DEBUG | 2587 | #ifdef CONFIG_SCHED_DEBUG |
| 2505 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2588 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
| 2506 | #endif | 2589 | #endif |
| 2590 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | ||
| 2507 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2591 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
| 2508 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2592 | INF("syscall", S_IRUSR, proc_pid_syscall), |
| 2509 | #endif | 2593 | #endif |
| @@ -2556,7 +2640,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
| 2556 | #ifdef CONFIG_FAULT_INJECTION | 2640 | #ifdef CONFIG_FAULT_INJECTION |
| 2557 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), | 2641 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), |
| 2558 | #endif | 2642 | #endif |
| 2559 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 2643 | #ifdef CONFIG_ELF_CORE |
| 2560 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), | 2644 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), |
| 2561 | #endif | 2645 | #endif |
| 2562 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 2646 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
| @@ -2597,8 +2681,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) | |||
| 2597 | name.len = snprintf(buf, sizeof(buf), "%d", pid); | 2681 | name.len = snprintf(buf, sizeof(buf), "%d", pid); |
| 2598 | dentry = d_hash_and_lookup(mnt->mnt_root, &name); | 2682 | dentry = d_hash_and_lookup(mnt->mnt_root, &name); |
| 2599 | if (dentry) { | 2683 | if (dentry) { |
| 2600 | if (!(current->flags & PF_EXITING)) | 2684 | shrink_dcache_parent(dentry); |
| 2601 | shrink_dcache_parent(dentry); | ||
| 2602 | d_drop(dentry); | 2685 | d_drop(dentry); |
| 2603 | dput(dentry); | 2686 | dput(dentry); |
| 2604 | } | 2687 | } |
| @@ -2839,6 +2922,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
| 2839 | #ifdef CONFIG_SCHED_DEBUG | 2922 | #ifdef CONFIG_SCHED_DEBUG |
| 2840 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2923 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
| 2841 | #endif | 2924 | #endif |
| 2925 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | ||
| 2842 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2926 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
| 2843 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2927 | INF("syscall", S_IRUSR, proc_pid_syscall), |
| 2844 | #endif | 2928 | #endif |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index fa678abc9db1..480cb1065eec 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -429,7 +429,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | |||
| 429 | unsigned int ino; | 429 | unsigned int ino; |
| 430 | 430 | ||
| 431 | ino = de->low_ino; | 431 | ino = de->low_ino; |
| 432 | de_get(de); | 432 | pde_get(de); |
| 433 | spin_unlock(&proc_subdir_lock); | 433 | spin_unlock(&proc_subdir_lock); |
| 434 | error = -EINVAL; | 434 | error = -EINVAL; |
| 435 | inode = proc_get_inode(dir->i_sb, ino, de); | 435 | inode = proc_get_inode(dir->i_sb, ino, de); |
| @@ -445,7 +445,7 @@ out_unlock: | |||
| 445 | return NULL; | 445 | return NULL; |
| 446 | } | 446 | } |
| 447 | if (de) | 447 | if (de) |
| 448 | de_put(de); | 448 | pde_put(de); |
| 449 | return ERR_PTR(error); | 449 | return ERR_PTR(error); |
| 450 | } | 450 | } |
| 451 | 451 | ||
| @@ -509,17 +509,17 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, | |||
| 509 | struct proc_dir_entry *next; | 509 | struct proc_dir_entry *next; |
| 510 | 510 | ||
| 511 | /* filldir passes info to user space */ | 511 | /* filldir passes info to user space */ |
| 512 | de_get(de); | 512 | pde_get(de); |
| 513 | spin_unlock(&proc_subdir_lock); | 513 | spin_unlock(&proc_subdir_lock); |
| 514 | if (filldir(dirent, de->name, de->namelen, filp->f_pos, | 514 | if (filldir(dirent, de->name, de->namelen, filp->f_pos, |
| 515 | de->low_ino, de->mode >> 12) < 0) { | 515 | de->low_ino, de->mode >> 12) < 0) { |
| 516 | de_put(de); | 516 | pde_put(de); |
| 517 | goto out; | 517 | goto out; |
| 518 | } | 518 | } |
| 519 | spin_lock(&proc_subdir_lock); | 519 | spin_lock(&proc_subdir_lock); |
| 520 | filp->f_pos++; | 520 | filp->f_pos++; |
| 521 | next = de->next; | 521 | next = de->next; |
| 522 | de_put(de); | 522 | pde_put(de); |
| 523 | de = next; | 523 | de = next; |
| 524 | } while (de); | 524 | } while (de); |
| 525 | spin_unlock(&proc_subdir_lock); | 525 | spin_unlock(&proc_subdir_lock); |
| @@ -763,7 +763,7 @@ out: | |||
| 763 | return NULL; | 763 | return NULL; |
| 764 | } | 764 | } |
| 765 | 765 | ||
| 766 | void free_proc_entry(struct proc_dir_entry *de) | 766 | static void free_proc_entry(struct proc_dir_entry *de) |
| 767 | { | 767 | { |
| 768 | unsigned int ino = de->low_ino; | 768 | unsigned int ino = de->low_ino; |
| 769 | 769 | ||
| @@ -777,6 +777,12 @@ void free_proc_entry(struct proc_dir_entry *de) | |||
| 777 | kfree(de); | 777 | kfree(de); |
| 778 | } | 778 | } |
| 779 | 779 | ||
| 780 | void pde_put(struct proc_dir_entry *pde) | ||
| 781 | { | ||
| 782 | if (atomic_dec_and_test(&pde->count)) | ||
| 783 | free_proc_entry(pde); | ||
| 784 | } | ||
| 785 | |||
| 780 | /* | 786 | /* |
| 781 | * Remove a /proc entry and free it if it's not currently in use. | 787 | * Remove a /proc entry and free it if it's not currently in use. |
| 782 | */ | 788 | */ |
| @@ -845,6 +851,5 @@ continue_removing: | |||
| 845 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " | 851 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " |
| 846 | "'%s/%s', leaking at least '%s'\n", __func__, | 852 | "'%s/%s', leaking at least '%s'\n", __func__, |
| 847 | de->parent->name, de->name, de->subdir->name); | 853 | de->parent->name, de->name, de->subdir->name); |
| 848 | if (atomic_dec_and_test(&de->count)) | 854 | pde_put(de); |
| 849 | free_proc_entry(de); | ||
| 850 | } | 855 | } |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index d78ade305541..445a02bcaab3 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
| @@ -24,29 +24,6 @@ | |||
| 24 | 24 | ||
| 25 | #include "internal.h" | 25 | #include "internal.h" |
| 26 | 26 | ||
| 27 | struct proc_dir_entry *de_get(struct proc_dir_entry *de) | ||
| 28 | { | ||
| 29 | atomic_inc(&de->count); | ||
| 30 | return de; | ||
| 31 | } | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Decrements the use count and checks for deferred deletion. | ||
| 35 | */ | ||
| 36 | void de_put(struct proc_dir_entry *de) | ||
| 37 | { | ||
| 38 | if (!atomic_read(&de->count)) { | ||
| 39 | printk("de_put: entry %s already free!\n", de->name); | ||
| 40 | return; | ||
| 41 | } | ||
| 42 | |||
| 43 | if (atomic_dec_and_test(&de->count)) | ||
| 44 | free_proc_entry(de); | ||
| 45 | } | ||
| 46 | |||
| 47 | /* | ||
| 48 | * Decrement the use count of the proc_dir_entry. | ||
| 49 | */ | ||
| 50 | static void proc_delete_inode(struct inode *inode) | 27 | static void proc_delete_inode(struct inode *inode) |
| 51 | { | 28 | { |
| 52 | struct proc_dir_entry *de; | 29 | struct proc_dir_entry *de; |
| @@ -59,7 +36,7 @@ static void proc_delete_inode(struct inode *inode) | |||
| 59 | /* Let go of any associated proc directory entry */ | 36 | /* Let go of any associated proc directory entry */ |
| 60 | de = PROC_I(inode)->pde; | 37 | de = PROC_I(inode)->pde; |
| 61 | if (de) | 38 | if (de) |
| 62 | de_put(de); | 39 | pde_put(de); |
| 63 | if (PROC_I(inode)->sysctl) | 40 | if (PROC_I(inode)->sysctl) |
| 64 | sysctl_head_put(PROC_I(inode)->sysctl); | 41 | sysctl_head_put(PROC_I(inode)->sysctl); |
| 65 | clear_inode(inode); | 42 | clear_inode(inode); |
| @@ -480,7 +457,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
| 480 | } | 457 | } |
| 481 | unlock_new_inode(inode); | 458 | unlock_new_inode(inode); |
| 482 | } else | 459 | } else |
| 483 | de_put(de); | 460 | pde_put(de); |
| 484 | return inode; | 461 | return inode; |
| 485 | } | 462 | } |
| 486 | 463 | ||
| @@ -495,7 +472,7 @@ int proc_fill_super(struct super_block *s) | |||
| 495 | s->s_op = &proc_sops; | 472 | s->s_op = &proc_sops; |
| 496 | s->s_time_gran = 1; | 473 | s->s_time_gran = 1; |
| 497 | 474 | ||
| 498 | de_get(&proc_root); | 475 | pde_get(&proc_root); |
| 499 | root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); | 476 | root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); |
| 500 | if (!root_inode) | 477 | if (!root_inode) |
| 501 | goto out_no_root; | 478 | goto out_no_root; |
| @@ -509,6 +486,6 @@ int proc_fill_super(struct super_block *s) | |||
| 509 | out_no_root: | 486 | out_no_root: |
| 510 | printk("proc_read_super: get root inode failed\n"); | 487 | printk("proc_read_super: get root inode failed\n"); |
| 511 | iput(root_inode); | 488 | iput(root_inode); |
| 512 | de_put(&proc_root); | 489 | pde_put(&proc_root); |
| 513 | return -ENOMEM; | 490 | return -ENOMEM; |
| 514 | } | 491 | } |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 753ca37002c8..1f24a3eddd12 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
| @@ -61,8 +61,6 @@ extern const struct file_operations proc_pagemap_operations; | |||
| 61 | extern const struct file_operations proc_net_operations; | 61 | extern const struct file_operations proc_net_operations; |
| 62 | extern const struct inode_operations proc_net_inode_operations; | 62 | extern const struct inode_operations proc_net_inode_operations; |
| 63 | 63 | ||
| 64 | void free_proc_entry(struct proc_dir_entry *de); | ||
| 65 | |||
| 66 | void proc_init_inodecache(void); | 64 | void proc_init_inodecache(void); |
| 67 | 65 | ||
| 68 | static inline struct pid *proc_pid(struct inode *inode) | 66 | static inline struct pid *proc_pid(struct inode *inode) |
| @@ -101,8 +99,12 @@ unsigned long task_vsize(struct mm_struct *); | |||
| 101 | int task_statm(struct mm_struct *, int *, int *, int *, int *); | 99 | int task_statm(struct mm_struct *, int *, int *, int *, int *); |
| 102 | void task_mem(struct seq_file *, struct mm_struct *); | 100 | void task_mem(struct seq_file *, struct mm_struct *); |
| 103 | 101 | ||
| 104 | struct proc_dir_entry *de_get(struct proc_dir_entry *de); | 102 | static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) |
| 105 | void de_put(struct proc_dir_entry *de); | 103 | { |
| 104 | atomic_inc(&pde->count); | ||
| 105 | return pde; | ||
| 106 | } | ||
| 107 | void pde_put(struct proc_dir_entry *pde); | ||
| 106 | 108 | ||
| 107 | extern struct vfsmount *proc_mnt; | 109 | extern struct vfsmount *proc_mnt; |
| 108 | int proc_fill_super(struct super_block *); | 110 | int proc_fill_super(struct super_block *); |
diff --git a/fs/proc/page.c b/fs/proc/page.c index 5033ce0d254b..180cf5a0bd67 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/proc_fs.h> | 8 | #include <linux/proc_fs.h> |
| 9 | #include <linux/seq_file.h> | 9 | #include <linux/seq_file.h> |
| 10 | #include <linux/hugetlb.h> | 10 | #include <linux/hugetlb.h> |
| 11 | #include <linux/kernel-page-flags.h> | ||
| 11 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
| 12 | #include "internal.h" | 13 | #include "internal.h" |
| 13 | 14 | ||
| @@ -71,52 +72,12 @@ static const struct file_operations proc_kpagecount_operations = { | |||
| 71 | * physical page flags. | 72 | * physical page flags. |
| 72 | */ | 73 | */ |
| 73 | 74 | ||
| 74 | /* These macros are used to decouple internal flags from exported ones */ | ||
| 75 | |||
| 76 | #define KPF_LOCKED 0 | ||
| 77 | #define KPF_ERROR 1 | ||
| 78 | #define KPF_REFERENCED 2 | ||
| 79 | #define KPF_UPTODATE 3 | ||
| 80 | #define KPF_DIRTY 4 | ||
| 81 | #define KPF_LRU 5 | ||
| 82 | #define KPF_ACTIVE 6 | ||
| 83 | #define KPF_SLAB 7 | ||
| 84 | #define KPF_WRITEBACK 8 | ||
| 85 | #define KPF_RECLAIM 9 | ||
| 86 | #define KPF_BUDDY 10 | ||
| 87 | |||
| 88 | /* 11-20: new additions in 2.6.31 */ | ||
| 89 | #define KPF_MMAP 11 | ||
| 90 | #define KPF_ANON 12 | ||
| 91 | #define KPF_SWAPCACHE 13 | ||
| 92 | #define KPF_SWAPBACKED 14 | ||
| 93 | #define KPF_COMPOUND_HEAD 15 | ||
| 94 | #define KPF_COMPOUND_TAIL 16 | ||
| 95 | #define KPF_HUGE 17 | ||
| 96 | #define KPF_UNEVICTABLE 18 | ||
| 97 | #define KPF_HWPOISON 19 | ||
| 98 | #define KPF_NOPAGE 20 | ||
| 99 | |||
| 100 | #define KPF_KSM 21 | ||
| 101 | |||
| 102 | /* kernel hacking assistances | ||
| 103 | * WARNING: subject to change, never rely on them! | ||
| 104 | */ | ||
| 105 | #define KPF_RESERVED 32 | ||
| 106 | #define KPF_MLOCKED 33 | ||
| 107 | #define KPF_MAPPEDTODISK 34 | ||
| 108 | #define KPF_PRIVATE 35 | ||
| 109 | #define KPF_PRIVATE_2 36 | ||
| 110 | #define KPF_OWNER_PRIVATE 37 | ||
| 111 | #define KPF_ARCH 38 | ||
| 112 | #define KPF_UNCACHED 39 | ||
| 113 | |||
| 114 | static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit) | 75 | static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit) |
| 115 | { | 76 | { |
| 116 | return ((kflags >> kbit) & 1) << ubit; | 77 | return ((kflags >> kbit) & 1) << ubit; |
| 117 | } | 78 | } |
| 118 | 79 | ||
| 119 | static u64 get_uflags(struct page *page) | 80 | u64 stable_page_flags(struct page *page) |
| 120 | { | 81 | { |
| 121 | u64 k; | 82 | u64 k; |
| 122 | u64 u; | 83 | u64 u; |
| @@ -219,7 +180,7 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, | |||
| 219 | else | 180 | else |
| 220 | ppage = NULL; | 181 | ppage = NULL; |
| 221 | 182 | ||
| 222 | if (put_user(get_uflags(ppage), out)) { | 183 | if (put_user(stable_page_flags(ppage), out)) { |
| 223 | ret = -EFAULT; | 184 | ret = -EFAULT; |
| 224 | break; | 185 | break; |
| 225 | } | 186 | } |
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 7ba79a54948c..f8650dce74fb 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
| @@ -7,44 +7,49 @@ | |||
| 7 | #include <linux/init.h> | 7 | #include <linux/init.h> |
| 8 | #include <linux/time.h> | 8 | #include <linux/time.h> |
| 9 | #include <linux/proc_fs.h> | 9 | #include <linux/proc_fs.h> |
| 10 | #include <linux/seq_file.h> | ||
| 10 | #include <linux/stat.h> | 11 | #include <linux/stat.h> |
| 11 | #include <linux/string.h> | 12 | #include <linux/string.h> |
| 13 | #include <linux/of.h> | ||
| 14 | #include <linux/module.h> | ||
| 12 | #include <asm/prom.h> | 15 | #include <asm/prom.h> |
| 13 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
| 14 | #include "internal.h" | 17 | #include "internal.h" |
| 15 | 18 | ||
| 16 | #ifndef HAVE_ARCH_DEVTREE_FIXUPS | ||
| 17 | static inline void set_node_proc_entry(struct device_node *np, | 19 | static inline void set_node_proc_entry(struct device_node *np, |
| 18 | struct proc_dir_entry *de) | 20 | struct proc_dir_entry *de) |
| 19 | { | 21 | { |
| 20 | } | 22 | #ifdef HAVE_ARCH_DEVTREE_FIXUPS |
| 23 | np->pde = de; | ||
| 21 | #endif | 24 | #endif |
| 25 | } | ||
| 22 | 26 | ||
| 23 | static struct proc_dir_entry *proc_device_tree; | 27 | static struct proc_dir_entry *proc_device_tree; |
| 24 | 28 | ||
| 25 | /* | 29 | /* |
| 26 | * Supply data on a read from /proc/device-tree/node/property. | 30 | * Supply data on a read from /proc/device-tree/node/property. |
| 27 | */ | 31 | */ |
| 28 | static int property_read_proc(char *page, char **start, off_t off, | 32 | static int property_proc_show(struct seq_file *m, void *v) |
| 29 | int count, int *eof, void *data) | ||
| 30 | { | 33 | { |
| 31 | struct property *pp = data; | 34 | struct property *pp = m->private; |
| 32 | int n; | ||
| 33 | 35 | ||
| 34 | if (off >= pp->length) { | 36 | seq_write(m, pp->value, pp->length); |
| 35 | *eof = 1; | 37 | return 0; |
| 36 | return 0; | ||
| 37 | } | ||
| 38 | n = pp->length - off; | ||
| 39 | if (n > count) | ||
| 40 | n = count; | ||
| 41 | else | ||
| 42 | *eof = 1; | ||
| 43 | memcpy(page, (char *)pp->value + off, n); | ||
| 44 | *start = page; | ||
| 45 | return n; | ||
| 46 | } | 38 | } |
| 47 | 39 | ||
| 40 | static int property_proc_open(struct inode *inode, struct file *file) | ||
| 41 | { | ||
| 42 | return single_open(file, property_proc_show, PDE(inode)->data); | ||
| 43 | } | ||
| 44 | |||
| 45 | static const struct file_operations property_proc_fops = { | ||
| 46 | .owner = THIS_MODULE, | ||
| 47 | .open = property_proc_open, | ||
| 48 | .read = seq_read, | ||
| 49 | .llseek = seq_lseek, | ||
| 50 | .release = single_release, | ||
| 51 | }; | ||
| 52 | |||
| 48 | /* | 53 | /* |
| 49 | * For a node with a name like "gc@10", we make symlinks called "gc" | 54 | * For a node with a name like "gc@10", we make symlinks called "gc" |
| 50 | * and "@10" to it. | 55 | * and "@10" to it. |
| @@ -63,10 +68,9 @@ __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp, | |||
| 63 | * Unfortunately proc_register puts each new entry | 68 | * Unfortunately proc_register puts each new entry |
| 64 | * at the beginning of the list. So we rearrange them. | 69 | * at the beginning of the list. So we rearrange them. |
| 65 | */ | 70 | */ |
| 66 | ent = create_proc_read_entry(name, | 71 | ent = proc_create_data(name, |
| 67 | strncmp(name, "security-", 9) | 72 | strncmp(name, "security-", 9) ? S_IRUGO : S_IRUSR, |
| 68 | ? S_IRUGO : S_IRUSR, de, | 73 | de, &property_proc_fops, pp); |
| 69 | property_read_proc, pp); | ||
| 70 | if (ent == NULL) | 74 | if (ent == NULL) |
| 71 | return NULL; | 75 | return NULL; |
| 72 | 76 | ||
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index f667e8aeabdf..6ff9981f0a18 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
| @@ -48,7 +48,7 @@ out: | |||
| 48 | static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name) | 48 | static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name) |
| 49 | { | 49 | { |
| 50 | int len; | 50 | int len; |
| 51 | for ( ; p->ctl_name || p->procname; p++) { | 51 | for ( ; p->procname; p++) { |
| 52 | 52 | ||
| 53 | if (!p->procname) | 53 | if (!p->procname) |
| 54 | continue; | 54 | continue; |
| @@ -218,7 +218,7 @@ static int scan(struct ctl_table_header *head, ctl_table *table, | |||
| 218 | void *dirent, filldir_t filldir) | 218 | void *dirent, filldir_t filldir) |
| 219 | { | 219 | { |
| 220 | 220 | ||
| 221 | for (; table->ctl_name || table->procname; table++, (*pos)++) { | 221 | for (; table->procname; table++, (*pos)++) { |
| 222 | int res; | 222 | int res; |
| 223 | 223 | ||
| 224 | /* Can't do anything without a proc name */ | 224 | /* Can't do anything without a proc name */ |
diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 7cc726c6d70a..b9b7aad2003d 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c | |||
| @@ -27,7 +27,7 @@ static int show_stat(struct seq_file *p, void *v) | |||
| 27 | int i, j; | 27 | int i, j; |
| 28 | unsigned long jif; | 28 | unsigned long jif; |
| 29 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; | 29 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; |
| 30 | cputime64_t guest; | 30 | cputime64_t guest, guest_nice; |
| 31 | u64 sum = 0; | 31 | u64 sum = 0; |
| 32 | u64 sum_softirq = 0; | 32 | u64 sum_softirq = 0; |
| 33 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; | 33 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; |
| @@ -36,7 +36,7 @@ static int show_stat(struct seq_file *p, void *v) | |||
| 36 | 36 | ||
| 37 | user = nice = system = idle = iowait = | 37 | user = nice = system = idle = iowait = |
| 38 | irq = softirq = steal = cputime64_zero; | 38 | irq = softirq = steal = cputime64_zero; |
| 39 | guest = cputime64_zero; | 39 | guest = guest_nice = cputime64_zero; |
| 40 | getboottime(&boottime); | 40 | getboottime(&boottime); |
| 41 | jif = boottime.tv_sec; | 41 | jif = boottime.tv_sec; |
| 42 | 42 | ||
| @@ -51,6 +51,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
| 51 | softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); | 51 | softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); |
| 52 | steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); | 52 | steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); |
| 53 | guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); | 53 | guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); |
| 54 | guest_nice = cputime64_add(guest_nice, | ||
| 55 | kstat_cpu(i).cpustat.guest_nice); | ||
| 54 | for_each_irq_nr(j) { | 56 | for_each_irq_nr(j) { |
| 55 | sum += kstat_irqs_cpu(j, i); | 57 | sum += kstat_irqs_cpu(j, i); |
| 56 | } | 58 | } |
| @@ -65,7 +67,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
| 65 | } | 67 | } |
| 66 | sum += arch_irq_stat(); | 68 | sum += arch_irq_stat(); |
| 67 | 69 | ||
| 68 | seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", | 70 | seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu " |
| 71 | "%llu\n", | ||
| 69 | (unsigned long long)cputime64_to_clock_t(user), | 72 | (unsigned long long)cputime64_to_clock_t(user), |
| 70 | (unsigned long long)cputime64_to_clock_t(nice), | 73 | (unsigned long long)cputime64_to_clock_t(nice), |
| 71 | (unsigned long long)cputime64_to_clock_t(system), | 74 | (unsigned long long)cputime64_to_clock_t(system), |
| @@ -74,7 +77,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
| 74 | (unsigned long long)cputime64_to_clock_t(irq), | 77 | (unsigned long long)cputime64_to_clock_t(irq), |
| 75 | (unsigned long long)cputime64_to_clock_t(softirq), | 78 | (unsigned long long)cputime64_to_clock_t(softirq), |
| 76 | (unsigned long long)cputime64_to_clock_t(steal), | 79 | (unsigned long long)cputime64_to_clock_t(steal), |
| 77 | (unsigned long long)cputime64_to_clock_t(guest)); | 80 | (unsigned long long)cputime64_to_clock_t(guest), |
| 81 | (unsigned long long)cputime64_to_clock_t(guest_nice)); | ||
| 78 | for_each_online_cpu(i) { | 82 | for_each_online_cpu(i) { |
| 79 | 83 | ||
| 80 | /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ | 84 | /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ |
| @@ -88,8 +92,10 @@ static int show_stat(struct seq_file *p, void *v) | |||
| 88 | softirq = kstat_cpu(i).cpustat.softirq; | 92 | softirq = kstat_cpu(i).cpustat.softirq; |
| 89 | steal = kstat_cpu(i).cpustat.steal; | 93 | steal = kstat_cpu(i).cpustat.steal; |
| 90 | guest = kstat_cpu(i).cpustat.guest; | 94 | guest = kstat_cpu(i).cpustat.guest; |
| 95 | guest_nice = kstat_cpu(i).cpustat.guest_nice; | ||
| 91 | seq_printf(p, | 96 | seq_printf(p, |
| 92 | "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", | 97 | "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu " |
| 98 | "%llu\n", | ||
| 93 | i, | 99 | i, |
| 94 | (unsigned long long)cputime64_to_clock_t(user), | 100 | (unsigned long long)cputime64_to_clock_t(user), |
| 95 | (unsigned long long)cputime64_to_clock_t(nice), | 101 | (unsigned long long)cputime64_to_clock_t(nice), |
| @@ -99,7 +105,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
| 99 | (unsigned long long)cputime64_to_clock_t(irq), | 105 | (unsigned long long)cputime64_to_clock_t(irq), |
| 100 | (unsigned long long)cputime64_to_clock_t(softirq), | 106 | (unsigned long long)cputime64_to_clock_t(softirq), |
| 101 | (unsigned long long)cputime64_to_clock_t(steal), | 107 | (unsigned long long)cputime64_to_clock_t(steal), |
| 102 | (unsigned long long)cputime64_to_clock_t(guest)); | 108 | (unsigned long long)cputime64_to_clock_t(guest), |
| 109 | (unsigned long long)cputime64_to_clock_t(guest_nice)); | ||
| 103 | } | 110 | } |
| 104 | seq_printf(p, "intr %llu", (unsigned long long)sum); | 111 | seq_printf(p, "intr %llu", (unsigned long long)sum); |
| 105 | 112 | ||
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 2a1bef9203c6..f277c4a111cb 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
| @@ -361,12 +361,11 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
| 361 | if (!pte_present(ptent)) | 361 | if (!pte_present(ptent)) |
| 362 | continue; | 362 | continue; |
| 363 | 363 | ||
| 364 | mss->resident += PAGE_SIZE; | ||
| 365 | |||
| 366 | page = vm_normal_page(vma, addr, ptent); | 364 | page = vm_normal_page(vma, addr, ptent); |
| 367 | if (!page) | 365 | if (!page) |
| 368 | continue; | 366 | continue; |
| 369 | 367 | ||
| 368 | mss->resident += PAGE_SIZE; | ||
| 370 | /* Accumulate the size in pages that have been accessed. */ | 369 | /* Accumulate the size in pages that have been accessed. */ |
| 371 | if (pte_young(ptent) || PageReferenced(page)) | 370 | if (pte_young(ptent) || PageReferenced(page)) |
| 372 | mss->referenced += PAGE_SIZE; | 371 | mss->referenced += PAGE_SIZE; |
| @@ -650,6 +649,50 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
| 650 | return err; | 649 | return err; |
| 651 | } | 650 | } |
| 652 | 651 | ||
| 652 | static u64 huge_pte_to_pagemap_entry(pte_t pte, int offset) | ||
| 653 | { | ||
| 654 | u64 pme = 0; | ||
| 655 | if (pte_present(pte)) | ||
| 656 | pme = PM_PFRAME(pte_pfn(pte) + offset) | ||
| 657 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; | ||
| 658 | return pme; | ||
| 659 | } | ||
| 660 | |||
| 661 | static int pagemap_hugetlb_range(pte_t *pte, unsigned long addr, | ||
| 662 | unsigned long end, struct mm_walk *walk) | ||
| 663 | { | ||
| 664 | struct vm_area_struct *vma; | ||
| 665 | struct pagemapread *pm = walk->private; | ||
| 666 | struct hstate *hs = NULL; | ||
| 667 | int err = 0; | ||
| 668 | |||
| 669 | vma = find_vma(walk->mm, addr); | ||
| 670 | if (vma) | ||
| 671 | hs = hstate_vma(vma); | ||
| 672 | for (; addr != end; addr += PAGE_SIZE) { | ||
| 673 | u64 pfn = PM_NOT_PRESENT; | ||
| 674 | |||
| 675 | if (vma && (addr >= vma->vm_end)) { | ||
| 676 | vma = find_vma(walk->mm, addr); | ||
| 677 | if (vma) | ||
| 678 | hs = hstate_vma(vma); | ||
| 679 | } | ||
| 680 | |||
| 681 | if (vma && (vma->vm_start <= addr) && is_vm_hugetlb_page(vma)) { | ||
| 682 | /* calculate pfn of the "raw" page in the hugepage. */ | ||
| 683 | int offset = (addr & ~huge_page_mask(hs)) >> PAGE_SHIFT; | ||
| 684 | pfn = huge_pte_to_pagemap_entry(*pte, offset); | ||
| 685 | } | ||
| 686 | err = add_to_pagemap(addr, pfn, pm); | ||
| 687 | if (err) | ||
| 688 | return err; | ||
| 689 | } | ||
| 690 | |||
| 691 | cond_resched(); | ||
| 692 | |||
| 693 | return err; | ||
| 694 | } | ||
| 695 | |||
| 653 | /* | 696 | /* |
| 654 | * /proc/pid/pagemap - an array mapping virtual pages to pfns | 697 | * /proc/pid/pagemap - an array mapping virtual pages to pfns |
| 655 | * | 698 | * |
| @@ -742,6 +785,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
| 742 | 785 | ||
| 743 | pagemap_walk.pmd_entry = pagemap_pte_range; | 786 | pagemap_walk.pmd_entry = pagemap_pte_range; |
| 744 | pagemap_walk.pte_hole = pagemap_pte_hole; | 787 | pagemap_walk.pte_hole = pagemap_pte_hole; |
| 788 | pagemap_walk.hugetlb_entry = pagemap_hugetlb_range; | ||
| 745 | pagemap_walk.mm = mm; | 789 | pagemap_walk.mm = mm; |
| 746 | pagemap_walk.private = ± | 790 | pagemap_walk.private = ± |
| 747 | 791 | ||
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 8f5c05d3dbd3..5d9fd64ef81a 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
| @@ -110,9 +110,13 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, | |||
| 110 | } | 110 | } |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | size += (*text = mm->end_code - mm->start_code); | 113 | *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) |
| 114 | size += (*data = mm->start_stack - mm->start_data); | 114 | >> PAGE_SHIFT; |
| 115 | *data = (PAGE_ALIGN(mm->start_stack) - (mm->start_data & PAGE_MASK)) | ||
| 116 | >> PAGE_SHIFT; | ||
| 115 | up_read(&mm->mmap_sem); | 117 | up_read(&mm->mmap_sem); |
| 118 | size >>= PAGE_SHIFT; | ||
| 119 | size += *text + *data; | ||
| 116 | *resident = size; | 120 | *resident = size; |
| 117 | return size; | 121 | return size; |
| 118 | } | 122 | } |
