static int tapdisk_vbd_add_block_cache(td_vbd_t *vbd) { td_image_t *cache, *image, *target, *tmp; int err; target = NULL; tapdisk_vbd_for_each_image(vbd, image, tmp) if (td_flag_test(image->flags, TD_OPEN_RDONLY) && td_flag_test(image->flags, TD_OPEN_SHAREABLE)) { target = image; break; } if (!target) return 0; cache = tapdisk_image_allocate(target->name, DISK_TYPE_BLOCK_CACHE, target->flags); if (!cache) return -ENOMEM; /* try to load existing cache */ err = td_load(cache); if (!err) goto done; /* hack driver to send open() correct image size */ if (!target->driver) { err = -ENODEV; goto fail; } cache->driver = tapdisk_driver_allocate(cache->type, cache->name, cache->flags); if (!cache->driver) { err = -ENOMEM; goto fail; } cache->driver->info = target->driver->info; /* try to open new cache */ err = td_open(cache); if (!err) goto done; fail: /* give up */ tapdisk_image_free(target); return err; done: /* insert cache before image */ list_add(&cache->next, target->next.prev); return 0; }
int tapdisk_xenblkif_disconnect(const domid_t domid, const int devid) { struct td_xenblkif *blkif; blkif = tapdisk_xenblkif_find(domid, devid); if (!blkif) return -ENODEV; if (tapdisk_xenblkif_reqs_pending(blkif)) { RING_DEBUG(blkif, "disconnect from ring with %d pending requests\n", blkif->ring_size - blkif->n_reqs_free); if (td_flag_test(blkif->vbd->state, TD_VBD_PAUSED)) RING_ERR(blkif, "disconnect from ring with %d pending requests " "and the VBD paused\n", blkif->ring_size - blkif->n_reqs_free); list_move(&blkif->entry, &blkif->vbd->dead_rings); blkif->dead = true; if (blkif->ctx && blkif->port >= 0) { xc_evtchn_unbind(blkif->ctx->xce_handle, blkif->port); blkif->port = -1; } /* * FIXME shall we unmap the ring or will that lead to some fatal error * in tapdisk? IIUC if we don't unmap it we'll get errors during grant * copy. */ return 0; } else return tapdisk_xenblkif_destroy(blkif); }
static void vhd_index_complete_meta_read(void *arg, struct tiocb *tiocb, int err) { int i; uint32_t blk; td_request_t treq; vhd_index_t *index; vhd_index_block_t *block; vhd_index_request_t *req, *r, *tmp; req = (vhd_index_request_t *)arg; index = req->index; blk = req->treq.sec / index->vhdi.spb; block = vhd_index_get_block(index, blk); ASSERT(block && td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING)); td_flag_clear(block->state, VHD_INDEX_BLOCK_READ_PENDING); if (err) { memset(block->vhdi_block.table, 0, block->table_size); vhd_index_block_for_each_request(block, r, tmp) vhd_index_signal_completion(index, r, err); return; } for (i = 0; i < block->vhdi_block.entries; i++) vhdi_entry_in(block->vhdi_block.table + i); td_flag_set(block->state, VHD_INDEX_BLOCK_VALID); vhd_index_block_for_each_request(block, r, tmp) { treq = r->treq; vhd_index_free_request(index, r); vhd_index_queue_read(index->driver, treq); }
static int vhd_index_read_cache(vhd_index_t *index, uint64_t sector) { uint32_t blk, sec; vhd_index_block_t *block; blk = sector / index->vhdi.spb; if (blk >= index->bat.vhd_blocks) return -EINVAL; if (index->bat.table[blk] == DD_BLK_UNUSED) return VHD_INDEX_BAT_CLEAR; block = vhd_index_get_block(index, blk); if (!block) return VHD_INDEX_CACHE_MISS; vhd_index_touch_block(index, block); if (td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING)) return VHD_INDEX_META_READ_PENDING; sec = sector % index->vhdi.spb; if (block->vhdi_block.table[sec].offset == DD_BLK_UNUSED) return VHD_INDEX_BIT_CLEAR; return VHD_INDEX_BIT_SET; }
static inline vhd_index_block_t * vhd_index_get_lru_block(vhd_index_t *index) { int i, idx; uint32_t min; vhd_index_block_t *block, *lru; lru = NULL; min = (uint32_t)-1; idx = 0; for (i = 0; i < VHD_INDEX_CACHE_SIZE; i++) { block = index->cache[i]; if (!block) continue; if (td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING)) continue; if (!lru || block->seqno < min) { lru = block; min = block->seqno; idx = i; } } if (lru) index->cache[idx] = NULL; return lru; }
int tapdisk_image_check_td_request(td_image_t *image, td_request_t treq) { int rdonly, err; td_disk_info_t *info; err = -EINVAL; info = &image->info; rdonly = td_flag_test(image->flags, TD_OPEN_RDONLY); if (treq.op != TD_OP_READ && treq.op != TD_OP_WRITE) goto fail; if (treq.op == TD_OP_WRITE && rdonly) { err = -EPERM; goto fail; } if (treq.secs <= 0 || treq.sec + treq.secs > info->size) goto fail; return 0; fail: ERR(err, "bad td request on %s (%s, %"PRIu64"): %d at %"PRIu64, image->name, (rdonly ? "ro" : "rw"), info->size, treq.op, treq.sec + treq.secs); return err; }
void td_queue_read(td_image_t *image, td_request_t treq) { int err; td_driver_t *driver; driver = image->driver; if (!driver) { err = -ENODEV; goto fail; } if (!td_flag_test(driver->state, TD_DRIVER_OPEN)) { err = -EBADF; goto fail; } err = tapdisk_image_check_td_request(image, treq); if (err) goto fail; driver->ops->td_queue_read(driver, treq); return; fail: td_complete_request(treq, err); }
int td_validate_parent(td_image_t *image, td_image_t *parent) { td_driver_t *driver, *pdriver; driver = image->driver; pdriver = parent->driver; if (!driver || !pdriver) return -ENODEV; if (!td_flag_test(driver->state, TD_DRIVER_OPEN) || !td_flag_test(pdriver->state, TD_DRIVER_OPEN)) return -EBADF; return 0; return driver->ops->td_validate_parent(driver, pdriver, 0); }
void td_debug(td_image_t *image) { td_driver_t *driver; driver = image->driver; if (!driver || !td_flag_test(driver->state, TD_DRIVER_OPEN)) return; tapdisk_driver_debug(driver); }
int tapdisk_vbd_add_secondary(td_vbd_t *vbd) { td_image_t *leaf, *second = NULL; const char *path; int type, err; DPRINTF("Adding secondary image: %s\n", vbd->secondary_name); type = tapdisk_disktype_parse_params(vbd->secondary_name, &path); if (type < 0) return type; leaf = tapdisk_vbd_first_image(vbd); if (!leaf) { err = -EINVAL; goto fail; } err = tapdisk_image_open(type, path, leaf->flags, &second); if (err) goto fail; if (second->info.size != leaf->info.size) { EPRINTF("Secondary image size %"PRIu64" != image size %"PRIu64"\n", second->info.size, leaf->info.size); err = -EINVAL; goto fail; } vbd->secondary = second; leaf->flags |= TD_IGNORE_ENOSPC; if (td_flag_test(vbd->flags, TD_OPEN_STANDBY)) { DPRINTF("In standby mode\n"); vbd->secondary_mode = TD_VBD_SECONDARY_STANDBY; } else { DPRINTF("In mirror mode\n"); vbd->secondary_mode = TD_VBD_SECONDARY_MIRROR; /* we actually need this image to also be part of the chain, * since it may already contain data */ list_add(&second->next, &leaf->next); } DPRINTF("Added secondary image\n"); return 0; fail: if (second) tapdisk_image_close(second); return err; }
int tapdisk_image_check_request(td_image_t *image, td_vbd_request_t *vreq) { td_driver_t *driver; td_disk_info_t *info; int i, rdonly, secs, err; driver = image->driver; if (!driver) return -ENODEV; info = &driver->info; rdonly = td_flag_test(image->flags, TD_OPEN_RDONLY); secs = 0; if (vreq->iovcnt < 0) { err = -EINVAL; goto fail; } for (i = 0; i < vreq->iovcnt; i++) secs += vreq->iov[i].secs; switch (vreq->op) { case TD_OP_WRITE: if (rdonly) { err = -EPERM; goto fail; } /* continue */ case TD_OP_READ: if (vreq->sec + secs > info->size) { err = -EINVAL; goto fail; } break; default: err = -EOPNOTSUPP; goto fail; } return 0; fail: ERR(err, "bad request on %s (%s, %"PRIu64"): req %s op %d at %"PRIu64, image->name, (rdonly ? "ro" : "rw"), info->size, vreq->name, vreq->op, vreq->sec + secs); return err; }
int __td_open(td_image_t *image, td_disk_info_t *info) { int err; td_driver_t *driver; driver = image->driver; if (!driver) { driver = tapdisk_driver_allocate(image->type, image->name, image->flags); if (!driver) return -ENOMEM; if (info) /* pre-seed driver->info for virtual drivers */ driver->info = *info; } if (!td_flag_test(driver->state, TD_DRIVER_OPEN)) { err = driver->ops->td_open(driver, image->name, image->flags); if (err) { if (!image->driver) tapdisk_driver_free(driver); return err; } td_flag_set(driver->state, TD_DRIVER_OPEN); DPRINTF("opened image %s (%d users, state: 0x%08x, type: %d, %s)\n", driver->name, driver->refcnt + 1, driver->state, driver->type, td_flag_test(image->flags, TD_OPEN_RDONLY) ? "ro" : "rw"); } image->driver = driver; image->info = driver->info; driver->refcnt++; return 0; }
int td_get_parent_id(td_image_t *image, td_disk_id_t *id) { td_driver_t *driver; driver = image->driver; if (!driver) return -ENODEV; if (!td_flag_test(driver->state, TD_DRIVER_OPEN)) return -EBADF; return driver->ops->td_get_parent_id(driver, id); }
int td_get_oflags(td_image_t *image, int *flags) { td_driver_t *driver; driver = image->driver; if (!driver) return -ENODEV; if (!td_flag_test(driver->state, TD_DRIVER_OPEN)) return -EBADF; if (!driver->ops->td_get_oflags) return -ENOTSUP; return driver->ops->td_get_oflags(driver, flags); }
td_image_t * tapdisk_server_get_shared_image(td_image_t *image) { td_vbd_t *vbd, *tmpv; td_image_t *img, *tmpi; if (!td_flag_test(image->flags, TD_OPEN_SHAREABLE)) return NULL; tapdisk_server_for_each_vbd(vbd, tmpv) tapdisk_vbd_for_each_image(vbd, img, tmpi) if (img->type == image->type && !strcmp(img->name, image->name)) return img; return NULL; }
static int vhd_index_queue_request(vhd_index_t *index, td_request_t treq) { vhd_index_block_t *block; vhd_index_request_t *req; req = vhd_index_allocate_request(index); if (!req) return -EBUSY; req->treq = treq; block = vhd_index_get_block(index, treq.sec / index->vhdi.spb); ASSERT(block && td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING)); list_add_tail(&req->next, &block->queue); return 0; }
int td_close(td_image_t *image) { td_driver_t *driver; driver = image->driver; if (!driver) return -ENODEV; driver->refcnt--; if (!driver->refcnt && td_flag_test(driver->state, TD_DRIVER_OPEN)) { driver->ops->td_close(driver); td_flag_clear(driver->state, TD_DRIVER_OPEN); } DPRINTF("closed image %s (%d users, state: 0x%08x, type: %d)\n", driver->name, driver->refcnt, driver->state, driver->type); return 0; }
int tapdisk_vbd_open_vdi(td_vbd_t *vbd, const char *name, td_flag_t flags, int prt_devnum) { char *tmp = vbd->name; int err; if (!list_empty(&vbd->images)) { err = -EBUSY; goto fail; } if (!name && !vbd->name) { err = -EINVAL; goto fail; } if (name) { vbd->name = strdup(name); if (!vbd->name) { err = -errno; goto fail; } } err = tapdisk_image_open_chain(vbd->name, flags, prt_devnum, &vbd->images); if (err) goto fail; td_flag_clear(vbd->state, TD_VBD_CLOSED); vbd->flags = flags; if (td_flag_test(vbd->flags, TD_OPEN_LOG_DIRTY)) { err = tapdisk_vbd_add_dirty_log(vbd); if (err) goto fail; } if (td_flag_test(vbd->flags, TD_OPEN_ADD_CACHE)) { err = tapdisk_vbd_add_block_cache(vbd); if (err) goto fail; } if (td_flag_test(vbd->flags, TD_OPEN_LOCAL_CACHE)) { err = tapdisk_vbd_add_local_cache(vbd); if (err) goto fail; } err = tapdisk_vbd_validate_chain(vbd); if (err) goto fail; if (td_flag_test(vbd->flags, TD_OPEN_SECONDARY)) { err = tapdisk_vbd_add_secondary(vbd); if (err) { if (vbd->nbd_mirror_failed != 1) goto fail; INFO("Ignoring failed NBD secondary attach\n"); err = 0; } } if (tmp != vbd->name) free(tmp); return err; fail: if (vbd->name != tmp) { free(vbd->name); vbd->name = tmp; } if (!list_empty(&vbd->images)) tapdisk_image_close_chain(&vbd->images); vbd->flags = 0; return err; }
static inline int vhd_index_block_valid(vhd_index_block_t *block) { return (!td_flag_test(block->state, VHD_INDEX_BLOCK_READ_PENDING) && td_flag_test(block->state, VHD_INDEX_BLOCK_VALID)); }