Root/
1 | #include <linux/bootmem.h> |
2 | #include <linux/compiler.h> |
3 | #include <linux/fs.h> |
4 | #include <linux/init.h> |
5 | #include <linux/mm.h> |
6 | #include <linux/mmzone.h> |
7 | #include <linux/proc_fs.h> |
8 | #include <linux/seq_file.h> |
9 | #include <linux/hugetlb.h> |
10 | #include <asm/uaccess.h> |
11 | #include "internal.h" |
12 | |
13 | #define KPMSIZE sizeof(u64) |
14 | #define KPMMASK (KPMSIZE - 1) |
15 | |
16 | /* /proc/kpagecount - an array exposing page counts |
17 | * |
18 | * Each entry is a u64 representing the corresponding |
19 | * physical page count. |
20 | */ |
21 | static ssize_t kpagecount_read(struct file *file, char __user *buf, |
22 | size_t count, loff_t *ppos) |
23 | { |
24 | u64 __user *out = (u64 __user *)buf; |
25 | struct page *ppage; |
26 | unsigned long src = *ppos; |
27 | unsigned long pfn; |
28 | ssize_t ret = 0; |
29 | u64 pcount; |
30 | |
31 | pfn = src / KPMSIZE; |
32 | count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); |
33 | if (src & KPMMASK || count & KPMMASK) |
34 | return -EINVAL; |
35 | |
36 | while (count > 0) { |
37 | if (pfn_valid(pfn)) |
38 | ppage = pfn_to_page(pfn); |
39 | else |
40 | ppage = NULL; |
41 | if (!ppage) |
42 | pcount = 0; |
43 | else |
44 | pcount = page_mapcount(ppage); |
45 | |
46 | if (put_user(pcount, out)) { |
47 | ret = -EFAULT; |
48 | break; |
49 | } |
50 | |
51 | pfn++; |
52 | out++; |
53 | count -= KPMSIZE; |
54 | } |
55 | |
56 | *ppos += (char __user *)out - buf; |
57 | if (!ret) |
58 | ret = (char __user *)out - buf; |
59 | return ret; |
60 | } |
61 | |
62 | static const struct file_operations proc_kpagecount_operations = { |
63 | .llseek = mem_lseek, |
64 | .read = kpagecount_read, |
65 | }; |
66 | |
67 | /* /proc/kpageflags - an array exposing page flags |
68 | * |
69 | * Each entry is a u64 representing the corresponding |
70 | * physical page flags. |
71 | */ |
72 | |
73 | /* These macros are used to decouple internal flags from exported ones */ |
74 | |
75 | #define KPF_LOCKED 0 |
76 | #define KPF_ERROR 1 |
77 | #define KPF_REFERENCED 2 |
78 | #define KPF_UPTODATE 3 |
79 | #define KPF_DIRTY 4 |
80 | #define KPF_LRU 5 |
81 | #define KPF_ACTIVE 6 |
82 | #define KPF_SLAB 7 |
83 | #define KPF_WRITEBACK 8 |
84 | #define KPF_RECLAIM 9 |
85 | #define KPF_BUDDY 10 |
86 | |
87 | /* 11-20: new additions in 2.6.31 */ |
88 | #define KPF_MMAP 11 |
89 | #define KPF_ANON 12 |
90 | #define KPF_SWAPCACHE 13 |
91 | #define KPF_SWAPBACKED 14 |
92 | #define KPF_COMPOUND_HEAD 15 |
93 | #define KPF_COMPOUND_TAIL 16 |
94 | #define KPF_HUGE 17 |
95 | #define KPF_UNEVICTABLE 18 |
96 | #define KPF_NOPAGE 20 |
97 | |
98 | /* kernel hacking assistances |
99 | * WARNING: subject to change, never rely on them! |
100 | */ |
101 | #define KPF_RESERVED 32 |
102 | #define KPF_MLOCKED 33 |
103 | #define KPF_MAPPEDTODISK 34 |
104 | #define KPF_PRIVATE 35 |
105 | #define KPF_PRIVATE_2 36 |
106 | #define KPF_OWNER_PRIVATE 37 |
107 | #define KPF_ARCH 38 |
108 | #define KPF_UNCACHED 39 |
109 | |
110 | static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit) |
111 | { |
112 | return ((kflags >> kbit) & 1) << ubit; |
113 | } |
114 | |
115 | static u64 get_uflags(struct page *page) |
116 | { |
117 | u64 k; |
118 | u64 u; |
119 | |
120 | /* |
121 | * pseudo flag: KPF_NOPAGE |
122 | * it differentiates a memory hole from a page with no flags |
123 | */ |
124 | if (!page) |
125 | return 1 << KPF_NOPAGE; |
126 | |
127 | k = page->flags; |
128 | u = 0; |
129 | |
130 | /* |
131 | * pseudo flags for the well known (anonymous) memory mapped pages |
132 | * |
133 | * Note that page->_mapcount is overloaded in SLOB/SLUB/SLQB, so the |
134 | * simple test in page_mapped() is not enough. |
135 | */ |
136 | if (!PageSlab(page) && page_mapped(page)) |
137 | u |= 1 << KPF_MMAP; |
138 | if (PageAnon(page)) |
139 | u |= 1 << KPF_ANON; |
140 | |
141 | /* |
142 | * compound pages: export both head/tail info |
143 | * they together define a compound page's start/end pos and order |
144 | */ |
145 | if (PageHead(page)) |
146 | u |= 1 << KPF_COMPOUND_HEAD; |
147 | if (PageTail(page)) |
148 | u |= 1 << KPF_COMPOUND_TAIL; |
149 | if (PageHuge(page)) |
150 | u |= 1 << KPF_HUGE; |
151 | |
152 | u |= kpf_copy_bit(k, KPF_LOCKED, PG_locked); |
153 | |
154 | /* |
155 | * Caveats on high order pages: |
156 | * PG_buddy will only be set on the head page; SLUB/SLQB do the same |
157 | * for PG_slab; SLOB won't set PG_slab at all on compound pages. |
158 | */ |
159 | u |= kpf_copy_bit(k, KPF_SLAB, PG_slab); |
160 | u |= kpf_copy_bit(k, KPF_BUDDY, PG_buddy); |
161 | |
162 | u |= kpf_copy_bit(k, KPF_ERROR, PG_error); |
163 | u |= kpf_copy_bit(k, KPF_DIRTY, PG_dirty); |
164 | u |= kpf_copy_bit(k, KPF_UPTODATE, PG_uptodate); |
165 | u |= kpf_copy_bit(k, KPF_WRITEBACK, PG_writeback); |
166 | |
167 | u |= kpf_copy_bit(k, KPF_LRU, PG_lru); |
168 | u |= kpf_copy_bit(k, KPF_REFERENCED, PG_referenced); |
169 | u |= kpf_copy_bit(k, KPF_ACTIVE, PG_active); |
170 | u |= kpf_copy_bit(k, KPF_RECLAIM, PG_reclaim); |
171 | |
172 | u |= kpf_copy_bit(k, KPF_SWAPCACHE, PG_swapcache); |
173 | u |= kpf_copy_bit(k, KPF_SWAPBACKED, PG_swapbacked); |
174 | |
175 | u |= kpf_copy_bit(k, KPF_UNEVICTABLE, PG_unevictable); |
176 | u |= kpf_copy_bit(k, KPF_MLOCKED, PG_mlocked); |
177 | |
178 | #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR |
179 | u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached); |
180 | #endif |
181 | |
182 | u |= kpf_copy_bit(k, KPF_RESERVED, PG_reserved); |
183 | u |= kpf_copy_bit(k, KPF_MAPPEDTODISK, PG_mappedtodisk); |
184 | u |= kpf_copy_bit(k, KPF_PRIVATE, PG_private); |
185 | u |= kpf_copy_bit(k, KPF_PRIVATE_2, PG_private_2); |
186 | u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1); |
187 | u |= kpf_copy_bit(k, KPF_ARCH, PG_arch_1); |
188 | |
189 | return u; |
190 | }; |
191 | |
192 | static ssize_t kpageflags_read(struct file *file, char __user *buf, |
193 | size_t count, loff_t *ppos) |
194 | { |
195 | u64 __user *out = (u64 __user *)buf; |
196 | struct page *ppage; |
197 | unsigned long src = *ppos; |
198 | unsigned long pfn; |
199 | ssize_t ret = 0; |
200 | |
201 | pfn = src / KPMSIZE; |
202 | count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); |
203 | if (src & KPMMASK || count & KPMMASK) |
204 | return -EINVAL; |
205 | |
206 | while (count > 0) { |
207 | if (pfn_valid(pfn)) |
208 | ppage = pfn_to_page(pfn); |
209 | else |
210 | ppage = NULL; |
211 | |
212 | if (put_user(get_uflags(ppage), out)) { |
213 | ret = -EFAULT; |
214 | break; |
215 | } |
216 | |
217 | pfn++; |
218 | out++; |
219 | count -= KPMSIZE; |
220 | } |
221 | |
222 | *ppos += (char __user *)out - buf; |
223 | if (!ret) |
224 | ret = (char __user *)out - buf; |
225 | return ret; |
226 | } |
227 | |
228 | static const struct file_operations proc_kpageflags_operations = { |
229 | .llseek = mem_lseek, |
230 | .read = kpageflags_read, |
231 | }; |
232 | |
233 | static int __init proc_page_init(void) |
234 | { |
235 | proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations); |
236 | proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations); |
237 | return 0; |
238 | } |
239 | module_init(proc_page_init); |
240 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9