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