memcg: replace ss->id_lock with a rwlock
[pandora-kernel.git] / arch / um / os-Linux / sys-i386 / task_size.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <sys/mman.h>
5 #include "longjmp.h"
6 #include "kern_constants.h"
7
8 static jmp_buf buf;
9
10 static void segfault(int sig)
11 {
12         longjmp(buf, 1);
13 }
14
15 static int page_ok(unsigned long page)
16 {
17         unsigned long *address = (unsigned long *) (page << UM_KERN_PAGE_SHIFT);
18         unsigned long n = ~0UL;
19         void *mapped = NULL;
20         int ok = 0;
21
22         /*
23          * First see if the page is readable.  If it is, it may still
24          * be a VDSO, so we go on to see if it's writable.  If not
25          * then try mapping memory there.  If that fails, then we're
26          * still in the kernel area.  As a sanity check, we'll fail if
27          * the mmap succeeds, but gives us an address different from
28          * what we wanted.
29          */
30         if (setjmp(buf) == 0)
31                 n = *address;
32         else {
33                 mapped = mmap(address, UM_KERN_PAGE_SIZE,
34                               PROT_READ | PROT_WRITE,
35                               MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
36                 if (mapped == MAP_FAILED)
37                         return 0;
38                 if (mapped != address)
39                         goto out;
40         }
41
42         /*
43          * Now, is it writeable?  If so, then we're in user address
44          * space.  If not, then try mprotecting it and try the write
45          * again.
46          */
47         if (setjmp(buf) == 0) {
48                 *address = n;
49                 ok = 1;
50                 goto out;
51         } else if (mprotect(address, UM_KERN_PAGE_SIZE,
52                             PROT_READ | PROT_WRITE) != 0)
53                 goto out;
54
55         if (setjmp(buf) == 0) {
56                 *address = n;
57                 ok = 1;
58         }
59
60  out:
61         if (mapped != NULL)
62                 munmap(mapped, UM_KERN_PAGE_SIZE);
63         return ok;
64 }
65
66 unsigned long os_get_top_address(void)
67 {
68         struct sigaction sa, old;
69         unsigned long bottom = 0;
70         /*
71          * A 32-bit UML on a 64-bit host gets confused about the VDSO at
72          * 0xffffe000.  It is mapped, is readable, can be reprotected writeable
73          * and written.  However, exec discovers later that it can't be
74          * unmapped.  So, just set the highest address to be checked to just
75          * below it.  This might waste some address space on 4G/4G 32-bit
76          * hosts, but shouldn't hurt otherwise.
77          */
78         unsigned long top = 0xffffd000 >> UM_KERN_PAGE_SHIFT;
79         unsigned long test, original;
80
81         printf("Locating the bottom of the address space ... ");
82         fflush(stdout);
83
84         /*
85          * We're going to be longjmping out of the signal handler, so
86          * SA_DEFER needs to be set.
87          */
88         sa.sa_handler = segfault;
89         sigemptyset(&sa.sa_mask);
90         sa.sa_flags = SA_NODEFER;
91         if (sigaction(SIGSEGV, &sa, &old)) {
92                 perror("os_get_top_address");
93                 exit(1);
94         }
95
96         /* Manually scan the address space, bottom-up, until we find
97          * the first valid page (or run out of them).
98          */
99         for (bottom = 0; bottom < top; bottom++) {
100                 if (page_ok(bottom))
101                         break;
102         }
103
104         /* If we've got this far, we ran out of pages. */
105         if (bottom == top) {
106                 fprintf(stderr, "Unable to determine bottom of address "
107                         "space.\n");
108                 exit(1);
109         }
110
111         printf("0x%x\n", bottom << UM_KERN_PAGE_SHIFT);
112         printf("Locating the top of the address space ... ");
113         fflush(stdout);
114
115         original = bottom;
116
117         /* This could happen with a 4G/4G split */
118         if (page_ok(top))
119                 goto out;
120
121         do {
122                 test = bottom + (top - bottom) / 2;
123                 if (page_ok(test))
124                         bottom = test;
125                 else
126                         top = test;
127         } while (top - bottom > 1);
128
129 out:
130         /* Restore the old SIGSEGV handling */
131         if (sigaction(SIGSEGV, &old, NULL)) {
132                 perror("os_get_top_address");
133                 exit(1);
134         }
135         top <<= UM_KERN_PAGE_SHIFT;
136         printf("0x%x\n", top);
137
138         return top;
139 }