1 #include "kvm/disk-image.h" 2 3 #include "kvm/read-write.h" 4 #include "kvm/qcow.h" 5 #include "kvm/util.h" 6 7 #include <linux/fs.h> /* for BLKGETSIZE64 */ 8 9 #include <sys/ioctl.h> 10 #include <sys/types.h> 11 #include <linux/types.h> 12 #include <sys/mman.h> 13 #include <sys/stat.h> 14 #include <stdbool.h> 15 #include <stddef.h> 16 #include <stdlib.h> 17 #include <unistd.h> 18 #include <fcntl.h> 19 20 struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops) 21 { 22 struct disk_image *self; 23 24 self = malloc(sizeof *self); 25 if (!self) 26 return NULL; 27 28 self->fd = fd; 29 self->size = size; 30 self->ops = ops; 31 return self; 32 } 33 34 struct disk_image *disk_image__new_readonly(int fd, u64 size, struct disk_image_operations *ops) 35 { 36 struct disk_image *self; 37 38 self = disk_image__new(fd, size, ops); 39 if (!self) 40 return NULL; 41 42 self->priv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 43 if (self->priv == MAP_FAILED) 44 die("mmap() failed"); 45 return self; 46 } 47 48 static ssize_t raw_image__read_sector_iov(struct disk_image *self, u64 sector, const struct iovec *iov, int iovcount) 49 { 50 u64 offset = sector << SECTOR_SHIFT; 51 52 return preadv_in_full(self->fd, iov, iovcount, offset); 53 } 54 55 static ssize_t raw_image__write_sector_iov(struct disk_image *self, u64 sector, const struct iovec *iov, int iovcount) 56 { 57 u64 offset = sector << SECTOR_SHIFT; 58 59 return pwritev_in_full(self->fd, iov, iovcount, offset); 60 } 61 62 static int raw_image__read_sector_ro_mmap(struct disk_image *self, u64 sector, void *dst, u32 dst_len) 63 { 64 u64 offset = sector << SECTOR_SHIFT; 65 66 if (offset + dst_len > self->size) 67 return -1; 68 69 memcpy(dst, self->priv + offset, dst_len); 70 71 return 0; 72 } 73 74 static int raw_image__write_sector_ro_mmap(struct disk_image *self, u64 sector, void *src, u32 src_len) 75 { 76 u64 offset = sector << SECTOR_SHIFT; 77 78 if (offset + src_len > self->size) 79 return -1; 80 81 memcpy(self->priv + offset, src, src_len); 82 83 return 0; 84 } 85 86 static void raw_image__close_ro_mmap(struct disk_image *self) 87 { 88 if (self->priv != MAP_FAILED) 89 munmap(self->priv, self->size); 90 } 91 92 static struct disk_image_operations raw_image_ops = { 93 .read_sector_iov = raw_image__read_sector_iov, 94 .write_sector_iov = raw_image__write_sector_iov 95 }; 96 97 static struct disk_image_operations raw_image_ro_mmap_ops = { 98 .read_sector = raw_image__read_sector_ro_mmap, 99 .write_sector = raw_image__write_sector_ro_mmap, 100 .close = raw_image__close_ro_mmap, 101 }; 102 103 static struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly) 104 { 105 if (readonly) 106 return disk_image__new_readonly(fd, st->st_size, &raw_image_ro_mmap_ops); 107 else 108 return disk_image__new(fd, st->st_size, &raw_image_ops); 109 } 110 111 static struct disk_image *blkdev__probe(const char *filename, struct stat *st) 112 { 113 u64 size; 114 int fd; 115 116 if (!S_ISBLK(st->st_mode)) 117 return NULL; 118 119 fd = open(filename, O_RDONLY); 120 if (fd < 0) 121 return NULL; 122 123 if (ioctl(fd, BLKGETSIZE64, &size) < 0) { 124 close(fd); 125 return NULL; 126 } 127 128 return disk_image__new_readonly(fd, size, &raw_image_ro_mmap_ops); 129 } 130 131 struct disk_image *disk_image__open(const char *filename, bool readonly) 132 { 133 struct disk_image *self; 134 struct stat st; 135 int fd; 136 137 if (stat(filename, &st) < 0) 138 return NULL; 139 140 if (S_ISBLK(st.st_mode)) 141 return blkdev__probe(filename, &st); 142 143 fd = open(filename, readonly ? O_RDONLY : O_RDWR); 144 if (fd < 0) 145 return NULL; 146 147 self = qcow_probe(fd); 148 if (self) 149 return self; 150 151 self = raw_image__probe(fd, &st, readonly); 152 if (self) 153 return self; 154 155 if (close(fd) < 0) 156 warning("close() failed"); 157 158 return NULL; 159 } 160 161 void disk_image__close(struct disk_image *self) 162 { 163 /* If there was no disk image then there's nothing to do: */ 164 if (!self) 165 return; 166 167 if (self->ops->close) 168 self->ops->close(self); 169 170 if (close(self->fd) < 0) 171 warning("close() failed"); 172 173 free(self); 174 } 175