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 <unistd.h>
38 : : #include <stdlib.h>
39 : :
40 : : #include "debug.h"
41 : : #include "tapdisk.h"
42 : : #include "tapdisk-utils.h"
43 : : #include "tapdisk-driver.h"
44 : : #include "tapdisk-server.h"
45 : : #include "tapdisk-interface.h"
46 : :
47 : : #include "libvhd.h"
48 : : #include "libvhd-index.h"
49 : :
50 : : #define DBG(_level, _f, _a...) tlog_write(_level, _f, ##_a)
51 : : #define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
52 : : #define WARN(_f, _a...) tlog_write(TLOG_WARN, _f, ##_a)
53 : :
54 : : #define VHD_INDEX_FILE_POOL_SIZE 12
55 : : #define VHD_INDEX_CACHE_SIZE 4
56 : : #define VHD_INDEX_REQUESTS (TAPDISK_DATA_REQUESTS + VHD_INDEX_CACHE_SIZE)
57 : :
58 : : #define VHD_INDEX_BLOCK_READ_PENDING 0x0001
59 : : #define VHD_INDEX_BLOCK_VALID 0x0002
60 : :
61 : : #define VHD_INDEX_BAT_CLEAR 0
62 : : #define VHD_INDEX_BIT_CLEAR 1
63 : : #define VHD_INDEX_BIT_SET 2
64 : : #define VHD_INDEX_CACHE_MISS 3
65 : : #define VHD_INDEX_META_READ_PENDING 4
66 : :
67 : : typedef struct vhd_index vhd_index_t;
68 : : typedef struct vhd_index_block vhd_index_block_t;
69 : : typedef struct vhd_index_request vhd_index_request_t;
70 : : typedef struct vhd_index_file_ref vhd_index_file_ref_t;
71 : :
72 : : struct vhd_index_request {
73 : : off64_t off;
74 : : td_request_t treq;
75 : : vhd_index_t *index;
76 : : struct tiocb tiocb;
77 : : struct list_head next;
78 : : vhd_index_file_ref_t *file;
79 : : };
80 : :
81 : : struct vhd_index_block {
82 : : uint64_t blk;
83 : : uint32_t seqno;
84 : : td_flag_t state;
85 : : vhdi_block_t vhdi_block;
86 : : int table_size;
87 : : struct list_head queue;
88 : : vhd_index_request_t req;
89 : : };
90 : :
91 : : struct vhd_index_file_ref {
92 : : int fd;
93 : : vhdi_file_id_t fid;
94 : : uint32_t seqno;
95 : : uint32_t refcnt;
96 : : };
97 : :
98 : : struct vhd_index {
99 : : char *name;
100 : :
101 : : vhdi_bat_t bat;
102 : : vhdi_context_t vhdi;
103 : : vhdi_file_table_t files;
104 : :
105 : : vhd_index_file_ref_t fds[VHD_INDEX_FILE_POOL_SIZE];
106 : :
107 : : vhd_index_block_t *cache[VHD_INDEX_CACHE_SIZE];
108 : :
109 : : int cache_free_cnt;
110 : : vhd_index_block_t *cache_free_list[VHD_INDEX_CACHE_SIZE];
111 : : vhd_index_block_t cache_list[VHD_INDEX_CACHE_SIZE];
112 : :
113 : : int requests_free_cnt;
114 : : vhd_index_request_t *requests_free_list[VHD_INDEX_REQUESTS];
115 : : vhd_index_request_t requests_list[VHD_INDEX_REQUESTS];
116 : :
117 : : td_driver_t *driver;
118 : : };
119 : :
120 : : static void vhd_index_complete_meta_read(void *, struct tiocb *, int);
121 : : static void vhd_index_complete_data_read(void *, struct tiocb *, int);
122 : :
123 : : #define vhd_index_block_for_each_request(_block, _req, _tmp) \
124 : : list_for_each_entry_safe((_req), (_tmp), &(_block)->queue, next)
125 : :
126 : : static inline void
127 : : vhd_index_initialize_request(vhd_index_request_t *req)
128 : : {
129 : : memset(req, 0, sizeof(vhd_index_request_t));
130 : 0 : INIT_LIST_HEAD(&req->next);
131 : : }
132 : :
133 : : static inline void
134 : 0 : vhd_index_initialize_block(vhd_index_block_t *block)
135 : : {
136 : 0 : block->blk = 0;
137 : 0 : block->state = 0;
138 : 0 : INIT_LIST_HEAD(&block->queue);
139 : 0 : vhd_index_initialize_request(&block->req);
140 : 0 : memset(block->vhdi_block.table, 0, block->table_size);
141 : 0 : }
142 : :
143 : : static void
144 : 0 : vhd_index_init(vhd_index_t *index)
145 : : {
146 : : int i;
147 : :
148 : : memset(index, 0, sizeof(vhd_index_t));
149 : :
150 : 0 : index->cache_free_cnt = VHD_INDEX_CACHE_SIZE;
151 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
152 : 0 : index->cache_free_list[i] = index->cache_list + i;
153 : 0 : vhd_index_initialize_block(index->cache_free_list[i]);
154 : : }
155 : :
156 : 0 : index->requests_free_cnt = VHD_INDEX_REQUESTS;
157 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_REQUESTS; i++) {
158 : 0 : index->requests_free_list[i] = index->requests_list + i;
159 : 0 : vhd_index_initialize_request(index->requests_free_list[i]);
160 : : }
161 : :
162 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_FILE_POOL_SIZE; i++)
163 : 0 : index->fds[i].fd = -1;
164 : 0 : }
165 : :
166 : : static int
167 : 0 : vhd_index_allocate_cache(vhd_index_t *index)
168 : : {
169 : : void *buf;
170 : : int i, err;
171 : : size_t size;
172 : :
173 : 0 : size = vhd_bytes_padded(index->vhdi.spb * sizeof(vhdi_entry_t));
174 : :
175 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
176 : 0 : err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
177 [ # # ]: 0 : if (err)
178 : : goto fail;
179 : :
180 : 0 : memset(buf, 0, size);
181 : 0 : index->cache_list[i].vhdi_block.table = (vhdi_entry_t *)buf;
182 : 0 : index->cache_list[i].vhdi_block.entries = index->vhdi.spb;
183 : 0 : index->cache_list[i].table_size = size;
184 : : }
185 : :
186 : 0 : return 0;
187 : :
188 : : fail:
189 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
190 : 0 : free(index->cache_list[i].vhdi_block.table);
191 : 0 : index->cache_list[i].vhdi_block.table = NULL;
192 : : }
193 : :
194 : : return -ENOMEM;
195 : : }
196 : :
197 : : static void
198 : 0 : vhd_index_free(vhd_index_t *index)
199 : : {
200 : : int i;
201 : :
202 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++)
203 : 0 : free(index->cache_list[i].vhdi_block.table);
204 : :
205 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_FILE_POOL_SIZE; i++)
206 [ # # ]: 0 : if (index->fds[i].fd != -1)
207 : 0 : close(index->fds[i].fd);
208 : :
209 : 0 : vhdi_file_table_free(&index->files);
210 : 0 : free(index->bat.table);
211 : 0 : free(index->name);
212 : 0 : }
213 : :
214 : : static int
215 : 0 : vhd_index_load(vhd_index_t *index)
216 : : {
217 : : int err;
218 : :
219 : 0 : err = vhdi_bat_load(index->name, &index->bat);
220 [ # # ]: 0 : if (err)
221 : : return err;
222 : :
223 : 0 : err = vhdi_open(&index->vhdi,
224 : 0 : index->bat.index_path,
225 : : O_RDONLY | O_DIRECT | O_LARGEFILE);
226 [ # # ]: 0 : if (err)
227 : : goto fail;
228 : :
229 : 0 : err = vhdi_file_table_load(index->bat.file_table_path, &index->files);
230 [ # # ]: 0 : if (err) {
231 : 0 : vhdi_close(&index->vhdi);
232 : 0 : goto fail;
233 : : }
234 : :
235 : : return 0;
236 : :
237 : : fail:
238 : 0 : free(index->bat.table);
239 : 0 : memset(&index->bat, 0, sizeof(vhdi_bat_t));
240 : 0 : memset(&index->vhdi, 0, sizeof(vhdi_context_t));
241 : 0 : memset(&index->files, 0, sizeof(vhdi_file_table_t));
242 : 0 : return err;
243 : : }
244 : :
245 : : static int
246 : 0 : vhd_index_open(td_driver_t *driver, const char *name,
247 : : struct td_vbd_encryption *encryption, td_flag_t flags)
248 : : {
249 : : int err;
250 : : vhd_index_t *index;
251 : :
252 : 0 : index = (vhd_index_t *)driver->data;
253 : :
254 : 0 : vhd_index_init(index);
255 : :
256 : 0 : index->name = strdup(name);
257 [ # # ]: 0 : if (!index->name)
258 : : return -ENOMEM;
259 : :
260 : 0 : err = vhd_index_load(index);
261 [ # # ]: 0 : if (err) {
262 : 0 : free(index->name);
263 : 0 : return err;
264 : : }
265 : :
266 : 0 : err = vhd_index_allocate_cache(index);
267 [ # # ]: 0 : if (err) {
268 : 0 : vhd_index_free(index);
269 : 0 : return err;
270 : : }
271 : :
272 : 0 : driver->info.size = index->bat.vhd_blocks * index->bat.vhd_block_size;
273 : 0 : driver->info.sector_size = VHD_SECTOR_SIZE;
274 : 0 : driver->info.info = 0;
275 : :
276 : 0 : index->driver = driver;
277 : :
278 : : DPRINTF("opened vhd index %s\n", name);
279 : :
280 : 0 : return 0;
281 : : }
282 : :
283 : : static int
284 : 0 : vhd_index_close(td_driver_t *driver)
285 : : {
286 : : vhd_index_t *index;
287 : :
288 : 0 : index = (vhd_index_t *)driver->data;
289 : 0 : vhdi_close(&index->vhdi);
290 : :
291 : 0 : DPRINTF("closed vhd index %s\n", index->name);
292 : :
293 : 0 : vhd_index_free(index);
294 : :
295 : 0 : return 0;
296 : : }
297 : :
298 : : static inline void
299 : 0 : vhd_index_touch_file_ref(vhd_index_t *index, vhd_index_file_ref_t *ref)
300 : : {
301 : : int i;
302 : :
303 [ # # ][ # # ]: 0 : if (++ref->seqno == 0xFFFFFFFF)
304 [ # # ][ # # ]: 0 : for (i = 0; i < VHD_INDEX_FILE_POOL_SIZE; i++)
305 : 0 : index->fds[i].seqno >>= 1;
306 : 0 : }
307 : :
308 : : static inline void
309 : 0 : vhd_index_get_file_ref(vhd_index_file_ref_t *ref)
310 : : {
311 : 0 : ++ref->refcnt;
312 : 0 : }
313 : :
314 : : static inline void
315 : 0 : vhd_index_put_file_ref(vhd_index_file_ref_t *ref)
316 : : {
317 : 0 : --ref->refcnt;
318 : 0 : }
319 : :
320 : : static inline vhd_index_file_ref_t *
321 : : vhd_index_find_lru_file_ref(vhd_index_t *index)
322 : : {
323 : : int i;
324 : : uint32_t min;
325 : : vhd_index_file_ref_t *lru;
326 : :
327 : : lru = NULL;
328 : : min = (uint32_t)-1;
329 : :
330 [ # # ]: 0 : for (i = 1; i < VHD_INDEX_FILE_POOL_SIZE; i++) {
331 [ # # ]: 0 : if (index->fds[i].refcnt)
332 : 0 : continue;
333 : :
334 [ # # ][ # # ]: 0 : if (!lru || index->fds[i].seqno < min) {
335 : 0 : min = index->fds[i].seqno;
336 : 0 : lru = index->fds + i;
337 : : }
338 : : }
339 : :
340 : : return lru;
341 : : }
342 : :
343 : : static inline int
344 : 0 : vhd_index_open_file(vhd_index_t *index,
345 : : vhdi_file_id_t id, vhd_index_file_ref_t *ref)
346 : : {
347 : : int i;
348 : : char *path;
349 : :
350 : 0 : path = NULL;
351 : :
352 [ # # ]: 0 : for (i = 0; i < index->files.entries; i++)
353 [ # # ]: 0 : if (index->files.table[i].file_id == id) {
354 : 0 : path = index->files.table[i].path;
355 : 0 : break;
356 : : }
357 : :
358 [ # # ]: 0 : if (!path)
359 : : return -ENOENT;
360 : :
361 : 0 : ref->fd = open(path, O_RDONLY | O_DIRECT | O_LARGEFILE);
362 [ # # ]: 0 : if (ref->fd == -1)
363 : 0 : return -errno;
364 : :
365 : 0 : ref->fid = id;
366 : 0 : ref->refcnt = 0;
367 : :
368 : 0 : return 0;
369 : : }
370 : :
371 : : static int
372 : 0 : vhd_index_get_file(vhd_index_t *index,
373 : : vhdi_file_id_t id, vhd_index_file_ref_t **ref)
374 : : {
375 : : int i, err;
376 : : vhd_index_file_ref_t *lru;
377 : :
378 : 0 : *ref = NULL;
379 : :
380 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_FILE_POOL_SIZE; i++)
381 [ # # ]: 0 : if (id == index->fds[i].fid) {
382 : 0 : *ref = index->fds + i;
383 : 0 : vhd_index_touch_file_ref(index, *ref);
384 : 0 : vhd_index_get_file_ref(*ref);
385 : 0 : return 0;
386 : : }
387 : :
388 : 0 : lru = vhd_index_find_lru_file_ref(index);
389 [ # # ]: 0 : if (!lru)
390 : : return -EBUSY;
391 : :
392 [ # # ]: 0 : if (lru->fd != -1)
393 : 0 : close(lru->fd);
394 : :
395 : 0 : err = vhd_index_open_file(index, id, lru);
396 [ # # ]: 0 : if (err)
397 : : goto fail;
398 : :
399 : 0 : vhd_index_touch_file_ref(index, lru);
400 : 0 : vhd_index_get_file_ref(lru);
401 : 0 : *ref = lru;
402 : 0 : return 0;
403 : :
404 : : fail:
405 : 0 : lru->fd = -1;
406 : 0 : lru->fid = 0;
407 : 0 : lru->refcnt = 0;
408 : 0 : return err;
409 : : }
410 : :
411 : : static inline vhd_index_request_t *
412 : 0 : vhd_index_allocate_request(vhd_index_t *index)
413 : : {
414 : : vhd_index_request_t *req;
415 : :
416 [ # # ]: 0 : if (index->requests_free_cnt <= 0)
417 : : return NULL;
418 : :
419 : 0 : req = index->requests_free_list[--index->requests_free_cnt];
420 [ # # ]: 0 : ASSERT(!req->index);
421 : :
422 : : return req;
423 : : }
424 : :
425 : : static inline void
426 : 0 : vhd_index_free_request(vhd_index_t *index, vhd_index_request_t *req)
427 : : {
428 : 0 : list_del(&req->next);
429 : : vhd_index_initialize_request(req);
430 : 0 : index->requests_free_list[index->requests_free_cnt++] = req;
431 : 0 : }
432 : :
433 : : static inline int
434 : : vhd_index_block_valid(vhd_index_block_t *block)
435 : : {
436 : 0 : return (!td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING) &&
437 : : td_flag_test(block->state, VHD_INDEX_BLOCK_VALID));
438 : : }
439 : :
440 : : static inline void
441 : 0 : vhd_index_touch_block(vhd_index_t *index, vhd_index_block_t *block)
442 : : {
443 : : int i;
444 : :
445 [ # # ][ # # ]: 0 : if (++block->seqno == 0xFFFFFFFF)
446 [ # # ][ # # ]: 0 : for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++)
447 : 0 : index->cache_list[i].seqno >>= 1;
448 : 0 : }
449 : :
450 : : static inline vhd_index_block_t *
451 : 0 : vhd_index_get_lru_block(vhd_index_t *index)
452 : : {
453 : : int i, idx;
454 : : uint32_t min;
455 : : vhd_index_block_t *block, *lru;
456 : :
457 : 0 : lru = NULL;
458 : 0 : min = (uint32_t)-1;
459 : 0 : idx = 0;
460 : :
461 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
462 : 0 : block = index->cache[i];
463 : :
464 [ # # ]: 0 : if (!block)
465 : 0 : continue;
466 : :
467 [ # # ]: 0 : if (td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING))
468 : 0 : continue;
469 : :
470 [ # # ][ # # ]: 0 : if (!lru || block->seqno < min) {
471 : 0 : lru = block;
472 : 0 : min = block->seqno;
473 : 0 : idx = i;
474 : : }
475 : : }
476 : :
477 [ # # ]: 0 : if (lru)
478 : 0 : index->cache[idx] = NULL;
479 : :
480 : 0 : return lru;
481 : : }
482 : :
483 : : static inline int
484 : 0 : vhd_index_allocate_block(vhd_index_t *index, vhd_index_block_t **block)
485 : : {
486 : : vhd_index_block_t *b;
487 : :
488 : 0 : *block = NULL;
489 : :
490 [ # # ]: 0 : if (index->cache_free_cnt > 0)
491 : 0 : b = index->cache_free_list[--index->cache_free_cnt];
492 : : else {
493 : 0 : b = vhd_index_get_lru_block(index);
494 [ # # ]: 0 : if (!b)
495 : : return -EBUSY;
496 : : }
497 : :
498 : 0 : vhd_index_initialize_block(b);
499 : 0 : vhd_index_touch_block(index, b);
500 : 0 : *block = b;
501 : :
502 : 0 : return 0;
503 : : }
504 : :
505 : : static int
506 : 0 : vhd_index_install_block(vhd_index_t *index,
507 : : vhd_index_block_t **block, uint32_t blk)
508 : : {
509 : : int i, err;
510 : : vhd_index_block_t *b;
511 : :
512 : 0 : *block = NULL;
513 : :
514 : 0 : err = vhd_index_allocate_block(index, &b);
515 [ # # ]: 0 : if (err)
516 : 0 : return err;
517 : :
518 : 0 : b->blk = blk;
519 : :
520 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++)
521 [ # # ]: 0 : if (!index->cache[i]) {
522 : 0 : index->cache[i] = b;
523 : 0 : break;
524 : : }
525 : :
526 [ # # ]: 0 : ASSERT(i < VHD_INDEX_CACHE_SIZE);
527 : 0 : *block = b;
528 : :
529 : 0 : return 0;
530 : : }
531 : :
532 : : static inline vhd_index_block_t *
533 : : vhd_index_get_block(vhd_index_t *index, uint32_t blk)
534 : : {
535 : : int i;
536 : : vhd_index_block_t *block;
537 : :
538 [ # # ][ # # ]: 0 : for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
[ # # ][ # # ]
[ # # ][ # # ]
539 : 0 : block = index->cache[i];
540 [ # # ][ # # ]: 0 : if (!block)
[ # # ][ # # ]
[ # # ][ # # ]
541 : 0 : continue;
542 : :
543 [ # # ][ # # ]: 0 : if (block->blk == blk)
[ # # ][ # # ]
[ # # ][ # # ]
544 : : return block;
545 : : }
546 : :
547 : : return NULL;
548 : : }
549 : :
550 : : static int
551 : 0 : vhd_index_read_cache(vhd_index_t *index, uint64_t sector)
552 : : {
553 : : uint32_t blk, sec;
554 : : vhd_index_block_t *block;
555 : :
556 : 0 : blk = sector / index->vhdi.spb;
557 : :
558 [ # # ]: 0 : if (blk >= index->bat.vhd_blocks)
559 : : return -EINVAL;
560 : :
561 [ # # ]: 0 : if (index->bat.table[blk] == DD_BLK_UNUSED)
562 : : return VHD_INDEX_BAT_CLEAR;
563 : :
564 : 0 : block = vhd_index_get_block(index, blk);
565 [ # # ]: 0 : if (!block)
566 : : return VHD_INDEX_CACHE_MISS;
567 : :
568 : 0 : vhd_index_touch_block(index, block);
569 : :
570 [ # # ]: 0 : if (td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING))
571 : : return VHD_INDEX_META_READ_PENDING;
572 : :
573 : 0 : sec = sector % index->vhdi.spb;
574 [ # # ]: 0 : if (block->vhdi_block.table[sec].offset == DD_BLK_UNUSED)
575 : : return VHD_INDEX_BIT_CLEAR;
576 : :
577 : 0 : return VHD_INDEX_BIT_SET;
578 : : }
579 : :
580 : : static int
581 : 0 : vhd_index_read_cache_span(vhd_index_t *index,
582 : : uint64_t sector, int secs, int value)
583 : : {
584 : : int i;
585 : : uint32_t blk, sec;
586 : : vhd_index_block_t *block;
587 : :
588 : 0 : blk = sector / index->vhdi.spb;
589 : 0 : sec = sector % index->vhdi.spb;
590 : :
591 [ # # ]: 0 : ASSERT(blk < index->bat.vhd_blocks);
592 : :
593 : 0 : block = vhd_index_get_block(index, blk);
594 [ # # ][ # # ]: 0 : ASSERT(block && vhd_index_block_valid(block));
595 : :
596 [ # # ][ # # ]: 0 : for (i = 0; i < secs && i + sec < index->vhdi.spb; i++)
597 [ # # ]: 0 : if (value ^
598 : 0 : (block->vhdi_block.table[sec + i].offset != DD_BLK_UNUSED))
599 : : break;
600 : :
601 : 0 : return i;
602 : : }
603 : :
604 : : static int
605 : 0 : vhd_index_schedule_meta_read(vhd_index_t *index, uint32_t blk)
606 : : {
607 : : int err;
608 : : off64_t offset;
609 : : vhd_index_block_t *block;
610 : : vhd_index_request_t *req;
611 : :
612 [ # # ]: 0 : ASSERT(index->bat.table[blk] != DD_BLK_UNUSED);
613 : :
614 : 0 : block = vhd_index_get_block(index, blk);
615 [ # # ]: 0 : if (!block) {
616 : 0 : err = vhd_index_install_block(index, &block, blk);
617 [ # # ]: 0 : if (err)
618 : 0 : return err;
619 : : }
620 : :
621 : 0 : offset = vhd_sectors_to_bytes(index->bat.table[blk]);
622 : :
623 : 0 : req = &block->req;
624 : 0 : req->index = index;
625 : 0 : req->treq.sec = (td_sector_t)blk * index->vhdi.spb;
626 : 0 : req->treq.secs = block->table_size >> VHD_SECTOR_SHIFT;
627 : :
628 : 0 : td_prep_read(index->driver, &req->tiocb, index->vhdi.fd,
629 : 0 : (char *)block->vhdi_block.table, block->table_size,
630 : : offset, vhd_index_complete_meta_read, req);
631 : 0 : td_queue_tiocb(index->driver, &req->tiocb);
632 : :
633 : 0 : td_flag_set(block->state, VHD_INDEX_BLOCK_READ_PENDING);
634 : :
635 : 0 : return 0;
636 : : }
637 : :
638 : : static int
639 : 0 : vhd_index_schedule_data_read(vhd_index_t *index, td_request_t treq)
640 : : {
641 : : int i, err;
642 : : size_t size;
643 : : off64_t offset;
644 : : uint32_t blk, sec;
645 : : vhd_index_block_t *block;
646 : : vhd_index_request_t *req;
647 : : vhd_index_file_ref_t *file;
648 : :
649 : 0 : blk = treq.sec / index->vhdi.spb;
650 : 0 : sec = treq.sec % index->vhdi.spb;
651 : 0 : block = vhd_index_get_block(index, blk);
652 : :
653 [ # # ][ # # ]: 0 : ASSERT(block && vhd_index_block_valid(block));
654 [ # # ]: 0 : for (i = 0; i < treq.secs; i++) {
655 [ # # ]: 0 : ASSERT(block->vhdi_block.table[sec + i].file_id != 0);
656 [ # # ]: 0 : ASSERT(block->vhdi_block.table[sec + i].offset != DD_BLK_UNUSED);
657 : : }
658 : :
659 : 0 : req = vhd_index_allocate_request(index);
660 [ # # ]: 0 : if (!req)
661 : 0 : return -EBUSY;
662 : :
663 : 0 : err = vhd_index_get_file(index,
664 : 0 : block->vhdi_block.table[sec].file_id, &file);
665 [ # # ]: 0 : if (err) {
666 : 0 : vhd_index_free_request(index, req);
667 : 0 : return err;
668 : : }
669 : :
670 : 0 : size = vhd_sectors_to_bytes(treq.secs);
671 : 0 : offset = vhd_sectors_to_bytes(block->vhdi_block.table[sec].offset);
672 : :
673 : 0 : req->file = file;
674 : 0 : req->treq = treq;
675 : 0 : req->index = index;
676 : 0 : req->off = offset;
677 : :
678 : 0 : td_prep_read(index->driver, &req->tiocb, file->fd, treq.buf, size, offset,
679 : : vhd_index_complete_data_read, req);
680 : 0 : td_queue_tiocb(index->driver, &req->tiocb);
681 : :
682 : : return 0;
683 : : }
684 : :
685 : : static int
686 : 0 : vhd_index_queue_request(vhd_index_t *index, td_request_t treq)
687 : : {
688 : : vhd_index_block_t *block;
689 : : vhd_index_request_t *req;
690 : :
691 : 0 : req = vhd_index_allocate_request(index);
692 [ # # ]: 0 : if (!req)
693 : : return -EBUSY;
694 : :
695 : 0 : req->treq = treq;
696 : :
697 : 0 : block = vhd_index_get_block(index, treq.sec / index->vhdi.spb);
698 [ # # ][ # # ]: 0 : ASSERT(block && td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING));
699 : :
700 : 0 : list_add_tail(&req->next, &block->queue);
701 : 0 : return 0;
702 : : }
703 : :
704 : : static void
705 : 0 : vhd_index_queue_read(td_driver_t *driver, td_request_t treq)
706 : : {
707 : : vhd_index_t *index;
708 : :
709 : 0 : index = (vhd_index_t *)driver->data;
710 : :
711 [ # # ]: 0 : while (treq.secs) {
712 : : int err;
713 : : td_request_t clone;
714 : :
715 : 0 : err = 0;
716 : 0 : clone = treq;
717 : :
718 [ # # # # : 0 : switch (vhd_index_read_cache(index, clone.sec)) {
# # # ]
719 : : case -EINVAL:
720 : : err = -EINVAL;
721 : : goto fail;
722 : :
723 : : case VHD_INDEX_BAT_CLEAR:
724 : 0 : clone.secs = MIN(clone.secs, index->vhdi.spb - (clone.sec % index->vhdi.spb));
725 : 0 : td_forward_request(clone);
726 : : break;
727 : :
728 : : case VHD_INDEX_BIT_CLEAR:
729 : 0 : clone.secs = vhd_index_read_cache_span(index, clone.sec, clone.secs, 0);
730 : 0 : td_forward_request(clone);
731 : : break;
732 : :
733 : : case VHD_INDEX_BIT_SET:
734 : 0 : clone.secs = vhd_index_read_cache_span(index, clone.sec, clone.secs, 1);
735 : 0 : err = vhd_index_schedule_data_read(index, clone);
736 [ # # ]: 0 : if (err)
737 : : goto fail;
738 : : break;
739 : :
740 : : case VHD_INDEX_CACHE_MISS:
741 : 0 : err = vhd_index_schedule_meta_read(index, clone.sec / index->vhdi.spb);
742 [ # # ]: 0 : if (err)
743 : : goto fail;
744 : :
745 : 0 : clone.secs = MIN(clone.secs, index->vhdi.spb - (clone.sec % index->vhdi.spb));
746 : 0 : vhd_index_queue_request(index, clone);
747 : : break;
748 : :
749 : : case VHD_INDEX_META_READ_PENDING:
750 : 0 : clone.secs = MIN(clone.secs, index->vhdi.spb - (clone.sec % index->vhdi.spb));
751 : 0 : err = vhd_index_queue_request(index, clone);
752 [ # # ]: 0 : if (err)
753 : : goto fail;
754 : : break;
755 : : }
756 : :
757 : 0 : treq.sec += clone.secs;
758 : 0 : treq.secs -= clone.secs;
759 : 0 : treq.buf += vhd_sectors_to_bytes(clone.secs);
760 : 0 : continue;
761 : :
762 : : fail:
763 : 0 : clone.secs = treq.secs;
764 : 0 : td_complete_request(clone, err);
765 : 0 : break;
766 : : }
767 : 0 : }
768 : :
769 : : static void
770 : 0 : vhd_index_queue_write(td_driver_t *driver, td_request_t treq)
771 : : {
772 : 0 : td_complete_request(treq, -EPERM);
773 : 0 : }
774 : :
775 : : static inline void
776 : 0 : vhd_index_signal_completion(vhd_index_t *index,
777 : : vhd_index_request_t *req, int err)
778 : : {
779 : 0 : td_complete_request(req->treq, err);
780 : 0 : vhd_index_put_file_ref(req->file);
781 : 0 : vhd_index_free_request(index, req);
782 : 0 : }
783 : :
784 : : static void
785 : 0 : vhd_index_complete_meta_read(void *arg, struct tiocb *tiocb, int err)
786 : : {
787 : : int i;
788 : : uint32_t blk;
789 : : td_request_t treq;
790 : : vhd_index_t *index;
791 : : vhd_index_block_t *block;
792 : : vhd_index_request_t *req, *r, *tmp;
793 : :
794 : 0 : req = (vhd_index_request_t *)arg;
795 : 0 : index = req->index;
796 : :
797 : 0 : blk = req->treq.sec / index->vhdi.spb;
798 : 0 : block = vhd_index_get_block(index, blk);
799 [ # # ][ # # ]: 0 : ASSERT(block && td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING));
800 : 0 : td_flag_clear(block->state, VHD_INDEX_BLOCK_READ_PENDING);
801 : :
802 [ # # ]: 0 : if (err) {
803 : 0 : memset(block->vhdi_block.table, 0, block->table_size);
804 [ # # ]: 0 : vhd_index_block_for_each_request(block, r, tmp)
805 : 0 : vhd_index_signal_completion(index, r, err);
806 : 0 : return;
807 : : }
808 : :
809 [ # # ]: 0 : for (i = 0; i < block->vhdi_block.entries; i++)
810 : 0 : vhdi_entry_in(block->vhdi_block.table + i);
811 : :
812 : 0 : td_flag_set(block->state, VHD_INDEX_BLOCK_VALID);
813 : :
814 [ # # ]: 0 : vhd_index_block_for_each_request(block, r, tmp) {
815 : 0 : treq = r->treq;
816 : 0 : vhd_index_free_request(index, r);
817 : 0 : vhd_index_queue_read(index->driver, treq);
818 : : }
819 : : }
820 : :
821 : : static void
822 : 0 : vhd_index_complete_data_read(void *arg, struct tiocb *tiocb, int err)
823 : : {
824 : : vhd_index_t *index;
825 : : vhd_index_request_t *req;
826 : :
827 : 0 : req = (vhd_index_request_t *)arg;
828 : 0 : index = req->index;
829 : :
830 : 0 : vhd_index_signal_completion(index, req, err);
831 : 0 : }
832 : :
833 : : static int
834 : 0 : vhd_index_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
835 : : {
836 : 0 : return -EINVAL;
837 : : }
838 : :
839 : : static int
840 : 0 : vhd_index_validate_parent(td_driver_t *driver,
841 : : td_driver_t *parent, td_flag_t flags)
842 : : {
843 : 0 : return -EINVAL;
844 : : }
845 : :
846 : : static void
847 : 0 : vhd_index_debug(td_driver_t *driver)
848 : : {
849 : : int i;
850 : : vhd_index_t *index;
851 : :
852 : 0 : index = (vhd_index_t *)driver->data;
853 : :
854 : 0 : WARN("VHD INDEX %s\n", index->name);
855 : 0 : WARN("FILES:\n");
856 [ # # ]: 0 : for (i = 0; i < index->files.entries; i++) {
857 : : int j, fd, refcnt;
858 : :
859 : : fd = -1;
860 : : refcnt = 0;
861 : :
862 [ # # ]: 0 : for (j = 0; j < VHD_INDEX_FILE_POOL_SIZE; j++)
863 [ # # ]: 0 : if (index->fds[j].fid == index->files.table[i].file_id) {
864 : 0 : fd = index->fds[j].fd;
865 : 0 : refcnt = index->fds[j].refcnt;
866 : : }
867 : :
868 : 0 : WARN("%s %u %d %d\n",
869 : : index->files.table[i].path,
870 : : index->files.table[i].file_id,
871 : : fd, refcnt);
872 : : }
873 : :
874 : 0 : WARN("REQUESTS:\n");
875 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_REQUESTS; i++) {
876 : : vhd_index_request_t *req;
877 : :
878 : 0 : req = index->requests_list + i;
879 : :
880 [ # # ]: 0 : if (!req->index)
881 : 0 : continue;
882 : :
883 : 0 : WARN("%d: buf: %p, sec: 0x%08"PRIx64", secs: 0x%04x, "
884 : : "fid: %u, off: 0x%016"PRIx64"\n", i, req->treq.buf,
885 : : req->treq.sec, req->treq.secs, req->file->fid, req->off);
886 : : }
887 : :
888 : 0 : WARN("BLOCKS:\n");
889 [ # # ]: 0 : for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) {
890 : : int queued;
891 : : vhd_index_block_t *block;
892 : : vhd_index_request_t *req, *tmp;
893 : :
894 : 0 : queued = 0;
895 : 0 : block = index->cache[i];
896 : :
897 [ # # ]: 0 : if (!block)
898 : 0 : continue;
899 : :
900 [ # # ]: 0 : vhd_index_block_for_each_request(block, req, tmp)
901 : 0 : ++queued;
902 : :
903 : 0 : WARN("%d: blk: 0x%08"PRIx64", state: 0x%08x, queued: %d\n",
904 : : i, block->blk, block->state, queued);
905 : : }
906 : 0 : }
907 : :
908 : : struct tap_disk tapdisk_vhd_index = {
909 : : .disk_type = "tapdisk_vhd_index",
910 : : .flags = 0,
911 : : .private_data_size = sizeof(vhd_index_t),
912 : : .td_open = vhd_index_open,
913 : : .td_close = vhd_index_close,
914 : : .td_queue_read = vhd_index_queue_read,
915 : : .td_queue_write = vhd_index_queue_write,
916 : : .td_get_parent_id = vhd_index_get_parent_id,
917 : : .td_validate_parent = vhd_index_validate_parent,
918 : : .td_debug = vhd_index_debug,
919 : : };
|