Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <fcntl.h>
3 : : #include <stdio.h>
4 : : #include <sys/stat.h>
5 : : #include <sys/types.h>
6 : : #include <sys/mman.h>
7 : : #include <errno.h>
8 : :
9 : : #include "log.h"
10 : : #include "bug.h"
11 : : #include "kerndat.h"
12 : : #include "fs-magic.h"
13 : : #include "mem.h"
14 : : #include "compiler.h"
15 : : #include "sysctl.h"
16 : : #include "asm/types.h"
17 : : #include "cr_options.h"
18 : : #include "util.h"
19 : :
20 : : dev_t kerndat_shmem_dev;
21 : :
22 : : /*
23 : : * Anonymous shared mappings are backed by hidden tmpfs
24 : : * mount. Find out its dev to distinguish such mappings
25 : : * from real tmpfs files maps.
26 : : */
27 : :
28 : 1792 : static int kerndat_get_shmemdev(void)
29 : : {
30 : : void *map;
31 : : char maps[128];
32 : : struct stat buf;
33 : :
34 : 1792 : map = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
35 : : MAP_SHARED | MAP_ANONYMOUS, 0, 0);
36 [ - + ]: 1792 : if (map == MAP_FAILED) {
37 : 0 : pr_perror("Can't mmap memory for shmemdev test");
38 : 0 : return -1;
39 : : }
40 : :
41 : 1792 : sprintf(maps, "/proc/self/map_files/%lx-%lx",
42 : 1792 : (unsigned long)map, (unsigned long)map + PAGE_SIZE);
43 [ - + ]: 1792 : if (stat(maps, &buf) < 0) {
44 : 0 : munmap(map, PAGE_SIZE);
45 : 0 : pr_perror("Can't stat self map_files");
46 : 0 : return -1;
47 : : }
48 : :
49 : 1792 : munmap(map, PAGE_SIZE);
50 : :
51 : 1792 : kerndat_shmem_dev = buf.st_dev;
52 : 1792 : pr_info("Found anon-shmem device at %"PRIx64"\n", kerndat_shmem_dev);
53 : 1792 : return 0;
54 : : }
55 : :
56 : 210 : struct stat *kerndat_get_devpts_stat()
57 : : {
58 : : static struct stat st = {};
59 : : struct statfs fst;
60 : :
61 [ + - ]: 210 : if (st.st_dev != 0)
62 : : return &st;
63 : :
64 [ - + ]: 210 : if (statfs("/dev/pts", &fst)) {
65 : 0 : pr_perror("Unable to statefs /dev/pts");
66 : 0 : return NULL;
67 : : }
68 [ - + ]: 210 : if (fst.f_type != DEVPTS_SUPER_MAGIC) {
69 : 0 : pr_err("devpts isn't mount on the host\n");
70 : 0 : return NULL;
71 : : }
72 : :
73 : : /* The root /dev/pts is mounted w/o newinstance, isn't it? */
74 [ - + ]: 210 : if (stat("/dev/pts", &st)) {
75 : 0 : pr_perror("Unable to stat /dev/pts");
76 : 0 : return NULL;
77 : : }
78 : :
79 : : return &st;
80 : : }
81 : :
82 : : /*
83 : : * Check whether pagemap reports soft dirty bit. Kernel has
84 : : * this functionality under CONFIG_MEM_SOFT_DIRTY option.
85 : : */
86 : :
87 : : bool kerndat_has_dirty_track = false;
88 : :
89 : 1794 : int kerndat_get_dirty_track(void)
90 : : {
91 : : char *map;
92 : : int pm2;
93 : 1794 : u64 pmap = 0;
94 : : int ret = -1;
95 : :
96 : 1794 : map = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
97 : : MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
98 [ - + ]: 1794 : if (map == MAP_FAILED) {
99 : 0 : pr_perror("Can't mmap memory for pagemap test");
100 : 0 : return ret;
101 : : }
102 : :
103 : : /*
104 : : * Kernel shows soft-dirty bits only if this soft-dirty
105 : : * was at least once re-set. (this is to be removed in
106 : : * a couple of kernel releases)
107 : : */
108 : 1794 : do_task_reset_dirty_track(getpid());
109 : : pm2 = open("/proc/self/pagemap", O_RDONLY);
110 [ - + ]: 1794 : if (pm2 < 0) {
111 : 0 : pr_perror("Can't open pagemap file");
112 : 0 : munmap(map, PAGE_SIZE);
113 : 0 : return ret;
114 : : }
115 : :
116 : 1794 : map[0] = '\0';
117 : :
118 : 1794 : lseek(pm2, (unsigned long)map / PAGE_SIZE * sizeof(u64), SEEK_SET);
119 : 1794 : ret = read(pm2, &pmap, sizeof(pmap));
120 [ - + ]: 1794 : if (ret < 0)
121 : 0 : pr_perror("Read pmap err!");
122 : :
123 : 1794 : close(pm2);
124 : 1794 : munmap(map, PAGE_SIZE);
125 : :
126 [ + - ]: 1794 : if (pmap & PME_SOFT_DIRTY) {
127 : 1794 : pr_info("Dirty track supported on kernel\n");
128 : 1794 : kerndat_has_dirty_track = true;
129 : : } else {
130 : 0 : pr_info("Dirty tracking support is OFF\n");
131 [ # # ]: 0 : if (opts.track_mem) {
132 : 0 : pr_err("Tracking memory is not available\n");
133 : 0 : return -1;
134 : : }
135 : : }
136 : :
137 : : return 0;
138 : : }
139 : :
140 : : /*
141 : : * Strictly speaking, if there is a machine with huge amount
142 : : * of memory, we're allowed to send up to 4M and read up to
143 : : * 6M of tcp data at once. But we will figure out precise size
144 : : * of a limit a bit later when restore starts.
145 : : *
146 : : * Meanwhile set it up to 2M and 3M, which is safe enough to
147 : : * proceed without errors.
148 : : */
149 : : int tcp_max_wshare = 2U << 20;
150 : : int tcp_max_rshare = 3U << 20;
151 : :
152 : 1013 : static int tcp_read_sysctl_limits(void)
153 : : {
154 : 1013 : u32 vect[2][3] = { };
155 : : int ret;
156 : :
157 : 1013 : struct sysctl_req req[] = {
158 : : { "net/ipv4/tcp_wmem", &vect[0], CTL_U32A(ARRAY_SIZE(vect[0])) },
159 : : { "net/ipv4/tcp_rmem", &vect[1], CTL_U32A(ARRAY_SIZE(vect[1])) },
160 : : { },
161 : : };
162 : :
163 : : /*
164 : : * Lets figure out which exactly amount of memory is
165 : : * availabe for send/read queues on restore.
166 : : */
167 : 1013 : ret = sysctl_op(req, CTL_READ);
168 [ - + ]: 1013 : if (ret) {
169 : 0 : pr_warn("TCP mem sysctls are not available. Using defaults.\n");
170 : 0 : goto out;
171 : : }
172 : :
173 : 1013 : tcp_max_wshare = min(tcp_max_wshare, (int)vect[0][2]);
174 : 1013 : tcp_max_rshare = min(tcp_max_rshare, (int)vect[1][2]);
175 : :
176 [ + - ][ - + ]: 1013 : if (tcp_max_wshare < 128 || tcp_max_rshare < 128)
177 : 0 : pr_warn("The memory limits for TCP queues are suspiciously small\n");
178 : : out:
179 : 1013 : pr_debug("TCP queue memory limits are %d:%d\n", tcp_max_wshare, tcp_max_rshare);
180 : 1013 : return 0;
181 : : }
182 : :
183 : : /* The page frame number (PFN) is constant for the zero page */
184 : : u64 zero_page_pfn;
185 : :
186 : 1792 : static int init_zero_page_pfn()
187 : : {
188 : : void *addr;
189 : : int ret;
190 : :
191 : 1792 : addr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
192 [ - + ]: 1792 : if (addr == MAP_FAILED) {
193 : 0 : pr_perror("Unable to map zero page");
194 : 0 : return 0;
195 : : }
196 : :
197 [ - + ]: 1792 : if (*((int *) addr) != 0) {
198 : 0 : BUG();
199 : 0 : return -1;
200 : : }
201 : :
202 : 1792 : ret = vaddr_to_pfn((unsigned long)addr, &zero_page_pfn);
203 : 1792 : munmap(addr, PAGE_SIZE);
204 : :
205 [ - + ]: 1792 : if (zero_page_pfn == 0)
206 : : ret = -1;
207 : :
208 : 1792 : return ret;
209 : : }
210 : :
211 : 1792 : int kerndat_init(void)
212 : : {
213 : : int ret;
214 : :
215 : 1792 : ret = kerndat_get_shmemdev();
216 [ + - ]: 1792 : if (!ret)
217 : 1792 : ret = kerndat_get_dirty_track();
218 [ + - ]: 1792 : if (!ret)
219 : 1792 : ret = init_zero_page_pfn();
220 : :
221 : 1792 : return ret;
222 : : }
223 : :
224 : : int kern_last_cap;
225 : :
226 : 1013 : int get_last_cap(void)
227 : : {
228 : 1013 : struct sysctl_req req[] = {
229 : : { "kernel/cap_last_cap", &kern_last_cap, CTL_U32 },
230 : : { },
231 : : };
232 : :
233 : 1013 : return sysctl_op(req, CTL_READ);
234 : : }
235 : :
236 : 1013 : int kerndat_init_rst(void)
237 : : {
238 : : int ret;
239 : :
240 : : /*
241 : : * Read TCP sysctls before anything else,
242 : : * since the limits we're interested in are
243 : : * not available inside namespaces.
244 : : */
245 : :
246 : 1013 : ret = tcp_read_sysctl_limits();
247 [ + - ]: 1013 : if (!ret)
248 : 1013 : ret = get_last_cap();
249 : :
250 : 1013 : return ret;
251 : : }
|