Block patches for stable-0.14
The following changes since commit fd08f20c23465c82c62187d463dacc6d00f79508:
do not pass NULL to strdup. (2011-02-04 21:23:05 +0100)
are available in the git repository at:
git://repo.or.cz/qemu/kevin.git for-stable-0.14
Alexander Graf (5):
ahci: add license header in ahci.h
ahci: split ICH and AHCI even more
ahci: send init d2h fis on fis enable
ahci: Implement HBA reset
ahci: make number of ports runtime determined
Kevin Wolf (1):
qcow2: Really use cache=unsafe for image creation
MORITA Kazutaka (1):
Documentation: add Sheepdog disk images
Marcelo Tosatti (5):
block-migration: actually disable dirty tracking on cleanup
blockdev: add refcount to DriveInfo
block-migration: add reference to target DriveInfo Add flag to indicate external users to block device
block: enable in_use flag
Sebastian Herbszt (1):
ahci: split ICH9 from core
Stefan Weil (1):
block/vdi: Fix wrong size in conditionally used memset, memcmp
Makefile.objs | 1 + block-migration.c | 9 +- block.c | 13 ++ block.h | 2 + block/qcow2.c | 3 +- block/vdi.c | 4 +- block_int.h | 1 + blockdev.c | 22 +++- blockdev.h | 4 +- hw/ide/ahci.c | 485 +++++++---------------------------------------------- hw/ide/ahci.h | 333 ++++++++++++++++++++++++++++++++++++ hw/ide/ich.c | 148 ++++++++++++++++ hw/pci-hotplug.c | 2 +- qemu-doc.texi | 52 ++++++ 14 files changed, 642 insertions(+), 437 deletions(-) create mode 100644 hw/ide/ahci.h create mode 100644 hw/ide/ich.c
PATCH 1/14 qcow2: Really use cache=unsafe for image creation
For cache=unsafe we also need to set BDRV_O_CACHE_WB, otherwise we have some strange unsafe writethrough mode.
--- block/qcow2.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
block/qcow2.c +2 -1
@@ -975,7 +975,8 @@ static int qcow2_create2(const char *filename, int64_t total_size,*/ BlockDriver * drv =bdrv_find_format ("qcow2" );assert (drv !=NULL ); - ret =bdrv_open (bs, filename,BDRV_O_RDWR |BDRV_O_NO_FLUSH , drv); + ret =bdrv_open (bs, filename, +BDRV_O_RDWR |BDRV_O_CACHE_WB |BDRV_O_NO_FLUSH , drv);if (ret <0 ) { goto out; }
Signature · 1 line
1.7.2.3
PATCH 2/14 Documentation: add Sheepdog disk images
In reply to Kevin WolfFrom: MORITA Kazutaka <[email protected]>
--- qemu-doc.texi | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 52 insertions(+), 0 deletions(-)
qemu-doc.texi +52 -0
@@ -407,6 +407,7 @@ snapshots. * host_drives:: Using host drives * disk_images_fat_images:: Virtual FAT disk images * disk_images_nbd:: NBD access +* disk_images_sheepdog:: Sheepdog disk images @end menu @node disk_images_quickstart
@@ -630,6 +631,57 @@ qemu -cdrom nbd:localhost:exportname=debian-500-ppc-netinst qemu -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst @end example +@node disk_images_sheepdog +@subsection Sheepdog disk images + +Sheepdog is a distributed storage system for QEMU. It provides highly +available block level storage volumes that can be attached to +QEMU-based virtual machines. + +You can create a Sheepdog disk image with the command: +@example +qemu-img create sheepdog:@var{image} @var{size} +@end example +where @var{image} is the Sheepdog image name and @var{size} is its +size. + +To import the existing @var{filename} to Sheepdog, you can use a +convert command. +@example +qemu-img convert @var{filename} sheepdog:@var{image} +@end example + +You can boot from the Sheepdog disk image with the command: +@example +qemu sheepdog:@var{image} +@end example + +You can also create a snapshot of the Sheepdog image like qcow2. +@example +qemu-img snapshot -c @var{tag} sheepdog:@var{image} +@end example +where @var{tag} is a tag name of the newly created snapshot. + +To boot from the Sheepdog snapshot, specify the tag name of the +snapshot. +@example +qemu sheepdog:@var{image}:@var{tag} +@end example + +You can create a cloned image from the existing snapshot. +@example +qemu-img create -b sheepdog:@var{base}:@var{tag} sheepdog:@var{image} +@end example +where @var{base} is a image name of the source snapshot and @var{tag} +is its tag name. + +If the Sheepdog daemon doesn't run on the local host, you need to +specify one of the Sheepdog servers to connect to. +@example +qemu-img create sheepdog:@var{hostname}:@var{port}:@var{image} @var{size} +qemu sheepdog:@var{hostname}:@var{port}:@var{image} +@end example + @node pcsys_network @section Network emulation
Signature · 1 line
1.7.2.3
PATCH 3/14 block/vdi: Fix wrong size in conditionally used memset, memcmp
In reply to Kevin WolfFrom: Stefan Weil <[email protected]>
Error report from cppcheck:block/vdi.c:122: error: Using sizeof for array given as function argument returns the size of pointer. block/vdi.c:128: error: Using sizeof for array given as function argument returns the size of pointer.
Fix both by setting the correct size.
The buggy code is only used when QEMU is build without uuid support. The bug is not critical, so there is no urgent need to apply it to old versions of QEMU.
--- block/vdi.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
block/vdi.c +2 -2
@@ -119,13 +119,13 @@ void uuid_unparse(const uuid_t uu, char *out);#if !defined(CONFIG_UUID )void uuid_generate (uuid_t out) { -memset (out,0 ,sizeof (out)); +memset (out,0 ,sizeof (uuid_t)); }int uuid_is_null (const uuid_t uu) {uuid_t null_uuid = {0 }; -return memcmp (uu, null_uuid,sizeof (uu)) ==0 ; +return memcmp (uu, null_uuid,sizeof (uuid_t)) ==0 ; }void uuid_unparse (const uuid_t uu,char *out)
Signature · 1 line
1.7.2.3
PATCH 4/14 ahci: split ICH9 from core
In reply to Kevin WolfFrom: Sebastian Herbszt <[email protected]>
There are multiple ahci devices out there. The currently implemented ich-9 is only one of the many. So let's split that one out into a separate file to stress the difference.
--- Makefile.objs | 1 + hw/ide/ahci.c | 305 +------------------------------------------------------- hw/ide/ahci.h | 309 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/ide/ich.c | 61 +++++++++++ 4 files changed, 375 insertions(+), 301 deletions(-) create mode 100644 hw/ide/ahci.h create mode 100644 hw/ide/ich.c
Makefile.objs +1 -0
@@ -244,6 +244,7 @@ hw-obj-$(CONFIG_IDE_CMD646) += ide/cmd646.o hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o hw-obj-$(CONFIG_IDE_VIA) += ide/via.o hw-obj-$(CONFIG_AHCI) += ide/ahci.o +hw-obj-$(CONFIG_AHCI) += ide/ich.o # SCSI layer hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
hw/ide/ahci.c +4 -301
335 lines not on this page · raw message
hw/ide/ahci.h new file +309 -0
309 lines not on this page · raw message
hw/ide/ich.c new file +61 -0
61 lines not on this page · raw message
Signature · 1 line
1.7.2.3
PATCH 5/14 ahci: add license header in ahci.h
In reply to Kevin WolfFrom: Alexander Graf <[email protected]>
Due to popular request, this patch adds a license header to ahci.h
--- hw/ide/ahci.h | 23 +++++++++++++++++++++++ 1 files changed, 23 insertions(+), 0 deletions(-)
hw/ide/ahci.h +23 -0
@@ -1,3 +1,26 @@ +/* +* QEMU AHCI Emulation +* +* Copyright (c) 2010 [email protected] +* Copyright (c) 2010 Roland Elek <[email protected]> +* Copyright (c) 2010 Sebastian Herbszt <[email protected]> +* Copyright (c) 2010 Alexander Graf <[email protected]> +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, see <http://www.gnu.org/licenses/>. +* +*/ +#ifndef HW_IDE_AHCI_H #define HW_IDE_AHCI_H
Signature · 1 line
1.7.2.3
PATCH 6/14 ahci: split ICH and AHCI even more
In reply to Kevin WolfFrom: Alexander Graf <[email protected]>
Sebastian's patch already did a pretty good job at splitting up ICH-9 AHCI code and the AHCI core. We need some more though. Copyright was missing, the lspci dump belongs to ICH-9, we don't need the AHCI core to have its own qdev device duplicate.
So let's split them a bit more in this patch, making things easier to read an understand.
--- hw/ide/ahci.c | 110 --------------------------------------------------------- hw/ide/ich.c | 90 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 112 deletions(-)
hw/ide/ahci.c +0 -110
@@ -19,47 +19,6 @@* You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/>. * -* -* lspci dump of a ICH-9 real device in IDE mode (hopefully close enough): -* -* 00:1f.2 SATA controller [0106]: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] (rev 02) (prog-if 01 [AHCI 1.0]) -* Subsystem: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] -* Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+ -* Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx- -* Latency: 0 -* Interrupt: pin B routed to IRQ 222 -* Region 0: I/O ports at d000 [size=8] -* Region 1: I/O ports at cc00 [size=4] -* Region 2: I/O ports at c880 [size=8] -* Region 3: I/O ports at c800 [size=4] -* Region 4: I/O ports at c480 [size=32] -* Region 5: Memory at febf9000 (32-bit, non-prefetchable) [size=2K] -* Capabilities: [80] Message Signalled Interrupts: Mask- 64bit- Count=1/16 Enable+ -* Address: fee0f00c Data: 41d9 -* Capabilities: [70] Power Management version 3 -* Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-) -* Status: D0 PME-Enable- DSel=0 DScale=0 PME- -* Capabilities: [a8] SATA HBA <?> -* Capabilities: [b0] Vendor Specific Information <?> -* Kernel driver in use: ahci -* Kernel modules: ahci -* 00: 86 80 22 29 07 04 b0 02 02 01 06 01 00 00 00 00 -* 10: 01 d0 00 00 01 cc 00 00 81 c8 00 00 01 c8 00 00 -* 20: 81 c4 00 00 00 90 bf fe 00 00 00 00 86 80 22 29 -* 30: 00 00 00 00 80 00 00 00 00 00 00 00 0f 02 00 00 -* 40: 00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00 -* 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -* 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -* 70: 01 a8 03 40 08 00 00 00 00 00 00 00 00 00 00 00 -* 80: 05 70 09 00 0c f0 e0 fe d9 41 00 00 00 00 00 00 -* 90: 40 00 0f 82 93 01 00 00 00 00 00 00 00 00 00 00 -* a0: ac 00 00 00 0a 00 12 00 12 b0 10 00 48 00 00 00 -* b0: 09 00 06 20 00 00 00 00 00 00 00 00 00 00 00 00 -* c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -* d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -* e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -* f0: 00 00 00 00 00 00 00 00 86 0f 02 00 00 00 00 00 -* */ #include <hw/hw.h>
@@ -1155,72 +1114,3 @@ void ahci_reset(void *opaque)ahci_reset_port (&d->ahci, i); } } - -static int pci_ahci_init (PCIDevice *dev) -{ -struct AHCIPCIState *d; - d = DO_UPCAST(struct AHCIPCIState, card, dev); - -pci_config_set_vendor_id (d->card.config,PCI_VENDOR_ID_INTEL ); -pci_config_set_device_id (d->card.config,PCI_DEVICE_ID_INTEL_82801IR ); - -pci_config_set_class (d->card.config,PCI_CLASS_STORAGE_SATA ); -pci_config_set_revision (d->card.config,0x02 ); -pci_config_set_prog_interface (d->card.config,AHCI_PROGMODE_MAJOR_REV_1 ); - - d->card.config[PCI_CACHE_LINE_SIZE ] =0x08 ;/* Cache line size */ - d->card.config[PCI_LATENCY_TIMER ] =0x00 ;/* Latency timer */ -pci_config_set_interrupt_pin (d->card.config,1 ); - -/* XXX Software should program this register */ - d->card.config[0x90 ] =1 <<6 ;/* Address Map Register - AHCI mode */ - -qemu_register_reset (ahci_reset, d); - -/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */ -pci_register_bar (&d->card,5 ,0x1000 ,PCI_BASE_ADDRESS_SPACE_MEMORY , - ahci_pci_map); - -msi_init (dev,0x50 ,1 , true, false); - -ahci_init (&d->ahci, &dev->qdev); - d->ahci.irq = d->card.irq[0 ]; - -return 0 ; -} - -static int pci_ahci_uninit (PCIDevice *dev) -{ -struct AHCIPCIState *d; - d = DO_UPCAST(struct AHCIPCIState, card, dev); - -if (msi_enabled (dev)) { -msi_uninit (dev); - } - -qemu_unregister_reset (ahci_reset, d); - -return 0 ; -} - -static void pci_ahci_write_config (PCIDevice *pci,uint32_t addr, -uint32_t val,int len) -{ -pci_default_write_config (pci, addr, val, len); -msi_write_config (pci, addr, val, len); -} - -static PCIDeviceInfo ahci_info = { - .qdev.name ="ahci" , - .qdev.size =sizeof (AHCIPCIState), - .init = pci_ahci_init, - .exit = pci_ahci_uninit, - .config_write = pci_ahci_write_config, -}; - -static void ahci_pci_register_devices (void ) -{ -pci_qdev_register (&ahci_info); -} - -device_init (ahci_pci_register_devices)
hw/ide/ich.c +88 -2
109 lines not on this page · raw message
Signature · 1 line
1.7.2.3
PATCH 7/14 ahci: send init d2h fis on fis enable
In reply to Kevin WolfFrom: Alexander Graf <[email protected]>
The drive sends a d2h init fis on initialization. Usually, the guest doesn't receive fises yet at that point though, so the delivery is deferred.
Let's reflect that by sending the init fis on fis receive enablement.
--- hw/ide/ahci.c | 38 +++++++++++++++++++++++++++++++------- hw/ide/ahci.h | 1 + 2 files changed, 32 insertions(+), 7 deletions(-)
hw/ide/ahci.c +31 -7
@@ -47,6 +47,7 @@ static void check_cmd(AHCIState *s, int port);static int handle_cmd (AHCIState *s,int port,int slot);static void ahci_reset_port (AHCIState *s,int port);static void ahci_write_fis_d2h (AHCIDevice *ad,uint8_t *cmd_fis); +static void ahci_init_d2h (AHCIDevice *ad);static uint32_t ahci_port_read (AHCIState *s,int port,int offset) {
@@ -230,6 +231,16 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) pr->cmd |=PORT_CMD_FIS_ON ; } +/* XXX usually the FIS would be pending on the bus here and +issuing deferred until the OS enables FIS receival. +Instead, we only submit it once - which works in most +cases, but is a hack. */ +if ((pr->cmd &PORT_CMD_FIS_ON ) && + !s->dev[port].init_d2h_sent) { +ahci_init_d2h (&s->dev[port]); + s->dev[port].init_d2h_sent =1 ; + } +check_cmd (s, port);break ;case PORT_TFDATA :
@@ -462,12 +473,29 @@ static void ahci_check_cmd_bh(void *opaque)check_cmd (ad->hba, ad->port_no); } +static void ahci_init_d2h (AHCIDevice *ad) +{ +uint8_t init_fis[0x20 ]; +IDEState *ide_state = &ad->port.ifs[0 ]; + +memset (init_fis,0 ,sizeof (init_fis)); + + init_fis[4 ] =1 ; + init_fis[12 ] =1 ; + +if (ide_state->drive_kind ==IDE_CD ) { + init_fis[5 ] = ide_state->lcyl; + init_fis[6 ] = ide_state->hcyl; + } + +ahci_write_fis_d2h (ad, init_fis); +} +static void ahci_reset_port (AHCIState *s,int port) {AHCIDevice *d = &s->dev[port];AHCIPortRegs *pr = &d->port_regs;IDEState *ide_state = &d->port.ifs[0 ]; -uint8_t init_fis[0x20 ];int i;DPRINTF (port,"reset port\n" );
@@ -482,6 +510,7 @@ static void ahci_reset_port(AHCIState *s, int port) pr->scr_err =0 ; pr->scr_act =0 ; d->busy_slot =-1 ; + d->init_d2h_sent =0 ; ide_state = &s->dev[port].port.ifs[0 ];if (!ide_state->bs) {
@@ -504,7 +533,6 @@ static void ahci_reset_port(AHCIState *s, int port) ncq_tfs->used =0 ; } -memset (init_fis,0 ,sizeof (init_fis)); s->dev[port].port_state =STATE_RUN ;if (!ide_state->bs) { s->dev[port].port_regs.sig =0 ;
@@ -514,8 +542,6 @@ static void ahci_reset_port(AHCIState *s, int port) ide_state->lcyl =0x14 ; ide_state->hcyl =0xeb ;DPRINTF (port,"set lcyl = %d\n" , ide_state->lcyl); - init_fis[5 ] = ide_state->lcyl; - init_fis[6 ] = ide_state->hcyl; ide_state->status =SEEK_STAT |WRERR_STAT |READY_STAT ; }else { s->dev[port].port_regs.sig =SATA_SIGNATURE_DISK ;
@@ -523,9 +549,7 @@ static void ahci_reset_port(AHCIState *s, int port) } ide_state->error =1 ; - init_fis[4 ] =1 ; - init_fis[12 ] =1 ; -ahci_write_fis_d2h (d, init_fis); +ahci_init_d2h (d); }static void debug_print_fis (uint8_t *fis,int cmd_len)
hw/ide/ahci.h +1 -0
@@ -282,6 +282,7 @@ struct AHCIDevice {int dma_status;int done_atapi_packet;int busy_slot; +int init_d2h_sent;BlockDriverCompletionFunc *dma_cb;AHCICmdHdr *cur_cmd;NCQTransferState ncq_tfs[AHCI_MAX_CMDS ];
Signature · 1 line
1.7.2.3
PATCH 8/14 ahci: Implement HBA reset
In reply to Kevin WolfFrom: Alexander Graf <[email protected]>
The ahci code was missing its soft reset functionality. This wasn't really an issue for Linux guests, but Windows gets confused when the controller doesn't reset when it tells it so.
Using this patch I can now successfully boot Windows 7 from AHCI using AHCI enabled SeaBIOS.
--- hw/ide/ahci.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-)
hw/ide/ahci.c +4 -1
@@ -335,7 +335,7 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)case HOST_CTL :/* R/W */ if (val &HOST_CTL_RESET ) {DPRINTF (-1 ,"HBA Reset\n" ); -/* FIXME reset? */ +ahci_reset (container_of (s, AHCIPCIState, ahci)); }else { s->control_regs.ghc = (val &0x3 ) |HOST_CTL_AHCI_EN ;ahci_check_irq (s);
@@ -1134,6 +1134,9 @@ void ahci_reset(void *opaque)struct AHCIPCIState *d = opaque;int i; + d->ahci.control_regs.irqstatus =0 ; + d->ahci.control_regs.ghc =0 ; +for (i =0 ; i <SATA_PORTS ; i++) {ahci_reset_port (&d->ahci, i); }
Signature · 1 line
1.7.2.3
PATCH 9/14 ahci: make number of ports runtime determined
In reply to Kevin WolfFrom: Alexander Graf <[email protected]>
Different AHCI controllers have a different number of ports, so the core shouldn't care about the amount of ports available.
This patch makes the number of ports available to the AHCI core runtime configurable, allowing us to have multiple different AHCI implementations with different amounts of ports.
--- hw/ide/ahci.c | 29 +++++++++++++++++++---------- hw/ide/ahci.h | 10 +++++----- hw/ide/ich.c | 3 ++- 3 files changed, 26 insertions(+), 16 deletions(-)
hw/ide/ahci.c +19 -10
@@ -145,7 +145,7 @@ static void ahci_check_irq(AHCIState *s)DPRINTF (-1 ,"check irq %#x\n" , s->control_regs.irqstatus); -for (i =0 ; i <SATA_PORTS ; i++) { +for (i =0 ; i < s->ports; i++) {AHCIPortRegs *pr = &s->dev[i].port_regs;if (pr->irq_stat & pr->irq_mask) { s->control_regs.irqstatus |= (1 << i);
@@ -303,7 +303,8 @@ static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)DPRINTF (-1 ,"(addr 0x%08X), val 0x%08X\n" , (unsigned ) addr, val); }else if ((addr >=AHCI_PORT_REGS_START_ADDR ) && - (addr <AHCI_PORT_REGS_END_ADDR )) { + (addr < (AHCI_PORT_REGS_START_ADDR + + (s->ports *AHCI_PORT_ADDR_OFFSET_LEN )))) { val =ahci_port_read (s, (addr -AHCI_PORT_REGS_START_ADDR ) >>7 , addr &AHCI_PORT_ADDR_OFFSET_MASK ); }
@@ -355,7 +356,8 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)DPRINTF (-1 ,"write to unknown register 0x%x\n" , (unsigned )addr); } }else if ((addr >=AHCI_PORT_REGS_START_ADDR ) && - (addr <AHCI_PORT_REGS_END_ADDR )) { + (addr < (AHCI_PORT_REGS_START_ADDR + + (s->ports *AHCI_PORT_ADDR_OFFSET_LEN )))) {ahci_port_write (s, (addr -AHCI_PORT_REGS_START_ADDR ) >>7 , addr &AHCI_PORT_ADDR_OFFSET_MASK , val); }
@@ -378,16 +380,16 @@ static void ahci_reg_init(AHCIState *s) {int i; - s->control_regs.cap = (SATA_PORTS -1 ) | + s->control_regs.cap = (s->ports -1 ) | (AHCI_NUM_COMMAND_SLOTS <<8 ) | (AHCI_SUPPORTED_SPEED_GEN1 <<AHCI_SUPPORTED_SPEED ) |HOST_CAP_NCQ |HOST_CAP_AHCI ; - s->control_regs.impl = (1 <<SATA_PORTS ) -1 ; + s->control_regs.impl = (1 << s->ports) -1 ; s->control_regs.version =AHCI_VERSION_1_0 ; -for (i =0 ; i <SATA_PORTS ; i++) { +for (i =0 ; i < s->ports; i++) { s->dev[i].port_state =STATE_RUN ; } }
@@ -1096,17 +1098,19 @@ static const IDEDMAOps ahci_dma_ops = { .reset = ahci_dma_reset, }; -void ahci_init (AHCIState *s,DeviceState *qdev) +void ahci_init (AHCIState *s,DeviceState *qdev,int ports) {qemu_irq *irqs;int i; + s->ports = ports; + s->dev =qemu_mallocz (sizeof (AHCIDevice) * ports);ahci_reg_init (s); s->mem =cpu_register_io_memory (ahci_readfn, ahci_writefn, s,DEVICE_LITTLE_ENDIAN ); - irqs =qemu_allocate_irqs (ahci_irq_set, s,SATA_PORTS ); + irqs =qemu_allocate_irqs (ahci_irq_set, s, s->ports); -for (i =0 ; i <SATA_PORTS ; i++) { +for (i =0 ; i < s->ports; i++) {AHCIDevice *ad = &s->dev[i];ide_bus_new (&ad->port, qdev, i);
@@ -1120,6 +1124,11 @@ void ahci_init(AHCIState *s, DeviceState *qdev) } } +void ahci_uninit (AHCIState *s) +{ +qemu_free (s->dev); +} +void ahci_pci_map (PCIDevice *pci_dev,int region_num,pcibus_t addr,pcibus_t size,int type) {
@@ -1137,7 +1146,7 @@ void ahci_reset(void *opaque) d->ahci.control_regs.irqstatus =0 ; d->ahci.control_regs.ghc =0 ; -for (i =0 ; i <SATA_PORTS ; i++) { +for (i =0 ; i < d->ahci.ports; i++) {ahci_reset_port (&d->ahci, i); } }
hw/ide/ahci.h +5 -5
@@ -188,11 +188,9 @@#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20/* Shouldn't this be 0x2c? */ -#define SATA_PORTS 4 -#define AHCI_PORT_REGS_START_ADDR 0x100 -#define AHCI_PORT_REGS_END_ADDR (AHCI_PORT_REGS_START_ADDR + SATA_PORTS * 0x80)#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f +#define AHCI_PORT_ADDR_OFFSET_LEN 0x80#define AHCI_NUM_COMMAND_SLOTS 31#define AHCI_SUPPORTED_SPEED 20
@@ -289,9 +287,10 @@ struct AHCIDevice { };typedef struct AHCIState { -AHCIDevice dev[SATA_PORTS ]; +AHCIDevice *dev;AHCIControlRegs control_regs;int mem; +int ports;qemu_irq irq; }AHCIState ;
@@ -323,7 +322,8 @@ typedef struct NCQFrame {uint8_t reserved10; } __attribute__ ((packed)) NCQFrame; -void ahci_init (AHCIState *s,DeviceState *qdev); +void ahci_init (AHCIState *s,DeviceState *qdev,int ports); +void ahci_uninit (AHCIState *s);void ahci_pci_map (PCIDevice *pci_dev,int region_num,pcibus_t addr,pcibus_t size,int type);
hw/ide/ich.c +2 -1
@@ -100,7 +100,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)msi_init (dev,0x50 ,1 , true, false); -ahci_init (&d->ahci, &dev->qdev); +ahci_init (&d->ahci, &dev->qdev,6 ); d->ahci.irq = d->card.irq[0 ];return 0 ;
@@ -116,6 +116,7 @@ static int pci_ich9_uninit(PCIDevice *dev) }qemu_unregister_reset (ahci_reset, d); +ahci_uninit (&d->ahci);return 0 ; }
Signature · 1 line
1.7.2.3
PATCH 10/14 block-migration: actually disable dirty tracking on cleanup
In reply to Kevin WolfFrom: Marcelo Tosatti <[email protected]>
Call to set_dirty_tracking() is misplaced.
--- block-migration.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
block-migration.c +2 -2
@@ -533,6 +533,8 @@ static void blk_mig_cleanup(Monitor *mon)BlkMigDevState *bmds;BlkMigBlock *blk; +set_dirty_tracking (0 ); +while ((bmds =QSIMPLEQ_FIRST (&block_mig_state.bmds_list)) !=NULL ) {QSIMPLEQ_REMOVE_HEAD (&block_mig_state.bmds_list, entry);qemu_free (bmds->aio_bitmap);
@@ -545,8 +547,6 @@ static void blk_mig_cleanup(Monitor *mon)qemu_free (blk); } -set_dirty_tracking (0 ); -monitor_printf (mon,"\n" ); }
Signature · 1 line
1.7.2.3
PATCH 11/14 blockdev: add refcount to DriveInfo
In reply to Kevin WolfFrom: Marcelo Tosatti <[email protected]>
The host part of a block device can be deleted with in progress block migration.
To fix this, add a reference count to DriveInfo, freeing resources on last reference.
--- blockdev.c | 18 ++++++++++++++++-- blockdev.h | 4 +++- hw/pci-hotplug.c | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-)
blockdev.c +16 -2
@@ -71,7 +71,7 @@ void blockdev_auto_del(BlockDriverState *bs)DriveInfo *dinfo =drive_get_by_blockdev (bs);if (dinfo && dinfo->auto_del) { -drive_uninit (dinfo); +drive_put_ref (dinfo); } }
@@ -178,7 +178,7 @@ static void bdrv_format_print(void *opaque, const char *name)error_printf (" %s" , name); } -void drive_uninit (DriveInfo *dinfo) +static void drive_uninit (DriveInfo *dinfo) {qemu_opts_del (dinfo->opts);bdrv_delete (dinfo->bdrv);
@@ -186,6 +186,19 @@ void drive_uninit(DriveInfo *dinfo)qemu_free (dinfo); } +void drive_put_ref (DriveInfo *dinfo) +{ +assert (dinfo->refcount); +if (--dinfo->refcount ==0 ) { +drive_uninit (dinfo); + } +} + +void drive_get_ref (DriveInfo *dinfo) +{ + dinfo->refcount++; +} +static int parse_block_error_action (const char *buf,int is_read) {if (!strcmp (buf,"ignore" )) {
@@ -453,6 +466,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) dinfo->bus = bus_id; dinfo->unit = unit_id; dinfo->opts = opts; + dinfo->refcount =1 ;if (serial)strncpy (dinfo->serial, serial,sizeof (dinfo->serial) -1 );QTAILQ_INSERT_TAIL (&drives, dinfo, next);
blockdev.h +3 -1
@@ -36,13 +36,15 @@ struct DriveInfo {QemuOpts *opts;char serial[BLOCK_SERIAL_STRLEN +1 ];QTAILQ_ENTRY (DriveInfo) next; +int refcount; };DriveInfo *drive_get (BlockInterfaceType type,int bus,int unit);DriveInfo *drive_get_by_index (BlockInterfaceType type,int index);int drive_get_max_bus (BlockInterfaceType type);DriveInfo *drive_get_next (BlockInterfaceType type); -void drive_uninit (DriveInfo *dinfo); +void drive_get_ref (DriveInfo *dinfo); +void drive_put_ref (DriveInfo *dinfo);DriveInfo *drive_get_by_blockdev (BlockDriverState *bs);QemuOpts *drive_def (const char *optstr);
hw/pci-hotplug.c +1 -1
@@ -147,7 +147,7 @@ void drive_hot_add(Monitor *mon, const QDict *qdict) err:if (dinfo) -drive_uninit (dinfo); +drive_put_ref (dinfo);return ; }
Signature · 1 line
1.7.2.3
PATCH 12/14 block-migration: add reference to target DriveInfo
In reply to Kevin WolfFrom: Marcelo Tosatti <[email protected]>
So that ejection of attached device by guest does not free data in use by block migration instance.
--- block-migration.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
block-migration.c +3 -0
@@ -19,6 +19,7 @@#include "monitor.h" #include "block-migration.h" #include "migration.h" +#include "blockdev.h" #include <assert.h> #define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
@@ -299,6 +300,7 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs) bmds->completed_sectors =0 ; bmds->shared_base = block_mig_state.shared_base;alloc_aio_bitmap (bmds); +drive_get_ref (drive_get_by_blockdev (bs)); block_mig_state.total_sector_sum += sectors;
@@ -537,6 +539,7 @@ static void blk_mig_cleanup(Monitor *mon)while ((bmds =QSIMPLEQ_FIRST (&block_mig_state.bmds_list)) !=NULL ) {QSIMPLEQ_REMOVE_HEAD (&block_mig_state.bmds_list, entry); +drive_put_ref (drive_get_by_blockdev (bmds->bs));qemu_free (bmds->aio_bitmap);qemu_free (bmds); }
Signature · 1 line
1.7.2.3
PATCH 13/14 Add flag to indicate external users to block device
In reply to Kevin WolfFrom: Marcelo Tosatti <[email protected]>
Certain operations such as drive_del or resize cannot be performed while external users (eg. block migration) reference the block device.
Add a flag to indicate that.
--- block.c | 11 +++++++++++ block.h | 2 ++ block_int.h | 1 + 3 files changed, 14 insertions(+), 0 deletions(-)
block.c +11 -0
@@ -2774,6 +2774,17 @@ int64_t bdrv_get_dirty_count(BlockDriverState *bs)return bs->dirty_count; } +void bdrv_set_in_use (BlockDriverState *bs,int in_use) +{ +assert (bs->in_use != in_use); + bs->in_use = in_use; +} + +int bdrv_in_use (BlockDriverState *bs) +{ +return bs->in_use; +} +int bdrv_img_create (const char *filename,const char *fmt,const char *base_filename,const char *base_fmt,char *options,uint64_t img_size,int flags)
block.h +2 -0
@@ -241,6 +241,8 @@ void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);int64_t bdrv_get_dirty_count (BlockDriverState *bs); +void bdrv_set_in_use (BlockDriverState *bs,int in_use); +int bdrv_in_use (BlockDriverState *bs); typedef enum { BLKDBG_L1_UPDATE,
block_int.h +1 -0
@@ -199,6 +199,7 @@ struct BlockDriverState {char device_name[32 ];unsigned long *dirty_bitmap;int64_t dirty_count; +int in_use;/* users other than guest access, eg. block migration */ QTAILQ_ENTRY (BlockDriverState) list;void *private; };
Signature · 1 line
1.7.2.3
PATCH 14/14 block: enable in_use flag
In reply to Kevin WolfFrom: Marcelo Tosatti <[email protected]>
Set block device in use during block migration, disallow drive_del and bdrv_truncate for in use devices.
--- block-migration.c | 2 ++ block.c | 2 ++ blockdev.c | 4 ++++ 3 files changed, 8 insertions(+), 0 deletions(-)
block-migration.c +2 -0
@@ -301,6 +301,7 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs) bmds->shared_base = block_mig_state.shared_base;alloc_aio_bitmap (bmds);drive_get_ref (drive_get_by_blockdev (bs)); +bdrv_set_in_use (bs,1 ); block_mig_state.total_sector_sum += sectors;
@@ -539,6 +540,7 @@ static void blk_mig_cleanup(Monitor *mon)while ((bmds =QSIMPLEQ_FIRST (&block_mig_state.bmds_list)) !=NULL ) {QSIMPLEQ_REMOVE_HEAD (&block_mig_state.bmds_list, entry); +bdrv_set_in_use (bmds->bs,0 );drive_put_ref (drive_get_by_blockdev (bmds->bs));qemu_free (bmds->aio_bitmap);qemu_free (bmds);
block.c +2 -0
@@ -1132,6 +1132,8 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)return -ENOTSUP ;if (bs->read_only)return -EACCES ; +if (bdrv_in_use (bs)) +return -EBUSY ; ret = drv->bdrv_truncate (bs, offset);if (ret ==0 ) { ret =refresh_total_sectors (bs, offset >>BDRV_SECTOR_BITS );
blockdev.c +4 -0
@@ -726,6 +726,10 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)qerror_report (QERR_DEVICE_NOT_FOUND , id);return -1 ; } +if (bdrv_in_use (bs)) { +qerror_report (QERR_DEVICE_IN_USE , id); +return -1 ; + }/* quiesce block driver; prevent further io */ qemu_aio_flush ();
Signature · 1 line
1.7.2.3