Exemple #1
0
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;
}
Exemple #2
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);
}
Exemple #3
0
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);
	}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #6
0
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;

}
Exemple #7
0
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);
}
Exemple #8
0
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);
}
Exemple #9
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);
}
Exemple #10
0
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;
}
Exemple #11
0
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;
}
Exemple #13
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);
}
Exemple #14
0
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);
}
Exemple #15
0
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;
}
Exemple #16
0
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;
}
Exemple #17
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;
}
Exemple #18
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;
}
Exemple #19
0
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));
}