Skip to contentSkip to conversation

Block patches

GIT PULL New Kevin Wolf 1 participant 15 messages Jun 22, 2010 Block layer

lore
Share & tools
lore

Kevin Wolf

author
#0 lore raw

The following changes since commit cada87c432e3b9cd55869a24055baf2b7bc0b70c:
Blue Swirl (1):
Update OpenBIOS images

are available in the git repository at:

git://repo.or.cz/qemu/kevin.git for-anthony

Christoph Hellwig (1):
block: fix physical_block_size calculation

Eduardo Habkost (1):
monitor: allow device to be ejected if no disk is inserted

Kevin Wolf (8):
block: Add bdrv_(p)write_sync
cow: Use bdrv_(p)write_sync for metadata writes
qcow: Use bdrv_(p)write_sync for metadata writes
qcow2: Use bdrv_(p)write_sync for metadata writes
vmdk: Use bdrv_(p)write_sync for metadata writes
vpc: Use bdrv_(p)write_sync for metadata writes
qcow2: Fix qemu-img check segfault on corrupted images
qcow2: Don't try to check tables that couldn't be loaded

MORITA Kazutaka (1):
qemu-io: check registered fds in command_loop()

Nicholas Bellinger (2):
scsi-bus: Add PERSISTENT_RESERVE_OUT SCSIRequest->cmd.mode setup
scsi-bus: Add MAINTENANCE_IN and MAINTENANCE_OUT SCSIRequest xfer and mode assignments

Yoshiaki Tamura (1):
virtio-blk: fix the list operation in virtio_blk_load().

 block.c                |   37 +++++++++++++++++++++++++++++++++++++
 block.h                |    4 ++++
 block/cow.c            |   20 +++++++++++---------
 block/qcow.c           |   18 ++++++++++--------
 block/qcow2-cluster.c  |   24 ++++++++++++------------
 block/qcow2-refcount.c |   39 ++++++++++++++++++++++++---------------
 block/qcow2-snapshot.c |   23 +++++++++++------------
 block/qcow2.c          |   10 +++++-----
 block/vmdk.c           |   10 +++++-----
 block/vpc.c            |    9 +++++----
 block_int.h            |    4 +++-
 blockdev.c             |   22 ++++++++++------------
 cmd.c                  |   33 ++++++++++++++++++++++++++++++---
 hw/scsi-bus.c          |   11 +++++++++++
 hw/scsi-defs.h         |    2 ++
 hw/virtio-blk.c        |    2 +-
 16 files changed, 181 insertions(+), 87 deletions(-)
author
#1 lore raw

PATCH 1/14 scsi-bus: Add PERSISTENT_RESERVE_OUT SCSIRequest->cmd.mode setup

From: Nicholas Bellinger <[email protected]>

This patch updates hw/scsi-bus.c to add the PERSISTENT_RESERVE_OUT cdb case in scsi_req_xfer_mode() to set SCSI_XFER_TO_DEV for outgoing WRITE data.

---
 hw/scsi-bus.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
hw/scsi-bus.c +1 -0
index 055a94d..3575ba3 100644
@@ -306,6 +306,7 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
     case MEDIUM_SCAN:
     case SEND_VOLUME_TAG:
     case WRITE_LONG_2:
+    case PERSISTENT_RESERVE_OUT:
         req->cmd.mode = SCSI_XFER_TO_DEV;
         break;
     default:
Signature · 1 line
1.6.6.1
author
#2 lore raw

PATCH 2/14 scsi-bus: Add MAINTENANCE_IN and MAINTENANCE_OUT SCSIRequest xfer and mode assignments

In reply to Kevin Wolf

From: Nicholas Bellinger <[email protected]>

This patch updates hw/scsi-bus.c to add MAINTENANCE_IN and MAINTENANCE_OUT case in scsi_req_length() for TYPE_ROM with MMC commands. It also adds the MAINTENANCE_OUT case in scsi_req_xfer_mode() to set SCSI_XFER_TO_DEV for outgoing write data.

---
 hw/scsi-bus.c  |   10 ++++++++++
 hw/scsi-defs.h |    2 ++
 2 files changed, 12 insertions(+), 0 deletions(-)
hw/scsi-bus.c +10 -0
index 3575ba3..24bd060 100644
@@ -242,6 +242,13 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
     case INQUIRY:
         req->cmd.xfer = cmd[4] | (cmd[3] << 8);
         break;
+    case MAINTENANCE_OUT:
+    case MAINTENANCE_IN:
+        if (req->dev->type == TYPE_ROM) {
+            /* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
+            req->cmd.xfer = cmd[9] | (cmd[8] << 8);
+        }
+        break;
     }
     return 0;
 }
@@ -307,6 +314,7 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
     case SEND_VOLUME_TAG:
     case WRITE_LONG_2:
     case PERSISTENT_RESERVE_OUT:
+    case MAINTENANCE_OUT:
         req->cmd.mode = SCSI_XFER_TO_DEV;
         break;
     default:
@@ -387,6 +395,8 @@ static const char *scsi_command_name(uint8_t cmd)
         [ SPACE                    ] = "SPACE",
         [ INQUIRY                  ] = "INQUIRY",
         [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
+        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
+        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
         [ MODE_SELECT              ] = "MODE_SELECT",
         [ RESERVE                  ] = "RESERVE",
         [ RELEASE                  ] = "RELEASE",
hw/scsi-defs.h +2 -0
index 5890094..a4a3518 100644
@@ -84,6 +84,8 @@
 #define MODE_SENSE_10         0x5a
 #define PERSISTENT_RESERVE_IN 0x5e
 #define PERSISTENT_RESERVE_OUT 0x5f
+#define MAINTENANCE_IN        0xa3
+#define MAINTENANCE_OUT       0xa4
 #define MOVE_MEDIUM           0xa5
 #define READ_12               0xa8
 #define WRITE_12              0xaa
Signature · 1 line
1.6.6.1
author
#3 lore raw

PATCH 3/14 block: fix physical_block_size calculation

In reply to Kevin Wolf

From: Christoph Hellwig <[email protected]>

Both SCSI and virtio expect the physical block size relative to the logical block size. So get the factor first before calculating the log2.

---
 block_int.h |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
block_int.h +3 -1
index e3bfd19..b64a009 100644
@@ -224,7 +224,9 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
 {
     unsigned int exp = 0, size;
 
-    for (size = conf->physical_block_size; size > 512; size >>= 1) {
+    for (size = conf->physical_block_size;
+        size > conf->logical_block_size;
+        size >>= 1) {
         exp++;
     }
 
Signature · 1 line
1.6.6.1
author
#4 lore raw

PATCH 4/14 monitor: allow device to be ejected if no disk is inserted

In reply to Kevin Wolf

From: Eduardo Habkost <[email protected]>

This changes the monitor eject_device() function to not check for bdrv_is_inserted().

Example run where the bug manifests itself:

(output of 'info block' is stripped to include only the CD-ROM device)

(qemu) info block
ide1-cd0: type=cdrom removable=1 locked=0 [not inserted]
(qemu) change ide1-cd0 /dev/cdrom host_cdrom
(qemu) info block
ide1-cd0: type=cdrom removable=1 locked=0 file=/dev/cdrom ro=1 drv=host_cdrom encrypted=0 (qemu) eject ide1-cd0
(qemu) info block
ide1-cd0: type=cdrom removable=1 locked=0 file=/dev/cdrom ro=1 drv=host_cdrom encrypted=0

  # at this point, a disk was inserted on the host CD-ROM drive

(qemu) info block
ide1-cd0: type=cdrom removable=1 locked=0 file=/dev/cdrom ro=1 drv=host_cdrom encrypted=0 (qemu) eject ide1-cd0
(qemu) info block
ide1-cd0: type=cdrom removable=1 locked=0 [not inserted]
(qemu)

The first eject command didn't work because the is_inserted() check failed.

I have no clue why the code had the is_inserted() check, as it doesn't matter if there is a disk present at the host drive, when the user wants the virtual device to be disconnected from the host device.

The is_inserted() check has another side effect: a memory leak if the "change" command is used multiple times, as do_change() calls eject_device() before re-opening the block device, but bdrv_close() is never called.

---
 blockdev.c |   22 ++++++++++------------
 1 files changed, 10 insertions(+), 12 deletions(-)
blockdev.c +10 -12
index b376884..3b8c606 100644
@@ -503,20 +503,18 @@ void do_commit(Monitor *mon, const QDict *qdict)
 
 static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
 {
-    if (bdrv_is_inserted(bs)) {
-        if (!force) {
-            if (!bdrv_is_removable(bs)) {
-                qerror_report(QERR_DEVICE_NOT_REMOVABLE,
-                               bdrv_get_device_name(bs));
-                return -1;
-            }
-            if (bdrv_is_locked(bs)) {
-                qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
-                return -1;
-            }
+    if (!force) {
+        if (!bdrv_is_removable(bs)) {
+            qerror_report(QERR_DEVICE_NOT_REMOVABLE,
+                           bdrv_get_device_name(bs));
+            return -1;
+        }
+        if (bdrv_is_locked(bs)) {
+            qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+            return -1;
         }
-        bdrv_close(bs);
     }
+    bdrv_close(bs);
     return 0;
 }
 
Signature · 1 line
1.6.6.1
author
#5 lore raw

PATCH 5/14 block: Add bdrv_(p)write_sync

In reply to Kevin Wolf

Add new functions that write and flush the written data to disk immediately. This is what needs to be used for image format metadata to maintain integrity for cache=... modes that don't use O_DSYNC. (Actually, we only need barriers, and therefore the functions are defined as such, but flushes is what is implemented in this patch - we can try to change that later)

---
 block.c |   37 +++++++++++++++++++++++++++++++++++++
 block.h |    4 ++++
 2 files changed, 41 insertions(+), 0 deletions(-)
block.c +37 -0
index 3fc2969..e71a771 100644
@@ -1010,6 +1010,43 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
     return count1;
 }
 
+/*
+ * Writes to the file and ensures that no writes are reordered across this
+ * request (acts as a barrier)
+ *
+ * Returns 0 on success, -errno in error cases.
+ */
+int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
+    const void *buf, int count)
+{
+    int ret;
+
+    ret = bdrv_pwrite(bs, offset, buf, count);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* No flush needed for cache=writethrough, it uses O_DSYNC */
+    if ((bs->open_flags & BDRV_O_CACHE_MASK) != 0) {
+        bdrv_flush(bs);
+    }
+
+    return 0;
+}
+
+/*
+ * Writes to the file and ensures that no writes are reordered across this
+ * request (acts as a barrier)
+ *
+ * Returns 0 on success, -errno in error cases.
+ */
+int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
+    const uint8_t *buf, int nb_sectors)
+{
+    return bdrv_pwrite_sync(bs, BDRV_SECTOR_SIZE * sector_num,
+        buf, BDRV_SECTOR_SIZE * nb_sectors);
+}
+
 /**
  * Truncate file to 'offset' bytes (needed only for file protocols)
  */
block.h +4 -0
index 9df9b38..6a157f4 100644
@@ -80,6 +80,10 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
                void *buf, int count);
 int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
                 const void *buf, int count);
+int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
+    const void *buf, int count);
+int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
+    const uint8_t *buf, int nb_sectors);
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
 void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
Signature · 1 line
1.6.6.1
author
#6 lore raw

PATCH 6/14 cow: Use bdrv_(p)write_sync for metadata writes

In reply to Kevin Wolf

Use bdrv_(p)write_sync to ensure metadata integrity in case of a crash. While at it, correct the wrong usage of errno.

---
 block/cow.c |   20 +++++++++++---------
 1 files changed, 11 insertions(+), 9 deletions(-)
block/cow.c +11 -9
index d146434..eedcc48 100644
@@ -97,17 +97,18 @@ static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
 {
     uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
     uint8_t bitmap;
+    int ret;
 
-    if (bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap)) !=
-	    sizeof(bitmap)) {
-       return -errno;
+    ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
+    if (ret < 0) {
+       return ret;
     }
 
     bitmap |= (1 << (bitnum % 8));
 
-    if (bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap)) !=
-	    sizeof(bitmap)) {
-       return -errno;
+    ret = bdrv_pwrite_sync(bs->file, offset, &bitmap, sizeof(bitmap));
+    if (ret < 0) {
+       return ret;
     }
     return 0;
 }
@@ -116,10 +117,11 @@ static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum)
 {
     uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
     uint8_t bitmap;
+    int ret;
 
-    if (bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap)) !=
-	    sizeof(bitmap)) {
-       return -errno;
+    ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
+    if (ret < 0) {
+       return ret;
     }
 
     return !!(bitmap & (1 << (bitnum % 8)));
Signature · 1 line
1.6.6.1
author
#7 lore raw

PATCH 7/14 qcow: Use bdrv_(p)write_sync for metadata writes

In reply to Kevin Wolf

Use bdrv_(p)write_sync to ensure metadata integrity in case of a crash.

---
 block/qcow.c |   18 ++++++++++--------
 1 files changed, 10 insertions(+), 8 deletions(-)
block/qcow.c +10 -8
index 449858f..816103d 100644
@@ -273,8 +273,9 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
         /* update the L1 entry */
         s->l1_table[l1_index] = l2_offset;
         tmp = cpu_to_be64(l2_offset);
-        if (bdrv_pwrite(bs->file, s->l1_table_offset + l1_index * sizeof(tmp),
-                        &tmp, sizeof(tmp)) != sizeof(tmp))
+        if (bdrv_pwrite_sync(bs->file,
+                s->l1_table_offset + l1_index * sizeof(tmp),
+                &tmp, sizeof(tmp)) < 0)
             return 0;
         new_l2_table = 1;
     }
@@ -302,8 +303,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
     l2_table = s->l2_cache + (min_index << s->l2_bits);
     if (new_l2_table) {
         memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
-        if (bdrv_pwrite(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
-            s->l2_size * sizeof(uint64_t))
+        if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
+                s->l2_size * sizeof(uint64_t)) < 0)
             return 0;
     } else {
         if (bdrv_pread(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
@@ -368,8 +369,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
         /* update L2 table */
         tmp = cpu_to_be64(cluster_offset);
         l2_table[l2_index] = tmp;
-        if (bdrv_pwrite(bs->file,
-                        l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
+        if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
+                &tmp, sizeof(tmp)) < 0)
             return 0;
     }
     return cluster_offset;
@@ -835,8 +836,9 @@ static int qcow_make_empty(BlockDriverState *bs)
     int ret;
 
     memset(s->l1_table, 0, l1_length);
-    if (bdrv_pwrite(bs->file, s->l1_table_offset, s->l1_table, l1_length) < 0)
-	return -1;
+    if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
+            l1_length) < 0)
+        return -1;
     ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
     if (ret < 0)
         return ret;
Signature · 1 line
1.6.6.1
author
#8 lore raw

PATCH 8/14 qcow2: Use bdrv_(p)write_sync for metadata writes

In reply to Kevin Wolf

Use bdrv_(p)write_sync to ensure metadata integrity in case of a crash.

---
 block/qcow2-cluster.c  |   24 ++++++++++++------------
 block/qcow2-refcount.c |   24 ++++++++++++------------
 block/qcow2-snapshot.c |   23 +++++++++++------------
 block/qcow2.c          |   10 +++++-----
 4 files changed, 40 insertions(+), 41 deletions(-)
block/qcow2-cluster.c +12 -12
index 5760ad6..166922f 100644
@@ -64,8 +64,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
     BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
     for(i = 0; i < s->l1_size; i++)
         new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
-    ret = bdrv_pwrite(bs->file, new_l1_table_offset, new_l1_table, new_l1_size2);
-    if (ret != new_l1_size2)
+    ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset, new_l1_table, new_l1_size2);
+    if (ret < 0)
         goto fail;
     for(i = 0; i < s->l1_size; i++)
         new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
@@ -74,8 +74,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
     BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);
     cpu_to_be32w((uint32_t*)data, new_l1_size);
     cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
-    ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data));
-    if (ret != sizeof(data)) {
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data));
+    if (ret < 0) {
         goto fail;
     }
     qemu_free(s->l1_table);
@@ -87,7 +87,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
  fail:
     qemu_free(new_l1_table);
     qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2);
-    return ret < 0 ? ret : -EIO;
+    return ret;
 }
 
 void qcow2_l2_cache_reset(BlockDriverState *bs)
@@ -207,7 +207,7 @@ static int write_l1_entry(BlockDriverState *bs, int l1_index)
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
-    ret = bdrv_pwrite(bs->file, s->l1_table_offset + 8 * l1_start_index,
+    ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset + 8 * l1_start_index,
         buf, sizeof(buf));
     if (ret < 0) {
         return ret;
@@ -263,7 +263,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
     }
     /* write the l2 table to the file */
     BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
-    ret = bdrv_pwrite(bs->file, l2_offset, l2_table,
+    ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
         s->l2_size * sizeof(uint64_t));
     if (ret < 0) {
         goto fail;
@@ -413,8 +413,8 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
                         &s->aes_encrypt_key);
     }
     BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
-    ret = bdrv_write(bs->file, (cluster_offset >> 9) + n_start,
-                     s->cluster_data, n);
+    ret = bdrv_write_sync(bs->file, (cluster_offset >> 9) + n_start,
+        s->cluster_data, n);
     if (ret < 0)
         return ret;
     return 0;
@@ -631,10 +631,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 
     BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
     l2_table[l2_index] = cpu_to_be64(cluster_offset);
-    if (bdrv_pwrite(bs->file,
+    if (bdrv_pwrite_sync(bs->file,
                     l2_offset + l2_index * sizeof(uint64_t),
                     l2_table + l2_index,
-                    sizeof(uint64_t)) != sizeof(uint64_t))
+                    sizeof(uint64_t)) < 0)
         return 0;
 
     return cluster_offset;
@@ -655,7 +655,7 @@ static int write_l2_entries(BlockDriverState *bs, uint64_t *l2_table,
     int ret;
 
     BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
-    ret = bdrv_pwrite(bs->file, l2_offset + start_offset,
+    ret = bdrv_pwrite_sync(bs->file, l2_offset + start_offset,
         &l2_table[l2_start_index], len);
     if (ret < 0) {
         return ret;
block/qcow2-refcount.c +12 -12
index 41e1da9..c2d0e61 100644
@@ -44,8 +44,8 @@ static int write_refcount_block(BlockDriverState *bs)
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE);
-    if (bdrv_pwrite(bs->file, s->refcount_block_cache_offset,
-            s->refcount_block_cache, size) != size)
+    if (bdrv_pwrite_sync(bs->file, s->refcount_block_cache_offset,
+            s->refcount_block_cache, size) < 0)
     {
         return -EIO;
     }
@@ -269,7 +269,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
 
     /* Now the new refcount block needs to be written to disk */
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
-    ret = bdrv_pwrite(bs->file, new_block, s->refcount_block_cache,
+    ret = bdrv_pwrite_sync(bs->file, new_block, s->refcount_block_cache,
         s->cluster_size);
     if (ret < 0) {
         goto fail_block;
@@ -279,7 +279,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
     if (refcount_table_index < s->refcount_table_size) {
         uint64_t data64 = cpu_to_be64(new_block);
         BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
-        ret = bdrv_pwrite(bs->file,
+        ret = bdrv_pwrite_sync(bs->file,
             s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
             &data64, sizeof(data64));
         if (ret < 0) {
@@ -359,7 +359,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
 
     /* Write refcount blocks to disk */
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
-    ret = bdrv_pwrite(bs->file, meta_offset, new_blocks,
+    ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
         blocks_clusters * s->cluster_size);
     qemu_free(new_blocks);
     if (ret < 0) {
@@ -372,7 +372,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
-    ret = bdrv_pwrite(bs->file, table_offset, new_table,
+    ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
         table_size * sizeof(uint64_t));
     if (ret < 0) {
         goto fail_table;
@@ -387,7 +387,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
     cpu_to_be64w((uint64_t*)data, table_offset);
     cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
-    ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, refcount_table_offset),
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset),
         data, sizeof(data));
     if (ret < 0) {
         goto fail_table;
@@ -444,7 +444,7 @@ static int write_refcount_block_entries(BlockDriverState *bs,
     size = (last_index - first_index) << REFCOUNT_SHIFT;
 
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
-    ret = bdrv_pwrite(bs->file,
+    ret = bdrv_pwrite_sync(bs->file,
         refcount_block_offset + (first_index << REFCOUNT_SHIFT),
         &s->refcount_block_cache[first_index], size);
     if (ret < 0) {
@@ -826,8 +826,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                 }
             }
             if (l2_modified) {
-                if (bdrv_pwrite(bs->file,
-                                l2_offset, l2_table, l2_size) != l2_size)
+                if (bdrv_pwrite_sync(bs->file,
+                                l2_offset, l2_table, l2_size) < 0)
                     goto fail;
             }
 
@@ -850,8 +850,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
     if (l1_modified) {
         for(i = 0; i < l1_size; i++)
             cpu_to_be64s(&l1_table[i]);
-        if (bdrv_pwrite(bs->file, l1_table_offset, l1_table,
-                        l1_size2) != l1_size2)
+        if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table,
+                        l1_size2) < 0)
             goto fail;
         for(i = 0; i < l1_size; i++)
             be64_to_cpus(&l1_table[i]);
block/qcow2-snapshot.c +11 -12
index 2a21c17..6228612 100644
@@ -158,25 +158,25 @@ static int qcow_write_snapshots(BlockDriverState *bs)
         h.id_str_size = cpu_to_be16(id_str_size);
         h.name_size = cpu_to_be16(name_size);
         offset = align_offset(offset, 8);
-        if (bdrv_pwrite(bs->file, offset, &h, sizeof(h)) != sizeof(h))
+        if (bdrv_pwrite_sync(bs->file, offset, &h, sizeof(h)) < 0)
             goto fail;
         offset += sizeof(h);
-        if (bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size) != id_str_size)
+        if (bdrv_pwrite_sync(bs->file, offset, sn->id_str, id_str_size) < 0)
             goto fail;
         offset += id_str_size;
-        if (bdrv_pwrite(bs->file, offset, sn->name, name_size) != name_size)
+        if (bdrv_pwrite_sync(bs->file, offset, sn->name, name_size) < 0)
             goto fail;
         offset += name_size;
     }
 
     /* update the various header fields */
     data64 = cpu_to_be64(snapshots_offset);
-    if (bdrv_pwrite(bs->file, offsetof(QCowHeader, snapshots_offset),
-                    &data64, sizeof(data64)) != sizeof(data64))
+    if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, snapshots_offset),
+                    &data64, sizeof(data64)) < 0)
         goto fail;
     data32 = cpu_to_be32(s->nb_snapshots);
-    if (bdrv_pwrite(bs->file, offsetof(QCowHeader, nb_snapshots),
-                    &data32, sizeof(data32)) != sizeof(data32))
+    if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
+                    &data32, sizeof(data32)) < 0)
         goto fail;
 
     /* free the old snapshot table */
@@ -284,9 +284,8 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     for(i = 0; i < s->l1_size; i++) {
         l1_table[i] = cpu_to_be64(s->l1_table[i]);
     }
-    if (bdrv_pwrite(bs->file, sn->l1_table_offset,
-                    l1_table, s->l1_size * sizeof(uint64_t)) !=
-        (s->l1_size * sizeof(uint64_t)))
+    if (bdrv_pwrite_sync(bs->file, sn->l1_table_offset,
+                    l1_table, s->l1_size * sizeof(uint64_t)) < 0)
         goto fail;
     qemu_free(l1_table);
     l1_table = NULL;
@@ -335,8 +334,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     if (bdrv_pread(bs->file, sn->l1_table_offset,
                    s->l1_table, l1_size2) != l1_size2)
         goto fail;
-    if (bdrv_pwrite(bs->file, s->l1_table_offset,
-                    s->l1_table, l1_size2) != l1_size2)
+    if (bdrv_pwrite_sync(bs->file, s->l1_table_offset,
+                    s->l1_table, l1_size2) < 0)
         goto fail;
     for(i = 0;i < s->l1_size; i++) {
         be64_to_cpus(&s->l1_table[i]);
block/qcow2.c +5 -5
index 33fa9a9..d29e6b6 100644
@@ -735,7 +735,7 @@ static int qcow2_update_ext_header(BlockDriverState *bs,
         backing_file_offset = sizeof(QCowHeader) + offset;
     }
 
-    ret = bdrv_pwrite(bs->file, sizeof(QCowHeader), buf, ext_size);
+    ret = bdrv_pwrite_sync(bs->file, sizeof(QCowHeader), buf, ext_size);
     if (ret < 0) {
         goto fail;
     }
@@ -744,13 +744,13 @@ static int qcow2_update_ext_header(BlockDriverState *bs,
     uint64_t be_backing_file_offset = cpu_to_be64(backing_file_offset);
     uint32_t be_backing_file_size = cpu_to_be32(backing_file_len);
 
-    ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, backing_file_offset),
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_offset),
         &be_backing_file_offset, sizeof(uint64_t));
     if (ret < 0) {
         goto fail;
     }
 
-    ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, backing_file_size),
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_size),
         &be_backing_file_size, sizeof(uint32_t));
     if (ret < 0) {
         goto fail;
@@ -1131,8 +1131,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
 
     /* write updated header.size */
     offset = cpu_to_be64(offset);
-    ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, size),
-                      &offset, sizeof(uint64_t));
+    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
+                           &offset, sizeof(uint64_t));
     if (ret < 0) {
         return ret;
     }
Signature · 1 line
1.6.6.1
author
#9 lore raw

PATCH 9/14 vmdk: Use bdrv_(p)write_sync for metadata writes

In reply to Kevin Wolf

Use bdrv_(p)write_sync to ensure metadata integrity in case of a crash.

---
 block/vmdk.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)
block/vmdk.c +5 -5
index e659908..2d4ba42 100644
@@ -150,7 +150,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
         pstrcat(desc, sizeof(desc), tmp_desc);
     }
 
-    if (bdrv_pwrite(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+    if (bdrv_pwrite_sync(bs->file, 0x200, desc, DESC_SIZE) < 0)
         return -1;
     return 0;
 }
@@ -471,14 +471,14 @@ static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
     BDRVVmdkState *s = bs->opaque;
 
     /* update L2 table */
-    if (bdrv_pwrite(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
-                    &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
+    if (bdrv_pwrite_sync(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
+                    &(m_data->offset), sizeof(m_data->offset)) < 0)
         return -1;
     /* update backup L2 table */
     if (s->l1_backup_table_offset != 0) {
         m_data->l2_offset = s->l1_backup_table[m_data->l1_index];
-        if (bdrv_pwrite(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
-                        &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
+        if (bdrv_pwrite_sync(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
+                        &(m_data->offset), sizeof(m_data->offset)) < 0)
             return -1;
     }
 
Signature · 1 line
1.6.6.1
author
#10 lore raw

PATCH 10/14 vpc: Use bdrv_(p)write_sync for metadata writes

In reply to Kevin Wolf

Use bdrv_(p)write_sync to ensure metadata integrity in case of a crash.

---
 block/vpc.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
block/vpc.c +5 -4
index f1f73e2..e50509e 100644
@@ -261,7 +261,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
 
         s->last_bitmap_offset = bitmap_offset;
         memset(bitmap, 0xff, s->bitmap_size);
-        bdrv_pwrite(bs->file, bitmap_offset, bitmap, s->bitmap_size);
+        bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
     }
 
 //    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
@@ -311,7 +311,7 @@ static int rewrite_footer(BlockDriverState* bs)
     BDRVVPCState *s = bs->opaque;
     int64_t offset = s->free_data_block_offset;
 
-    ret = bdrv_pwrite(bs->file, offset, s->footer_buf, HEADER_SIZE);
+    ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
     if (ret < 0)
         return ret;
 
@@ -346,7 +346,8 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
 
     // Initialize the block's bitmap
     memset(bitmap, 0xff, s->bitmap_size);
-    bdrv_pwrite(bs->file, s->free_data_block_offset, bitmap, s->bitmap_size);
+    bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
+        s->bitmap_size);
 
     // Write new footer (the old one will be overwritten)
     s->free_data_block_offset += s->block_size + s->bitmap_size;
@@ -357,7 +358,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
     // Write BAT entry to disk
     bat_offset = s->bat_offset + (4 * index);
     bat_value = be32_to_cpu(s->pagetable[index]);
-    ret = bdrv_pwrite(bs->file, bat_offset, &bat_value, 4);
+    ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
     if (ret < 0)
         goto fail;
 
Signature · 1 line
1.6.6.1
author
#11 lore raw

PATCH 11/14 qemu-io: check registered fds in command_loop()

In reply to Kevin Wolf

From: MORITA Kazutaka <[email protected]>

Some block drivers use an aio handler and do I/O completion routines in it. However, the handler is not invoked if we only do aio_read/write, because registered fds are not checked at all.

This patch registers an aio handler of STDIO to checks whether we can read a command without blocking, and calls qemu_aio_wait() in command_loop(). Any other handlers can be invoked when user input is idle.

---
 cmd.c |   33 ++++++++++++++++++++++++++++++---
 1 files changed, 30 insertions(+), 3 deletions(-)
cmd.c +30 -3
index 2336334..db2c9c4 100644
@@ -24,6 +24,7 @@
 #include <getopt.h>
 
 #include "cmd.h"
+#include "qemu-aio.h"
 
 #define _(x)	x	/* not gettext support yet */
 
@@ -149,10 +150,20 @@ add_args_command(
 	args_func = af;
 }
 
+static void prep_fetchline(void *opaque)
+{
+    int *fetchable = opaque;
+
+    qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+    *fetchable= 1;
+}
+
+static char *get_prompt(void);
+
 void
 command_loop(void)
 {
-	int		c, i, j = 0, done = 0;
+	int		c, i, j = 0, done = 0, fetchable = 0, prompted = 0;
 	char		*input;
 	char		**v;
 	const cmdinfo_t	*ct;
@@ -186,7 +197,21 @@ command_loop(void)
 		free(cmdline);
 		return;
 	}
+
 	while (!done) {
+        if (!prompted) {
+            printf("%s", get_prompt());
+            fflush(stdout);
+            qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
+                                    NULL, &fetchable);
+            prompted = 1;
+        }
+
+        qemu_aio_wait();
+
+        if (!fetchable) {
+            continue;
+        }
 		if ((input = fetchline()) == NULL)
 			break;
 		v = breakline(input, &c);
@@ -199,7 +224,11 @@ command_loop(void)
 					v[0]);
 		}
 		doneline(input, v);
+
+        prompted = 0;
+        fetchable = 0;
 	}
+    qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
 }
 
 /* from libxcmd/input.c */
@@ -270,8 +299,6 @@ fetchline(void)
 
 	if (!line)
 		return NULL;
-	printf("%s", get_prompt());
-	fflush(stdout);
 	if (!fgets(line, MAXREADLINESZ, stdin)) {
 		free(line);
 		return NULL;
Signature · 1 line
1.6.6.1
author
#12 lore raw

PATCH 12/14 virtio-blk: fix the list operation in virtio_blk_load().

In reply to Kevin Wolf

From: Yoshiaki Tamura <[email protected]>

Although it is really rare to get in to the while loop, the list operation in the loop is obviously wrong.

---
 hw/virtio-blk.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
hw/virtio-blk.c +1 -1
index 75878eb..0bf929a 100644
@@ -470,7 +470,7 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
         VirtIOBlockReq *req = virtio_blk_alloc_request(s);
         qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
         req->next = s->rq;
-        s->rq = req->next;
+        s->rq = req;
     }
 
     return 0;
Signature · 1 line
1.6.6.1
author
#13 lore raw

PATCH 13/14 qcow2: Fix qemu-img check segfault on corrupted images

In reply to Kevin Wolf

With corrupted images, we can easily get an cluster index that exceeds the array size of the temporary refcount table.

---
 block/qcow2-refcount.c |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)
block/qcow2-refcount.c +11 -3
index c2d0e61..cedf57e 100644
@@ -1140,22 +1140,30 @@ int qcow2_check_refcounts(BlockDriverState *bs)
                   s->refcount_table_offset,
                   s->refcount_table_size * sizeof(uint64_t));
     for(i = 0; i < s->refcount_table_size; i++) {
-        int64_t offset;
+        uint64_t offset, cluster;
         offset = s->refcount_table[i];
+        cluster = offset >> s->cluster_bits;
 
         /* Refcount blocks are cluster aligned */
         if (offset & (s->cluster_size - 1)) {
             fprintf(stderr, "ERROR refcount block %d is not "
                 "cluster aligned; refcount table entry corrupted\n", i);
             errors++;
+            continue;
+        }
+
+        if (cluster >= nb_clusters) {
+            fprintf(stderr, "ERROR refcount block %d is outside image\n", i);
+            errors++;
+            continue;
         }
 
         if (offset != 0) {
             errors += inc_refcounts(bs, refcount_table, nb_clusters,
                           offset, s->cluster_size);
-            if (refcount_table[offset / s->cluster_size] != 1) {
+            if (refcount_table[cluster] != 1) {
                 fprintf(stderr, "ERROR refcount block %d refcount=%d\n",
-                    i, refcount_table[offset / s->cluster_size]);
+                    i, refcount_table[cluster]);
             }
         }
     }
Signature · 1 line
1.6.6.1
author
#14 lore raw

PATCH 14/14 qcow2: Don't try to check tables that couldn't be loaded

In reply to Kevin Wolf

Trying to check them leads to a second error message which is more confusing than helpful:

Can't get refcount for cluster 0: Invalid argument ERROR cluster 0 refcount=-22 reference=1

---
 block/qcow2-refcount.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
block/qcow2-refcount.c +1 -0
index cedf57e..4a96d98 100644
@@ -1174,6 +1174,7 @@ int qcow2_check_refcounts(BlockDriverState *bs)
         if (refcount1 < 0) {
             fprintf(stderr, "Can't get refcount for cluster %d: %s\n",
                 i, strerror(-refcount1));
+            continue;
         }
 
         refcount2 = refcount_table[i];
Signature · 1 line
1.6.6.1