File: raw.c

package info (click to toggle)
kvmtool 0.20161128-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,748 kB
  • ctags: 6,310
  • sloc: ansic: 25,215; makefile: 495; asm: 212; sh: 122
file content (141 lines) | stat: -rw-r--r-- 3,027 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "kvm/disk-image.h"

#include <linux/err.h>

#ifdef CONFIG_HAS_AIO
#include <libaio.h>
#endif

ssize_t raw_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov,
				int iovcount, void *param)
{
	u64 offset = sector << SECTOR_SHIFT;

#ifdef CONFIG_HAS_AIO
	struct iocb iocb;

	return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
				disk->evt, param);
#else
	return preadv_in_full(disk->fd, iov, iovcount, offset);
#endif
}

ssize_t raw_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov,
				int iovcount, void *param)
{
	u64 offset = sector << SECTOR_SHIFT;

#ifdef CONFIG_HAS_AIO
	struct iocb iocb;

	return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
				disk->evt, param);
#else
	return pwritev_in_full(disk->fd, iov, iovcount, offset);
#endif
}

ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
				int iovcount, void *param)
{
	u64 offset = sector << SECTOR_SHIFT;
	ssize_t total = 0;

	while (iovcount--) {
		memcpy(iov->iov_base, disk->priv + offset, iov->iov_len);

		sector	+= iov->iov_len >> SECTOR_SHIFT;
		offset	+= iov->iov_len;
		total	+= iov->iov_len;
		iov++;
	}

	return total;
}

ssize_t raw_image__write_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
				int iovcount, void *param)
{
	u64 offset = sector << SECTOR_SHIFT;
	ssize_t total = 0;

	while (iovcount--) {
		memcpy(disk->priv + offset, iov->iov_base, iov->iov_len);

		sector	+= iov->iov_len >> SECTOR_SHIFT;
		offset	+= iov->iov_len;
		total	+= iov->iov_len;
		iov++;
	}

	return total;
}

int raw_image__close(struct disk_image *disk)
{
	int ret = 0;

	if (disk->priv != MAP_FAILED)
		ret = munmap(disk->priv, disk->size);

	close(disk->evt);

#ifdef CONFIG_HAS_VIRTIO
	io_destroy(disk->ctx);
#endif

	return ret;
}

/*
 * multiple buffer based disk image operations
 */
static struct disk_image_operations raw_image_regular_ops = {
	.read	= raw_image__read,
	.write	= raw_image__write,
};

struct disk_image_operations ro_ops = {
	.read	= raw_image__read_mmap,
	.write	= raw_image__write_mmap,
	.close	= raw_image__close,
};

struct disk_image_operations ro_ops_nowrite = {
	.read	= raw_image__read,
};

struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly)
{
	struct disk_image *disk;

	if (readonly) {
		/*
		 * Use mmap's MAP_PRIVATE to implement non-persistent write
		 * FIXME: This does not work on 32-bit host.
		 */
		struct disk_image *disk;

		disk = disk_image__new(fd, st->st_size, &ro_ops, DISK_IMAGE_MMAP);
		if (IS_ERR_OR_NULL(disk)) {
			disk = disk_image__new(fd, st->st_size, &ro_ops_nowrite, DISK_IMAGE_REGULAR);
#ifdef CONFIG_HAS_AIO
			if (!IS_ERR_OR_NULL(disk))
				disk->async = 1;
#endif
		}

		return disk;
	} else {
		/*
		 * Use read/write instead of mmap
		 */
		disk = disk_image__new(fd, st->st_size, &raw_image_regular_ops, DISK_IMAGE_REGULAR);
#ifdef CONFIG_HAS_AIO
		if (!IS_ERR_OR_NULL(disk))
			disk->async = 1;
#endif
		return disk;
	}
}