xref: /kvmtool/disk/core.c (revision 86835ced6d416f4e6471db823b9ad9d1474e3735)
19f532d00SPekka Enberg #include "kvm/disk-image.h"
29f532d00SPekka Enberg 
3c4d7847bSPekka Enberg #include "kvm/read-write.h"
4*86835cedSPrasad Joshi #include "kvm/qcow.h"
59f532d00SPekka Enberg #include "kvm/util.h"
69f532d00SPekka Enberg 
79f532d00SPekka Enberg #include <sys/types.h>
833d33901SPekka Enberg #include <inttypes.h>
99f532d00SPekka Enberg #include <sys/mman.h>
109f532d00SPekka Enberg #include <sys/stat.h>
115646450dSPekka Enberg #include <stdbool.h>
129f532d00SPekka Enberg #include <stddef.h>
139f532d00SPekka Enberg #include <stdlib.h>
149f532d00SPekka Enberg #include <unistd.h>
159f532d00SPekka Enberg #include <fcntl.h>
169f532d00SPekka Enberg 
17f4ff38dfSPrasad Joshi struct disk_image *disk_image__new(int fd, uint64_t size, struct disk_image_operations *ops)
189f532d00SPekka Enberg {
19fffb37a9SPekka Enberg 	struct disk_image *self;
209f532d00SPekka Enberg 
21fffb37a9SPekka Enberg 	self		= malloc(sizeof *self);
22fffb37a9SPekka Enberg 	if (!self)
23fffb37a9SPekka Enberg 		return NULL;
249f532d00SPekka Enberg 
25fffb37a9SPekka Enberg 	self->fd	= fd;
26fffb37a9SPekka Enberg 	self->size	= size;
27fffb37a9SPekka Enberg 	self->ops	= ops;
28f4ff38dfSPrasad Joshi 	return self;
29f4ff38dfSPrasad Joshi }
30f4ff38dfSPrasad Joshi 
31f4ff38dfSPrasad Joshi struct disk_image *disk_image__new_readonly(int fd, uint64_t size, struct disk_image_operations *ops)
32f4ff38dfSPrasad Joshi {
33f4ff38dfSPrasad Joshi 	struct disk_image *self;
34f4ff38dfSPrasad Joshi 
35f4ff38dfSPrasad Joshi 	self = disk_image__new(fd, size, ops);
36f4ff38dfSPrasad Joshi 	if (!self)
37f4ff38dfSPrasad Joshi 		return NULL;
38f4ff38dfSPrasad Joshi 
399ac38fe1SSasha Levin 	self->priv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
409ac38fe1SSasha Levin 	if (self->priv == MAP_FAILED)
419ac38fe1SSasha Levin 		die("mmap() failed");
42fffb37a9SPekka Enberg 	return self;
439f532d00SPekka Enberg }
449f532d00SPekka Enberg 
45f4ff38dfSPrasad Joshi 
46499f3bedSPekka Enberg static int raw_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len)
479f532d00SPekka Enberg {
489f532d00SPekka Enberg 	uint64_t offset = sector << SECTOR_SHIFT;
499f532d00SPekka Enberg 
505a24a9f2SPekka Enberg 	if (offset + dst_len > self->size)
519f532d00SPekka Enberg 		return -1;
529f532d00SPekka Enberg 
536b7deb02SPekka Enberg 	if (pread_in_full(self->fd, dst, dst_len, offset) < 0)
54c4d7847bSPekka Enberg 		return -1;
559f532d00SPekka Enberg 
569f532d00SPekka Enberg 	return 0;
579f532d00SPekka Enberg }
58258dd093SPekka Enberg 
59499f3bedSPekka Enberg static int raw_image__write_sector(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len)
60258dd093SPekka Enberg {
61258dd093SPekka Enberg 	uint64_t offset = sector << SECTOR_SHIFT;
62258dd093SPekka Enberg 
63258dd093SPekka Enberg 	if (offset + src_len > self->size)
64258dd093SPekka Enberg 		return -1;
65258dd093SPekka Enberg 
666b7deb02SPekka Enberg 	if (pwrite_in_full(self->fd, src, src_len, offset) < 0)
67c4d7847bSPekka Enberg 		return -1;
68258dd093SPekka Enberg 
69258dd093SPekka Enberg 	return 0;
70258dd093SPekka Enberg }
71499f3bedSPekka Enberg 
729ac38fe1SSasha Levin static int raw_image__read_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len)
739ac38fe1SSasha Levin {
749ac38fe1SSasha Levin 	uint64_t offset = sector << SECTOR_SHIFT;
759ac38fe1SSasha Levin 
769ac38fe1SSasha Levin 	if (offset + dst_len > self->size)
779ac38fe1SSasha Levin 		return -1;
789ac38fe1SSasha Levin 
799ac38fe1SSasha Levin 	memcpy(dst, self->priv + offset, dst_len);
809ac38fe1SSasha Levin 
819ac38fe1SSasha Levin 	return 0;
829ac38fe1SSasha Levin }
839ac38fe1SSasha Levin 
849ac38fe1SSasha Levin static int raw_image__write_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len)
859ac38fe1SSasha Levin {
869ac38fe1SSasha Levin 	uint64_t offset = sector << SECTOR_SHIFT;
879ac38fe1SSasha Levin 
889ac38fe1SSasha Levin 	if (offset + src_len > self->size)
899ac38fe1SSasha Levin 		return -1;
909ac38fe1SSasha Levin 
919ac38fe1SSasha Levin 	memcpy(self->priv + offset, src, src_len);
929ac38fe1SSasha Levin 
939ac38fe1SSasha Levin 	return 0;
949ac38fe1SSasha Levin }
959ac38fe1SSasha Levin 
96177a5815SPrasad Joshi static void raw_image__close_sector_ro_mmap(struct disk_image *self)
97177a5815SPrasad Joshi {
98177a5815SPrasad Joshi 	if (self->priv != MAP_FAILED)
99177a5815SPrasad Joshi 		munmap(self->priv, self->size);
100177a5815SPrasad Joshi }
101177a5815SPrasad Joshi 
102499f3bedSPekka Enberg static struct disk_image_operations raw_image_ops = {
103499f3bedSPekka Enberg 	.read_sector		= raw_image__read_sector,
104499f3bedSPekka Enberg 	.write_sector		= raw_image__write_sector,
105499f3bedSPekka Enberg };
106499f3bedSPekka Enberg 
1079ac38fe1SSasha Levin static struct disk_image_operations raw_image_ro_mmap_ops = {
1089ac38fe1SSasha Levin 	.read_sector		= raw_image__read_sector_ro_mmap,
1099ac38fe1SSasha Levin 	.write_sector		= raw_image__write_sector_ro_mmap,
110177a5815SPrasad Joshi 	.close			= raw_image__close_sector_ro_mmap,
1119ac38fe1SSasha Levin };
1129ac38fe1SSasha Levin 
1139ac38fe1SSasha Levin static struct disk_image *raw_image__probe(int fd, bool readonly)
114499f3bedSPekka Enberg {
115499f3bedSPekka Enberg 	struct stat st;
116499f3bedSPekka Enberg 
117499f3bedSPekka Enberg 	if (fstat(fd, &st) < 0)
118499f3bedSPekka Enberg 		return NULL;
119499f3bedSPekka Enberg 
120f4ff38dfSPrasad Joshi 	if (readonly)
121f4ff38dfSPrasad Joshi 		return disk_image__new_readonly(fd, st.st_size, &raw_image_ro_mmap_ops);
122f4ff38dfSPrasad Joshi 	else
123f4ff38dfSPrasad Joshi 		return disk_image__new(fd, st.st_size, &raw_image_ops);
124499f3bedSPekka Enberg }
125499f3bedSPekka Enberg 
1269ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly)
127499f3bedSPekka Enberg {
128499f3bedSPekka Enberg 	struct disk_image *self;
129499f3bedSPekka Enberg 	int fd;
130499f3bedSPekka Enberg 
1319ac38fe1SSasha Levin 	fd		= open(filename, readonly ? O_RDONLY : O_RDWR);
132499f3bedSPekka Enberg 	if (fd < 0)
133499f3bedSPekka Enberg 		return NULL;
134499f3bedSPekka Enberg 
135*86835cedSPrasad Joshi 	self = qcow_probe(fd);
136*86835cedSPrasad Joshi 	if (self)
137*86835cedSPrasad Joshi 		return self;
138*86835cedSPrasad Joshi 
1399ac38fe1SSasha Levin 	self = raw_image__probe(fd, readonly);
140499f3bedSPekka Enberg 	if (self)
141499f3bedSPekka Enberg 		return self;
142499f3bedSPekka Enberg 
143d6c58e5bSPrasad Joshi 	if (close(fd) < 0)
144499f3bedSPekka Enberg 		warning("close() failed");
145499f3bedSPekka Enberg 
146499f3bedSPekka Enberg 	return NULL;
147499f3bedSPekka Enberg }
148499f3bedSPekka Enberg 
149499f3bedSPekka Enberg void disk_image__close(struct disk_image *self)
150499f3bedSPekka Enberg {
15182d94c50SIngo Molnar 	/* If there was no disk image then there's nothing to do: */
15282d94c50SIngo Molnar 	if (!self)
15382d94c50SIngo Molnar 		return;
15482d94c50SIngo Molnar 
155499f3bedSPekka Enberg 	if (self->ops->close)
156499f3bedSPekka Enberg 		self->ops->close(self);
157499f3bedSPekka Enberg 
158499f3bedSPekka Enberg 	if (close(self->fd) < 0)
159499f3bedSPekka Enberg 		warning("close() failed");
160499f3bedSPekka Enberg 
161499f3bedSPekka Enberg 	free(self);
162499f3bedSPekka Enberg }
163