19f532d00SPekka Enberg #include "kvm/disk-image.h" 29f532d00SPekka Enberg 3c4d7847bSPekka Enberg #include "kvm/read-write.h" 486835cedSPrasad Joshi #include "kvm/qcow.h" 59f532d00SPekka Enberg #include "kvm/util.h" 69f532d00SPekka Enberg 76ec60cfdSPekka Enberg #include <linux/fs.h> /* for BLKGETSIZE64 */ 86ec60cfdSPekka Enberg 96ec60cfdSPekka Enberg #include <sys/ioctl.h> 109f532d00SPekka Enberg #include <sys/types.h> 11*3fdf659dSSasha Levin #include <linux/types.h> 129f532d00SPekka Enberg #include <sys/mman.h> 139f532d00SPekka Enberg #include <sys/stat.h> 145646450dSPekka Enberg #include <stdbool.h> 159f532d00SPekka Enberg #include <stddef.h> 169f532d00SPekka Enberg #include <stdlib.h> 179f532d00SPekka Enberg #include <unistd.h> 189f532d00SPekka Enberg #include <fcntl.h> 199f532d00SPekka Enberg 20*3fdf659dSSasha Levin struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops) 219f532d00SPekka Enberg { 22fffb37a9SPekka Enberg struct disk_image *self; 239f532d00SPekka Enberg 24fffb37a9SPekka Enberg self = malloc(sizeof *self); 25fffb37a9SPekka Enberg if (!self) 26fffb37a9SPekka Enberg return NULL; 279f532d00SPekka Enberg 28fffb37a9SPekka Enberg self->fd = fd; 29fffb37a9SPekka Enberg self->size = size; 30fffb37a9SPekka Enberg self->ops = ops; 31f4ff38dfSPrasad Joshi return self; 32f4ff38dfSPrasad Joshi } 33f4ff38dfSPrasad Joshi 34*3fdf659dSSasha Levin struct disk_image *disk_image__new_readonly(int fd, u64 size, struct disk_image_operations *ops) 35f4ff38dfSPrasad Joshi { 36f4ff38dfSPrasad Joshi struct disk_image *self; 37f4ff38dfSPrasad Joshi 38f4ff38dfSPrasad Joshi self = disk_image__new(fd, size, ops); 39f4ff38dfSPrasad Joshi if (!self) 40f4ff38dfSPrasad Joshi return NULL; 41f4ff38dfSPrasad Joshi 429ac38fe1SSasha Levin self->priv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 439ac38fe1SSasha Levin if (self->priv == MAP_FAILED) 449ac38fe1SSasha Levin die("mmap() failed"); 45fffb37a9SPekka Enberg return self; 469f532d00SPekka Enberg } 479f532d00SPekka Enberg 48*3fdf659dSSasha Levin static ssize_t raw_image__read_sector_iov(struct disk_image *self, u64 sector, const struct iovec *iov, int iovcount) 4970b53f25SSasha Levin { 50*3fdf659dSSasha Levin u64 offset = sector << SECTOR_SHIFT; 5170b53f25SSasha Levin 5270b53f25SSasha Levin return preadv_in_full(self->fd, iov, iovcount, offset); 5370b53f25SSasha Levin } 5470b53f25SSasha Levin 55*3fdf659dSSasha Levin static ssize_t raw_image__write_sector_iov(struct disk_image *self, u64 sector, const struct iovec *iov, int iovcount) 5670b53f25SSasha Levin { 57*3fdf659dSSasha Levin u64 offset = sector << SECTOR_SHIFT; 5870b53f25SSasha Levin 5970b53f25SSasha Levin return pwritev_in_full(self->fd, iov, iovcount, offset); 6070b53f25SSasha Levin } 6170b53f25SSasha Levin 62*3fdf659dSSasha Levin static int raw_image__read_sector_ro_mmap(struct disk_image *self, u64 sector, void *dst, u32 dst_len) 639ac38fe1SSasha Levin { 64*3fdf659dSSasha Levin u64 offset = sector << SECTOR_SHIFT; 659ac38fe1SSasha Levin 669ac38fe1SSasha Levin if (offset + dst_len > self->size) 679ac38fe1SSasha Levin return -1; 689ac38fe1SSasha Levin 699ac38fe1SSasha Levin memcpy(dst, self->priv + offset, dst_len); 709ac38fe1SSasha Levin 719ac38fe1SSasha Levin return 0; 729ac38fe1SSasha Levin } 739ac38fe1SSasha Levin 74*3fdf659dSSasha Levin static int raw_image__write_sector_ro_mmap(struct disk_image *self, u64 sector, void *src, u32 src_len) 759ac38fe1SSasha Levin { 76*3fdf659dSSasha Levin u64 offset = sector << SECTOR_SHIFT; 779ac38fe1SSasha Levin 789ac38fe1SSasha Levin if (offset + src_len > self->size) 799ac38fe1SSasha Levin return -1; 809ac38fe1SSasha Levin 819ac38fe1SSasha Levin memcpy(self->priv + offset, src, src_len); 829ac38fe1SSasha Levin 839ac38fe1SSasha Levin return 0; 849ac38fe1SSasha Levin } 859ac38fe1SSasha Levin 860ff5e559SSasha Levin static void raw_image__close_ro_mmap(struct disk_image *self) 87177a5815SPrasad Joshi { 88177a5815SPrasad Joshi if (self->priv != MAP_FAILED) 89177a5815SPrasad Joshi munmap(self->priv, self->size); 90177a5815SPrasad Joshi } 91177a5815SPrasad Joshi 92499f3bedSPekka Enberg static struct disk_image_operations raw_image_ops = { 932d103098SSasha Levin .read_sector_iov = raw_image__read_sector_iov, 942d103098SSasha Levin .write_sector_iov = raw_image__write_sector_iov 95499f3bedSPekka Enberg }; 96499f3bedSPekka Enberg 979ac38fe1SSasha Levin static struct disk_image_operations raw_image_ro_mmap_ops = { 989ac38fe1SSasha Levin .read_sector = raw_image__read_sector_ro_mmap, 999ac38fe1SSasha Levin .write_sector = raw_image__write_sector_ro_mmap, 1000ff5e559SSasha Levin .close = raw_image__close_ro_mmap, 1019ac38fe1SSasha Levin }; 1029ac38fe1SSasha Levin 1036ec60cfdSPekka Enberg static struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly) 104499f3bedSPekka Enberg { 1056ec60cfdSPekka Enberg if (readonly) 1066ec60cfdSPekka Enberg return disk_image__new_readonly(fd, st->st_size, &raw_image_ro_mmap_ops); 1076ec60cfdSPekka Enberg else 1086ec60cfdSPekka Enberg return disk_image__new(fd, st->st_size, &raw_image_ops); 1096ec60cfdSPekka Enberg } 110499f3bedSPekka Enberg 1116ec60cfdSPekka Enberg static struct disk_image *blkdev__probe(const char *filename, struct stat *st) 1126ec60cfdSPekka Enberg { 113*3fdf659dSSasha Levin u64 size; 1146ec60cfdSPekka Enberg int fd; 1156ec60cfdSPekka Enberg 1166ec60cfdSPekka Enberg if (!S_ISBLK(st->st_mode)) 117499f3bedSPekka Enberg return NULL; 118499f3bedSPekka Enberg 1196ec60cfdSPekka Enberg fd = open(filename, O_RDONLY); 1206ec60cfdSPekka Enberg if (fd < 0) 1216ec60cfdSPekka Enberg return NULL; 1226ec60cfdSPekka Enberg 12372756070SSasha Levin if (ioctl(fd, BLKGETSIZE64, &size) < 0) { 12472756070SSasha Levin close(fd); 1256ec60cfdSPekka Enberg return NULL; 12672756070SSasha Levin } 1276ec60cfdSPekka Enberg 1286ec60cfdSPekka Enberg return disk_image__new_readonly(fd, size, &raw_image_ro_mmap_ops); 129499f3bedSPekka Enberg } 130499f3bedSPekka Enberg 1319ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 132499f3bedSPekka Enberg { 133499f3bedSPekka Enberg struct disk_image *self; 1346ec60cfdSPekka Enberg struct stat st; 135499f3bedSPekka Enberg int fd; 136499f3bedSPekka Enberg 1376ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 1386ec60cfdSPekka Enberg return NULL; 1396ec60cfdSPekka Enberg 1406ec60cfdSPekka Enberg if (S_ISBLK(st.st_mode)) 1416ec60cfdSPekka Enberg return blkdev__probe(filename, &st); 1426ec60cfdSPekka Enberg 1439ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 144499f3bedSPekka Enberg if (fd < 0) 145499f3bedSPekka Enberg return NULL; 146499f3bedSPekka Enberg 14786835cedSPrasad Joshi self = qcow_probe(fd); 14886835cedSPrasad Joshi if (self) 14986835cedSPrasad Joshi return self; 15086835cedSPrasad Joshi 1516ec60cfdSPekka Enberg self = raw_image__probe(fd, &st, readonly); 152499f3bedSPekka Enberg if (self) 153499f3bedSPekka Enberg return self; 154499f3bedSPekka Enberg 155d6c58e5bSPrasad Joshi if (close(fd) < 0) 156499f3bedSPekka Enberg warning("close() failed"); 157499f3bedSPekka Enberg 158499f3bedSPekka Enberg return NULL; 159499f3bedSPekka Enberg } 160499f3bedSPekka Enberg 161499f3bedSPekka Enberg void disk_image__close(struct disk_image *self) 162499f3bedSPekka Enberg { 16382d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 16482d94c50SIngo Molnar if (!self) 16582d94c50SIngo Molnar return; 16682d94c50SIngo Molnar 167499f3bedSPekka Enberg if (self->ops->close) 168499f3bedSPekka Enberg self->ops->close(self); 169499f3bedSPekka Enberg 170499f3bedSPekka Enberg if (close(self->fd) < 0) 171499f3bedSPekka Enberg warning("close() failed"); 172499f3bedSPekka Enberg 173499f3bedSPekka Enberg free(self); 174499f3bedSPekka Enberg } 175