diff options
Diffstat (limited to 'fs/proc')
| -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 |
7 files changed, 147 insertions, 85 deletions
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 | } |
