Branch data Line data Source code
1 : : #include <sys/uio.h>
2 : : #include <fcntl.h>
3 : : #include <linux/falloc.h>
4 : : #include <unistd.h>
5 : :
6 : : #include "crtools.h"
7 : : #include "page-read.h"
8 : : #include "restorer.h"
9 : :
10 : : #define MAX_BUNCH_SIZE 256
11 : :
12 : : static int cr_dedup_one_pagemap(int pid);
13 : :
14 : 0 : int cr_dedup(void)
15 : : {
16 : : int close_ret, ret = 0;
17 : : int pid;
18 : : DIR * dirp;
19 : : struct dirent *ent;
20 : :
21 : 0 : dirp = opendir(CR_PARENT_LINK);
22 [ # # ]: 0 : if (dirp == NULL) {
23 : 0 : pr_perror("Can't enter previous snapshot folder, error=%d", errno);
24 : : ret = -1;
25 : 0 : goto err;
26 : : }
27 : :
28 : : while (1) {
29 : 0 : errno = 0;
30 : 0 : ent = readdir(dirp);
31 [ # # ]: 0 : if (ent == NULL) {
32 [ # # ]: 0 : if (errno) {
33 : 0 : pr_perror("Failed readdir, error=%d", errno);
34 : : ret = -1;
35 : 0 : goto err;
36 : : }
37 : : break;
38 : : }
39 : :
40 : 0 : ret = sscanf(ent->d_name, "pagemap-%d.img", &pid);
41 [ # # ]: 0 : if (ret == 1) {
42 : 0 : pr_info("pid=%d\n", pid);
43 : 0 : ret = cr_dedup_one_pagemap(pid);
44 [ # # ]: 0 : if (ret < 0)
45 : : break;
46 : : }
47 : : }
48 : :
49 : : err:
50 [ # # ]: 0 : if (dirp) {
51 : 0 : close_ret = closedir(dirp);
52 [ # # ]: 0 : if (close_ret == -1)
53 : : return close_ret;
54 : : }
55 : :
56 [ # # ]: 0 : if (ret < 0)
57 : : return ret;
58 : :
59 : 0 : pr_info("Deduplicated\n");
60 : 0 : return 0;
61 : : }
62 : :
63 : 0 : static int cr_dedup_one_pagemap(int pid)
64 : : {
65 : : int ret;
66 : : struct page_read pr;
67 : : struct page_read * prp;
68 : : struct iovec iov;
69 : :
70 : 0 : ret = open_page_read(pid, &pr, O_RDWR, false);
71 [ # # ]: 0 : if (ret) {
72 : : ret = -1;
73 : : goto exit;
74 : : }
75 : :
76 : 0 : prp = pr.parent;
77 [ # # ]: 0 : if (!prp)
78 : : goto exit;
79 : :
80 : 0 : ret = pr.get_pagemap(&pr, &iov);
81 [ # # ]: 0 : if (ret <= 0)
82 : : goto exit;
83 : :
84 : : while (1) {
85 : 0 : pr_debug("dedup iovec base=%p, len=%zu\n", iov.iov_base, iov.iov_len);
86 [ # # ]: 0 : if (!pr.pe->in_parent) {
87 : 0 : ret = dedup_one_iovec(prp, &iov);
88 [ # # ]: 0 : if (ret)
89 : : goto exit;
90 : : }
91 : :
92 : 0 : pr.put_pagemap(&pr);
93 : 0 : ret = pr.get_pagemap(&pr, &iov);
94 [ # # ]: 0 : if (ret <= 0)
95 : : goto exit;
96 : : }
97 : : exit:
98 : 0 : pr.close(&pr);
99 : :
100 [ # # ]: 0 : if (ret < 0)
101 : 0 : return ret;
102 : :
103 : : return 0;
104 : : }
105 : :
106 : : static inline bool can_extend_batch(struct iovec *bunch,
107 : : unsigned long off, unsigned long len)
108 : : {
109 : 327102 : return /* The next region is the continuation of the existing */
110 [ + + ][ + + ]: 327102 : ((unsigned long)bunch->iov_base + bunch->iov_len == off) &&
111 : : /* The resulting region is non empty and is small enough */
112 [ + + ]: 321135 : (bunch->iov_len == 0 || bunch->iov_len + len < MAX_BUNCH_SIZE * PAGE_SIZE);
113 : : }
114 : :
115 : 333547 : int punch_hole(struct page_read *pr, unsigned long off, unsigned long len,
116 : : bool cleanup)
117 : : {
118 : : int ret;
119 : : struct iovec * bunch = &pr->bunch;
120 : :
121 [ + + ][ + + ]: 660649 : if (!cleanup && can_extend_batch(bunch, off, len)) {
122 : 315038 : pr_debug("pr%d:Extend bunch len from %zu to %lu\n", pr->id,
123 : : bunch->iov_len, bunch->iov_len + len);
124 : 315038 : bunch->iov_len += len;
125 : : } else {
126 [ + + ]: 18509 : if (bunch->iov_len > 0) {
127 : 18031 : pr_debug("Punch!/%p/%zu/\n", bunch->iov_base, bunch->iov_len);
128 : 18031 : ret = fallocate(pr->fd_pg, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
129 : 36062 : (unsigned long)bunch->iov_base, bunch->iov_len);
130 [ - + ]: 18031 : if (ret != 0) {
131 : 0 : pr_perror("Error punching hole");
132 : 0 : return -1;
133 : : }
134 : : }
135 : 18509 : bunch->iov_base = (void *)off;
136 : 18509 : bunch->iov_len = len;
137 : 18509 : pr_debug("pr%d:New bunch/%p/%zu/\n", pr->id, bunch->iov_base, bunch->iov_len);
138 : : }
139 : : return 0;
140 : : }
141 : :
142 : 98799 : int dedup_one_iovec(struct page_read *pr, struct iovec *iov)
143 : : {
144 : : unsigned long off;
145 : : unsigned long off_real;
146 : : unsigned long iov_end;
147 : :
148 : 98799 : iov_end = (unsigned long)iov->iov_base + iov->iov_len;
149 : : off = (unsigned long)iov->iov_base;
150 : : while (1) {
151 : : int ret;
152 : : struct iovec piov;
153 : : unsigned long piov_end;
154 : : struct iovec tiov;
155 : : struct page_read * prp;
156 : :
157 : 99022 : ret = seek_pagemap_page(pr, off, false);
158 [ + - ]: 99022 : if (ret == -1)
159 : 98799 : return -1;
160 : :
161 [ + + ]: 99022 : if (ret == 0) {
162 [ + - ][ + + ]: 77420 : if (off < pr->cvaddr && pr->cvaddr < iov_end)
163 : : off = pr->cvaddr;
164 : : else
165 : : return 0;
166 : : }
167 : :
168 [ + - ]: 21827 : if (!pr->pe)
169 : : return -1;
170 : 21827 : pagemap2iovec(pr->pe, &piov);
171 : 21827 : piov_end = (unsigned long)piov.iov_base + piov.iov_len;
172 : 21827 : off_real = lseek(pr->fd_pg, 0, SEEK_CUR);
173 [ + + ]: 21827 : if (!pr->pe->in_parent) {
174 : 21741 : ret = punch_hole(pr, off_real, min(piov_end, iov_end) - off, false);
175 [ + - ]: 21741 : if (ret == -1)
176 : : return ret;
177 : : }
178 : :
179 : 21827 : prp = pr->parent;
180 [ + + ]: 21827 : if (prp) {
181 : : /* recursively */
182 : 11335 : pr_debug("Go to next parent level\n");
183 : 11335 : tiov.iov_base = (void*)off;
184 : 11335 : tiov.iov_len = min(piov_end, iov_end) - off;
185 : 11335 : ret = dedup_one_iovec(prp, &tiov);
186 [ + - ]: 11335 : if (ret != 0)
187 : : return -1;
188 : : }
189 : :
190 [ + + ]: 21827 : if (piov_end < iov_end) {
191 : : off = piov_end;
192 : 223 : continue;
193 : : } else
194 : : return 0;
195 : : }
196 : : return 0;
197 : : }
|