hw/block: Request permissions

This makes all device emulations with a qdev drive property request
permissions on their BlockBackend. The only thing we block at this point
is resizing images for some devices that can't support it.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Acked-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Kevin Wolf 2017-01-24 13:43:31 +01:00
parent 39829a01ae
commit a17c17a274
17 changed files with 142 additions and 27 deletions

View File

@ -51,11 +51,31 @@ void blkconf_blocksizes(BlockConf *conf)
}
}
void blkconf_apply_backend_options(BlockConf *conf)
void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
bool resizable, Error **errp)
{
BlockBackend *blk = conf->blk;
BlockdevOnError rerror, werror;
uint64_t perm, shared_perm;
bool wce;
int ret;
perm = BLK_PERM_CONSISTENT_READ;
if (!readonly) {
perm |= BLK_PERM_WRITE;
}
/* TODO Remove BLK_PERM_WRITE unless explicitly configured so */
shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
BLK_PERM_GRAPH_MOD | BLK_PERM_WRITE;
if (resizable) {
shared_perm |= BLK_PERM_RESIZE;
}
ret = blk_set_perm(blk, perm, shared_perm, errp);
if (ret < 0) {
return;
}
switch (conf->wce) {
case ON_OFF_AUTO_ON: wce = true; break;

View File

@ -186,6 +186,7 @@ typedef enum FDiskFlags {
struct FDrive {
FDCtrl *fdctrl;
BlockBackend *blk;
BlockConf *conf;
/* Drive status */
FloppyDriveType drive; /* CMOS drive type */
uint8_t perpendicular; /* 2.88 MB access mode */
@ -472,6 +473,19 @@ static void fd_revalidate(FDrive *drv)
static void fd_change_cb(void *opaque, bool load, Error **errp)
{
FDrive *drive = opaque;
Error *local_err = NULL;
if (!load) {
blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
} else {
blkconf_apply_backend_options(drive->conf,
blk_is_read_only(drive->blk), false,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
drive->media_changed = 1;
drive->media_validated = false;
@ -508,6 +522,7 @@ static int floppy_drive_init(DeviceState *qdev)
FloppyDrive *dev = FLOPPY_DRIVE(qdev);
FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
FDrive *drive;
Error *local_err = NULL;
int ret;
if (dev->unit == -1) {
@ -533,7 +548,6 @@ static int floppy_drive_init(DeviceState *qdev)
if (!dev->conf.blk) {
/* Anonymous BlockBackend for an empty drive */
/* FIXME Use real permissions */
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
ret = blk_attach_dev(dev->conf.blk, qdev);
assert(ret == 0);
@ -552,7 +566,13 @@ static int floppy_drive_init(DeviceState *qdev)
* blkconf_apply_backend_options(). */
dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
blkconf_apply_backend_options(&dev->conf);
blkconf_apply_backend_options(&dev->conf, blk_is_read_only(dev->conf.blk),
false, &local_err);
if (local_err) {
error_report_err(local_err);
return -1;
}
/* 'enospc' is the default for -drive, 'report' is what blk_new() gives us
* for empty drives. */
@ -566,6 +586,7 @@ static int floppy_drive_init(DeviceState *qdev)
return -1;
}
drive->conf = &dev->conf;
drive->blk = dev->conf.blk;
drive->fdctrl = bus->fdc;

View File

@ -1215,6 +1215,7 @@ static void m25p80_realize(SSISlave *ss, Error **errp)
{
Flash *s = M25P80(ss);
M25P80Class *mc = M25P80_GET_CLASS(s);
int ret;
s->pi = mc->pi;
@ -1222,6 +1223,13 @@ static void m25p80_realize(SSISlave *ss, Error **errp)
s->dirty_page = -1;
if (s->blk) {
uint64_t perm = BLK_PERM_CONSISTENT_READ |
(blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE);
ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
if (ret < 0) {
return;
}
DB_PRINT_L(0, "Binding to IF_MTD drive\n");
s->storage = blk_blockalign(s->blk, s->size);

View File

@ -373,6 +373,8 @@ static void nand_realize(DeviceState *dev, Error **errp)
{
int pagesize;
NANDFlashState *s = NAND(dev);
int ret;
s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
s->size = nand_flash_ids[s->chip_id].size << 20;
@ -407,6 +409,11 @@ static void nand_realize(DeviceState *dev, Error **errp)
error_setg(errp, "Can't use a read-only drive");
return;
}
ret = blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
BLK_PERM_ALL, errp);
if (ret < 0) {
return;
}
if (blk_getlength(s->blk) >=
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
pagesize = 0;

View File

@ -835,6 +835,7 @@ static int nvme_init(PCIDevice *pci_dev)
int i;
int64_t bs_size;
uint8_t *pci_conf;
Error *local_err = NULL;
if (!n->conf.blk) {
return -1;
@ -850,7 +851,12 @@ static int nvme_init(PCIDevice *pci_dev)
return -1;
}
blkconf_blocksizes(&n->conf);
blkconf_apply_backend_options(&n->conf);
blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
false, &local_err);
if (local_err) {
error_report_err(local_err);
return -1;
}
pci_conf = pci_dev->config;
pci_conf[PCI_INTERRUPT_PIN] = 1;

View File

@ -778,6 +778,7 @@ static int onenand_initfn(SysBusDevice *sbd)
OneNANDState *s = ONE_NAND(dev);
uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
void *ram;
Error *local_err = NULL;
s->base = (hwaddr)-1;
s->rdy = NULL;
@ -796,6 +797,12 @@ static int onenand_initfn(SysBusDevice *sbd)
error_report("Can't use a read-only drive");
return -1;
}
blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
BLK_PERM_ALL, &local_err);
if (local_err) {
error_report_err(local_err);
return -1;
}
s->blk_cur = s->blk;
}
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),

View File

@ -757,6 +757,18 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
if (pfl->blk) {
uint64_t perm;
pfl->ro = blk_is_read_only(pfl->blk);
perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
if (ret < 0) {
return;
}
} else {
pfl->ro = 0;
}
if (pfl->blk) {
/* read the initial flash content */
ret = blk_pread(pfl->blk, 0, pfl->storage, total_len);
@ -768,12 +780,6 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
}
}
if (pfl->blk) {
pfl->ro = blk_is_read_only(pfl->blk);
} else {
pfl->ro = 0;
}
/* Default to devices being used at their maximum device width. This was
* assumed before the device_width support was added.
*/

View File

@ -632,6 +632,19 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
pfl->chip_len = chip_len;
if (pfl->blk) {
uint64_t perm;
pfl->ro = blk_is_read_only(pfl->blk);
perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
if (ret < 0) {
return;
}
} else {
pfl->ro = 0;
}
if (pfl->blk) {
/* read the initial flash content */
ret = blk_pread(pfl->blk, 0, pfl->storage, chip_len);
@ -646,12 +659,6 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
pfl->rom_mode = 1;
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
if (pfl->blk) {
pfl->ro = blk_is_read_only(pfl->blk);
} else {
pfl->ro = 0;
}
pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl);
pfl->wcycle = 0;
pfl->cmd = 0;

View File

@ -928,7 +928,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
}
blkconf_serial(&conf->conf, &conf->serial);
blkconf_apply_backend_options(&conf->conf);
blkconf_apply_backend_options(&conf->conf,
blk_is_read_only(conf->conf.blk), true,
&err);
if (err) {
error_propagate(errp, err);
return;
}
s->original_wce = blk_enable_write_cache(conf->conf.blk);
blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err);
if (err) {

View File

@ -79,7 +79,6 @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
if (!blk) {
BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
if (bs) {
/* FIXME Use real permissions */
blk = blk_new(0, BLK_PERM_ALL);
blk_created = true;

View File

@ -170,7 +170,6 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
return -1;
} else {
/* Anonymous BlockBackend for an empty drive */
/* FIXME Use real permissions */
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
}
}
@ -197,7 +196,12 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
return -1;
}
}
blkconf_apply_backend_options(&dev->conf);
blkconf_apply_backend_options(&dev->conf, kind == IDE_CD, kind != IDE_CD,
&err);
if (err) {
error_report_err(err);
return -1;
}
if (ide_init_drive(s, dev->conf.blk, kind,
dev->version, dev->serial, dev->model, dev->wwn,

View File

@ -141,9 +141,17 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static void spapr_nvram_realize(VIOsPAPRDevice *dev, Error **errp)
{
sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
int ret;
if (nvram->blk) {
nvram->size = blk_getlength(nvram->blk);
ret = blk_set_perm(nvram->blk,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
BLK_PERM_ALL, errp);
if (ret < 0) {
return;
}
} else {
nvram->size = DEFAULT_NVRAM_SIZE;
}

View File

@ -2328,7 +2328,13 @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
return;
}
}
blkconf_apply_backend_options(&dev->conf);
blkconf_apply_backend_options(&dev->conf,
blk_is_read_only(s->qdev.conf.blk),
dev->type == TYPE_DISK, &err);
if (err) {
error_propagate(errp, err);
return;
}
if (s->qdev.conf.discard_granularity == -1) {
s->qdev.conf.discard_granularity =
@ -2380,7 +2386,6 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
if (!dev->conf.blk) {
/* FIXME Use real permissions */
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
}

View File

@ -1887,6 +1887,7 @@ static void sd_instance_finalize(Object *obj)
static void sd_realize(DeviceState *dev, Error **errp)
{
SDState *sd = SD_CARD(dev);
int ret;
if (sd->blk && blk_is_read_only(sd->blk)) {
error_setg(errp, "Cannot use read-only drive as SD card");
@ -1894,6 +1895,11 @@ static void sd_realize(DeviceState *dev, Error **errp)
}
if (sd->blk) {
ret = blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
BLK_PERM_ALL, errp);
if (ret < 0) {
return;
}
blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
}
}

View File

@ -603,7 +603,11 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
blkconf_serial(&s->conf, &dev->serial);
blkconf_blocksizes(&s->conf);
blkconf_apply_backend_options(&s->conf);
blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, &err);
if (err) {
error_propagate(errp, err);
return;
}
/*
* Hack alert: this pretends to be a block device, but it's really

View File

@ -73,7 +73,8 @@ void blkconf_geometry(BlockConf *conf, int *trans,
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
Error **errp);
void blkconf_blocksizes(BlockConf *conf);
void blkconf_apply_backend_options(BlockConf *conf);
void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
bool resizable, Error **errp);
/* Hard disk geometry */

View File

@ -179,7 +179,7 @@ qququiquit
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: Can't use a read-only drive
(qemu) QEMU_PROG: Block node is read-only
QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on
@ -201,12 +201,12 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Block node is read-only
QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Block node is read-only
QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk