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> 113fdf659dSSasha 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 203fdf659dSSasha Levin struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops) 219f532d00SPekka Enberg { 22*43835ac9SSasha Levin struct disk_image *disk; 239f532d00SPekka Enberg 24*43835ac9SSasha Levin disk = malloc(sizeof *disk); 25*43835ac9SSasha Levin if (!disk) 26fffb37a9SPekka Enberg return NULL; 279f532d00SPekka Enberg 28*43835ac9SSasha Levin disk->fd = fd; 29*43835ac9SSasha Levin disk->size = size; 30*43835ac9SSasha Levin disk->ops = ops; 31*43835ac9SSasha Levin return disk; 32f4ff38dfSPrasad Joshi } 33f4ff38dfSPrasad Joshi 343fdf659dSSasha Levin struct disk_image *disk_image__new_readonly(int fd, u64 size, struct disk_image_operations *ops) 35f4ff38dfSPrasad Joshi { 36*43835ac9SSasha Levin struct disk_image *disk; 37f4ff38dfSPrasad Joshi 38*43835ac9SSasha Levin disk = disk_image__new(fd, size, ops); 39*43835ac9SSasha Levin if (!disk) 40f4ff38dfSPrasad Joshi return NULL; 41f4ff38dfSPrasad Joshi 42*43835ac9SSasha Levin disk->priv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 43*43835ac9SSasha Levin if (disk->priv == MAP_FAILED) 449ac38fe1SSasha Levin die("mmap() failed"); 45*43835ac9SSasha Levin return disk; 469f532d00SPekka Enberg } 479f532d00SPekka Enberg 48*43835ac9SSasha Levin static ssize_t raw_image__read_sector_iov(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 4970b53f25SSasha Levin { 503fdf659dSSasha Levin u64 offset = sector << SECTOR_SHIFT; 5170b53f25SSasha Levin 52*43835ac9SSasha Levin return preadv_in_full(disk->fd, iov, iovcount, offset); 5370b53f25SSasha Levin } 5470b53f25SSasha Levin 55*43835ac9SSasha Levin static ssize_t raw_image__write_sector_iov(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 5670b53f25SSasha Levin { 573fdf659dSSasha Levin u64 offset = sector << SECTOR_SHIFT; 5870b53f25SSasha Levin 59*43835ac9SSasha Levin return pwritev_in_full(disk->fd, iov, iovcount, offset); 6070b53f25SSasha Levin } 6170b53f25SSasha Levin 62*43835ac9SSasha Levin static int raw_image__read_sector_ro_mmap(struct disk_image *disk, u64 sector, void *dst, u32 dst_len) 639ac38fe1SSasha Levin { 643fdf659dSSasha Levin u64 offset = sector << SECTOR_SHIFT; 659ac38fe1SSasha Levin 66*43835ac9SSasha Levin if (offset + dst_len > disk->size) 679ac38fe1SSasha Levin return -1; 689ac38fe1SSasha Levin 69*43835ac9SSasha Levin memcpy(dst, disk->priv + offset, dst_len); 709ac38fe1SSasha Levin 719ac38fe1SSasha Levin return 0; 729ac38fe1SSasha Levin } 739ac38fe1SSasha Levin 74*43835ac9SSasha Levin static int raw_image__write_sector_ro_mmap(struct disk_image *disk, u64 sector, void *src, u32 src_len) 759ac38fe1SSasha Levin { 763fdf659dSSasha Levin u64 offset = sector << SECTOR_SHIFT; 779ac38fe1SSasha Levin 78*43835ac9SSasha Levin if (offset + src_len > disk->size) 799ac38fe1SSasha Levin return -1; 809ac38fe1SSasha Levin 81*43835ac9SSasha Levin memcpy(disk->priv + offset, src, src_len); 829ac38fe1SSasha Levin 839ac38fe1SSasha Levin return 0; 849ac38fe1SSasha Levin } 859ac38fe1SSasha Levin 86*43835ac9SSasha Levin static void raw_image__close_ro_mmap(struct disk_image *disk) 87177a5815SPrasad Joshi { 88*43835ac9SSasha Levin if (disk->priv != MAP_FAILED) 89*43835ac9SSasha Levin munmap(disk->priv, disk->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 { 1133fdf659dSSasha 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 { 133*43835ac9SSasha Levin struct disk_image *disk; 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 147*43835ac9SSasha Levin disk = qcow_probe(fd); 148*43835ac9SSasha Levin if (disk) 149*43835ac9SSasha Levin return disk; 15086835cedSPrasad Joshi 151*43835ac9SSasha Levin disk = raw_image__probe(fd, &st, readonly); 152*43835ac9SSasha Levin if (disk) 153*43835ac9SSasha Levin return disk; 154499f3bedSPekka Enberg 155d6c58e5bSPrasad Joshi if (close(fd) < 0) 156499f3bedSPekka Enberg warning("close() failed"); 157499f3bedSPekka Enberg 158499f3bedSPekka Enberg return NULL; 159499f3bedSPekka Enberg } 160499f3bedSPekka Enberg 161*43835ac9SSasha Levin void disk_image__close(struct disk_image *disk) 162499f3bedSPekka Enberg { 16382d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 164*43835ac9SSasha Levin if (!disk) 16582d94c50SIngo Molnar return; 16682d94c50SIngo Molnar 167*43835ac9SSasha Levin if (disk->ops->close) 168*43835ac9SSasha Levin disk->ops->close(disk); 169499f3bedSPekka Enberg 170*43835ac9SSasha Levin if (close(disk->fd) < 0) 171499f3bedSPekka Enberg warning("close() failed"); 172499f3bedSPekka Enberg 173*43835ac9SSasha Levin free(disk); 174499f3bedSPekka Enberg } 175