Branch data Line data Source code
1 : : #include <fcntl.h>
2 : : #include <stdio.h>
3 : : #include <unistd.h>
4 : :
5 : : #include "image.h"
6 : : #include "cr_options.h"
7 : : #include "servicefd.h"
8 : : #include "page-read.h"
9 : :
10 : : #include "protobuf.h"
11 : : #include "protobuf/pagemap.pb-c.h"
12 : :
13 : : #ifndef SEEK_DATA
14 : : #define SEEK_DATA 3
15 : : #define SEEK_HOLE 4
16 : : #endif
17 : :
18 : 0 : static int get_page_vaddr(struct page_read *pr, struct iovec *iov)
19 : : {
20 : : int ret;
21 : : u64 img_va;
22 : :
23 : 0 : ret = read_img_eof(pr->fd_pg, &img_va);
24 [ # # ]: 0 : if (ret <= 0)
25 : : return ret;
26 : :
27 : 0 : iov->iov_base = (void *)decode_pointer(img_va);
28 : 0 : iov->iov_len = PAGE_SIZE;
29 : :
30 : 0 : return 1;
31 : : }
32 : :
33 : 0 : static int read_page(struct page_read *pr, unsigned long vaddr, void *buf)
34 : : {
35 : : int ret;
36 : :
37 : 0 : ret = read(pr->fd_pg, buf, PAGE_SIZE);
38 [ # # ]: 0 : if (ret != PAGE_SIZE) {
39 : 0 : pr_err("Can't read mapping page %d\n", ret);
40 : 0 : return -1;
41 : : }
42 : :
43 : : return 1;
44 : : }
45 : :
46 : 53622 : void pagemap2iovec(PagemapEntry *pe, struct iovec *iov)
47 : : {
48 : 2677296 : iov->iov_base = decode_pointer(pe->vaddr);
49 : 958724 : iov->iov_len = pe->nr_pages * PAGE_SIZE;
50 : 53622 : }
51 : :
52 : 326796 : static int get_pagemap(struct page_read *pr, struct iovec *iov)
53 : : {
54 : : int ret;
55 : : PagemapEntry *pe;
56 : :
57 : 326796 : ret = pb_read_one_eof(pr->fd, &pe, PB_PAGEMAP);
58 [ + + ]: 326796 : if (ret <= 0)
59 : : return ret;
60 : :
61 : 326302 : pagemap2iovec(pe, iov);
62 : :
63 : 326302 : pr->pe = pe;
64 : 326302 : pr->cvaddr = (unsigned long)iov->iov_base;
65 : :
66 [ + + ][ - + ]: 326302 : if (pe->in_parent && !pr->parent) {
67 : 0 : pr_err("No parent for snapshot pagemap\n");
68 : 0 : return -1;
69 : : }
70 : :
71 : : return 1;
72 : : }
73 : :
74 : 27530 : static void put_pagemap(struct page_read *pr)
75 : : {
76 : 319414 : pagemap_entry__free_unpacked(pr->pe, NULL);
77 : 27530 : }
78 : :
79 : : static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, void *buf);
80 : :
81 : 1180076 : static void skip_pagemap_pages(struct page_read *pr, unsigned long len)
82 : : {
83 [ + + ]: 1180076 : if (!len)
84 : 1180076 : return;
85 : :
86 : 284096 : pr_debug("\tpr%u Skip %lx bytes from page-dump\n", pr->id, len);
87 [ + + ]: 284096 : if (!pr->pe->in_parent)
88 : 256989 : lseek(pr->fd_pg, len, SEEK_CUR);
89 : 284096 : pr->cvaddr += len;
90 : : }
91 : :
92 : 965612 : int seek_pagemap_page(struct page_read *pr, unsigned long vaddr, bool warn)
93 : : {
94 : : int ret;
95 : : struct iovec iov;
96 : :
97 [ + + ]: 965612 : if (pr->pe)
98 : : pagemap2iovec(pr->pe, &iov);
99 : : else
100 : : goto new_pagemap;
101 : :
102 : : while (1) {
103 : : unsigned long iov_end;
104 : :
105 [ + + ]: 1257496 : if (vaddr < pr->cvaddr) {
106 [ - + ]: 77420 : if (warn)
107 : 0 : pr_err("Missing %lu in parent pagemap, current iov: base=%lx,len=%zu\n",
108 : : vaddr, (unsigned long)iov.iov_base, iov.iov_len);
109 : : return 0;
110 : : }
111 : 1180076 : iov_end = (unsigned long)iov.iov_base + iov.iov_len;
112 : :
113 [ + + ]: 1180076 : if (iov_end <= vaddr) {
114 : 291884 : skip_pagemap_pages(pr, iov_end - pr->cvaddr);
115 : : put_pagemap(pr);
116 : : new_pagemap:
117 : 298772 : ret = get_pagemap(pr, &iov);
118 [ + - ]: 298772 : if (ret <= 0)
119 : : return ret;
120 : :
121 : 298772 : continue;
122 : : }
123 : :
124 : 888192 : skip_pagemap_pages(pr, vaddr - pr->cvaddr);
125 : 888192 : return 1;
126 : 298772 : }
127 : : }
128 : :
129 : 1140216 : static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, void *buf)
130 : : {
131 : : int ret;
132 : :
133 [ + + ]: 1140216 : if (pr->pe->in_parent) {
134 : 834795 : pr_debug("\tpr%u Read page %lx from parent\n", pr->id, vaddr);
135 : 834795 : ret = seek_pagemap_page(pr->parent, vaddr, true);
136 [ + - ]: 834795 : if (ret <= 0)
137 : : return -1;
138 : 834795 : ret = read_pagemap_page(pr->parent, vaddr, buf);
139 [ + - ]: 834795 : if (ret == -1)
140 : : return ret;
141 : : } else {
142 : 305421 : off_t current_vaddr = lseek(pr->fd_pg, 0, SEEK_CUR);
143 : 305421 : pr_debug("\tpr%u Read page %lx from self %lx/%"PRIx64"\n", pr->id,
144 : : vaddr, pr->cvaddr, current_vaddr);
145 : 610842 : ret = read(pr->fd_pg, buf, PAGE_SIZE);
146 [ - + ]: 305421 : if (ret != PAGE_SIZE) {
147 : 0 : pr_perror("Can't read mapping page %d", ret);
148 : 0 : return -1;
149 : : }
150 : :
151 [ + - ]: 305421 : if (opts.auto_dedup) {
152 : 305421 : ret = punch_hole(pr, current_vaddr, (unsigned int)PAGE_SIZE, false);
153 [ + - ]: 305421 : if (ret == -1) {
154 : : return -1;
155 : : }
156 : : }
157 : : }
158 : :
159 : 1140216 : pr->cvaddr += PAGE_SIZE;
160 : :
161 : 1140216 : return 1;
162 : : }
163 : :
164 : 7391 : static void close_page_read(struct page_read *pr)
165 : : {
166 : : int ret;
167 : :
168 [ + + ]: 7391 : if (pr->bunch.iov_len > 0) {
169 : 6451 : ret = punch_hole(pr, 0, 0, true);
170 [ + - ]: 6451 : if (ret == -1)
171 : 7391 : return;
172 : :
173 : 6451 : pr->bunch.iov_len = 0;
174 : : }
175 : :
176 [ + + ]: 7391 : if (pr->parent) {
177 : 4155 : close_page_read(pr->parent);
178 [ + - ]: 4155 : xfree(pr->parent);
179 : : }
180 : :
181 : 7391 : close(pr->fd_pg);
182 : 7391 : close(pr->fd);
183 : : }
184 : :
185 : 7371 : static int try_open_parent(int dfd, int pid, struct page_read *pr, int flags)
186 : : {
187 : : int pfd;
188 : : struct page_read *parent = NULL;
189 : :
190 : : pfd = openat(dfd, CR_PARENT_LINK, O_RDONLY);
191 [ + + ][ - + ]: 7371 : if (pfd < 0 && errno == ENOENT)
192 : : goto out;
193 : :
194 [ - + ]: 4158 : parent = xmalloc(sizeof(*parent));
195 [ + - ]: 4158 : if (!parent)
196 : : goto err_cl;
197 : :
198 [ + + ]: 4158 : if (open_page_read_at(pfd, pid, parent, flags, false)) {
199 [ + - ]: 3 : if (errno != ENOENT)
200 : : goto err_free;
201 [ + - ]: 3 : xfree(parent);
202 : : parent = NULL;
203 : : }
204 : :
205 : 4158 : close(pfd);
206 : : out:
207 : 7371 : pr->parent = parent;
208 : : return 0;
209 : :
210 : : err_free:
211 [ # # ]: 0 : xfree(parent);
212 : : err_cl:
213 : 0 : close(pfd);
214 : : return -1;
215 : : }
216 : :
217 : 7401 : int open_page_read_at(int dfd, int pid, struct page_read *pr, int flags, bool shmem)
218 : : {
219 : 7401 : pr->pe = NULL;
220 : 7401 : pr->parent = NULL;
221 : 7401 : pr->bunch.iov_len = 0;
222 : 7401 : pr->bunch.iov_base = NULL;
223 : :
224 [ + + ]: 7401 : pr->fd = open_image_at(dfd, shmem ? CR_FD_SHMEM_PAGEMAP : CR_FD_PAGEMAP, O_RSTR, (long)pid);
225 [ + + ]: 7401 : if (pr->fd < 0) {
226 [ + - ]: 10 : pr->fd_pg = open_image_at(dfd, shmem ? CR_FD_SHM_PAGES_OLD : CR_FD_PAGES_OLD, flags, pid);
227 [ - + ]: 10 : if (pr->fd_pg < 0)
228 : : return -1;
229 : :
230 : 0 : pr->get_pagemap = get_page_vaddr;
231 : 0 : pr->put_pagemap = NULL;
232 : 0 : pr->read_page = read_page;
233 : : } else {
234 : : static unsigned ids = 1;
235 : :
236 [ + + ][ - + ]: 7391 : if (!shmem && try_open_parent(dfd, pid, pr, flags)) {
237 : 0 : close(pr->fd);
238 : 0 : return -1;
239 : : }
240 : :
241 : 7391 : pr->fd_pg = open_pages_image_at(dfd, flags, pr->fd);
242 [ - + ]: 7391 : if (pr->fd_pg < 0) {
243 : 0 : close_page_read(pr);
244 : 0 : return -1;
245 : : }
246 : :
247 : 7391 : pr->get_pagemap = get_pagemap;
248 : 7391 : pr->put_pagemap = put_pagemap;
249 : 7391 : pr->read_page = read_pagemap_page;
250 : 7391 : pr->id = ids++;
251 : :
252 [ + + ]: 7391 : pr_debug("Opened page read %u (parent %u)\n",
253 : : pr->id, pr->parent ? pr->parent->id : 0);
254 : : }
255 : :
256 : 7391 : pr->close = close_page_read;
257 : :
258 : 7391 : return 0;
259 : : }
260 : :
261 : 494 : int open_page_read(int pid, struct page_read *pr, int flags, bool shmem)
262 : : {
263 : 494 : return open_page_read_at(get_service_fd(IMG_FD_OFF), pid, pr, flags, shmem);
264 : : }
|