12e6fc7ebSEric Blake /* BlockDriver implementation for "raw" format driver 22e6fc7ebSEric Blake * 32e6fc7ebSEric Blake * Copyright (C) 2010-2016 Red Hat, Inc. 42e6fc7ebSEric Blake * Copyright (C) 2010, Blue Swirl <blauwirbel@gmail.com> 52e6fc7ebSEric Blake * Copyright (C) 2009, Anthony Liguori <aliguori@us.ibm.com> 62e6fc7ebSEric Blake * 72e6fc7ebSEric Blake * Author: 82e6fc7ebSEric Blake * Laszlo Ersek <lersek@redhat.com> 92e6fc7ebSEric Blake * 102e6fc7ebSEric Blake * Permission is hereby granted, free of charge, to any person obtaining a copy 112e6fc7ebSEric Blake * of this software and associated documentation files (the "Software"), to 122e6fc7ebSEric Blake * deal in the Software without restriction, including without limitation the 132e6fc7ebSEric Blake * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 142e6fc7ebSEric Blake * sell copies of the Software, and to permit persons to whom the Software is 152e6fc7ebSEric Blake * furnished to do so, subject to the following conditions: 162e6fc7ebSEric Blake * 172e6fc7ebSEric Blake * The above copyright notice and this permission notice shall be included in 182e6fc7ebSEric Blake * all copies or substantial portions of the Software. 192e6fc7ebSEric Blake * 202e6fc7ebSEric Blake * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 212e6fc7ebSEric Blake * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 222e6fc7ebSEric Blake * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 232e6fc7ebSEric Blake * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 242e6fc7ebSEric Blake * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 252e6fc7ebSEric Blake * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 262e6fc7ebSEric Blake * IN THE SOFTWARE. 272e6fc7ebSEric Blake */ 282e6fc7ebSEric Blake 292e6fc7ebSEric Blake #include "qemu/osdep.h" 30e2c1c34fSMarkus Armbruster #include "block/block-io.h" 312e6fc7ebSEric Blake #include "block/block_int.h" 322e6fc7ebSEric Blake #include "qapi/error.h" 330b8fa32fSMarkus Armbruster #include "qemu/module.h" 342e6fc7ebSEric Blake #include "qemu/option.h" 355df022cfSPeter Maydell #include "qemu/memalign.h" 362e6fc7ebSEric Blake 372e6fc7ebSEric Blake typedef struct BDRVRawState { 382e6fc7ebSEric Blake uint64_t offset; 392e6fc7ebSEric Blake uint64_t size; 402e6fc7ebSEric Blake bool has_size; 412e6fc7ebSEric Blake } BDRVRawState; 422e6fc7ebSEric Blake 438a2ce0bcSAlberto Garcia static const char *const mutable_opts[] = { "offset", "size", NULL }; 448a2ce0bcSAlberto Garcia 452e6fc7ebSEric Blake static QemuOptsList raw_runtime_opts = { 462e6fc7ebSEric Blake .name = "raw", 472e6fc7ebSEric Blake .head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head), 482e6fc7ebSEric Blake .desc = { 492e6fc7ebSEric Blake { 502e6fc7ebSEric Blake .name = "offset", 512e6fc7ebSEric Blake .type = QEMU_OPT_SIZE, 522e6fc7ebSEric Blake .help = "offset in the disk where the image starts", 532e6fc7ebSEric Blake }, 542e6fc7ebSEric Blake { 552e6fc7ebSEric Blake .name = "size", 562e6fc7ebSEric Blake .type = QEMU_OPT_SIZE, 572e6fc7ebSEric Blake .help = "virtual disk size", 582e6fc7ebSEric Blake }, 592e6fc7ebSEric Blake { /* end of list */ } 602e6fc7ebSEric Blake }, 612e6fc7ebSEric Blake }; 622e6fc7ebSEric Blake 632e6fc7ebSEric Blake static QemuOptsList raw_create_opts = { 642e6fc7ebSEric Blake .name = "raw-create-opts", 652e6fc7ebSEric Blake .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head), 662e6fc7ebSEric Blake .desc = { 672e6fc7ebSEric Blake { 682e6fc7ebSEric Blake .name = BLOCK_OPT_SIZE, 692e6fc7ebSEric Blake .type = QEMU_OPT_SIZE, 702e6fc7ebSEric Blake .help = "Virtual disk size" 712e6fc7ebSEric Blake }, 722e6fc7ebSEric Blake { /* end of list */ } 732e6fc7ebSEric Blake } 742e6fc7ebSEric Blake }; 752e6fc7ebSEric Blake 76500e2434SMax Reitz static int raw_read_options(QDict *options, uint64_t *offset, bool *has_size, 77500e2434SMax Reitz uint64_t *size, Error **errp) 782e6fc7ebSEric Blake { 792e6fc7ebSEric Blake QemuOpts *opts = NULL; 802e6fc7ebSEric Blake int ret; 812e6fc7ebSEric Blake 822e6fc7ebSEric Blake opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); 83af175e85SMarkus Armbruster if (!qemu_opts_absorb_qdict(opts, options, errp)) { 842e6fc7ebSEric Blake ret = -EINVAL; 852e6fc7ebSEric Blake goto end; 862e6fc7ebSEric Blake } 872e6fc7ebSEric Blake 88500e2434SMax Reitz *offset = qemu_opt_get_size(opts, "offset", 0); 89500e2434SMax Reitz *has_size = qemu_opt_find(opts, "size"); 90500e2434SMax Reitz *size = qemu_opt_get_size(opts, "size", 0); 91500e2434SMax Reitz 92500e2434SMax Reitz ret = 0; 93500e2434SMax Reitz end: 94500e2434SMax Reitz qemu_opts_del(opts); 95500e2434SMax Reitz return ret; 962e6fc7ebSEric Blake } 972e6fc7ebSEric Blake 98500e2434SMax Reitz static int raw_apply_options(BlockDriverState *bs, BDRVRawState *s, 99500e2434SMax Reitz uint64_t offset, bool has_size, uint64_t size, 100500e2434SMax Reitz Error **errp) 101500e2434SMax Reitz { 102500e2434SMax Reitz int64_t real_size = 0; 103500e2434SMax Reitz 104500e2434SMax Reitz real_size = bdrv_getlength(bs->file->bs); 105500e2434SMax Reitz if (real_size < 0) { 106500e2434SMax Reitz error_setg_errno(errp, -real_size, "Could not get image size"); 107500e2434SMax Reitz return real_size; 1082e6fc7ebSEric Blake } 1092e6fc7ebSEric Blake 1102e6fc7ebSEric Blake /* Check size and offset */ 111500e2434SMax Reitz if (offset > real_size) { 112500e2434SMax Reitz error_setg(errp, "Offset (%" PRIu64 ") cannot be greater than " 113500e2434SMax Reitz "size of the containing file (%" PRId64 ")", 114500e2434SMax Reitz s->offset, real_size); 115500e2434SMax Reitz return -EINVAL; 116500e2434SMax Reitz } 117500e2434SMax Reitz 118500e2434SMax Reitz if (has_size && (real_size - offset) < size) { 1192e6fc7ebSEric Blake error_setg(errp, "The sum of offset (%" PRIu64 ") and size " 1202e6fc7ebSEric Blake "(%" PRIu64 ") has to be smaller or equal to the " 1212e6fc7ebSEric Blake " actual size of the containing file (%" PRId64 ")", 1222e6fc7ebSEric Blake s->offset, s->size, real_size); 123500e2434SMax Reitz return -EINVAL; 1242e6fc7ebSEric Blake } 1252e6fc7ebSEric Blake 1262e6fc7ebSEric Blake /* Make sure size is multiple of BDRV_SECTOR_SIZE to prevent rounding 1272e6fc7ebSEric Blake * up and leaking out of the specified area. */ 128500e2434SMax Reitz if (has_size && !QEMU_IS_ALIGNED(size, BDRV_SECTOR_SIZE)) { 1292e6fc7ebSEric Blake error_setg(errp, "Specified size is not multiple of %llu", 1302e6fc7ebSEric Blake BDRV_SECTOR_SIZE); 131500e2434SMax Reitz return -EINVAL; 1322e6fc7ebSEric Blake } 1332e6fc7ebSEric Blake 134500e2434SMax Reitz s->offset = offset; 135500e2434SMax Reitz s->has_size = has_size; 136500e2434SMax Reitz s->size = has_size ? size : real_size - offset; 1372e6fc7ebSEric Blake 138500e2434SMax Reitz return 0; 1392e6fc7ebSEric Blake } 1402e6fc7ebSEric Blake 1412e6fc7ebSEric Blake static int raw_reopen_prepare(BDRVReopenState *reopen_state, 1422e6fc7ebSEric Blake BlockReopenQueue *queue, Error **errp) 1432e6fc7ebSEric Blake { 144500e2434SMax Reitz bool has_size; 145500e2434SMax Reitz uint64_t offset, size; 146500e2434SMax Reitz int ret; 147500e2434SMax Reitz 1482e6fc7ebSEric Blake assert(reopen_state != NULL); 1492e6fc7ebSEric Blake assert(reopen_state->bs != NULL); 1502e6fc7ebSEric Blake 1512e6fc7ebSEric Blake reopen_state->opaque = g_new0(BDRVRawState, 1); 1522e6fc7ebSEric Blake 153500e2434SMax Reitz ret = raw_read_options(reopen_state->options, &offset, &has_size, &size, 1542e6fc7ebSEric Blake errp); 155500e2434SMax Reitz if (ret < 0) { 156500e2434SMax Reitz return ret; 157500e2434SMax Reitz } 158500e2434SMax Reitz 159500e2434SMax Reitz ret = raw_apply_options(reopen_state->bs, reopen_state->opaque, 160500e2434SMax Reitz offset, has_size, size, errp); 161500e2434SMax Reitz if (ret < 0) { 162500e2434SMax Reitz return ret; 163500e2434SMax Reitz } 164500e2434SMax Reitz 165500e2434SMax Reitz return 0; 1662e6fc7ebSEric Blake } 1672e6fc7ebSEric Blake 1682e6fc7ebSEric Blake static void raw_reopen_commit(BDRVReopenState *state) 1692e6fc7ebSEric Blake { 1702e6fc7ebSEric Blake BDRVRawState *new_s = state->opaque; 1712e6fc7ebSEric Blake BDRVRawState *s = state->bs->opaque; 1722e6fc7ebSEric Blake 1732e6fc7ebSEric Blake memcpy(s, new_s, sizeof(BDRVRawState)); 1742e6fc7ebSEric Blake 1752e6fc7ebSEric Blake g_free(state->opaque); 1762e6fc7ebSEric Blake state->opaque = NULL; 1772e6fc7ebSEric Blake } 1782e6fc7ebSEric Blake 1792e6fc7ebSEric Blake static void raw_reopen_abort(BDRVReopenState *state) 1802e6fc7ebSEric Blake { 1812e6fc7ebSEric Blake g_free(state->opaque); 1822e6fc7ebSEric Blake state->opaque = NULL; 1832e6fc7ebSEric Blake } 1842e6fc7ebSEric Blake 18538445538SFam Zheng /* Check and adjust the offset, against 'offset' and 'size' options. */ 186f7ef38ddSVladimir Sementsov-Ogievskiy static inline int raw_adjust_offset(BlockDriverState *bs, int64_t *offset, 187f7ef38ddSVladimir Sementsov-Ogievskiy int64_t bytes, bool is_write) 18838445538SFam Zheng { 18938445538SFam Zheng BDRVRawState *s = bs->opaque; 19038445538SFam Zheng 19138445538SFam Zheng if (s->has_size && (*offset > s->size || bytes > (s->size - *offset))) { 19238445538SFam Zheng /* There's not enough space for the write, or the read request is 19338445538SFam Zheng * out-of-range. Don't read/write anything to prevent leaking out of 19438445538SFam Zheng * the size specified in options. */ 1956d6bcc46SFam Zheng return is_write ? -ENOSPC : -EINVAL; 19638445538SFam Zheng } 19738445538SFam Zheng 19838445538SFam Zheng if (*offset > INT64_MAX - s->offset) { 19938445538SFam Zheng return -EINVAL; 20038445538SFam Zheng } 20138445538SFam Zheng *offset += s->offset; 20238445538SFam Zheng 20338445538SFam Zheng return 0; 20438445538SFam Zheng } 20538445538SFam Zheng 206b9b10c35SKevin Wolf static int coroutine_fn GRAPH_RDLOCK 207b9b10c35SKevin Wolf raw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, 208b9b10c35SKevin Wolf QEMUIOVector *qiov, BdrvRequestFlags flags) 2092e6fc7ebSEric Blake { 21038445538SFam Zheng int ret; 2112e6fc7ebSEric Blake 21238445538SFam Zheng ret = raw_adjust_offset(bs, &offset, bytes, false); 21338445538SFam Zheng if (ret) { 21438445538SFam Zheng return ret; 2152e6fc7ebSEric Blake } 2162e6fc7ebSEric Blake 21717362398SPaolo Bonzini BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO); 2182e6fc7ebSEric Blake return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); 2192e6fc7ebSEric Blake } 2202e6fc7ebSEric Blake 221b9b10c35SKevin Wolf static int coroutine_fn GRAPH_RDLOCK 222b9b10c35SKevin Wolf raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, 223b9b10c35SKevin Wolf QEMUIOVector *qiov, BdrvRequestFlags flags) 2242e6fc7ebSEric Blake { 2252e6fc7ebSEric Blake void *buf = NULL; 2262e6fc7ebSEric Blake BlockDriver *drv; 2272e6fc7ebSEric Blake QEMUIOVector local_qiov; 2282e6fc7ebSEric Blake int ret; 2292e6fc7ebSEric Blake 2302e6fc7ebSEric Blake if (bs->probed && offset < BLOCK_PROBE_BUF_SIZE && bytes) { 2312e6fc7ebSEric Blake /* Handling partial writes would be a pain - so we just 2322e6fc7ebSEric Blake * require that guests have 512-byte request alignment if 2332e6fc7ebSEric Blake * probing occurred */ 2342e6fc7ebSEric Blake QEMU_BUILD_BUG_ON(BLOCK_PROBE_BUF_SIZE != 512); 2352e6fc7ebSEric Blake QEMU_BUILD_BUG_ON(BDRV_SECTOR_SIZE != 512); 2362e6fc7ebSEric Blake assert(offset == 0 && bytes >= BLOCK_PROBE_BUF_SIZE); 2372e6fc7ebSEric Blake 2382e6fc7ebSEric Blake buf = qemu_try_blockalign(bs->file->bs, 512); 2392e6fc7ebSEric Blake if (!buf) { 2402e6fc7ebSEric Blake ret = -ENOMEM; 2412e6fc7ebSEric Blake goto fail; 2422e6fc7ebSEric Blake } 2432e6fc7ebSEric Blake 2442e6fc7ebSEric Blake ret = qemu_iovec_to_buf(qiov, 0, buf, 512); 2452e6fc7ebSEric Blake if (ret != 512) { 2462e6fc7ebSEric Blake ret = -EINVAL; 2472e6fc7ebSEric Blake goto fail; 2482e6fc7ebSEric Blake } 2492e6fc7ebSEric Blake 2502e6fc7ebSEric Blake drv = bdrv_probe_all(buf, 512, NULL); 2512e6fc7ebSEric Blake if (drv != bs->drv) { 2522e6fc7ebSEric Blake ret = -EPERM; 2532e6fc7ebSEric Blake goto fail; 2542e6fc7ebSEric Blake } 2552e6fc7ebSEric Blake 2562e6fc7ebSEric Blake /* Use the checked buffer, a malicious guest might be overwriting its 2572e6fc7ebSEric Blake * original buffer in the background. */ 2582e6fc7ebSEric Blake qemu_iovec_init(&local_qiov, qiov->niov + 1); 2592e6fc7ebSEric Blake qemu_iovec_add(&local_qiov, buf, 512); 2602e6fc7ebSEric Blake qemu_iovec_concat(&local_qiov, qiov, 512, qiov->size - 512); 2612e6fc7ebSEric Blake qiov = &local_qiov; 262e8b65355SStefan Hajnoczi 263e8b65355SStefan Hajnoczi flags &= ~BDRV_REQ_REGISTERED_BUF; 2642e6fc7ebSEric Blake } 2652e6fc7ebSEric Blake 266e75abedaSVladimir Sementsov-Ogievskiy ret = raw_adjust_offset(bs, &offset, bytes, true); 26738445538SFam Zheng if (ret) { 26838445538SFam Zheng goto fail; 26938445538SFam Zheng } 2702e6fc7ebSEric Blake 27117362398SPaolo Bonzini BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO); 2722e6fc7ebSEric Blake ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); 2732e6fc7ebSEric Blake 2742e6fc7ebSEric Blake fail: 2752e6fc7ebSEric Blake if (qiov == &local_qiov) { 2762e6fc7ebSEric Blake qemu_iovec_destroy(&local_qiov); 2772e6fc7ebSEric Blake } 2782e6fc7ebSEric Blake qemu_vfree(buf); 2792e6fc7ebSEric Blake return ret; 2802e6fc7ebSEric Blake } 2812e6fc7ebSEric Blake 282d41aa7e3SEric Blake static int coroutine_fn raw_co_block_status(BlockDriverState *bs, 283d41aa7e3SEric Blake bool want_zero, int64_t offset, 284d41aa7e3SEric Blake int64_t bytes, int64_t *pnum, 285d41aa7e3SEric Blake int64_t *map, 2862e6fc7ebSEric Blake BlockDriverState **file) 2872e6fc7ebSEric Blake { 2882e6fc7ebSEric Blake BDRVRawState *s = bs->opaque; 289d41aa7e3SEric Blake *pnum = bytes; 2902e6fc7ebSEric Blake *file = bs->file->bs; 291d41aa7e3SEric Blake *map = offset + s->offset; 292d41aa7e3SEric Blake return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID; 2932e6fc7ebSEric Blake } 2942e6fc7ebSEric Blake 295abaf8b75SKevin Wolf static int coroutine_fn GRAPH_RDLOCK 296abaf8b75SKevin Wolf raw_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, 2972e6fc7ebSEric Blake BdrvRequestFlags flags) 2982e6fc7ebSEric Blake { 29938445538SFam Zheng int ret; 30038445538SFam Zheng 301f7ef38ddSVladimir Sementsov-Ogievskiy ret = raw_adjust_offset(bs, &offset, bytes, true); 30238445538SFam Zheng if (ret) { 30338445538SFam Zheng return ret; 3042e6fc7ebSEric Blake } 305f5a5ca79SManos Pitsidianakis return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); 3062e6fc7ebSEric Blake } 3072e6fc7ebSEric Blake 3089a5a1c62SEmanuele Giuseppe Esposito static int coroutine_fn GRAPH_RDLOCK 3099a5a1c62SEmanuele Giuseppe Esposito raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) 3102e6fc7ebSEric Blake { 31138445538SFam Zheng int ret; 31238445538SFam Zheng 313f7ef38ddSVladimir Sementsov-Ogievskiy ret = raw_adjust_offset(bs, &offset, bytes, true); 31438445538SFam Zheng if (ret) { 31538445538SFam Zheng return ret; 3162e6fc7ebSEric Blake } 3170b9fd3f4SFam Zheng return bdrv_co_pdiscard(bs->file, offset, bytes); 3182e6fc7ebSEric Blake } 3192e6fc7ebSEric Blake 32050c4bcd4SSam Li static int coroutine_fn GRAPH_RDLOCK 32150c4bcd4SSam Li raw_co_zone_report(BlockDriverState *bs, int64_t offset, 32250c4bcd4SSam Li unsigned int *nr_zones, 32350c4bcd4SSam Li BlockZoneDescriptor *zones) 32450c4bcd4SSam Li { 32550c4bcd4SSam Li return bdrv_co_zone_report(bs->file->bs, offset, nr_zones, zones); 32650c4bcd4SSam Li } 32750c4bcd4SSam Li 32850c4bcd4SSam Li static int coroutine_fn GRAPH_RDLOCK 32950c4bcd4SSam Li raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, 33050c4bcd4SSam Li int64_t offset, int64_t len) 33150c4bcd4SSam Li { 33250c4bcd4SSam Li return bdrv_co_zone_mgmt(bs->file->bs, op, offset, len); 33350c4bcd4SSam Li } 33450c4bcd4SSam Li 3354751d09aSSam Li static int coroutine_fn GRAPH_RDLOCK 3364751d09aSSam Li raw_co_zone_append(BlockDriverState *bs,int64_t *offset, QEMUIOVector *qiov, 3374751d09aSSam Li BdrvRequestFlags flags) 3384751d09aSSam Li { 3394751d09aSSam Li return bdrv_co_zone_append(bs->file->bs, offset, qiov, flags); 3404751d09aSSam Li } 3414751d09aSSam Li 3428ab8140aSKevin Wolf static int64_t coroutine_fn GRAPH_RDLOCK 3438ab8140aSKevin Wolf raw_co_getlength(BlockDriverState *bs) 3442e6fc7ebSEric Blake { 3452e6fc7ebSEric Blake int64_t len; 3462e6fc7ebSEric Blake BDRVRawState *s = bs->opaque; 3472e6fc7ebSEric Blake 3482e6fc7ebSEric Blake /* Update size. It should not change unless the file was externally 3492e6fc7ebSEric Blake * modified. */ 350c86422c5SEmanuele Giuseppe Esposito len = bdrv_co_getlength(bs->file->bs); 3512e6fc7ebSEric Blake if (len < 0) { 3522e6fc7ebSEric Blake return len; 3532e6fc7ebSEric Blake } 3542e6fc7ebSEric Blake 3552e6fc7ebSEric Blake if (len < s->offset) { 3562e6fc7ebSEric Blake s->size = 0; 3572e6fc7ebSEric Blake } else { 3582e6fc7ebSEric Blake if (s->has_size) { 3592e6fc7ebSEric Blake /* Try to honour the size */ 3602e6fc7ebSEric Blake s->size = MIN(s->size, len - s->offset); 3612e6fc7ebSEric Blake } else { 3622e6fc7ebSEric Blake s->size = len - s->offset; 3632e6fc7ebSEric Blake } 3642e6fc7ebSEric Blake } 3652e6fc7ebSEric Blake 3662e6fc7ebSEric Blake return s->size; 3672e6fc7ebSEric Blake } 3682e6fc7ebSEric Blake 369a843a22aSStefan Hajnoczi static BlockMeasureInfo *raw_measure(QemuOpts *opts, BlockDriverState *in_bs, 370a843a22aSStefan Hajnoczi Error **errp) 371a843a22aSStefan Hajnoczi { 372a843a22aSStefan Hajnoczi BlockMeasureInfo *info; 373a843a22aSStefan Hajnoczi int64_t required; 374a843a22aSStefan Hajnoczi 375a843a22aSStefan Hajnoczi if (in_bs) { 376a843a22aSStefan Hajnoczi required = bdrv_getlength(in_bs); 377a843a22aSStefan Hajnoczi if (required < 0) { 378a843a22aSStefan Hajnoczi error_setg_errno(errp, -required, "Unable to get image size"); 379a843a22aSStefan Hajnoczi return NULL; 380a843a22aSStefan Hajnoczi } 381a843a22aSStefan Hajnoczi } else { 382a843a22aSStefan Hajnoczi required = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), 383a843a22aSStefan Hajnoczi BDRV_SECTOR_SIZE); 384a843a22aSStefan Hajnoczi } 385a843a22aSStefan Hajnoczi 3865d72c68bSEric Blake info = g_new0(BlockMeasureInfo, 1); 387a843a22aSStefan Hajnoczi info->required = required; 388a843a22aSStefan Hajnoczi 389a843a22aSStefan Hajnoczi /* Unallocated sectors count towards the file size in raw images */ 390a843a22aSStefan Hajnoczi info->fully_allocated = info->required; 391a843a22aSStefan Hajnoczi return info; 392a843a22aSStefan Hajnoczi } 393a843a22aSStefan Hajnoczi 394a00e70c0SEmanuele Giuseppe Esposito static int coroutine_fn GRAPH_RDLOCK 3953d47eb0aSEmanuele Giuseppe Esposito raw_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) 3962e6fc7ebSEric Blake { 3973d47eb0aSEmanuele Giuseppe Esposito return bdrv_co_get_info(bs->file->bs, bdi); 3982e6fc7ebSEric Blake } 3992e6fc7ebSEric Blake 4002e6fc7ebSEric Blake static void raw_refresh_limits(BlockDriverState *bs, Error **errp) 4012e6fc7ebSEric Blake { 4028c6f27e7SPaolo Bonzini bs->bl.has_variable_length = bs->file->bs->bl.has_variable_length; 4038c6f27e7SPaolo Bonzini 4042e6fc7ebSEric Blake if (bs->probed) { 4052e6fc7ebSEric Blake /* To make it easier to protect the first sector, any probed 4062e6fc7ebSEric Blake * image is restricted to read-modify-write on sub-sector 4072e6fc7ebSEric Blake * operations. */ 4082e6fc7ebSEric Blake bs->bl.request_alignment = BDRV_SECTOR_SIZE; 4092e6fc7ebSEric Blake } 4102e6fc7ebSEric Blake } 4112e6fc7ebSEric Blake 412c2b8e315SKevin Wolf static int coroutine_fn GRAPH_RDLOCK 413c2b8e315SKevin Wolf raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, 414c2b8e315SKevin Wolf PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) 4152e6fc7ebSEric Blake { 4162e6fc7ebSEric Blake BDRVRawState *s = bs->opaque; 4172e6fc7ebSEric Blake 4182e6fc7ebSEric Blake if (s->has_size) { 419f59adb32SMax Reitz error_setg(errp, "Cannot resize fixed-size raw disks"); 4202e6fc7ebSEric Blake return -ENOTSUP; 4212e6fc7ebSEric Blake } 4222e6fc7ebSEric Blake 4232e6fc7ebSEric Blake if (INT64_MAX - offset < s->offset) { 424f59adb32SMax Reitz error_setg(errp, "Disk size too large for the chosen offset"); 4252e6fc7ebSEric Blake return -EINVAL; 4262e6fc7ebSEric Blake } 4272e6fc7ebSEric Blake 4282e6fc7ebSEric Blake s->size = offset; 4292e6fc7ebSEric Blake offset += s->offset; 4301ddaabaeSKevin Wolf return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp); 4312e6fc7ebSEric Blake } 4322e6fc7ebSEric Blake 43379a292e5SKevin Wolf static void coroutine_fn GRAPH_RDLOCK 43479a292e5SKevin Wolf raw_co_eject(BlockDriverState *bs, bool eject_flag) 4352e6fc7ebSEric Blake { 4362531b390SEmanuele Giuseppe Esposito bdrv_co_eject(bs->file->bs, eject_flag); 4372e6fc7ebSEric Blake } 4382e6fc7ebSEric Blake 43979a292e5SKevin Wolf static void coroutine_fn GRAPH_RDLOCK 44079a292e5SKevin Wolf raw_co_lock_medium(BlockDriverState *bs, bool locked) 4412e6fc7ebSEric Blake { 4422c75261cSEmanuele Giuseppe Esposito bdrv_co_lock_medium(bs->file->bs, locked); 4432e6fc7ebSEric Blake } 4442e6fc7ebSEric Blake 44526c518abSKevin Wolf static int coroutine_fn GRAPH_RDLOCK 44626c518abSKevin Wolf raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) 4472e6fc7ebSEric Blake { 4482e6fc7ebSEric Blake BDRVRawState *s = bs->opaque; 4492e6fc7ebSEric Blake if (s->offset || s->has_size) { 4502e6fc7ebSEric Blake return -ENOTSUP; 4512e6fc7ebSEric Blake } 4522e6fc7ebSEric Blake return bdrv_co_ioctl(bs->file->bs, req, buf); 4532e6fc7ebSEric Blake } 4542e6fc7ebSEric Blake 4552e6fc7ebSEric Blake static int raw_has_zero_init(BlockDriverState *bs) 4562e6fc7ebSEric Blake { 4572e6fc7ebSEric Blake return bdrv_has_zero_init(bs->file->bs); 4582e6fc7ebSEric Blake } 4592e6fc7ebSEric Blake 4604db7ba3bSKevin Wolf static int coroutine_fn GRAPH_UNLOCKED 4614ec8df01SKevin Wolf raw_co_create_opts(BlockDriver *drv, const char *filename, 4624ec8df01SKevin Wolf QemuOpts *opts, Error **errp) 4632e6fc7ebSEric Blake { 4642475a0d0SEmanuele Giuseppe Esposito return bdrv_co_create_file(filename, opts, errp); 4652e6fc7ebSEric Blake } 4662e6fc7ebSEric Blake 4672e6fc7ebSEric Blake static int raw_open(BlockDriverState *bs, QDict *options, int flags, 4682e6fc7ebSEric Blake Error **errp) 4692e6fc7ebSEric Blake { 4702e6fc7ebSEric Blake BDRVRawState *s = bs->opaque; 4716e012159SKevin Wolf AioContext *ctx; 472500e2434SMax Reitz bool has_size; 473500e2434SMax Reitz uint64_t offset, size; 47458944401SMax Reitz BdrvChildRole file_role; 4752e6fc7ebSEric Blake int ret; 4762e6fc7ebSEric Blake 477500e2434SMax Reitz ret = raw_read_options(options, &offset, &has_size, &size, errp); 478500e2434SMax Reitz if (ret < 0) { 479500e2434SMax Reitz return ret; 480500e2434SMax Reitz } 481500e2434SMax Reitz 48258944401SMax Reitz /* 48358944401SMax Reitz * Without offset and a size limit, this driver behaves very much 48458944401SMax Reitz * like a filter. With any such limit, it does not. 48558944401SMax Reitz */ 48658944401SMax Reitz if (offset || has_size) { 48758944401SMax Reitz file_role = BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY; 48858944401SMax Reitz } else { 48958944401SMax Reitz file_role = BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY; 49058944401SMax Reitz } 49158944401SMax Reitz 4925bb04747SVladimir Sementsov-Ogievskiy bdrv_open_child(NULL, options, "file", bs, &child_of_bds, 49358944401SMax Reitz file_role, false, errp); 4944e4bf5c4SKevin Wolf if (!bs->file) { 4954e4bf5c4SKevin Wolf return -EINVAL; 4964e4bf5c4SKevin Wolf } 4974e4bf5c4SKevin Wolf 498006e1962SDenis V. Lunev bs->sg = bdrv_is_sg(bs->file->bs); 499228345bfSMax Reitz bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | 500228345bfSMax Reitz (BDRV_REQ_FUA & bs->file->bs->supported_write_flags); 501228345bfSMax Reitz bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | 50280f5c33fSKevin Wolf ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & 503228345bfSMax Reitz bs->file->bs->supported_zero_flags); 5041ddaabaeSKevin Wolf bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags & 5051ddaabaeSKevin Wolf BDRV_REQ_ZERO_WRITE; 5062e6fc7ebSEric Blake 5072e6fc7ebSEric Blake if (bs->probed && !bdrv_is_read_only(bs)) { 508b7cfc7d5SKevin Wolf bdrv_graph_rdlock_main_loop(); 509f30c66baSMax Reitz bdrv_refresh_filename(bs->file->bs); 510b7cfc7d5SKevin Wolf bdrv_graph_rdunlock_main_loop(); 5112e6fc7ebSEric Blake fprintf(stderr, 5122e6fc7ebSEric Blake "WARNING: Image format was not specified for '%s' and probing " 5132e6fc7ebSEric Blake "guessed raw.\n" 5142e6fc7ebSEric Blake " Automatically detecting the format is dangerous for " 5152e6fc7ebSEric Blake "raw images, write operations on block 0 will be restricted.\n" 5162e6fc7ebSEric Blake " Specify the 'raw' format explicitly to remove the " 5172e6fc7ebSEric Blake "restrictions.\n", 5182e6fc7ebSEric Blake bs->file->bs->filename); 5192e6fc7ebSEric Blake } 5202e6fc7ebSEric Blake 5216e012159SKevin Wolf ctx = bdrv_get_aio_context(bs); 5226e012159SKevin Wolf aio_context_acquire(ctx); 523500e2434SMax Reitz ret = raw_apply_options(bs, s, offset, has_size, size, errp); 5246e012159SKevin Wolf aio_context_release(ctx); 5256e012159SKevin Wolf 5262e6fc7ebSEric Blake if (ret < 0) { 5272e6fc7ebSEric Blake return ret; 5282e6fc7ebSEric Blake } 5292e6fc7ebSEric Blake 530006e1962SDenis V. Lunev if (bdrv_is_sg(bs) && (s->offset || s->has_size)) { 5312e6fc7ebSEric Blake error_setg(errp, "Cannot use offset/size with SCSI generic devices"); 5322e6fc7ebSEric Blake return -EINVAL; 5332e6fc7ebSEric Blake } 5342e6fc7ebSEric Blake 5352e6fc7ebSEric Blake return 0; 5362e6fc7ebSEric Blake } 5372e6fc7ebSEric Blake 5382e6fc7ebSEric Blake static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) 5392e6fc7ebSEric Blake { 5402e6fc7ebSEric Blake /* smallest possible positive score so that raw is used if and only if no 5412e6fc7ebSEric Blake * other block driver works 5422e6fc7ebSEric Blake */ 5432e6fc7ebSEric Blake return 1; 5442e6fc7ebSEric Blake } 5452e6fc7ebSEric Blake 546221caadcSKevin Wolf static int GRAPH_RDLOCK 547221caadcSKevin Wolf raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz) 5482e6fc7ebSEric Blake { 5492e6fc7ebSEric Blake BDRVRawState *s = bs->opaque; 5502e6fc7ebSEric Blake int ret; 5512e6fc7ebSEric Blake 5522e6fc7ebSEric Blake ret = bdrv_probe_blocksizes(bs->file->bs, bsz); 5532e6fc7ebSEric Blake if (ret < 0) { 5542e6fc7ebSEric Blake return ret; 5552e6fc7ebSEric Blake } 5562e6fc7ebSEric Blake 5572e6fc7ebSEric Blake if (!QEMU_IS_ALIGNED(s->offset, MAX(bsz->log, bsz->phys))) { 5582e6fc7ebSEric Blake return -ENOTSUP; 5592e6fc7ebSEric Blake } 5602e6fc7ebSEric Blake 5612e6fc7ebSEric Blake return 0; 5622e6fc7ebSEric Blake } 5632e6fc7ebSEric Blake 5642e6fc7ebSEric Blake static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo) 5652e6fc7ebSEric Blake { 5662e6fc7ebSEric Blake BDRVRawState *s = bs->opaque; 5672e6fc7ebSEric Blake if (s->offset || s->has_size) { 5682e6fc7ebSEric Blake return -ENOTSUP; 5692e6fc7ebSEric Blake } 5702e6fc7ebSEric Blake return bdrv_probe_geometry(bs->file->bs, geo); 5712e6fc7ebSEric Blake } 5722e6fc7ebSEric Blake 573742bf09bSEmanuele Giuseppe Esposito static int coroutine_fn GRAPH_RDLOCK 574742bf09bSEmanuele Giuseppe Esposito raw_co_copy_range_from(BlockDriverState *bs, 575742bf09bSEmanuele Giuseppe Esposito BdrvChild *src, int64_t src_offset, 576742bf09bSEmanuele Giuseppe Esposito BdrvChild *dst, int64_t dst_offset, 577742bf09bSEmanuele Giuseppe Esposito int64_t bytes, BdrvRequestFlags read_flags, 57867b51fb9SVladimir Sementsov-Ogievskiy BdrvRequestFlags write_flags) 57972d219e2SFam Zheng { 58072d219e2SFam Zheng int ret; 58172d219e2SFam Zheng 58248535049SVladimir Sementsov-Ogievskiy ret = raw_adjust_offset(bs, &src_offset, bytes, false); 58372d219e2SFam Zheng if (ret) { 58472d219e2SFam Zheng return ret; 58572d219e2SFam Zheng } 58672d219e2SFam Zheng return bdrv_co_copy_range_from(bs->file, src_offset, dst, dst_offset, 58767b51fb9SVladimir Sementsov-Ogievskiy bytes, read_flags, write_flags); 58872d219e2SFam Zheng } 58972d219e2SFam Zheng 590742bf09bSEmanuele Giuseppe Esposito static int coroutine_fn GRAPH_RDLOCK 591742bf09bSEmanuele Giuseppe Esposito raw_co_copy_range_to(BlockDriverState *bs, 592742bf09bSEmanuele Giuseppe Esposito BdrvChild *src, int64_t src_offset, 593742bf09bSEmanuele Giuseppe Esposito BdrvChild *dst, int64_t dst_offset, 594742bf09bSEmanuele Giuseppe Esposito int64_t bytes, BdrvRequestFlags read_flags, 59567b51fb9SVladimir Sementsov-Ogievskiy BdrvRequestFlags write_flags) 59672d219e2SFam Zheng { 59772d219e2SFam Zheng int ret; 59872d219e2SFam Zheng 59948535049SVladimir Sementsov-Ogievskiy ret = raw_adjust_offset(bs, &dst_offset, bytes, true); 60072d219e2SFam Zheng if (ret) { 60172d219e2SFam Zheng return ret; 60272d219e2SFam Zheng } 60372d219e2SFam Zheng return bdrv_co_copy_range_to(src, src_offset, bs->file, dst_offset, bytes, 60467b51fb9SVladimir Sementsov-Ogievskiy read_flags, write_flags); 60572d219e2SFam Zheng } 60672d219e2SFam Zheng 6072654267cSMax Reitz static const char *const raw_strong_runtime_opts[] = { 6082654267cSMax Reitz "offset", 6092654267cSMax Reitz "size", 6102654267cSMax Reitz 6112654267cSMax Reitz NULL 6122654267cSMax Reitz }; 6132654267cSMax Reitz 6143fc1ec37SVladimir Sementsov-Ogievskiy static void raw_cancel_in_flight(BlockDriverState *bs) 6153fc1ec37SVladimir Sementsov-Ogievskiy { 6163fc1ec37SVladimir Sementsov-Ogievskiy bdrv_cancel_in_flight(bs->file->bs); 6173fc1ec37SVladimir Sementsov-Ogievskiy } 6183fc1ec37SVladimir Sementsov-Ogievskiy 619b68ce824SStefan Hajnoczi static void raw_child_perm(BlockDriverState *bs, BdrvChild *c, 620b68ce824SStefan Hajnoczi BdrvChildRole role, 621b68ce824SStefan Hajnoczi BlockReopenQueue *reopen_queue, 622b68ce824SStefan Hajnoczi uint64_t parent_perm, uint64_t parent_shared, 623b68ce824SStefan Hajnoczi uint64_t *nperm, uint64_t *nshared) 624b68ce824SStefan Hajnoczi { 625b68ce824SStefan Hajnoczi bdrv_default_perms(bs, c, role, reopen_queue, parent_perm, 626b68ce824SStefan Hajnoczi parent_shared, nperm, nshared); 627b68ce824SStefan Hajnoczi 628b68ce824SStefan Hajnoczi /* 629b68ce824SStefan Hajnoczi * bdrv_default_perms() may add WRITE and/or RESIZE (see comment in 630b68ce824SStefan Hajnoczi * bdrv_default_perms_for_storage() for an explanation) but we only need 631b68ce824SStefan Hajnoczi * them if they are in parent_perm. Drop WRITE and RESIZE whenever possible 632b68ce824SStefan Hajnoczi * to avoid permission conflicts. 633b68ce824SStefan Hajnoczi */ 634b68ce824SStefan Hajnoczi *nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); 635b68ce824SStefan Hajnoczi *nperm |= parent_perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE); 636b68ce824SStefan Hajnoczi } 637b68ce824SStefan Hajnoczi 6382e6fc7ebSEric Blake BlockDriver bdrv_raw = { 6392e6fc7ebSEric Blake .format_name = "raw", 6402e6fc7ebSEric Blake .instance_size = sizeof(BDRVRawState), 641774c726cSSam Li .supports_zoned_children = true, 6422e6fc7ebSEric Blake .bdrv_probe = &raw_probe, 6432e6fc7ebSEric Blake .bdrv_reopen_prepare = &raw_reopen_prepare, 6442e6fc7ebSEric Blake .bdrv_reopen_commit = &raw_reopen_commit, 6452e6fc7ebSEric Blake .bdrv_reopen_abort = &raw_reopen_abort, 6462e6fc7ebSEric Blake .bdrv_open = &raw_open, 647b68ce824SStefan Hajnoczi .bdrv_child_perm = raw_child_perm, 648efc75e2aSStefan Hajnoczi .bdrv_co_create_opts = &raw_co_create_opts, 6492e6fc7ebSEric Blake .bdrv_co_preadv = &raw_co_preadv, 6502e6fc7ebSEric Blake .bdrv_co_pwritev = &raw_co_pwritev, 6512e6fc7ebSEric Blake .bdrv_co_pwrite_zeroes = &raw_co_pwrite_zeroes, 6522e6fc7ebSEric Blake .bdrv_co_pdiscard = &raw_co_pdiscard, 65350c4bcd4SSam Li .bdrv_co_zone_report = &raw_co_zone_report, 65450c4bcd4SSam Li .bdrv_co_zone_mgmt = &raw_co_zone_mgmt, 6554751d09aSSam Li .bdrv_co_zone_append = &raw_co_zone_append, 656d41aa7e3SEric Blake .bdrv_co_block_status = &raw_co_block_status, 65772d219e2SFam Zheng .bdrv_co_copy_range_from = &raw_co_copy_range_from, 65872d219e2SFam Zheng .bdrv_co_copy_range_to = &raw_co_copy_range_to, 659061ca8a3SKevin Wolf .bdrv_co_truncate = &raw_co_truncate, 660c86422c5SEmanuele Giuseppe Esposito .bdrv_co_getlength = &raw_co_getlength, 661d67066d8SMax Reitz .is_format = true, 662a843a22aSStefan Hajnoczi .bdrv_measure = &raw_measure, 6633d47eb0aSEmanuele Giuseppe Esposito .bdrv_co_get_info = &raw_co_get_info, 6642e6fc7ebSEric Blake .bdrv_refresh_limits = &raw_refresh_limits, 6652e6fc7ebSEric Blake .bdrv_probe_blocksizes = &raw_probe_blocksizes, 6662e6fc7ebSEric Blake .bdrv_probe_geometry = &raw_probe_geometry, 6672531b390SEmanuele Giuseppe Esposito .bdrv_co_eject = &raw_co_eject, 6682c75261cSEmanuele Giuseppe Esposito .bdrv_co_lock_medium = &raw_co_lock_medium, 6692e6fc7ebSEric Blake .bdrv_co_ioctl = &raw_co_ioctl, 6702e6fc7ebSEric Blake .create_opts = &raw_create_opts, 6712654267cSMax Reitz .bdrv_has_zero_init = &raw_has_zero_init, 6722654267cSMax Reitz .strong_runtime_opts = raw_strong_runtime_opts, 6738a2ce0bcSAlberto Garcia .mutable_opts = mutable_opts, 6743fc1ec37SVladimir Sementsov-Ogievskiy .bdrv_cancel_in_flight = raw_cancel_in_flight, 6752e6fc7ebSEric Blake }; 6762e6fc7ebSEric Blake 6772e6fc7ebSEric Blake static void bdrv_raw_init(void) 6782e6fc7ebSEric Blake { 6792e6fc7ebSEric Blake bdrv_register(&bdrv_raw); 6802e6fc7ebSEric Blake } 6812e6fc7ebSEric Blake 6822e6fc7ebSEric Blake block_init(bdrv_raw_init); 683