⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 block-qcow2.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 4 页
字号:
		if ((cluster_offset + s->cluster_size) == offset) {			/* we are lucky: contiguous data */			offset = s->free_byte_offset;			update_cluster_refcount(bs, offset >> s->cluster_bits, 1);			s->free_byte_offset += size;		} else {			s->free_byte_offset = offset;			goto redo;		}	}	return offset;}static void free_clusters(struct disk_driver *bs,		int64_t offset, int64_t size){	update_refcount(bs, offset, size, -1);}static int grow_refcount_table(struct disk_driver *bs, int min_size){	BDRVQcowState *s = bs->private;	int new_table_size, new_table_size2, refcount_table_clusters, i, ret;	uint64_t *new_table;	int64_t table_offset;	uint64_t data64;	uint32_t data32;	int old_table_size;	int64_t old_table_offset;	if (min_size <= s->refcount_table_size)		return 0;		/* compute new table size */	refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);	for(;;) {		if (refcount_table_clusters == 0) {			refcount_table_clusters = 1;		} else {			refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;		}		new_table_size = refcount_table_clusters << (s->cluster_bits - 3);		if (min_size <= new_table_size)			break;	}#ifdef DEBUG_ALLOC2	printf("grow_refcount_table from %d to %d\n",		   s->refcount_table_size,		   new_table_size);#endif	new_table_size2 = new_table_size * sizeof(uint64_t);	new_table = qemu_mallocz(new_table_size2);	if (!new_table)		return -ENOMEM;	memcpy(new_table, s->refcount_table,		   s->refcount_table_size * sizeof(uint64_t));	for(i = 0; i < s->refcount_table_size; i++)		cpu_to_be64s(&new_table[i]);	/* Note: we cannot update the refcount now to avoid recursion */	table_offset = alloc_clusters_noref(bs, new_table_size2);	ret = bdrv_pwrite(s->fd, table_offset, new_table, new_table_size2);	if (ret != new_table_size2)		goto fail;	for(i = 0; i < s->refcount_table_size; i++)		be64_to_cpus(&new_table[i]);	data64 = cpu_to_be64(table_offset);	if (bdrv_pwrite(s->fd, offsetof(QCowHeader, refcount_table_offset),					&data64, sizeof(data64)) != sizeof(data64))		goto fail;	data32 = cpu_to_be32(refcount_table_clusters);	if (bdrv_pwrite(s->fd, offsetof(QCowHeader, refcount_table_clusters),					&data32, sizeof(data32)) != sizeof(data32))		goto fail;	qemu_free(s->refcount_table);	old_table_offset = s->refcount_table_offset;	old_table_size = s->refcount_table_size;	s->refcount_table = new_table;	s->refcount_table_size = new_table_size;	s->refcount_table_offset = table_offset;	update_refcount(bs, table_offset, new_table_size2, 1);	free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));	return 0; fail:	free_clusters(bs, table_offset, new_table_size2);	qemu_free(new_table);	return -EIO;}/* addend must be 1 or -1 *//* XXX: cache several refcount block clusters ? */static int update_cluster_refcount(struct disk_driver *bs,		int64_t cluster_index,		int addend){	BDRVQcowState *s = bs->private;	int64_t offset, refcount_block_offset;	int ret, refcount_table_index, block_index, refcount;	uint64_t data64;	refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);	if (refcount_table_index >= s->refcount_table_size) {		if (addend < 0)			return -EINVAL;		ret = grow_refcount_table(bs, refcount_table_index + 1);		if (ret < 0)			return ret;	}	refcount_block_offset = s->refcount_table[refcount_table_index];	if (!refcount_block_offset) {		if (addend < 0)			return -EINVAL;		/* create a new refcount block */		/* Note: we cannot update the refcount now to avoid recursion */		offset = alloc_clusters_noref(bs, s->cluster_size);		memset(s->refcount_block_cache, 0, s->cluster_size);		ret = bdrv_pwrite(s->fd, offset, s->refcount_block_cache, s->cluster_size);		if (ret != s->cluster_size)			return -EINVAL;		s->refcount_table[refcount_table_index] = offset;		data64 = cpu_to_be64(offset);		ret = bdrv_pwrite(s->fd, s->refcount_table_offset +						  refcount_table_index * sizeof(uint64_t),						  &data64, sizeof(data64));		if (ret != sizeof(data64))			return -EINVAL;		refcount_block_offset = offset;		s->refcount_block_cache_offset = offset;		update_refcount(bs, offset, s->cluster_size, 1);	} else {		if (refcount_block_offset != s->refcount_block_cache_offset) {			if (load_refcount_block(bs, refcount_block_offset) < 0)				return -EIO;		}	}	/* we can update the count and save it */	block_index = cluster_index &		((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);	refcount = be16_to_cpu(s->refcount_block_cache[block_index]);	refcount += addend;	if (refcount < 0 || refcount > 0xffff)		return -EINVAL;	if (refcount == 0 && cluster_index < s->free_cluster_index) {		s->free_cluster_index = cluster_index;	}	s->refcount_block_cache[block_index] = cpu_to_be16(refcount);	if (bdrv_pwrite(s->fd,					refcount_block_offset + (block_index << REFCOUNT_SHIFT),					&s->refcount_block_cache[block_index], 2) != 2)		return -EIO;	return refcount;}static void update_refcount(struct disk_driver *bs,		int64_t offset, int64_t length,		int addend){	BDRVQcowState *s = bs->private;	int64_t start, last, cluster_offset;#ifdef DEBUG_ALLOC2	printf("update_refcount: offset=%lld size=%lld addend=%d\n",		   offset, length, addend);#endif	if (length <= 0)		return;	start = offset & ~(s->cluster_size - 1);	last = (offset + length - 1) & ~(s->cluster_size - 1);	for(cluster_offset = start; cluster_offset <= last;		cluster_offset += s->cluster_size) {		update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);	}}#ifdef DEBUG_ALLOCstatic void inc_refcounts(struct disk_driver *bs,		uint16_t *refcount_table,		int refcount_table_size,		int64_t offset, int64_t size){	BDRVQcowState *s = bs->private;	int64_t start, last, cluster_offset;	int k;	if (size <= 0)		return;	start = offset & ~(s->cluster_size - 1);	last = (offset + size - 1) & ~(s->cluster_size - 1);	for(cluster_offset = start; cluster_offset <= last;		cluster_offset += s->cluster_size) {		k = cluster_offset >> s->cluster_bits;		if (k < 0 || k >= refcount_table_size) {			printf("ERROR: invalid cluster offset=0x%llx\n", cluster_offset);		} else {			if (++refcount_table[k] == 0) {				printf("ERROR: overflow cluster offset=0x%llx\n", cluster_offset);			}		}	}}static int check_refcounts_l1(struct disk_driver *bs,		uint16_t *refcount_table,		int refcount_table_size,		int64_t l1_table_offset, int l1_size,		int check_copied){	BDRVQcowState *s = bs->private;	uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;	int l2_size, i, j, nb_csectors, refcount;	l2_table = NULL;	l1_size2 = l1_size * sizeof(uint64_t);	inc_refcounts(bs, refcount_table, refcount_table_size,				  l1_table_offset, l1_size2);	l1_table = qemu_malloc(l1_size2);	if (!l1_table)		goto fail;	if (bdrv_pread(s->fd, l1_table_offset,				   l1_table, l1_size2) != l1_size2)		goto fail;	for(i = 0;i < l1_size; i++)		be64_to_cpus(&l1_table[i]);	l2_size = s->l2_size * sizeof(uint64_t);	l2_table = qemu_malloc(l2_size);	if (!l2_table)		goto fail;	for(i = 0; i < l1_size; i++) {		l2_offset = l1_table[i];		if (l2_offset) {			if (check_copied) {				refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);				if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {					printf("ERROR OFLAG_COPIED: l2_offset=%llx refcount=%d\n",						   l2_offset, refcount);				}			}			l2_offset &= ~QCOW_OFLAG_COPIED;			if (bdrv_pread(s->fd, l2_offset, l2_table, l2_size) != l2_size)				goto fail;			for(j = 0; j < s->l2_size; j++) {				offset = be64_to_cpu(l2_table[j]);				if (offset != 0) {					if (offset & QCOW_OFLAG_COMPRESSED) {						if (offset & QCOW_OFLAG_COPIED) {							printf("ERROR: cluster %lld: copied flag must never be set for compressed clusters\n",								   offset >> s->cluster_bits);							offset &= ~QCOW_OFLAG_COPIED;						}						nb_csectors = ((offset >> s->csize_shift) &									   s->csize_mask) + 1;						offset &= s->cluster_offset_mask;						inc_refcounts(bs, refcount_table,								refcount_table_size,								offset & ~511, nb_csectors * 512);					} else {						if (check_copied) {							refcount = get_refcount(bs, (offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);							if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) {								printf("ERROR OFLAG_COPIED: offset=%llx refcount=%d\n",									   offset, refcount);							}						}						offset &= ~QCOW_OFLAG_COPIED;						inc_refcounts(bs, refcount_table,								refcount_table_size,								offset, s->cluster_size);					}				}			}			inc_refcounts(bs, refcount_table,					refcount_table_size,					l2_offset,					s->cluster_size);		}	}	qemu_free(l1_table);	qemu_free(l2_table);	return 0; fail:	printf("ERROR: I/O error in check_refcounts_l1\n");	qemu_free(l1_table);	qemu_free(l2_table);	return -EIO;}static void check_refcounts(struct disk_driver *bs){	BDRVQcowState *s = bs->private;	int64_t size;	int nb_clusters, refcount1, refcount2, i;	QCowSnapshot *sn;	uint16_t *refcount_table;	size = bdrv_getlength(s->fd);	nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;	refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));	/* header */	inc_refcounts(bs, refcount_table, nb_clusters,			0, s->cluster_size);	check_refcounts_l1(bs, refcount_table, nb_clusters,			s->l1_table_offset, s->l1_size, 1);	/* snapshots */	for(i = 0; i < s->nb_snapshots; i++) {		sn = s->snapshots + i;		check_refcounts_l1(bs, refcount_table, nb_clusters,						   sn->l1_table_offset, sn->l1_size, 0);	}	inc_refcounts(bs, refcount_table, nb_clusters,				  s->snapshots_offset, s->snapshots_size);	/* refcount data */	inc_refcounts(bs, refcount_table, nb_clusters,			s->refcount_table_offset,			s->refcount_table_size * sizeof(uint64_t));	for(i = 0; i < s->refcount_table_size; i++) {		int64_t offset;		offset = s->refcount_table[i];		if (offset != 0) {			inc_refcounts(bs, refcount_table, nb_clusters,					offset, s->cluster_size);		}	}	/* compare ref counts */	for(i = 0; i < nb_clusters; i++) {		refcount1 = get_refcount(bs, i);		refcount2 = refcount_table[i];		if (refcount1 != refcount2)			printf("ERROR cluster %d refcount=%d reference=%d\n",				   i, refcount1, refcount2);	}	qemu_free(refcount_table);}#endif/** * Wrapper for synchronous read. * This function is called when not using AIO at all (#undef USE_AIO) or * for accessing the backing file. */static int qcow_sync_read(struct disk_driver *dd, uint64_t sector,		int nb_sectors, char *buf, td_callback_t cb,		int id, void *prv){	int ret = qcow_read(dd, sector, (uint8_t*) buf, nb_sectors);	if (cb != NULL) {		return cb(dd, (ret < 0) ? ret : 0, sector, nb_sectors, id, prv);	} else {		return ret;	}}#ifndef USE_AIO/** * Wrapper for synchronous write */static int qcow_sync_write(struct disk_driver *dd, uint64_t sector,		int nb_sectors, char *buf, td_callback_t cb,		int id, void *prv){	int ret = qcow_write(dd, sector, (uint8_t*) buf, nb_sectors);		return cb(dd, (ret < 0) ? ret : 0, sector, nb_sectors, id, prv);}#endif#ifndef USE_AIOstatic int qcow_do_callbacks(struct disk_driver *dd, int sid){	return 1;}#elsestatic int qcow_do_callbacks(struct disk_driver *dd, int sid){	int ret, i, nr_events, rsp = 0,*ptr;	struct io_event *ep;	struct BDRVQcowState *prv = (struct BDRVQcowState*)dd->private;	if (sid > MAX_IOFD) return 1;	nr_events = tap_aio_get_events(&prv->async.aio_ctx);repeat:	for (ep = prv->async.aio_events, i = nr_events; i-- > 0; ep++) {		struct iocb		   *io	= ep->obj;		struct pending_aio *pio;		pio = &prv->async.pending_aio[(long)io->data];		tap_aio_unlock(&prv->async, pio->sector);		if (prv->crypt_method)			encrypt_sectors(prv, pio->sector, 					(unsigned char *)pio->buf, 					(unsigned char *)pio->buf, 					pio->nb_sectors, 0, 					&prv->aes_decrypt_key);		rsp += pio->cb(dd, ep->res == io->u.c.nbytes ? 0 : 1, 			pio->sector, pio->nb_sectors,			pio->id, pio->private);		prv->async.iocb_free[prv->async.iocb_free_count++] = io;	}	if (nr_events) {		nr_events = tap_aio_more_events(&prv->async.aio_ctx);		goto repeat;	}	tap_aio_continue(&prv->async.aio_ctx);	return rsp;}#endif	/** * @return  *	   0 if parent id successfully retrieved; *	   TD_NO_PARENT if no parent exists; *	   -errno on error */static int qcow_get_parent_id(struct disk_driver *dd, struct disk_id *id){	struct BDRVQcowState* s = (struct BDRVQcowState*) dd->private;	if (s->backing_file[0] == '\0')		return TD_NO_PARENT;	id->name = strdup(s->backing_file);	id->drivertype = DISK_TYPE_QCOW2;	return 0;}static int qcow_validate_parent(struct disk_driver *child, 		struct disk_driver *parent, td_flag_t flags){	struct BDRVQcowState *cs = (struct BDRVQcowState*) child->private;	struct BDRVQcowState *ps = (struct BDRVQcowState*) parent->private;	if (ps->total_sectors != cs->total_sectors) {		DPRINTF("qcow_validate_parent(): %#"PRIx64" != %#"PRIx64"\n",			ps->total_sectors, cs->total_sectors);		return -EINVAL;	}		return 0;}struct tap_disk tapdisk_qcow2 = {	"qcow2",	sizeof(BDRVQcowState),	qcow_open,#ifdef USE_AIO	qcow_queue_read,	qcow_queue_write,#else	qcow_sync_read,	qcow_sync_write,#endif	qcow_submit,	qcow_close,	qcow_do_callbacks,	qcow_get_parent_id,	qcow_validate_parent};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -