Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <errno.h>
36 : : #include <fcntl.h>
37 : : #include <stdio.h>
38 : : #include <stdlib.h>
39 : : #include <unistd.h>
40 : : #include <limits.h>
41 : : #include <assert.h>
42 : : #include <stdbool.h>
43 : :
44 : : #include "libvhd.h"
45 : :
46 : : #ifndef ULLONG_MAX
47 : : #define ULLONG_MAX (~0ULL)
48 : : #endif
49 : :
50 : : int
51 : 0 : vhd_init_bitmap(vhd_context_t *ctx, const uint32_t block)
52 : : {
53 : : int err;
54 : : void *buf;
55 : : int i;
56 : : int size;
57 : :
58 [ # # ]: 0 : assert(ctx);
59 : :
60 : 0 : size = vhd_bytes_padded(ctx->spb >> 3);
61 : :
62 : 0 : err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
63 [ # # ]: 0 : if (err)
64 : 0 : return err;
65 : :
66 [ # # ]: 0 : for (i = 0; i < ctx->spb; i++)
67 : 0 : vhd_bitmap_set(ctx, buf, i);
68 : :
69 : 0 : err = vhd_write_bitmap(ctx, block, buf);
70 : 0 : free(buf);
71 [ # # ]: 0 : if (err) {
72 : 0 : printf("failed to write bitmap for extent %u: %s\n", block,
73 : : strerror(-err));
74 : : return err;
75 : : }
76 : :
77 : : return 0;
78 : : }
79 : :
80 : : int
81 : 0 : vhd_init_bitmaps(vhd_context_t *ctx, const uint32_t from_extent,
82 : : const uint32_t to_extent) {
83 : :
84 : : unsigned int i;
85 : : int err;
86 : :
87 [ # # ]: 0 : assert(ctx);
88 [ # # ]: 0 : assert(from_extent <= to_extent);
89 : :
90 [ # # ]: 0 : for (i = from_extent; i <= to_extent; i++) {
91 [ # # ]: 0 : if (ctx->bat.bat[i] == DD_BLK_UNUSED)
92 : 0 : continue;
93 : 0 : err = vhd_init_bitmap(ctx, i);
94 [ # # ]: 0 : if (err) {
95 : 0 : printf("failed to initialise bitmap for extent %u: %s\n", i,
96 : : strerror(-err));
97 : 0 : return err;
98 : : }
99 : : }
100 : :
101 : : return 0;
102 : : }
103 : :
104 : : int
105 : 0 : vhd_io_allocate_blocks_fast(vhd_context_t *ctx, const uint32_t from_extent,
106 : : const uint32_t to_extent, const bool ignore_2tb_limit)
107 : : {
108 : : off64_t max;
109 : : int err, gap;
110 : 0 : int i = 0;
111 : 0 : int spp = getpagesize() >> VHD_SECTOR_SHIFT;
112 : :
113 [ # # ]: 0 : assert(ctx);
114 [ # # ]: 0 : assert(from_extent <= to_extent);
115 : :
116 : 0 : err = vhd_end_of_data(ctx, &max);
117 [ # # ]: 0 : if (err)
118 : 0 : return err;
119 : :
120 : 0 : gap = 0;
121 : 0 : max >>= VHD_SECTOR_SHIFT;
122 : :
123 : : /* data region of segment should begin on page boundary */
124 [ # # ]: 0 : if ((max + ctx->bm_secs) % spp) {
125 : 0 : gap = (spp - ((max + ctx->bm_secs) % spp));
126 : 0 : max += gap;
127 : : }
128 : :
129 [ # # ]: 0 : for (i = from_extent; i <= to_extent; i++) {
130 [ # # ][ # # ]: 0 : if (max > UINT_MAX && !ignore_2tb_limit) {
131 : : printf("sector offset for extent %u exceeds the 2 TB limit\n", i);
132 : : err = -EOVERFLOW;
133 : : goto out;
134 : : }
135 : 0 : ctx->bat.bat[i] = max;
136 : 0 : max += ctx->bm_secs + ctx->bat.spb;
137 [ # # ]: 0 : if ((max + ctx->bm_secs) % spp) {
138 : 0 : gap = (spp - ((max + ctx->bm_secs) % spp));
139 : 0 : max += gap;
140 : : }
141 : : }
142 : 0 : err = vhd_write_bat(ctx, &ctx->bat);
143 [ # # ]: 0 : if (err)
144 : : goto out;
145 : :
146 : 0 : err = vhd_init_bitmaps(ctx, from_extent, to_extent);
147 [ # # ]: 0 : if (err)
148 : 0 : printf("failed to initialise bitmaps: %s\n", strerror(-err));
149 : :
150 : : out:
151 : 0 : return err;
152 : : }
153 : :
154 : : int
155 : 0 : vhd_util_fill(int argc, char **argv)
156 : : {
157 : : int err, c;
158 : : char *name;
159 : : void *buf;
160 : : vhd_context_t vhd;
161 : : uint64_t i, sec, secs, from_sector, to_sector;
162 : : int init_bat;
163 : : bool ignore_2tb_limit;
164 : :
165 : 0 : buf = NULL;
166 : 0 : name = NULL;
167 : 0 : init_bat = 0;
168 : 0 : from_sector = ULLONG_MAX;
169 : 0 : to_sector = ULLONG_MAX;
170 : 0 : ignore_2tb_limit = false;
171 : :
172 [ # # ]: 0 : if (!argc || !argv)
173 : : goto usage;
174 : :
175 : 0 : optind = 0;
176 [ # # ]: 0 : while ((c = getopt(argc, argv, "n:f:t:bBh")) != -1) {
177 [ # # # # : 0 : switch (c) {
# # ]
178 : : case 'n':
179 : 0 : name = optarg;
180 : 0 : break;
181 : : case 'f':
182 : 0 : from_sector = strtoull(optarg, NULL, 10);
183 : 0 : break;
184 : : case 't':
185 : 0 : to_sector = strtoull(optarg, NULL, 10);
186 : 0 : break;
187 : : case 'b':
188 : : init_bat = 1;
189 : : break;
190 : : case 'B':
191 : 0 : ignore_2tb_limit = true;
192 : 0 : break;
193 : : case 'h':
194 : : default:
195 : : goto usage;
196 : : }
197 : : }
198 : :
199 [ # # ][ # # ]: 0 : if (!name || optind != argc)
200 : : goto usage;
201 : :
202 [ # # ][ # # ]: 0 : if ((from_sector != ULLONG_MAX || to_sector != ULLONG_MAX) && !init_bat) {
203 : : printf("-f/-t can only be used with -b\n");
204 : : goto usage;
205 : : }
206 : :
207 [ # # ]: 0 : if (from_sector != ULLONG_MAX && to_sector != ULLONG_MAX) {
208 [ # # ]: 0 : if (to_sector < from_sector) {
209 : : printf("invalid sector range %llu-%llu\n",
210 : : (unsigned long long)from_sector,
211 : : (unsigned long long)to_sector);
212 : : goto usage;
213 : : }
214 : : }
215 : :
216 [ # # ]: 0 : if (ignore_2tb_limit && !init_bat) {
217 : : printf("-B can only be used with -b\n");
218 : : goto usage;
219 : : }
220 : :
221 : 0 : err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
222 [ # # ]: 0 : if (err) {
223 : : printf("error opening %s: %d\n", name, err);
224 : 0 : return err;
225 : : }
226 : :
227 : 0 : err = vhd_get_bat(&vhd);
228 [ # # ]: 0 : if (err)
229 : : goto done;
230 : :
231 [ # # ]: 0 : if (init_bat) {
232 : : uint32_t from_extent;
233 : : uint32_t to_extent;
234 : :
235 [ # # ]: 0 : if (from_sector != ULLONG_MAX)
236 : 0 : from_extent = from_sector / vhd.spb;
237 : : else
238 : : from_extent = 0;
239 [ # # ]: 0 : if (to_sector != ULLONG_MAX)
240 : 0 : to_extent = to_sector / vhd.spb;
241 : : else
242 : 0 : to_extent = vhd.bat.entries - 1;
243 : 0 : err = vhd_io_allocate_blocks_fast(&vhd, from_extent, to_extent,
244 : : ignore_2tb_limit);
245 : : if (err)
246 : : goto done;
247 : : } else {
248 : 0 : err = posix_memalign(&buf, 4096, vhd.header.block_size);
249 [ # # ]: 0 : if (err) {
250 : 0 : err = -err;
251 : 0 : goto done;
252 : : }
253 : :
254 : 0 : sec = 0;
255 : 0 : secs = vhd.header.block_size >> VHD_SECTOR_SHIFT;
256 : :
257 [ # # ]: 0 : for (i = 0; i < vhd.header.max_bat_size; i++) {
258 : 0 : err = vhd_io_read(&vhd, buf, sec, secs);
259 [ # # ]: 0 : if (err)
260 : : goto done;
261 : :
262 : 0 : err = vhd_io_write(&vhd, buf, sec, secs);
263 [ # # ]: 0 : if (err)
264 : : goto done;
265 : :
266 : 0 : sec += secs;
267 : : }
268 : :
269 : : err = 0;
270 : : }
271 : :
272 : : done:
273 : 0 : free(buf);
274 : 0 : vhd_close(&vhd);
275 : : return err;
276 : :
277 : : usage:
278 : : printf("options: <-n name> [-h help] [-b initialise the BAT and bitmaps, "
279 : : "don't write to the data blocks (much faster)] [-f start "
280 : : "intialisation from this sector, only usable with -b] [-t "
281 : : "intialise up to this sector (inclusive), only usable with -b] "
282 : : "[-B ignore the 2 TB limit, only usable with -b]\n");
283 : : return -EINVAL;
284 : : }
|