diff options
author | Jaroslav Kysela <perex@perex.cz> | 2010-01-08 03:26:34 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2010-01-08 03:26:34 -0500 |
commit | 1cb4f624ea38361b6397966470f0a1bed5532483 (patch) | |
tree | 418b05ddc854b09d64f7d5ee0c78875e42b5f151 /fs/proc | |
parent | 444c1953d496d272208902ff7010dc70d1f887f0 (diff) | |
parent | 2c1f1895ef2aa8f0e5497893eff71304aef332e1 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into fixes
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 19 | ||||
-rw-r--r-- | fs/proc/base.c | 72 | ||||
-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/task_mmu.c | 45 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 8 |
8 files changed, 159 insertions, 92 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 4badde179b18..f560325c444f 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; |
diff --git a/fs/proc/base.c b/fs/proc/base.c index af643b5aefe8..18d5cc62d8ed 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1265,6 +1265,72 @@ static const struct file_operations proc_pid_sched_operations = { | |||
1265 | 1265 | ||
1266 | #endif | 1266 | #endif |
1267 | 1267 | ||
1268 | static ssize_t comm_write(struct file *file, const char __user *buf, | ||
1269 | size_t count, loff_t *offset) | ||
1270 | { | ||
1271 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1272 | struct task_struct *p; | ||
1273 | char buffer[TASK_COMM_LEN]; | ||
1274 | |||
1275 | memset(buffer, 0, sizeof(buffer)); | ||
1276 | if (count > sizeof(buffer) - 1) | ||
1277 | count = sizeof(buffer) - 1; | ||
1278 | if (copy_from_user(buffer, buf, count)) | ||
1279 | return -EFAULT; | ||
1280 | |||
1281 | p = get_proc_task(inode); | ||
1282 | if (!p) | ||
1283 | return -ESRCH; | ||
1284 | |||
1285 | if (same_thread_group(current, p)) | ||
1286 | set_task_comm(p, buffer); | ||
1287 | else | ||
1288 | count = -EINVAL; | ||
1289 | |||
1290 | put_task_struct(p); | ||
1291 | |||
1292 | return count; | ||
1293 | } | ||
1294 | |||
1295 | static int comm_show(struct seq_file *m, void *v) | ||
1296 | { | ||
1297 | struct inode *inode = m->private; | ||
1298 | struct task_struct *p; | ||
1299 | |||
1300 | p = get_proc_task(inode); | ||
1301 | if (!p) | ||
1302 | return -ESRCH; | ||
1303 | |||
1304 | task_lock(p); | ||
1305 | seq_printf(m, "%s\n", p->comm); | ||
1306 | task_unlock(p); | ||
1307 | |||
1308 | put_task_struct(p); | ||
1309 | |||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | static int comm_open(struct inode *inode, struct file *filp) | ||
1314 | { | ||
1315 | int ret; | ||
1316 | |||
1317 | ret = single_open(filp, comm_show, NULL); | ||
1318 | if (!ret) { | ||
1319 | struct seq_file *m = filp->private_data; | ||
1320 | |||
1321 | m->private = inode; | ||
1322 | } | ||
1323 | return ret; | ||
1324 | } | ||
1325 | |||
1326 | static const struct file_operations proc_pid_set_comm_operations = { | ||
1327 | .open = comm_open, | ||
1328 | .read = seq_read, | ||
1329 | .write = comm_write, | ||
1330 | .llseek = seq_lseek, | ||
1331 | .release = single_release, | ||
1332 | }; | ||
1333 | |||
1268 | /* | 1334 | /* |
1269 | * We added or removed a vma mapping the executable. The vmas are only mapped | 1335 | * 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. | 1336 | * during exec and are not mapped with the mmap system call. |
@@ -2200,7 +2266,7 @@ static const struct inode_operations proc_attr_dir_inode_operations = { | |||
2200 | 2266 | ||
2201 | #endif | 2267 | #endif |
2202 | 2268 | ||
2203 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 2269 | #ifdef CONFIG_ELF_CORE |
2204 | static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, | 2270 | static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, |
2205 | size_t count, loff_t *ppos) | 2271 | size_t count, loff_t *ppos) |
2206 | { | 2272 | { |
@@ -2504,6 +2570,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2504 | #ifdef CONFIG_SCHED_DEBUG | 2570 | #ifdef CONFIG_SCHED_DEBUG |
2505 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2571 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
2506 | #endif | 2572 | #endif |
2573 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | ||
2507 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2574 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
2508 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2575 | INF("syscall", S_IRUSR, proc_pid_syscall), |
2509 | #endif | 2576 | #endif |
@@ -2556,7 +2623,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2556 | #ifdef CONFIG_FAULT_INJECTION | 2623 | #ifdef CONFIG_FAULT_INJECTION |
2557 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), | 2624 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), |
2558 | #endif | 2625 | #endif |
2559 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 2626 | #ifdef CONFIG_ELF_CORE |
2560 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), | 2627 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), |
2561 | #endif | 2628 | #endif |
2562 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 2629 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
@@ -2838,6 +2905,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
2838 | #ifdef CONFIG_SCHED_DEBUG | 2905 | #ifdef CONFIG_SCHED_DEBUG |
2839 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2906 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
2840 | #endif | 2907 | #endif |
2908 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | ||
2841 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2909 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
2842 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2910 | INF("syscall", S_IRUSR, proc_pid_syscall), |
2843 | #endif | 2911 | #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/task_mmu.c b/fs/proc/task_mmu.c index 2a1bef9203c6..47c03f4336b8 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -650,6 +650,50 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
650 | return err; | 650 | return err; |
651 | } | 651 | } |
652 | 652 | ||
653 | static u64 huge_pte_to_pagemap_entry(pte_t pte, int offset) | ||
654 | { | ||
655 | u64 pme = 0; | ||
656 | if (pte_present(pte)) | ||
657 | pme = PM_PFRAME(pte_pfn(pte) + offset) | ||
658 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; | ||
659 | return pme; | ||
660 | } | ||
661 | |||
662 | static int pagemap_hugetlb_range(pte_t *pte, unsigned long addr, | ||
663 | unsigned long end, struct mm_walk *walk) | ||
664 | { | ||
665 | struct vm_area_struct *vma; | ||
666 | struct pagemapread *pm = walk->private; | ||
667 | struct hstate *hs = NULL; | ||
668 | int err = 0; | ||
669 | |||
670 | vma = find_vma(walk->mm, addr); | ||
671 | if (vma) | ||
672 | hs = hstate_vma(vma); | ||
673 | for (; addr != end; addr += PAGE_SIZE) { | ||
674 | u64 pfn = PM_NOT_PRESENT; | ||
675 | |||
676 | if (vma && (addr >= vma->vm_end)) { | ||
677 | vma = find_vma(walk->mm, addr); | ||
678 | if (vma) | ||
679 | hs = hstate_vma(vma); | ||
680 | } | ||
681 | |||
682 | if (vma && (vma->vm_start <= addr) && is_vm_hugetlb_page(vma)) { | ||
683 | /* calculate pfn of the "raw" page in the hugepage. */ | ||
684 | int offset = (addr & ~huge_page_mask(hs)) >> PAGE_SHIFT; | ||
685 | pfn = huge_pte_to_pagemap_entry(*pte, offset); | ||
686 | } | ||
687 | err = add_to_pagemap(addr, pfn, pm); | ||
688 | if (err) | ||
689 | return err; | ||
690 | } | ||
691 | |||
692 | cond_resched(); | ||
693 | |||
694 | return err; | ||
695 | } | ||
696 | |||
653 | /* | 697 | /* |
654 | * /proc/pid/pagemap - an array mapping virtual pages to pfns | 698 | * /proc/pid/pagemap - an array mapping virtual pages to pfns |
655 | * | 699 | * |
@@ -742,6 +786,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
742 | 786 | ||
743 | pagemap_walk.pmd_entry = pagemap_pte_range; | 787 | pagemap_walk.pmd_entry = pagemap_pte_range; |
744 | pagemap_walk.pte_hole = pagemap_pte_hole; | 788 | pagemap_walk.pte_hole = pagemap_pte_hole; |
789 | pagemap_walk.hugetlb_entry = pagemap_hugetlb_range; | ||
745 | pagemap_walk.mm = mm; | 790 | pagemap_walk.mm = mm; |
746 | pagemap_walk.private = ± | 791 | pagemap_walk.private = ± |
747 | 792 | ||
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 | } |