1*75411d23SStefan Hajnoczi /* 2*75411d23SStefan Hajnoczi * QEMU Enhanced Disk Format 3*75411d23SStefan Hajnoczi * 4*75411d23SStefan Hajnoczi * Copyright IBM, Corp. 2010 5*75411d23SStefan Hajnoczi * 6*75411d23SStefan Hajnoczi * Authors: 7*75411d23SStefan Hajnoczi * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> 8*75411d23SStefan Hajnoczi * Anthony Liguori <aliguori@us.ibm.com> 9*75411d23SStefan Hajnoczi * 10*75411d23SStefan Hajnoczi * This work is licensed under the terms of the GNU LGPL, version 2 or later. 11*75411d23SStefan Hajnoczi * See the COPYING.LIB file in the top-level directory. 12*75411d23SStefan Hajnoczi * 13*75411d23SStefan Hajnoczi */ 14*75411d23SStefan Hajnoczi 15*75411d23SStefan Hajnoczi #include "qed.h" 16*75411d23SStefan Hajnoczi 17*75411d23SStefan Hajnoczi static int bdrv_qed_probe(const uint8_t *buf, int buf_size, 18*75411d23SStefan Hajnoczi const char *filename) 19*75411d23SStefan Hajnoczi { 20*75411d23SStefan Hajnoczi const QEDHeader *header = (const QEDHeader *)buf; 21*75411d23SStefan Hajnoczi 22*75411d23SStefan Hajnoczi if (buf_size < sizeof(*header)) { 23*75411d23SStefan Hajnoczi return 0; 24*75411d23SStefan Hajnoczi } 25*75411d23SStefan Hajnoczi if (le32_to_cpu(header->magic) != QED_MAGIC) { 26*75411d23SStefan Hajnoczi return 0; 27*75411d23SStefan Hajnoczi } 28*75411d23SStefan Hajnoczi return 100; 29*75411d23SStefan Hajnoczi } 30*75411d23SStefan Hajnoczi 31*75411d23SStefan Hajnoczi /** 32*75411d23SStefan Hajnoczi * Check whether an image format is raw 33*75411d23SStefan Hajnoczi * 34*75411d23SStefan Hajnoczi * @fmt: Backing file format, may be NULL 35*75411d23SStefan Hajnoczi */ 36*75411d23SStefan Hajnoczi static bool qed_fmt_is_raw(const char *fmt) 37*75411d23SStefan Hajnoczi { 38*75411d23SStefan Hajnoczi return fmt && strcmp(fmt, "raw") == 0; 39*75411d23SStefan Hajnoczi } 40*75411d23SStefan Hajnoczi 41*75411d23SStefan Hajnoczi static void qed_header_le_to_cpu(const QEDHeader *le, QEDHeader *cpu) 42*75411d23SStefan Hajnoczi { 43*75411d23SStefan Hajnoczi cpu->magic = le32_to_cpu(le->magic); 44*75411d23SStefan Hajnoczi cpu->cluster_size = le32_to_cpu(le->cluster_size); 45*75411d23SStefan Hajnoczi cpu->table_size = le32_to_cpu(le->table_size); 46*75411d23SStefan Hajnoczi cpu->header_size = le32_to_cpu(le->header_size); 47*75411d23SStefan Hajnoczi cpu->features = le64_to_cpu(le->features); 48*75411d23SStefan Hajnoczi cpu->compat_features = le64_to_cpu(le->compat_features); 49*75411d23SStefan Hajnoczi cpu->autoclear_features = le64_to_cpu(le->autoclear_features); 50*75411d23SStefan Hajnoczi cpu->l1_table_offset = le64_to_cpu(le->l1_table_offset); 51*75411d23SStefan Hajnoczi cpu->image_size = le64_to_cpu(le->image_size); 52*75411d23SStefan Hajnoczi cpu->backing_filename_offset = le32_to_cpu(le->backing_filename_offset); 53*75411d23SStefan Hajnoczi cpu->backing_filename_size = le32_to_cpu(le->backing_filename_size); 54*75411d23SStefan Hajnoczi } 55*75411d23SStefan Hajnoczi 56*75411d23SStefan Hajnoczi static void qed_header_cpu_to_le(const QEDHeader *cpu, QEDHeader *le) 57*75411d23SStefan Hajnoczi { 58*75411d23SStefan Hajnoczi le->magic = cpu_to_le32(cpu->magic); 59*75411d23SStefan Hajnoczi le->cluster_size = cpu_to_le32(cpu->cluster_size); 60*75411d23SStefan Hajnoczi le->table_size = cpu_to_le32(cpu->table_size); 61*75411d23SStefan Hajnoczi le->header_size = cpu_to_le32(cpu->header_size); 62*75411d23SStefan Hajnoczi le->features = cpu_to_le64(cpu->features); 63*75411d23SStefan Hajnoczi le->compat_features = cpu_to_le64(cpu->compat_features); 64*75411d23SStefan Hajnoczi le->autoclear_features = cpu_to_le64(cpu->autoclear_features); 65*75411d23SStefan Hajnoczi le->l1_table_offset = cpu_to_le64(cpu->l1_table_offset); 66*75411d23SStefan Hajnoczi le->image_size = cpu_to_le64(cpu->image_size); 67*75411d23SStefan Hajnoczi le->backing_filename_offset = cpu_to_le32(cpu->backing_filename_offset); 68*75411d23SStefan Hajnoczi le->backing_filename_size = cpu_to_le32(cpu->backing_filename_size); 69*75411d23SStefan Hajnoczi } 70*75411d23SStefan Hajnoczi 71*75411d23SStefan Hajnoczi static int qed_write_header_sync(BDRVQEDState *s) 72*75411d23SStefan Hajnoczi { 73*75411d23SStefan Hajnoczi QEDHeader le; 74*75411d23SStefan Hajnoczi int ret; 75*75411d23SStefan Hajnoczi 76*75411d23SStefan Hajnoczi qed_header_cpu_to_le(&s->header, &le); 77*75411d23SStefan Hajnoczi ret = bdrv_pwrite(s->bs->file, 0, &le, sizeof(le)); 78*75411d23SStefan Hajnoczi if (ret != sizeof(le)) { 79*75411d23SStefan Hajnoczi return ret; 80*75411d23SStefan Hajnoczi } 81*75411d23SStefan Hajnoczi return 0; 82*75411d23SStefan Hajnoczi } 83*75411d23SStefan Hajnoczi 84*75411d23SStefan Hajnoczi static uint64_t qed_max_image_size(uint32_t cluster_size, uint32_t table_size) 85*75411d23SStefan Hajnoczi { 86*75411d23SStefan Hajnoczi uint64_t table_entries; 87*75411d23SStefan Hajnoczi uint64_t l2_size; 88*75411d23SStefan Hajnoczi 89*75411d23SStefan Hajnoczi table_entries = (table_size * cluster_size) / sizeof(uint64_t); 90*75411d23SStefan Hajnoczi l2_size = table_entries * cluster_size; 91*75411d23SStefan Hajnoczi 92*75411d23SStefan Hajnoczi return l2_size * table_entries; 93*75411d23SStefan Hajnoczi } 94*75411d23SStefan Hajnoczi 95*75411d23SStefan Hajnoczi static bool qed_is_cluster_size_valid(uint32_t cluster_size) 96*75411d23SStefan Hajnoczi { 97*75411d23SStefan Hajnoczi if (cluster_size < QED_MIN_CLUSTER_SIZE || 98*75411d23SStefan Hajnoczi cluster_size > QED_MAX_CLUSTER_SIZE) { 99*75411d23SStefan Hajnoczi return false; 100*75411d23SStefan Hajnoczi } 101*75411d23SStefan Hajnoczi if (cluster_size & (cluster_size - 1)) { 102*75411d23SStefan Hajnoczi return false; /* not power of 2 */ 103*75411d23SStefan Hajnoczi } 104*75411d23SStefan Hajnoczi return true; 105*75411d23SStefan Hajnoczi } 106*75411d23SStefan Hajnoczi 107*75411d23SStefan Hajnoczi static bool qed_is_table_size_valid(uint32_t table_size) 108*75411d23SStefan Hajnoczi { 109*75411d23SStefan Hajnoczi if (table_size < QED_MIN_TABLE_SIZE || 110*75411d23SStefan Hajnoczi table_size > QED_MAX_TABLE_SIZE) { 111*75411d23SStefan Hajnoczi return false; 112*75411d23SStefan Hajnoczi } 113*75411d23SStefan Hajnoczi if (table_size & (table_size - 1)) { 114*75411d23SStefan Hajnoczi return false; /* not power of 2 */ 115*75411d23SStefan Hajnoczi } 116*75411d23SStefan Hajnoczi return true; 117*75411d23SStefan Hajnoczi } 118*75411d23SStefan Hajnoczi 119*75411d23SStefan Hajnoczi static bool qed_is_image_size_valid(uint64_t image_size, uint32_t cluster_size, 120*75411d23SStefan Hajnoczi uint32_t table_size) 121*75411d23SStefan Hajnoczi { 122*75411d23SStefan Hajnoczi if (image_size % BDRV_SECTOR_SIZE != 0) { 123*75411d23SStefan Hajnoczi return false; /* not multiple of sector size */ 124*75411d23SStefan Hajnoczi } 125*75411d23SStefan Hajnoczi if (image_size > qed_max_image_size(cluster_size, table_size)) { 126*75411d23SStefan Hajnoczi return false; /* image is too large */ 127*75411d23SStefan Hajnoczi } 128*75411d23SStefan Hajnoczi return true; 129*75411d23SStefan Hajnoczi } 130*75411d23SStefan Hajnoczi 131*75411d23SStefan Hajnoczi /** 132*75411d23SStefan Hajnoczi * Read a string of known length from the image file 133*75411d23SStefan Hajnoczi * 134*75411d23SStefan Hajnoczi * @file: Image file 135*75411d23SStefan Hajnoczi * @offset: File offset to start of string, in bytes 136*75411d23SStefan Hajnoczi * @n: String length in bytes 137*75411d23SStefan Hajnoczi * @buf: Destination buffer 138*75411d23SStefan Hajnoczi * @buflen: Destination buffer length in bytes 139*75411d23SStefan Hajnoczi * @ret: 0 on success, -errno on failure 140*75411d23SStefan Hajnoczi * 141*75411d23SStefan Hajnoczi * The string is NUL-terminated. 142*75411d23SStefan Hajnoczi */ 143*75411d23SStefan Hajnoczi static int qed_read_string(BlockDriverState *file, uint64_t offset, size_t n, 144*75411d23SStefan Hajnoczi char *buf, size_t buflen) 145*75411d23SStefan Hajnoczi { 146*75411d23SStefan Hajnoczi int ret; 147*75411d23SStefan Hajnoczi if (n >= buflen) { 148*75411d23SStefan Hajnoczi return -EINVAL; 149*75411d23SStefan Hajnoczi } 150*75411d23SStefan Hajnoczi ret = bdrv_pread(file, offset, buf, n); 151*75411d23SStefan Hajnoczi if (ret < 0) { 152*75411d23SStefan Hajnoczi return ret; 153*75411d23SStefan Hajnoczi } 154*75411d23SStefan Hajnoczi buf[n] = '\0'; 155*75411d23SStefan Hajnoczi return 0; 156*75411d23SStefan Hajnoczi } 157*75411d23SStefan Hajnoczi 158*75411d23SStefan Hajnoczi static int bdrv_qed_open(BlockDriverState *bs, int flags) 159*75411d23SStefan Hajnoczi { 160*75411d23SStefan Hajnoczi BDRVQEDState *s = bs->opaque; 161*75411d23SStefan Hajnoczi QEDHeader le_header; 162*75411d23SStefan Hajnoczi int64_t file_size; 163*75411d23SStefan Hajnoczi int ret; 164*75411d23SStefan Hajnoczi 165*75411d23SStefan Hajnoczi s->bs = bs; 166*75411d23SStefan Hajnoczi 167*75411d23SStefan Hajnoczi ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header)); 168*75411d23SStefan Hajnoczi if (ret < 0) { 169*75411d23SStefan Hajnoczi return ret; 170*75411d23SStefan Hajnoczi } 171*75411d23SStefan Hajnoczi ret = 0; /* ret should always be 0 or -errno */ 172*75411d23SStefan Hajnoczi qed_header_le_to_cpu(&le_header, &s->header); 173*75411d23SStefan Hajnoczi 174*75411d23SStefan Hajnoczi if (s->header.magic != QED_MAGIC) { 175*75411d23SStefan Hajnoczi return -EINVAL; 176*75411d23SStefan Hajnoczi } 177*75411d23SStefan Hajnoczi if (s->header.features & ~QED_FEATURE_MASK) { 178*75411d23SStefan Hajnoczi return -ENOTSUP; /* image uses unsupported feature bits */ 179*75411d23SStefan Hajnoczi } 180*75411d23SStefan Hajnoczi if (!qed_is_cluster_size_valid(s->header.cluster_size)) { 181*75411d23SStefan Hajnoczi return -EINVAL; 182*75411d23SStefan Hajnoczi } 183*75411d23SStefan Hajnoczi 184*75411d23SStefan Hajnoczi /* Round down file size to the last cluster */ 185*75411d23SStefan Hajnoczi file_size = bdrv_getlength(bs->file); 186*75411d23SStefan Hajnoczi if (file_size < 0) { 187*75411d23SStefan Hajnoczi return file_size; 188*75411d23SStefan Hajnoczi } 189*75411d23SStefan Hajnoczi s->file_size = qed_start_of_cluster(s, file_size); 190*75411d23SStefan Hajnoczi 191*75411d23SStefan Hajnoczi if (!qed_is_table_size_valid(s->header.table_size)) { 192*75411d23SStefan Hajnoczi return -EINVAL; 193*75411d23SStefan Hajnoczi } 194*75411d23SStefan Hajnoczi if (!qed_is_image_size_valid(s->header.image_size, 195*75411d23SStefan Hajnoczi s->header.cluster_size, 196*75411d23SStefan Hajnoczi s->header.table_size)) { 197*75411d23SStefan Hajnoczi return -EINVAL; 198*75411d23SStefan Hajnoczi } 199*75411d23SStefan Hajnoczi if (!qed_check_table_offset(s, s->header.l1_table_offset)) { 200*75411d23SStefan Hajnoczi return -EINVAL; 201*75411d23SStefan Hajnoczi } 202*75411d23SStefan Hajnoczi 203*75411d23SStefan Hajnoczi s->table_nelems = (s->header.cluster_size * s->header.table_size) / 204*75411d23SStefan Hajnoczi sizeof(uint64_t); 205*75411d23SStefan Hajnoczi s->l2_shift = ffs(s->header.cluster_size) - 1; 206*75411d23SStefan Hajnoczi s->l2_mask = s->table_nelems - 1; 207*75411d23SStefan Hajnoczi s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1; 208*75411d23SStefan Hajnoczi 209*75411d23SStefan Hajnoczi if ((s->header.features & QED_F_BACKING_FILE)) { 210*75411d23SStefan Hajnoczi if ((uint64_t)s->header.backing_filename_offset + 211*75411d23SStefan Hajnoczi s->header.backing_filename_size > 212*75411d23SStefan Hajnoczi s->header.cluster_size * s->header.header_size) { 213*75411d23SStefan Hajnoczi return -EINVAL; 214*75411d23SStefan Hajnoczi } 215*75411d23SStefan Hajnoczi 216*75411d23SStefan Hajnoczi ret = qed_read_string(bs->file, s->header.backing_filename_offset, 217*75411d23SStefan Hajnoczi s->header.backing_filename_size, bs->backing_file, 218*75411d23SStefan Hajnoczi sizeof(bs->backing_file)); 219*75411d23SStefan Hajnoczi if (ret < 0) { 220*75411d23SStefan Hajnoczi return ret; 221*75411d23SStefan Hajnoczi } 222*75411d23SStefan Hajnoczi 223*75411d23SStefan Hajnoczi if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) { 224*75411d23SStefan Hajnoczi pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw"); 225*75411d23SStefan Hajnoczi } 226*75411d23SStefan Hajnoczi } 227*75411d23SStefan Hajnoczi 228*75411d23SStefan Hajnoczi /* Reset unknown autoclear feature bits. This is a backwards 229*75411d23SStefan Hajnoczi * compatibility mechanism that allows images to be opened by older 230*75411d23SStefan Hajnoczi * programs, which "knock out" unknown feature bits. When an image is 231*75411d23SStefan Hajnoczi * opened by a newer program again it can detect that the autoclear 232*75411d23SStefan Hajnoczi * feature is no longer valid. 233*75411d23SStefan Hajnoczi */ 234*75411d23SStefan Hajnoczi if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 && 235*75411d23SStefan Hajnoczi !bdrv_is_read_only(bs->file)) { 236*75411d23SStefan Hajnoczi s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK; 237*75411d23SStefan Hajnoczi 238*75411d23SStefan Hajnoczi ret = qed_write_header_sync(s); 239*75411d23SStefan Hajnoczi if (ret) { 240*75411d23SStefan Hajnoczi return ret; 241*75411d23SStefan Hajnoczi } 242*75411d23SStefan Hajnoczi 243*75411d23SStefan Hajnoczi /* From here on only known autoclear feature bits are valid */ 244*75411d23SStefan Hajnoczi bdrv_flush(bs->file); 245*75411d23SStefan Hajnoczi } 246*75411d23SStefan Hajnoczi 247*75411d23SStefan Hajnoczi return ret; 248*75411d23SStefan Hajnoczi } 249*75411d23SStefan Hajnoczi 250*75411d23SStefan Hajnoczi static void bdrv_qed_close(BlockDriverState *bs) 251*75411d23SStefan Hajnoczi { 252*75411d23SStefan Hajnoczi } 253*75411d23SStefan Hajnoczi 254*75411d23SStefan Hajnoczi static int bdrv_qed_flush(BlockDriverState *bs) 255*75411d23SStefan Hajnoczi { 256*75411d23SStefan Hajnoczi return bdrv_flush(bs->file); 257*75411d23SStefan Hajnoczi } 258*75411d23SStefan Hajnoczi 259*75411d23SStefan Hajnoczi static int qed_create(const char *filename, uint32_t cluster_size, 260*75411d23SStefan Hajnoczi uint64_t image_size, uint32_t table_size, 261*75411d23SStefan Hajnoczi const char *backing_file, const char *backing_fmt) 262*75411d23SStefan Hajnoczi { 263*75411d23SStefan Hajnoczi QEDHeader header = { 264*75411d23SStefan Hajnoczi .magic = QED_MAGIC, 265*75411d23SStefan Hajnoczi .cluster_size = cluster_size, 266*75411d23SStefan Hajnoczi .table_size = table_size, 267*75411d23SStefan Hajnoczi .header_size = 1, 268*75411d23SStefan Hajnoczi .features = 0, 269*75411d23SStefan Hajnoczi .compat_features = 0, 270*75411d23SStefan Hajnoczi .l1_table_offset = cluster_size, 271*75411d23SStefan Hajnoczi .image_size = image_size, 272*75411d23SStefan Hajnoczi }; 273*75411d23SStefan Hajnoczi QEDHeader le_header; 274*75411d23SStefan Hajnoczi uint8_t *l1_table = NULL; 275*75411d23SStefan Hajnoczi size_t l1_size = header.cluster_size * header.table_size; 276*75411d23SStefan Hajnoczi int ret = 0; 277*75411d23SStefan Hajnoczi BlockDriverState *bs = NULL; 278*75411d23SStefan Hajnoczi 279*75411d23SStefan Hajnoczi ret = bdrv_create_file(filename, NULL); 280*75411d23SStefan Hajnoczi if (ret < 0) { 281*75411d23SStefan Hajnoczi return ret; 282*75411d23SStefan Hajnoczi } 283*75411d23SStefan Hajnoczi 284*75411d23SStefan Hajnoczi ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR | BDRV_O_CACHE_WB); 285*75411d23SStefan Hajnoczi if (ret < 0) { 286*75411d23SStefan Hajnoczi return ret; 287*75411d23SStefan Hajnoczi } 288*75411d23SStefan Hajnoczi 289*75411d23SStefan Hajnoczi if (backing_file) { 290*75411d23SStefan Hajnoczi header.features |= QED_F_BACKING_FILE; 291*75411d23SStefan Hajnoczi header.backing_filename_offset = sizeof(le_header); 292*75411d23SStefan Hajnoczi header.backing_filename_size = strlen(backing_file); 293*75411d23SStefan Hajnoczi 294*75411d23SStefan Hajnoczi if (qed_fmt_is_raw(backing_fmt)) { 295*75411d23SStefan Hajnoczi header.features |= QED_F_BACKING_FORMAT_NO_PROBE; 296*75411d23SStefan Hajnoczi } 297*75411d23SStefan Hajnoczi } 298*75411d23SStefan Hajnoczi 299*75411d23SStefan Hajnoczi qed_header_cpu_to_le(&header, &le_header); 300*75411d23SStefan Hajnoczi ret = bdrv_pwrite(bs, 0, &le_header, sizeof(le_header)); 301*75411d23SStefan Hajnoczi if (ret < 0) { 302*75411d23SStefan Hajnoczi goto out; 303*75411d23SStefan Hajnoczi } 304*75411d23SStefan Hajnoczi ret = bdrv_pwrite(bs, sizeof(le_header), backing_file, 305*75411d23SStefan Hajnoczi header.backing_filename_size); 306*75411d23SStefan Hajnoczi if (ret < 0) { 307*75411d23SStefan Hajnoczi goto out; 308*75411d23SStefan Hajnoczi } 309*75411d23SStefan Hajnoczi 310*75411d23SStefan Hajnoczi l1_table = qemu_mallocz(l1_size); 311*75411d23SStefan Hajnoczi ret = bdrv_pwrite(bs, header.l1_table_offset, l1_table, l1_size); 312*75411d23SStefan Hajnoczi if (ret < 0) { 313*75411d23SStefan Hajnoczi goto out; 314*75411d23SStefan Hajnoczi } 315*75411d23SStefan Hajnoczi 316*75411d23SStefan Hajnoczi ret = 0; /* success */ 317*75411d23SStefan Hajnoczi out: 318*75411d23SStefan Hajnoczi qemu_free(l1_table); 319*75411d23SStefan Hajnoczi bdrv_delete(bs); 320*75411d23SStefan Hajnoczi return ret; 321*75411d23SStefan Hajnoczi } 322*75411d23SStefan Hajnoczi 323*75411d23SStefan Hajnoczi static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options) 324*75411d23SStefan Hajnoczi { 325*75411d23SStefan Hajnoczi uint64_t image_size = 0; 326*75411d23SStefan Hajnoczi uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE; 327*75411d23SStefan Hajnoczi uint32_t table_size = QED_DEFAULT_TABLE_SIZE; 328*75411d23SStefan Hajnoczi const char *backing_file = NULL; 329*75411d23SStefan Hajnoczi const char *backing_fmt = NULL; 330*75411d23SStefan Hajnoczi 331*75411d23SStefan Hajnoczi while (options && options->name) { 332*75411d23SStefan Hajnoczi if (!strcmp(options->name, BLOCK_OPT_SIZE)) { 333*75411d23SStefan Hajnoczi image_size = options->value.n; 334*75411d23SStefan Hajnoczi } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { 335*75411d23SStefan Hajnoczi backing_file = options->value.s; 336*75411d23SStefan Hajnoczi } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) { 337*75411d23SStefan Hajnoczi backing_fmt = options->value.s; 338*75411d23SStefan Hajnoczi } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) { 339*75411d23SStefan Hajnoczi if (options->value.n) { 340*75411d23SStefan Hajnoczi cluster_size = options->value.n; 341*75411d23SStefan Hajnoczi } 342*75411d23SStefan Hajnoczi } else if (!strcmp(options->name, BLOCK_OPT_TABLE_SIZE)) { 343*75411d23SStefan Hajnoczi if (options->value.n) { 344*75411d23SStefan Hajnoczi table_size = options->value.n; 345*75411d23SStefan Hajnoczi } 346*75411d23SStefan Hajnoczi } 347*75411d23SStefan Hajnoczi options++; 348*75411d23SStefan Hajnoczi } 349*75411d23SStefan Hajnoczi 350*75411d23SStefan Hajnoczi if (!qed_is_cluster_size_valid(cluster_size)) { 351*75411d23SStefan Hajnoczi fprintf(stderr, "QED cluster size must be within range [%u, %u] and power of 2\n", 352*75411d23SStefan Hajnoczi QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE); 353*75411d23SStefan Hajnoczi return -EINVAL; 354*75411d23SStefan Hajnoczi } 355*75411d23SStefan Hajnoczi if (!qed_is_table_size_valid(table_size)) { 356*75411d23SStefan Hajnoczi fprintf(stderr, "QED table size must be within range [%u, %u] and power of 2\n", 357*75411d23SStefan Hajnoczi QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE); 358*75411d23SStefan Hajnoczi return -EINVAL; 359*75411d23SStefan Hajnoczi } 360*75411d23SStefan Hajnoczi if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) { 361*75411d23SStefan Hajnoczi fprintf(stderr, "QED image size must be a non-zero multiple of " 362*75411d23SStefan Hajnoczi "cluster size and less than %" PRIu64 " bytes\n", 363*75411d23SStefan Hajnoczi qed_max_image_size(cluster_size, table_size)); 364*75411d23SStefan Hajnoczi return -EINVAL; 365*75411d23SStefan Hajnoczi } 366*75411d23SStefan Hajnoczi 367*75411d23SStefan Hajnoczi return qed_create(filename, cluster_size, image_size, table_size, 368*75411d23SStefan Hajnoczi backing_file, backing_fmt); 369*75411d23SStefan Hajnoczi } 370*75411d23SStefan Hajnoczi 371*75411d23SStefan Hajnoczi static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num, 372*75411d23SStefan Hajnoczi int nb_sectors, int *pnum) 373*75411d23SStefan Hajnoczi { 374*75411d23SStefan Hajnoczi return -ENOTSUP; 375*75411d23SStefan Hajnoczi } 376*75411d23SStefan Hajnoczi 377*75411d23SStefan Hajnoczi static int bdrv_qed_make_empty(BlockDriverState *bs) 378*75411d23SStefan Hajnoczi { 379*75411d23SStefan Hajnoczi return -ENOTSUP; 380*75411d23SStefan Hajnoczi } 381*75411d23SStefan Hajnoczi 382*75411d23SStefan Hajnoczi static BlockDriverAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs, 383*75411d23SStefan Hajnoczi int64_t sector_num, 384*75411d23SStefan Hajnoczi QEMUIOVector *qiov, int nb_sectors, 385*75411d23SStefan Hajnoczi BlockDriverCompletionFunc *cb, 386*75411d23SStefan Hajnoczi void *opaque) 387*75411d23SStefan Hajnoczi { 388*75411d23SStefan Hajnoczi return NULL; 389*75411d23SStefan Hajnoczi } 390*75411d23SStefan Hajnoczi 391*75411d23SStefan Hajnoczi static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs, 392*75411d23SStefan Hajnoczi int64_t sector_num, 393*75411d23SStefan Hajnoczi QEMUIOVector *qiov, int nb_sectors, 394*75411d23SStefan Hajnoczi BlockDriverCompletionFunc *cb, 395*75411d23SStefan Hajnoczi void *opaque) 396*75411d23SStefan Hajnoczi { 397*75411d23SStefan Hajnoczi return NULL; 398*75411d23SStefan Hajnoczi } 399*75411d23SStefan Hajnoczi 400*75411d23SStefan Hajnoczi static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs, 401*75411d23SStefan Hajnoczi BlockDriverCompletionFunc *cb, 402*75411d23SStefan Hajnoczi void *opaque) 403*75411d23SStefan Hajnoczi { 404*75411d23SStefan Hajnoczi return bdrv_aio_flush(bs->file, cb, opaque); 405*75411d23SStefan Hajnoczi } 406*75411d23SStefan Hajnoczi 407*75411d23SStefan Hajnoczi static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset) 408*75411d23SStefan Hajnoczi { 409*75411d23SStefan Hajnoczi return -ENOTSUP; 410*75411d23SStefan Hajnoczi } 411*75411d23SStefan Hajnoczi 412*75411d23SStefan Hajnoczi static int64_t bdrv_qed_getlength(BlockDriverState *bs) 413*75411d23SStefan Hajnoczi { 414*75411d23SStefan Hajnoczi BDRVQEDState *s = bs->opaque; 415*75411d23SStefan Hajnoczi return s->header.image_size; 416*75411d23SStefan Hajnoczi } 417*75411d23SStefan Hajnoczi 418*75411d23SStefan Hajnoczi static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) 419*75411d23SStefan Hajnoczi { 420*75411d23SStefan Hajnoczi BDRVQEDState *s = bs->opaque; 421*75411d23SStefan Hajnoczi 422*75411d23SStefan Hajnoczi memset(bdi, 0, sizeof(*bdi)); 423*75411d23SStefan Hajnoczi bdi->cluster_size = s->header.cluster_size; 424*75411d23SStefan Hajnoczi return 0; 425*75411d23SStefan Hajnoczi } 426*75411d23SStefan Hajnoczi 427*75411d23SStefan Hajnoczi static int bdrv_qed_change_backing_file(BlockDriverState *bs, 428*75411d23SStefan Hajnoczi const char *backing_file, 429*75411d23SStefan Hajnoczi const char *backing_fmt) 430*75411d23SStefan Hajnoczi { 431*75411d23SStefan Hajnoczi BDRVQEDState *s = bs->opaque; 432*75411d23SStefan Hajnoczi QEDHeader new_header, le_header; 433*75411d23SStefan Hajnoczi void *buffer; 434*75411d23SStefan Hajnoczi size_t buffer_len, backing_file_len; 435*75411d23SStefan Hajnoczi int ret; 436*75411d23SStefan Hajnoczi 437*75411d23SStefan Hajnoczi /* Refuse to set backing filename if unknown compat feature bits are 438*75411d23SStefan Hajnoczi * active. If the image uses an unknown compat feature then we may not 439*75411d23SStefan Hajnoczi * know the layout of data following the header structure and cannot safely 440*75411d23SStefan Hajnoczi * add a new string. 441*75411d23SStefan Hajnoczi */ 442*75411d23SStefan Hajnoczi if (backing_file && (s->header.compat_features & 443*75411d23SStefan Hajnoczi ~QED_COMPAT_FEATURE_MASK)) { 444*75411d23SStefan Hajnoczi return -ENOTSUP; 445*75411d23SStefan Hajnoczi } 446*75411d23SStefan Hajnoczi 447*75411d23SStefan Hajnoczi memcpy(&new_header, &s->header, sizeof(new_header)); 448*75411d23SStefan Hajnoczi 449*75411d23SStefan Hajnoczi new_header.features &= ~(QED_F_BACKING_FILE | 450*75411d23SStefan Hajnoczi QED_F_BACKING_FORMAT_NO_PROBE); 451*75411d23SStefan Hajnoczi 452*75411d23SStefan Hajnoczi /* Adjust feature flags */ 453*75411d23SStefan Hajnoczi if (backing_file) { 454*75411d23SStefan Hajnoczi new_header.features |= QED_F_BACKING_FILE; 455*75411d23SStefan Hajnoczi 456*75411d23SStefan Hajnoczi if (qed_fmt_is_raw(backing_fmt)) { 457*75411d23SStefan Hajnoczi new_header.features |= QED_F_BACKING_FORMAT_NO_PROBE; 458*75411d23SStefan Hajnoczi } 459*75411d23SStefan Hajnoczi } 460*75411d23SStefan Hajnoczi 461*75411d23SStefan Hajnoczi /* Calculate new header size */ 462*75411d23SStefan Hajnoczi backing_file_len = 0; 463*75411d23SStefan Hajnoczi 464*75411d23SStefan Hajnoczi if (backing_file) { 465*75411d23SStefan Hajnoczi backing_file_len = strlen(backing_file); 466*75411d23SStefan Hajnoczi } 467*75411d23SStefan Hajnoczi 468*75411d23SStefan Hajnoczi buffer_len = sizeof(new_header); 469*75411d23SStefan Hajnoczi new_header.backing_filename_offset = buffer_len; 470*75411d23SStefan Hajnoczi new_header.backing_filename_size = backing_file_len; 471*75411d23SStefan Hajnoczi buffer_len += backing_file_len; 472*75411d23SStefan Hajnoczi 473*75411d23SStefan Hajnoczi /* Make sure we can rewrite header without failing */ 474*75411d23SStefan Hajnoczi if (buffer_len > new_header.header_size * new_header.cluster_size) { 475*75411d23SStefan Hajnoczi return -ENOSPC; 476*75411d23SStefan Hajnoczi } 477*75411d23SStefan Hajnoczi 478*75411d23SStefan Hajnoczi /* Prepare new header */ 479*75411d23SStefan Hajnoczi buffer = qemu_malloc(buffer_len); 480*75411d23SStefan Hajnoczi 481*75411d23SStefan Hajnoczi qed_header_cpu_to_le(&new_header, &le_header); 482*75411d23SStefan Hajnoczi memcpy(buffer, &le_header, sizeof(le_header)); 483*75411d23SStefan Hajnoczi buffer_len = sizeof(le_header); 484*75411d23SStefan Hajnoczi 485*75411d23SStefan Hajnoczi memcpy(buffer + buffer_len, backing_file, backing_file_len); 486*75411d23SStefan Hajnoczi buffer_len += backing_file_len; 487*75411d23SStefan Hajnoczi 488*75411d23SStefan Hajnoczi /* Write new header */ 489*75411d23SStefan Hajnoczi ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len); 490*75411d23SStefan Hajnoczi qemu_free(buffer); 491*75411d23SStefan Hajnoczi if (ret == 0) { 492*75411d23SStefan Hajnoczi memcpy(&s->header, &new_header, sizeof(new_header)); 493*75411d23SStefan Hajnoczi } 494*75411d23SStefan Hajnoczi return ret; 495*75411d23SStefan Hajnoczi } 496*75411d23SStefan Hajnoczi 497*75411d23SStefan Hajnoczi static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result) 498*75411d23SStefan Hajnoczi { 499*75411d23SStefan Hajnoczi return -ENOTSUP; 500*75411d23SStefan Hajnoczi } 501*75411d23SStefan Hajnoczi 502*75411d23SStefan Hajnoczi static QEMUOptionParameter qed_create_options[] = { 503*75411d23SStefan Hajnoczi { 504*75411d23SStefan Hajnoczi .name = BLOCK_OPT_SIZE, 505*75411d23SStefan Hajnoczi .type = OPT_SIZE, 506*75411d23SStefan Hajnoczi .help = "Virtual disk size (in bytes)" 507*75411d23SStefan Hajnoczi }, { 508*75411d23SStefan Hajnoczi .name = BLOCK_OPT_BACKING_FILE, 509*75411d23SStefan Hajnoczi .type = OPT_STRING, 510*75411d23SStefan Hajnoczi .help = "File name of a base image" 511*75411d23SStefan Hajnoczi }, { 512*75411d23SStefan Hajnoczi .name = BLOCK_OPT_BACKING_FMT, 513*75411d23SStefan Hajnoczi .type = OPT_STRING, 514*75411d23SStefan Hajnoczi .help = "Image format of the base image" 515*75411d23SStefan Hajnoczi }, { 516*75411d23SStefan Hajnoczi .name = BLOCK_OPT_CLUSTER_SIZE, 517*75411d23SStefan Hajnoczi .type = OPT_SIZE, 518*75411d23SStefan Hajnoczi .help = "Cluster size (in bytes)" 519*75411d23SStefan Hajnoczi }, { 520*75411d23SStefan Hajnoczi .name = BLOCK_OPT_TABLE_SIZE, 521*75411d23SStefan Hajnoczi .type = OPT_SIZE, 522*75411d23SStefan Hajnoczi .help = "L1/L2 table size (in clusters)" 523*75411d23SStefan Hajnoczi }, 524*75411d23SStefan Hajnoczi { /* end of list */ } 525*75411d23SStefan Hajnoczi }; 526*75411d23SStefan Hajnoczi 527*75411d23SStefan Hajnoczi static BlockDriver bdrv_qed = { 528*75411d23SStefan Hajnoczi .format_name = "qed", 529*75411d23SStefan Hajnoczi .instance_size = sizeof(BDRVQEDState), 530*75411d23SStefan Hajnoczi .create_options = qed_create_options, 531*75411d23SStefan Hajnoczi 532*75411d23SStefan Hajnoczi .bdrv_probe = bdrv_qed_probe, 533*75411d23SStefan Hajnoczi .bdrv_open = bdrv_qed_open, 534*75411d23SStefan Hajnoczi .bdrv_close = bdrv_qed_close, 535*75411d23SStefan Hajnoczi .bdrv_create = bdrv_qed_create, 536*75411d23SStefan Hajnoczi .bdrv_flush = bdrv_qed_flush, 537*75411d23SStefan Hajnoczi .bdrv_is_allocated = bdrv_qed_is_allocated, 538*75411d23SStefan Hajnoczi .bdrv_make_empty = bdrv_qed_make_empty, 539*75411d23SStefan Hajnoczi .bdrv_aio_readv = bdrv_qed_aio_readv, 540*75411d23SStefan Hajnoczi .bdrv_aio_writev = bdrv_qed_aio_writev, 541*75411d23SStefan Hajnoczi .bdrv_aio_flush = bdrv_qed_aio_flush, 542*75411d23SStefan Hajnoczi .bdrv_truncate = bdrv_qed_truncate, 543*75411d23SStefan Hajnoczi .bdrv_getlength = bdrv_qed_getlength, 544*75411d23SStefan Hajnoczi .bdrv_get_info = bdrv_qed_get_info, 545*75411d23SStefan Hajnoczi .bdrv_change_backing_file = bdrv_qed_change_backing_file, 546*75411d23SStefan Hajnoczi .bdrv_check = bdrv_qed_check, 547*75411d23SStefan Hajnoczi }; 548*75411d23SStefan Hajnoczi 549*75411d23SStefan Hajnoczi static void bdrv_qed_init(void) 550*75411d23SStefan Hajnoczi { 551*75411d23SStefan Hajnoczi bdrv_register(&bdrv_qed); 552*75411d23SStefan Hajnoczi } 553*75411d23SStefan Hajnoczi 554*75411d23SStefan Hajnoczi block_init(bdrv_qed_init); 555