Skip to contentSkip to conversation

ide: Set BSY bit during FLUSH

PATCH Superseded Kevin Wolf 3 participants 8 messages May 29, 2013 – May 30, 2013 Block layer

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Kevin Wolf

author
#0 lore raw

cover ide: Set BSY bit during FLUSH

The test case depends on the qemu-io series I sent yesterday. ("[PATCH 00/16] Make qemu-io commands available in the monitor")

Andreas Färber (1):
ide: Set BSY bit during FLUSH

Kevin Wolf (2):
blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events
ide-test: Add FLUSH CACHE test case

 block.c               |  8 ++++----
 block/blkdebug.c      |  3 +++
 hw/ide/core.c         |  3 +++
 include/block/block.h |  3 +++
 tests/ide-test.c      | 40 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 53 insertions(+), 4 deletions(-)
Signature · 1 line
1.8.1.4
author
#1 lore raw

PATCH 1/3 blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events

---
 block.c               | 8 ++++----
 block/blkdebug.c      | 3 +++
 include/block/block.h | 3 +++
 3 files changed, 10 insertions(+), 4 deletions(-)
block.c +4 -4
index 3f87489..52a2101 100644
@@ -3307,13 +3307,11 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
 
 void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
 {
-    BlockDriver *drv = bs->drv;
-
-    if (!drv || !drv->bdrv_debug_event) {
+    if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) {
         return;
     }
 
-    drv->bdrv_debug_event(bs, event);
+    bs->drv->bdrv_debug_event(bs, event);
 }
 
 int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
@@ -4326,6 +4324,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
     }
 
     /* Write back cached data to the OS even with cache=unsafe */
+    BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_OS);
     if (bs->drv->bdrv_co_flush_to_os) {
         ret = bs->drv->bdrv_co_flush_to_os(bs);
         if (ret < 0) {
@@ -4338,6 +4337,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
         goto flush_parent;
     }
 
+    BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_DISK);
     if (bs->drv->bdrv_co_flush_to_disk) {
         ret = bs->drv->bdrv_co_flush_to_disk(bs);
     } else if (bs->drv->bdrv_aio_flush) {
block/blkdebug.c +3 -0
index 71f99e4..ccb627a 100644
@@ -182,6 +182,9 @@ static const char *event_names[BLKDBG_EVENT_MAX] = {
     [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
     [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
     [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
+
+    [BLKDBG_FLUSH_TO_OS]                    = "flush_to_os",
+    [BLKDBG_FLUSH_TO_DISK]                  = "flush_to_disk",
 };
 
 static int get_event_by_name(const char *name, BlkDebugEvent *event)
include/block/block.h +3 -0
index 1251c5c..ce350c7 100644
@@ -449,6 +449,9 @@ typedef enum {
     BLKDBG_CLUSTER_ALLOC_BYTES,
     BLKDBG_CLUSTER_FREE,
 
+    BLKDBG_FLUSH_TO_OS,
+    BLKDBG_FLUSH_TO_DISK,
+
     BLKDBG_EVENT_MAX,
 } BlkDebugEvent;
 
Signature · 1 line
1.8.1.4
author
#2 lore raw

PATCH 2/3 ide: Set BSY bit during FLUSH

In reply to Kevin Wolf

From: Andreas Färber <[email protected]>

The implementation of the ATA FLUSH command invokes a flush at the block layer, which may on raw files on POSIX entail a synchronous fdatasync(). This may in some cases take so long that the SLES 11 SP1 guest driver reports I/O errors and filesystems get corrupted or remounted read-only.

Avoid this by setting BUSY_STAT, so that the guest is made aware we are in the middle of an operation and no ATA commands are attempted to be processed concurrently.

Addresses BNC#637297.

---
 hw/ide/core.c | 3 +++
 1 file changed, 3 insertions(+)
hw/ide/core.c +3 -0
index c7a8041..bf1ff18 100644
@@ -795,6 +795,8 @@ static void ide_flush_cb(void *opaque, int ret)
 {
     IDEState *s = opaque;
 
+    s->status &= ~BUSY_STAT;
+
     if (ret < 0) {
         /* XXX: What sector number to set here? */
         if (ide_handle_rw_error(s, -ret, BM_STATUS_RETRY_FLUSH)) {
@@ -814,6 +816,7 @@ void ide_flush_cache(IDEState *s)
         return;
     }
 
+    s->status |= BUSY_STAT;
     bdrv_acct_start(s->bs, &s->acct, 0, BDRV_ACCT_FLUSH);
     bdrv_aio_flush(s->bs, ide_flush_cb, s);
 }
Signature · 1 line
1.8.1.4
#3 lore raw

Am 29.05.2013 13:34, schrieb Kevin Wolf:

Quoted 25 lines

From: Andreas Färber <[email protected]>

The implementation of the ATA FLUSH command invokes a flush at the block layer, which may on raw files on POSIX entail a synchronous fdatasync(). This may in some cases take so long that the SLES 11 SP1 guest driver reports I/O errors and filesystems get corrupted or remounted read-only.

Avoid this by setting BUSY_STAT, so that the guest is made aware we are in the middle of an operation and no ATA commands are attempted to be processed concurrently.

Addresses BNC#637297.

---
 hw/ide/core.c | 3 +++
 1 file changed, 3 insertions(+)
hw/ide/core.c +0 -0
index c7a8041..bf1ff18 100644

hw/ide/core.c static void ide_flush_cb(void *opaque, int ret) · line 802

Quoted 8 lines
hw/ide/core.c +2 -0
@@ -795,6 +795,8 @@ static void ide_flush_cb(void *opaque, int ret)
 {
     IDEState *s = opaque;
 
+    s->status &= ~BUSY_STAT;
+
     if (ret < 0) {
         /* XXX: What sector number to set here? */
         if (ide_handle_rw_error(s, -ret, BM_STATUS_RETRY_FLUSH)) {

Didn't you want this hunk to be dropped?

But thanks for picking the patch up already.

Andreas

Quoted 9 lines
hw/ide/core.c +1 -0
@@ -814,6 +816,7 @@ void ide_flush_cache(IDEState *s)
         return;
     }
 
+    s->status |= BUSY_STAT;
     bdrv_acct_start(s->bs, &s->acct, 0, BDRV_ACCT_FLUSH);
     bdrv_aio_flush(s->bs, ide_flush_cb, s);
 }
Signature · 2 lines
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
author
#4 lore raw

Am 29.05.2013 um 13:50 hat Andreas Färber geschrieben:

Quoted 37 lines

Am 29.05.2013 13:34, schrieb Kevin Wolf:

Quoted 25 lines

From: Andreas Färber <[email protected]>

The implementation of the ATA FLUSH command invokes a flush at the block layer, which may on raw files on POSIX entail a synchronous fdatasync(). This may in some cases take so long that the SLES 11 SP1 guest driver reports I/O errors and filesystems get corrupted or remounted read-only.

Avoid this by setting BUSY_STAT, so that the guest is made aware we are in the middle of an operation and no ATA commands are attempted to be processed concurrently.

Addresses BNC#637297.

---
 hw/ide/core.c | 3 +++
 1 file changed, 3 insertions(+)
hw/ide/core.c +0 -0
index c7a8041..bf1ff18 100644

hw/ide/core.c static void ide_flush_cb(void *opaque, int ret) · line 802

Quoted 8 lines
hw/ide/core.c +2 -0
@@ -795,6 +795,8 @@ static void ide_flush_cb(void *opaque, int ret)
 {
     IDEState *s = opaque;
 
+    s->status &= ~BUSY_STAT;
+
     if (ret < 0) {
         /* XXX: What sector number to set here? */
         if (ide_handle_rw_error(s, -ret, BM_STATUS_RETRY_FLUSH)) {

Didn't you want this hunk to be dropped?

Quoted 1 line

But thanks for picking the patch up already.

Ah, right, dropped it now. Thanks.

Kevin

author
#5 lore raw

PATCH 3/3 ide-test: Add FLUSH CACHE test case

In reply to Kevin Wolf

This checks in particular that BSY is set while the flush request is in flight.

---
 tests/ide-test.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
tests/ide-test.c +40 -0
index 365e995..5744462 100644
@@ -76,6 +76,7 @@ enum {
 enum {
     CMD_READ_DMA    = 0xc8,
     CMD_WRITE_DMA   = 0xca,
+    CMD_FLUSH_CACHE = 0xe7,
     CMD_IDENTIFY    = 0xec,
 
     CMDF_ABORT      = 0x100,
@@ -423,6 +424,43 @@ static void test_identify(void)
     ide_test_quit();
 }
 
+static void test_flush(void)
+{
+    uint8_t data;
+
+    ide_test_start(
+        "-vnc none "
+        "-drive file=blkdebug::%s,if=ide,cache=writeback",
+        tmp_path);
+
+    /* Delay the completion of the flush request until we explicitly do it */
+    qmp("{'execute':'__org.qemu.debug-qemu-io-command', 'arguments': { "
+        "'device': 'ide0-hd0', 'command': 'break flush_to_os A'} }");
+
+    /* FLUSH CACHE command on device 0*/
+    outb(IDE_BASE + reg_device, 0);
+    outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE);
+
+    /* Check status while request is in flight*/
+    data = inb(IDE_BASE + reg_status);
+    assert_bit_set(data, BSY | DRDY);
+    assert_bit_clear(data, DF | ERR | DRQ);
+
+    /* Complete the command */
+    qmp("{'execute':'__org.qemu.debug-qemu-io-command', 'arguments': { "
+        "'device': 'ide0-hd0', 'command': 'resume A'} }");
+
+    /* Check registers */
+    data = inb(IDE_BASE + reg_device);
+    g_assert_cmpint(data & 0x10, ==, 0);
+
+    data = inb(IDE_BASE + reg_status);
+    assert_bit_set(data, DRDY);
+    assert_bit_clear(data, BSY | DF | ERR | DRQ);
+
+    ide_test_quit();
+}
+
 int main(int argc, char **argv)
 {
     const char *arch = qtest_get_arch();
@@ -453,6 +491,8 @@ int main(int argc, char **argv)
     qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt);
     qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown);
 
+    qtest_add_func("/ide/flush", test_flush);
+
     ret = g_test_run();
 
     /* Cleanup */
Signature · 1 line
1.8.1.4
#6 lore raw

Re: [Qemu-devel] [PATCH 3/3] ide-test: Add FLUSH CACHE test case

tests/ide-test.c static void test_identify(void) · line 455

Quoted 3 lines · Kevin Wolf
tests/ide-test.c +3 -0
+    /* Check registers */
+    data = inb(IDE_BASE + reg_device);
+    g_assert_cmpint(data & 0x10, ==, 0);

assert_bit_clear() with a constant instead of the 0x10 magic number?

#7 lore raw
In reply to Kevin Wolf
Quoted 10 lines · Kevin Wolf

The test case depends on the qemu-io series I sent yesterday. ("[PATCH 00/16] Make qemu-io commands available in the monitor")

Andreas Färber (1):
ide: Set BSY bit during FLUSH

Kevin Wolf (2):
blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events
ide-test: Add FLUSH CACHE test case

Quoted 6 lines
 block.c               |  8 ++++----
 block/blkdebug.c      |  3 +++
 hw/ide/core.c         |  3 +++
 include/block/block.h |  3 +++
 tests/ide-test.c      | 40 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 53 insertions(+), 4 deletions(-)

Looks good. I really like the test case.

Posted a minor comment on the test case.

Stefan