1 #include "kvm/disk-image.h" 2 #include "kvm/qcow.h" 3 4 int debug_iodelay; 5 6 struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops, int use_mmap) 7 { 8 struct disk_image *disk; 9 10 disk = malloc(sizeof *disk); 11 if (!disk) 12 return NULL; 13 14 disk->fd = fd; 15 disk->size = size; 16 disk->ops = ops; 17 18 if (use_mmap == DISK_IMAGE_MMAP) { 19 /* 20 * The write to disk image will be discarded 21 */ 22 disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0); 23 if (disk->priv == MAP_FAILED) 24 die("mmap() failed"); 25 } 26 27 return disk; 28 } 29 30 struct disk_image *disk_image__open(const char *filename, bool readonly) 31 { 32 struct disk_image *disk; 33 struct stat st; 34 int fd; 35 36 if (stat(filename, &st) < 0) 37 return NULL; 38 39 /* blk device ?*/ 40 disk = blkdev__probe(filename, &st); 41 if (disk) 42 return disk; 43 44 fd = open(filename, readonly ? O_RDONLY : O_RDWR); 45 if (fd < 0) 46 return NULL; 47 48 /* qcow image ?*/ 49 disk = qcow_probe(fd, true); 50 if (disk) { 51 pr_warning("Forcing read-only support for QCOW"); 52 return disk; 53 } 54 55 /* raw image ?*/ 56 disk = raw_image__probe(fd, &st, readonly); 57 if (disk) 58 return disk; 59 60 if (close(fd) < 0) 61 pr_warning("close() failed"); 62 63 return NULL; 64 } 65 66 struct disk_image **disk_image__open_all(const char **filenames, bool *readonly, int count) 67 { 68 struct disk_image **disks; 69 int i; 70 71 if (!count || count > MAX_DISK_IMAGES) 72 return NULL; 73 74 disks = calloc(count, sizeof(*disks)); 75 if (!disks) 76 return NULL; 77 78 for (i = 0; i < count; i++) { 79 if (!filenames[i]) 80 continue; 81 82 disks[i] = disk_image__open(filenames[i], readonly[i]); 83 if (!disks[i]) { 84 pr_error("Loading disk image '%s' failed", filenames[i]); 85 goto error; 86 } 87 } 88 return disks; 89 error: 90 for (i = 0; i < count; i++) 91 disk_image__close(disks[i]); 92 93 free(disks); 94 return NULL; 95 } 96 97 int disk_image__flush(struct disk_image *disk) 98 { 99 if (disk->ops->flush) 100 return disk->ops->flush(disk); 101 102 return fsync(disk->fd); 103 } 104 105 int disk_image__close(struct disk_image *disk) 106 { 107 /* If there was no disk image then there's nothing to do: */ 108 if (!disk) 109 return 0; 110 111 if (disk->ops->close) 112 return disk->ops->close(disk); 113 114 if (close(disk->fd) < 0) 115 pr_warning("close() failed"); 116 117 free(disk); 118 119 return 0; 120 } 121 122 void disk_image__close_all(struct disk_image **disks, int count) 123 { 124 while (count) 125 disk_image__close(disks[--count]); 126 127 free(disks); 128 } 129 130 /* 131 * Fill iov with disk data, starting from sector 'sector'. 132 * Return amount of bytes read. 133 */ 134 ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 135 { 136 ssize_t total = 0; 137 ssize_t nr; 138 139 if (debug_iodelay) 140 msleep(debug_iodelay); 141 142 if (disk->ops->read_sector_iov) { 143 /* 144 * Try mulitple buffer based operation first 145 */ 146 total = disk->ops->read_sector_iov(disk, sector, iov, iovcount); 147 if (total < 0) { 148 pr_info("disk_image__read error: total=%ld\n", (long)total); 149 return -1; 150 } 151 } else if (disk->ops->read_sector) { 152 /* 153 * Fallback to single buffer based operation 154 */ 155 while (iovcount--) { 156 nr = disk->ops->read_sector(disk, sector, iov->iov_base, iov->iov_len); 157 if (nr != (ssize_t)iov->iov_len) { 158 pr_info("disk_image__read error: nr = %ld iov_len=%ld\n", (long)nr, (long)iov->iov_len); 159 return -1; 160 } 161 sector += iov->iov_len >> SECTOR_SHIFT; 162 iov++; 163 total += nr; 164 } 165 } else 166 die("No disk image operation for read\n"); 167 168 return total; 169 } 170 171 /* 172 * Write iov to disk, starting from sector 'sector'. 173 * Return amount of bytes written. 174 */ 175 ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov, int iovcount) 176 { 177 ssize_t total = 0; 178 ssize_t nr; 179 180 if (debug_iodelay) 181 msleep(debug_iodelay); 182 183 if (disk->ops->write_sector_iov) { 184 /* 185 * Try writev based operation first 186 */ 187 total = disk->ops->write_sector_iov(disk, sector, iov, iovcount); 188 if (total < 0) { 189 pr_info("disk_image__write error: total=%ld\n", (long)total); 190 return -1; 191 } 192 } else if (disk->ops->write_sector) { 193 /* 194 * Fallback to single buffer based operation 195 */ 196 while (iovcount--) { 197 nr = disk->ops->write_sector(disk, sector, iov->iov_base, iov->iov_len); 198 if (nr != (ssize_t)iov->iov_len) { 199 pr_info("disk_image__write error: nr=%ld iov_len=%ld\n", (long)nr, (long)iov->iov_len); 200 return -1; 201 } 202 203 sector += iov->iov_len >> SECTOR_SHIFT; 204 iov++; 205 total += nr; 206 } 207 } else 208 die("No disk image operation for read\n"); 209 210 return total; 211 } 212 213 ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len) 214 { 215 struct stat st; 216 217 if (fstat(disk->fd, &st) != 0) 218 return 0; 219 220 *len = snprintf(buffer, *len, "%llu%llu%llu", (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino); 221 return *len; 222 } 223