1c9310ac4SAsias He #include "kvm/disk-image.h" 2c9310ac4SAsias He 3*9f9207c5SSasha Levin #include <linux/err.h> 4*9f9207c5SSasha Levin 5f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 6f41a132bSSasha Levin #include <libaio.h> 7f41a132bSSasha Levin #endif 8f41a132bSSasha Levin 95af21162SSasha Levin ssize_t raw_image__read_sector(struct disk_image *disk, u64 sector, const struct iovec *iov, 105af21162SSasha Levin int iovcount, void *param) 11c9310ac4SAsias He { 12c9310ac4SAsias He u64 offset = sector << SECTOR_SHIFT; 13c9310ac4SAsias He 14f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 15f41a132bSSasha Levin struct iocb iocb; 16f41a132bSSasha Levin 17f41a132bSSasha Levin return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount, offset, 18f41a132bSSasha Levin disk->evt, param); 19f41a132bSSasha Levin #else 20c9310ac4SAsias He return preadv_in_full(disk->fd, iov, iovcount, offset); 21f41a132bSSasha Levin #endif 22c9310ac4SAsias He } 23c9310ac4SAsias He 245af21162SSasha Levin ssize_t raw_image__write_sector(struct disk_image *disk, u64 sector, const struct iovec *iov, 255af21162SSasha Levin int iovcount, void *param) 26c9310ac4SAsias He { 27c9310ac4SAsias He u64 offset = sector << SECTOR_SHIFT; 28c9310ac4SAsias He 29f41a132bSSasha Levin #ifdef CONFIG_HAS_AIO 30f41a132bSSasha Levin struct iocb iocb; 31f41a132bSSasha Levin 32f41a132bSSasha Levin return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount, offset, 33f41a132bSSasha Levin disk->evt, param); 34f41a132bSSasha Levin #else 35c9310ac4SAsias He return pwritev_in_full(disk->fd, iov, iovcount, offset); 36f41a132bSSasha Levin #endif 37c9310ac4SAsias He } 38c9310ac4SAsias He 395af21162SSasha Levin ssize_t raw_image__read_sector_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov, 405af21162SSasha Levin int iovcount, void *param) 41c9310ac4SAsias He { 42c9310ac4SAsias He u64 offset = sector << SECTOR_SHIFT; 439d15c39aSSasha Levin ssize_t total = 0; 44c9310ac4SAsias He 452534c9b6SSasha Levin while (iovcount--) { 462534c9b6SSasha Levin memcpy(iov->iov_base, disk->priv + offset, iov->iov_len); 47c9310ac4SAsias He 482534c9b6SSasha Levin sector += iov->iov_len >> SECTOR_SHIFT; 499d15c39aSSasha Levin offset += iov->iov_len; 509d15c39aSSasha Levin total += iov->iov_len; 512534c9b6SSasha Levin iov++; 52c9310ac4SAsias He } 53c9310ac4SAsias He 542534c9b6SSasha Levin return total; 552534c9b6SSasha Levin } 562534c9b6SSasha Levin 575af21162SSasha Levin ssize_t raw_image__write_sector_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov, 585af21162SSasha Levin int iovcount, void *param) 59c9310ac4SAsias He { 60c9310ac4SAsias He u64 offset = sector << SECTOR_SHIFT; 619d15c39aSSasha Levin ssize_t total = 0; 62c9310ac4SAsias He 632534c9b6SSasha Levin while (iovcount--) { 642534c9b6SSasha Levin memcpy(disk->priv + offset, iov->iov_base, iov->iov_len); 65c9310ac4SAsias He 662534c9b6SSasha Levin sector += iov->iov_len >> SECTOR_SHIFT; 679d15c39aSSasha Levin offset += iov->iov_len; 689d15c39aSSasha Levin total += iov->iov_len; 692534c9b6SSasha Levin iov++; 702534c9b6SSasha Levin } 71c9310ac4SAsias He 722534c9b6SSasha Levin return total; 73c9310ac4SAsias He } 74c9310ac4SAsias He 7587ee33c8SAsias He int raw_image__close(struct disk_image *disk) 76c9310ac4SAsias He { 7772133dd2SAsias He int ret = 0; 7872133dd2SAsias He 79c9310ac4SAsias He if (disk->priv != MAP_FAILED) 8072133dd2SAsias He ret = munmap(disk->priv, disk->size); 8172133dd2SAsias He 82f41a132bSSasha Levin close(disk->evt); 83f41a132bSSasha Levin 84f41a132bSSasha Levin #ifdef CONFIG_HAS_VIRTIO 85f41a132bSSasha Levin io_destroy(disk->ctx); 86f41a132bSSasha Levin #endif 87f41a132bSSasha Levin 8872133dd2SAsias He return ret; 89c9310ac4SAsias He } 90c9310ac4SAsias He 9187ee33c8SAsias He /* 9287ee33c8SAsias He * multiple buffer based disk image operations 9387ee33c8SAsias He */ 942534c9b6SSasha Levin static struct disk_image_operations raw_image_regular_ops = { 952534c9b6SSasha Levin .read_sector = raw_image__read_sector, 962534c9b6SSasha Levin .write_sector = raw_image__write_sector, 97c9310ac4SAsias He }; 98c9310ac4SAsias He 999d15c39aSSasha Levin struct disk_image_operations ro_ops = { 1002534c9b6SSasha Levin .read_sector = raw_image__read_sector_mmap, 1012534c9b6SSasha Levin .write_sector = raw_image__write_sector_mmap, 10287ee33c8SAsias He .close = raw_image__close, 103c9310ac4SAsias He }; 104c9310ac4SAsias He 1059d15c39aSSasha Levin struct disk_image_operations ro_ops_nowrite = { 1069d15c39aSSasha Levin .read_sector = raw_image__read_sector, 1079d15c39aSSasha Levin }; 1089d15c39aSSasha Levin 109c9310ac4SAsias He struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly) 110c9310ac4SAsias He { 111f41a132bSSasha Levin struct disk_image *disk; 1127d22135fSAsias He 1139d15c39aSSasha Levin if (readonly) { 1147d22135fSAsias He /* 1157d22135fSAsias He * Use mmap's MAP_PRIVATE to implement non-persistent write 1167d22135fSAsias He * FIXME: This does not work on 32-bit host. 1177d22135fSAsias He */ 1189d15c39aSSasha Levin struct disk_image *disk; 1199d15c39aSSasha Levin 1209d15c39aSSasha Levin disk = disk_image__new(fd, st->st_size, &ro_ops, DISK_IMAGE_MMAP); 121*9f9207c5SSasha Levin if (IS_ERR_OR_NULL(disk)) { 1229d15c39aSSasha Levin disk = disk_image__new(fd, st->st_size, &ro_ops_nowrite, DISK_IMAGE_REGULAR); 1237dd56391SSasha Levin #ifdef CONFIG_HAS_AIO 124*9f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 125f41a132bSSasha Levin disk->async = 1; 126f41a132bSSasha Levin #endif 1279d15c39aSSasha Levin } 1289d15c39aSSasha Levin 1299d15c39aSSasha Levin return disk; 1309d15c39aSSasha Levin } else { 1317d22135fSAsias He /* 1327d22135fSAsias He * Use read/write instead of mmap 1337d22135fSAsias He */ 134f41a132bSSasha Levin disk = disk_image__new(fd, st->st_size, &raw_image_regular_ops, DISK_IMAGE_REGULAR); 1357dd56391SSasha Levin #ifdef CONFIG_HAS_AIO 136*9f9207c5SSasha Levin if (!IS_ERR_OR_NULL(disk)) 137f41a132bSSasha Levin disk->async = 1; 138f41a132bSSasha Levin #endif 139f41a132bSSasha Levin return disk; 140c9310ac4SAsias He } 1419d15c39aSSasha Levin } 142