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> 1133d33901SPekka Enberg #include <inttypes.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 20f4ff38dfSPrasad Joshi struct disk_image *disk_image__new(int fd, uint64_t 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 34f4ff38dfSPrasad Joshi struct disk_image *disk_image__new_readonly(int fd, uint64_t 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 48f4ff38dfSPrasad Joshi 49499f3bedSPekka Enberg static int raw_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 509f532d00SPekka Enberg { 519f532d00SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 529f532d00SPekka Enberg 535a24a9f2SPekka Enberg if (offset + dst_len > self->size) 549f532d00SPekka Enberg return -1; 559f532d00SPekka Enberg 566b7deb02SPekka Enberg if (pread_in_full(self->fd, dst, dst_len, offset) < 0) 57c4d7847bSPekka Enberg return -1; 589f532d00SPekka Enberg 599f532d00SPekka Enberg return 0; 609f532d00SPekka Enberg } 61258dd093SPekka Enberg 62499f3bedSPekka Enberg static int raw_image__write_sector(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len) 63258dd093SPekka Enberg { 64258dd093SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 65258dd093SPekka Enberg 66258dd093SPekka Enberg if (offset + src_len > self->size) 67258dd093SPekka Enberg return -1; 68258dd093SPekka Enberg 696b7deb02SPekka Enberg if (pwrite_in_full(self->fd, src, src_len, offset) < 0) 70c4d7847bSPekka Enberg return -1; 71258dd093SPekka Enberg 72258dd093SPekka Enberg return 0; 73258dd093SPekka Enberg } 74499f3bedSPekka Enberg 75*70b53f25SSasha Levin static ssize_t raw_image__read_sector_sg(struct disk_image *self, uint64_t sector, const struct iovec *iov, int iovcount) 76*70b53f25SSasha Levin { 77*70b53f25SSasha Levin uint64_t offset = sector << SECTOR_SHIFT; 78*70b53f25SSasha Levin 79*70b53f25SSasha Levin return preadv_in_full(self->fd, iov, iovcount, offset); 80*70b53f25SSasha Levin } 81*70b53f25SSasha Levin 82*70b53f25SSasha Levin static ssize_t raw_image__write_sector_sg(struct disk_image *self, uint64_t sector, const struct iovec *iov, int iovcount) 83*70b53f25SSasha Levin { 84*70b53f25SSasha Levin uint64_t offset = sector << SECTOR_SHIFT; 85*70b53f25SSasha Levin 86*70b53f25SSasha Levin return pwritev_in_full(self->fd, iov, iovcount, offset); 87*70b53f25SSasha Levin } 88*70b53f25SSasha Levin 899ac38fe1SSasha Levin static int raw_image__read_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 909ac38fe1SSasha Levin { 919ac38fe1SSasha Levin uint64_t offset = sector << SECTOR_SHIFT; 929ac38fe1SSasha Levin 939ac38fe1SSasha Levin if (offset + dst_len > self->size) 949ac38fe1SSasha Levin return -1; 959ac38fe1SSasha Levin 969ac38fe1SSasha Levin memcpy(dst, self->priv + offset, dst_len); 979ac38fe1SSasha Levin 989ac38fe1SSasha Levin return 0; 999ac38fe1SSasha Levin } 1009ac38fe1SSasha Levin 1019ac38fe1SSasha Levin static int raw_image__write_sector_ro_mmap(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len) 1029ac38fe1SSasha Levin { 1039ac38fe1SSasha Levin uint64_t offset = sector << SECTOR_SHIFT; 1049ac38fe1SSasha Levin 1059ac38fe1SSasha Levin if (offset + src_len > self->size) 1069ac38fe1SSasha Levin return -1; 1079ac38fe1SSasha Levin 1089ac38fe1SSasha Levin memcpy(self->priv + offset, src, src_len); 1099ac38fe1SSasha Levin 1109ac38fe1SSasha Levin return 0; 1119ac38fe1SSasha Levin } 1129ac38fe1SSasha Levin 1130ff5e559SSasha Levin static void raw_image__close_ro_mmap(struct disk_image *self) 114177a5815SPrasad Joshi { 115177a5815SPrasad Joshi if (self->priv != MAP_FAILED) 116177a5815SPrasad Joshi munmap(self->priv, self->size); 117177a5815SPrasad Joshi } 118177a5815SPrasad Joshi 119499f3bedSPekka Enberg static struct disk_image_operations raw_image_ops = { 120499f3bedSPekka Enberg .read_sector = raw_image__read_sector, 121499f3bedSPekka Enberg .write_sector = raw_image__write_sector, 122*70b53f25SSasha Levin .read_sector_sg = raw_image__read_sector_sg, 123*70b53f25SSasha Levin .write_sector_sg = raw_image__write_sector_sg 124499f3bedSPekka Enberg }; 125499f3bedSPekka Enberg 1269ac38fe1SSasha Levin static struct disk_image_operations raw_image_ro_mmap_ops = { 1279ac38fe1SSasha Levin .read_sector = raw_image__read_sector_ro_mmap, 1289ac38fe1SSasha Levin .write_sector = raw_image__write_sector_ro_mmap, 1290ff5e559SSasha Levin .close = raw_image__close_ro_mmap, 1309ac38fe1SSasha Levin }; 1319ac38fe1SSasha Levin 1326ec60cfdSPekka Enberg static struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly) 133499f3bedSPekka Enberg { 1346ec60cfdSPekka Enberg if (readonly) 1356ec60cfdSPekka Enberg return disk_image__new_readonly(fd, st->st_size, &raw_image_ro_mmap_ops); 1366ec60cfdSPekka Enberg else 1376ec60cfdSPekka Enberg return disk_image__new(fd, st->st_size, &raw_image_ops); 1386ec60cfdSPekka Enberg } 139499f3bedSPekka Enberg 1406ec60cfdSPekka Enberg static struct disk_image *blkdev__probe(const char *filename, struct stat *st) 1416ec60cfdSPekka Enberg { 1426ec60cfdSPekka Enberg uint64_t size; 1436ec60cfdSPekka Enberg int fd; 1446ec60cfdSPekka Enberg 1456ec60cfdSPekka Enberg if (!S_ISBLK(st->st_mode)) 146499f3bedSPekka Enberg return NULL; 147499f3bedSPekka Enberg 1486ec60cfdSPekka Enberg fd = open(filename, O_RDONLY); 1496ec60cfdSPekka Enberg if (fd < 0) 1506ec60cfdSPekka Enberg return NULL; 1516ec60cfdSPekka Enberg 1526ec60cfdSPekka Enberg if (ioctl(fd, BLKGETSIZE64, &size) < 0) 1536ec60cfdSPekka Enberg return NULL; 1546ec60cfdSPekka Enberg 1556ec60cfdSPekka Enberg return disk_image__new_readonly(fd, size, &raw_image_ro_mmap_ops); 156499f3bedSPekka Enberg } 157499f3bedSPekka Enberg 1589ac38fe1SSasha Levin struct disk_image *disk_image__open(const char *filename, bool readonly) 159499f3bedSPekka Enberg { 160499f3bedSPekka Enberg struct disk_image *self; 1616ec60cfdSPekka Enberg struct stat st; 162499f3bedSPekka Enberg int fd; 163499f3bedSPekka Enberg 1646ec60cfdSPekka Enberg if (stat(filename, &st) < 0) 1656ec60cfdSPekka Enberg return NULL; 1666ec60cfdSPekka Enberg 1676ec60cfdSPekka Enberg if (S_ISBLK(st.st_mode)) 1686ec60cfdSPekka Enberg return blkdev__probe(filename, &st); 1696ec60cfdSPekka Enberg 1709ac38fe1SSasha Levin fd = open(filename, readonly ? O_RDONLY : O_RDWR); 171499f3bedSPekka Enberg if (fd < 0) 172499f3bedSPekka Enberg return NULL; 173499f3bedSPekka Enberg 17486835cedSPrasad Joshi self = qcow_probe(fd); 17586835cedSPrasad Joshi if (self) 17686835cedSPrasad Joshi return self; 17786835cedSPrasad Joshi 1786ec60cfdSPekka Enberg self = raw_image__probe(fd, &st, readonly); 179499f3bedSPekka Enberg if (self) 180499f3bedSPekka Enberg return self; 181499f3bedSPekka Enberg 182d6c58e5bSPrasad Joshi if (close(fd) < 0) 183499f3bedSPekka Enberg warning("close() failed"); 184499f3bedSPekka Enberg 185499f3bedSPekka Enberg return NULL; 186499f3bedSPekka Enberg } 187499f3bedSPekka Enberg 188499f3bedSPekka Enberg void disk_image__close(struct disk_image *self) 189499f3bedSPekka Enberg { 19082d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 19182d94c50SIngo Molnar if (!self) 19282d94c50SIngo Molnar return; 19382d94c50SIngo Molnar 194499f3bedSPekka Enberg if (self->ops->close) 195499f3bedSPekka Enberg self->ops->close(self); 196499f3bedSPekka Enberg 197499f3bedSPekka Enberg if (close(self->fd) < 0) 198499f3bedSPekka Enberg warning("close() failed"); 199499f3bedSPekka Enberg 200499f3bedSPekka Enberg free(self); 201499f3bedSPekka Enberg } 202