Merge remote-tracking branch 'kwolf/for-anthony' into staging
authorAnthony Liguori <aliguori@us.ibm.com>
Mon, 28 Jan 2013 20:46:45 +0000 (14:46 -0600)
committerAnthony Liguori <aliguori@us.ibm.com>
Mon, 28 Jan 2013 20:46:45 +0000 (14:46 -0600)
# By Paolo Bonzini (14) and others
# Via Kevin Wolf
* kwolf/for-anthony: (24 commits)
  ide: Add fall through annotations
  block: Create proper size file for disk mirror
  ahci: Add migration support
  ahci: Change data types in preparation for migration
  ahci: Remove unused AHCIDevice fields
  hbitmap: add assertion on hbitmap_iter_init
  mirror: do nothing on zero-sized disk
  block/vdi: Check for bad signature
  block/vdi: Improved return values from vdi_open
  block/vdi: Improve debug output for signature
  block: Use error code EMEDIUMTYPE for wrong format in some block drivers
  block: Add special error code for wrong format
  mirror: support arbitrarily-sized iterations
  mirror: support more than one in-flight AIO operation
  mirror: add buf-size argument to drive-mirror
  mirror: switch mirror_iteration to AIO
  mirror: allow customizing the granularity
  block: allow customizing the granularity of the dirty bitmap
  block: return count of dirty sectors, not chunks
  mirror: perform COW if the cluster size is bigger than the granularity
  ...

1  2 
blockdev.c
hmp.c
qapi-schema.json
qmp-commands.hx
tests/Makefile

diff --combined blockdev.c
index 030070b607d107385498e1c427dc959257a64d1f,fdc573f5198d7096ccc98ddc50ce28475d4ca5c5..63e6f1eafa81e3517767246a00bd695a6f3cf867
@@@ -617,8 -617,13 +617,13 @@@ DriveInfo *drive_init(QemuOpts *opts, B
  
      ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
      if (ret < 0) {
-         error_report("could not open disk image %s: %s",
-                      file, strerror(-ret));
+         if (ret == -EMEDIUMTYPE) {
+             error_report("could not open disk image %s: not in %s format",
+                          file, drv->format_name);
+         } else {
+             error_report("could not open disk image %s: %s",
+                          file, strerror(-ret));
+         }
          goto err;
      }
  
@@@ -642,17 -647,21 +647,17 @@@ void do_commit(Monitor *mon, const QDic
  
      if (!strcmp(device, "all")) {
          ret = bdrv_commit_all();
 -        if (ret == -EBUSY) {
 -            qerror_report(QERR_DEVICE_IN_USE, device);
 -            return;
 -        }
      } else {
          bs = bdrv_find(device);
          if (!bs) {
 -            qerror_report(QERR_DEVICE_NOT_FOUND, device);
 +            monitor_printf(mon, "Device '%s' not found\n", device);
              return;
          }
          ret = bdrv_commit(bs);
 -        if (ret == -EBUSY) {
 -            qerror_report(QERR_DEVICE_IN_USE, device);
 -            return;
 -        }
 +    }
 +    if (ret < 0) {
 +        monitor_printf(mon, "'commit' error for '%s': %s\n", device,
 +                       strerror(-ret));
      }
  }
  
@@@ -1184,16 -1193,19 +1189,19 @@@ void qmp_block_commit(const char *devic
      drive_get_ref(drive_get_by_blockdev(bs));
  }
  
+ #define DEFAULT_MIRROR_BUF_SIZE   (10 << 20)
  void qmp_drive_mirror(const char *device, const char *target,
                        bool has_format, const char *format,
                        enum MirrorSyncMode sync,
                        bool has_mode, enum NewImageMode mode,
                        bool has_speed, int64_t speed,
+                       bool has_granularity, uint32_t granularity,
+                       bool has_buf_size, int64_t buf_size,
                        bool has_on_source_error, BlockdevOnError on_source_error,
                        bool has_on_target_error, BlockdevOnError on_target_error,
                        Error **errp)
  {
-     BlockDriverInfo bdi;
      BlockDriverState *bs;
      BlockDriverState *source, *target_bs;
      BlockDriver *proto_drv;
      if (!has_mode) {
          mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
      }
+     if (!has_granularity) {
+         granularity = 0;
+     }
+     if (!has_buf_size) {
+         buf_size = DEFAULT_MIRROR_BUF_SIZE;
+     }
+     if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
+         error_set(errp, QERR_INVALID_PARAMETER, device);
+         return;
+     }
+     if (granularity & (granularity - 1)) {
+         error_set(errp, QERR_INVALID_PARAMETER, device);
+         return;
+     }
  
      bs = bdrv_find(device);
      if (!bs) {
          return;
      }
  
+     bdrv_get_geometry(bs, &size);
+     size *= 512;
      if (sync == MIRROR_SYNC_MODE_FULL && mode != NEW_IMAGE_MODE_EXISTING) {
          /* create new image w/o backing file */
          assert(format && drv);
-         bdrv_get_geometry(bs, &size);
-         size *= 512;
          bdrv_img_create(target, format,
                          NULL, NULL, NULL, size, flags, &local_err);
      } else {
              bdrv_img_create(target, format,
                              source->filename,
                              source->drv->format_name,
-                             NULL, -1, flags, &local_err);
+                             NULL, size, flags, &local_err);
              break;
          default:
              abort();
          return;
      }
  
+     /* Mirroring takes care of copy-on-write using the source's backing
+      * file.
+      */
      target_bs = bdrv_new("");
      ret = bdrv_open(target_bs, target, flags | BDRV_O_NO_BACKING, drv);
  
          return;
      }
  
-     /* We need a backing file if we will copy parts of a cluster.  */
-     if (bdrv_get_info(target_bs, &bdi) >= 0 && bdi.cluster_size != 0 &&
-         bdi.cluster_size >= BDRV_SECTORS_PER_DIRTY_CHUNK * 512) {
-         ret = bdrv_open_backing_file(target_bs);
-         if (ret < 0) {
-             bdrv_delete(target_bs);
-             error_set(errp, QERR_OPEN_FILE_FAILED, target);
-             return;
-         }
-     }
-     mirror_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
+     mirror_start(bs, target_bs, speed, granularity, buf_size, sync,
+                  on_source_error, on_target_error,
                   block_job_cb, bs, &local_err);
      if (local_err != NULL) {
          bdrv_delete(target_bs);
diff --combined hmp.c
index 7e259c2b567b5bb7ad800c3de04db3639af5b9ce,99fd89206b2a01a674e57ecc32acbb4947d0c958..249b89b7e37c5525b3bafe0164eac6c48374b819
--- 1/hmp.c
--- 2/hmp.c
+++ b/hmp.c
@@@ -465,7 -465,29 +465,7 @@@ void hmp_info_balloon(Monitor *mon, con
          return;
      }
  
 -    monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
 -    if (info->has_mem_swapped_in) {
 -        monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
 -    }
 -    if (info->has_mem_swapped_out) {
 -        monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
 -    }
 -    if (info->has_major_page_faults) {
 -        monitor_printf(mon, " major_page_faults=%" PRId64,
 -                       info->major_page_faults);
 -    }
 -    if (info->has_minor_page_faults) {
 -        monitor_printf(mon, " minor_page_faults=%" PRId64,
 -                       info->minor_page_faults);
 -    }
 -    if (info->has_free_mem) {
 -        monitor_printf(mon, " free_mem=%" PRId64, info->free_mem);
 -    }
 -    if (info->has_total_mem) {
 -        monitor_printf(mon, " total_mem=%" PRId64, info->total_mem);
 -    }
 -
 -    monitor_printf(mon, "\n");
 +    monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);
  
      qapi_free_BalloonInfo(info);
  }
@@@ -661,40 -683,6 +661,40 @@@ void hmp_pmemsave(Monitor *mon, const Q
      qmp_pmemsave(addr, size, filename, &errp);
      hmp_handle_error(mon, &errp);
  }
 +
 +void hmp_memchar_write(Monitor *mon, const QDict *qdict)
 +{
 +    uint32_t size;
 +    const char *chardev = qdict_get_str(qdict, "device");
 +    const char *data = qdict_get_str(qdict, "data");
 +    Error *errp = NULL;
 +
 +    size = strlen(data);
 +    qmp_memchar_write(chardev, size, data, false, 0, &errp);
 +
 +    hmp_handle_error(mon, &errp);
 +}
 +
 +void hmp_memchar_read(Monitor *mon, const QDict *qdict)
 +{
 +    uint32_t size = qdict_get_int(qdict, "size");
 +    const char *chardev = qdict_get_str(qdict, "device");
 +    MemCharRead *meminfo;
 +    Error *errp = NULL;
 +
 +    meminfo = qmp_memchar_read(chardev, size, false, 0, &errp);
 +    if (errp) {
 +        monitor_printf(mon, "%s\n", error_get_pretty(errp));
 +        error_free(errp);
 +        return;
 +    }
 +
 +    if (meminfo->count > 0) {
 +        monitor_printf(mon, "%s\n", meminfo->data);
 +    }
 +
 +    qapi_free_MemCharRead(meminfo);
 +}
  
  static void hmp_cont_cb(void *opaque, int err)
  {
@@@ -808,7 -796,7 +808,7 @@@ void hmp_drive_mirror(Monitor *mon, con
  
      qmp_drive_mirror(device, filename, !!format, format,
                       full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
-                      true, mode, false, 0,
+                      true, mode, false, 0, false, 0, false, 0,
                       false, 0, false, 0, &errp);
      hmp_handle_error(mon, &errp);
  }
diff --combined qapi-schema.json
index 6c29f569b9449e51a408aa173f8c7e4b21884163,ba75c4de12eff40084f03666a4cad31a4208368d..3a4817b39107d63d27f290f9e51d855d16023d41
  ##
  { 'command': 'query-chardev', 'returns': ['ChardevInfo'] }
  
 +##
 +# @DataFormat:
 +#
 +# An enumeration of data format.
 +#
 +# @utf8: The data format is 'utf8'.
 +#
 +# @base64: The data format is 'base64'.
 +#
 +# Since: 1.4
 +##
 +{ 'enum': 'DataFormat'
 +  'data': [ 'utf8', 'base64' ] }
 +
 +##
 +# @memchar-write:
 +#
 +# Provide writing interface for memchardev. Write data to char
 +# device 'memory'.
 +#
 +# @device: the name of the memory char device.
 +#
 +# @size: the size to write in bytes.
 +#
 +# @data: the source data write to memchar.
 +#
 +# @format: #optional the format of the data write to chardev 'memory',
 +#          by default is 'utf8'.
 +#
 +# Returns: Nothing on success
 +#          If @device is not a valid char device, DeviceNotFound
 +#
 +# Since: 1.4
 +##
 +{ 'command': 'memchar-write',
 +  'data': {'device': 'str', 'size': 'int', 'data': 'str',
 +           '*format': 'DataFormat'} }
 +
 +##
 +# @MemCharRead
 +#
 +# Result of QMP command memchar-read.
 +#
 +# @data: The data read from memchar as string.
 +#
 +# @count: The numbers of bytes read from.
 +#
 +# Since: 1.4
 +##
 +{ 'type': 'MemCharRead',
 +  'data': { 'data': 'str', 'count': 'int' } }
 +
 +##
 +# @memchar-read:
 +#
 +# Provide read interface for memchardev. Read from the char
 +# device 'memory' and return the data.
 +#
 +# @device: the name of the memory char device.
 +#
 +# @size: the size to read in bytes.
 +#
 +# @format: #optional the format of the data want to read from
 +#          memchardev, by default is 'utf8'.
 +#
 +# Returns: @MemCharRead
 +#          If @device is not a valid memchr device, DeviceNotFound
 +#
 +# Since: 1.4
 +##
 +{ 'command': 'memchar-read',
 +  'data': {'device': 'str', 'size': 'int', '*format': 'DataFormat'},
 +  'returns': 'MemCharRead' }
 +
  ##
  # @CommandInfo:
  #
  #
  # @count: number of dirty bytes according to the dirty bitmap
  #
+ # @granularity: granularity of the dirty bitmap in bytes (since 1.4)
+ #
  # Since: 1.3
  ##
  { 'type': 'BlockDirtyInfo',
-   'data': {'count': 'int'} }
+   'data': {'count': 'int', 'granularity': 'int'} }
  
  ##
  # @BlockInfo:
  #
  # @actual: the number of bytes the balloon currently contains
  #
 -# @mem_swapped_in: #optional number of pages swapped in within the guest
 -#
 -# @mem_swapped_out: #optional number of pages swapped out within the guest
 -#
 -# @major_page_faults: #optional number of major page faults within the guest
 -#
 -# @minor_page_faults: #optional number of minor page faults within the guest
 -#
 -# @free_mem: #optional amount of memory (in bytes) free in the guest
 -#
 -# @total_mem: #optional amount of memory (in bytes) visible to the guest
 -#
  # Since: 0.14.0
  #
 -# Notes: all current versions of QEMU do not fill out optional information in
 -#        this structure.
  ##
 -{ 'type': 'BalloonInfo',
 -  'data': {'actual': 'int', '*mem_swapped_in': 'int',
 -           '*mem_swapped_out': 'int', '*major_page_faults': 'int',
 -           '*minor_page_faults': 'int', '*free_mem': 'int',
 -           '*total_mem': 'int'} }
 +{ 'type': 'BalloonInfo', 'data': {'actual': 'int' } }
  
  ##
  # @query-balloon:
  #        (all the disk, only the sectors allocated in the topmost image, or
  #        only new I/O).
  #
+ # @granularity: #optional granularity of the dirty bitmap, default is 64K
+ #               if the image format doesn't have clusters, 4K if the clusters
+ #               are smaller than that, else the cluster size.  Must be a
+ #               power of 2 between 512 and 64M (since 1.4).
+ #
+ # @buf-size: #optional maximum amount of data in flight from source to
+ #            target (since 1.4).
+ #
  # @on-source-error: #optional the action to take on an error on the source,
  #                   default 'report'.  'stop' and 'enospc' can only be used
  #                   if the block device supports io-status (see BlockInfo).
  { 'command': 'drive-mirror',
    'data': { 'device': 'str', 'target': 'str', '*format': 'str',
              'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
-             '*speed': 'int', '*on-source-error': 'BlockdevOnError',
+             '*speed': 'int', '*granularity': 'uint32',
+             '*buf-size': 'int', '*on-source-error': 'BlockdevOnError',
              '*on-target-error': 'BlockdevOnError' } }
  
  ##
diff --combined qmp-commands.hx
index f0f7d2b395078344c22343f5bbe58c48fd3b4b66,273b4a67ba172522389b30b695a053ce132f9a23..f58a8411eafbf5b8e7d0282961f09daae0d12120
@@@ -463,72 -463,6 +463,72 @@@ Example
  Note: inject-nmi fails when the guest doesn't support injecting.
        Currently, only x86 guests do.
  
 +EQMP
 +
 +    {
 +        .name       = "memchar-write",
 +        .args_type  = "device:s,size:i,data:s,format:s?",
 +        .mhandler.cmd_new = qmp_marshal_input_memchar_write,
 +    },
 +
 +SQMP
 +memchar-write
 +-------------
 +
 +Provide writing interface for CirMemCharDriver. Write data to memory
 +char device.
 +
 +Arguments:
 +
 +- "device": the name of the char device, must be unique (json-string)
 +- "size": the memory size, in bytes, should be power of 2 (json-int)
 +- "data": the source data write to memory (json-string)
 +- "format": the data format write to memory, default is
 +            utf8. (json-string, optional)
 +          - Possible values: "utf8", "base64"
 +
 +Example:
 +
 +-> { "execute": "memchar-write",
 +                "arguments": { "device": foo,
 +                               "size": 8,
 +                               "data": "abcdefgh",
 +                               "format": "utf8" } }
 +<- { "return": {} }
 +
 +EQMP
 +
 +    {
 +        .name       = "memchar-read",
 +        .args_type  = "device:s,size:i,format:s?",
 +        .mhandler.cmd_new = qmp_marshal_input_memchar_read,
 +    },
 +
 +SQMP
 +memchar-read
 +-------------
 +
 +Provide read interface for CirMemCharDriver. Read from the char
 +device memory and return the data with size.
 +
 +Arguments:
 +
 +- "device": the name of the char device, must be unique (json-string)
 +- "size": the memory size wanted to read in bytes (refer to unencoded
 +          size of the raw data), would adjust to the init size of the
 +          memchar if the requested size is larger than it. (json-int)
 +- "format": the data format write to memchardev, default is
 +            utf8. (json-string, optional)
 +          - Possible values: "utf8", "base64"
 +
 +Example:
 +
 +-> { "execute": "memchar-read",
 +                "arguments": { "device": foo,
 +                               "size": 1000,
 +                               "format": "utf8" } }
 +<- { "return": { "data": "data string...", "count": 1000 } }
 +
  EQMP
  
      {
@@@ -1004,7 -938,8 +1004,8 @@@ EQM
      {
          .name       = "drive-mirror",
          .args_type  = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?,"
-                       "on-source-error:s?,on-target-error:s?",
+                       "on-source-error:s?,on-target-error:s?,"
+                       "granularity:i?,buf-size:i?",
          .mhandler.cmd_new = qmp_marshal_input_drive_mirror,
      },
  
@@@ -1028,6 -963,9 +1029,9 @@@ Arguments
    file/device (NewImageMode, optional, default 'absolute-paths')
  - "speed": maximum speed of the streaming job, in bytes per second
    (json-int)
+ - "granularity": granularity of the dirty bitmap, in bytes (json-int, optional)
+ - "buf_size": maximum amount of data in flight from source to target, in bytes
+   (json-int, default 10M)
  - "sync": what parts of the disk image should be copied to the destination;
    possibilities include "full" for all the disk, "top" for only the sectors
    allocated in the topmost image, or "none" to only replicate new I/O
  - "on-target-error": the action to take on an error on the target
    (BlockdevOnError, default 'report')
  
+ The default value of the granularity is the image cluster size clamped
+ between 4096 and 65536, if the image format defines one.  If the format
+ does not define a cluster size, the default value of the granularity
+ is 65536.
  
  
  Example:
@@@ -2615,6 -2557,13 +2623,6 @@@ Make an asynchronous request for balloo
  json-object will be returned containing the following data:
  
  - "actual": current balloon value in bytes (json-int)
 -- "mem_swapped_in": Amount of memory swapped in bytes (json-int, optional)
 -- "mem_swapped_out": Amount of memory swapped out in bytes (json-int, optional)
 -- "major_page_faults": Number of major faults (json-int, optional)
 -- "minor_page_faults": Number of minor faults (json-int, optional)
 -- "free_mem": Total amount of free and unused memory in
 -              bytes (json-int, optional)
 -- "total_mem": Total amount of available memory in bytes (json-int, optional)
  
  Example:
  
  <- {
        "return":{
           "actual":1073741824,
 -         "mem_swapped_in":0,
 -         "mem_swapped_out":0,
 -         "major_page_faults":142,
 -         "minor_page_faults":239245,
 -         "free_mem":1014185984,
 -         "total_mem":1044668416
        }
     }
  
diff --combined tests/Makefile
index 442b286ccf182805b478a51164eb205475ec19c8,b3a6d8697bea5756a31b03dd7d0594b972c22f88..a77f26a25637663c9ec94fab404db7b73db973b0
@@@ -1,17 -1,17 +1,17 @@@
  export SRC_PATH
  
  check-unit-y = tests/check-qdict$(EXESUF)
 -gcov-files-check-qdict-y = qdict.c
 +gcov-files-check-qdict-y = qobject/qdict.c
  check-unit-y += tests/check-qfloat$(EXESUF)
 -gcov-files-check-qfloat-y = qfloat.c
 +gcov-files-check-qfloat-y = qobject/qfloat.c
  check-unit-y += tests/check-qint$(EXESUF)
 -gcov-files-check-qint-y = qint.c
 +gcov-files-check-qint-y = qobject/qint.c
  check-unit-y += tests/check-qstring$(EXESUF)
 -gcov-files-check-qstring-y = qstring.c
 +gcov-files-check-qstring-y = qobject/qstring.c
  check-unit-y += tests/check-qlist$(EXESUF)
 -gcov-files-check-qlist-y = qlist.c
 +gcov-files-check-qlist-y = qobject/qlist.c
  check-unit-y += tests/check-qjson$(EXESUF)
 -gcov-files-check-qjson-y = qjson.c
 +gcov-files-check-qjson-y = qobject/qjson.c
  check-unit-y += tests/test-qmp-output-visitor$(EXESUF)
  gcov-files-test-qmp-output-visitor-y = qapi/qmp-output-visitor.c
  check-unit-y += tests/test-qmp-input-visitor$(EXESUF)
@@@ -39,12 -39,14 +39,14 @@@ endi
  endif
  check-unit-y += tests/test-visitor-serialization$(EXESUF)
  check-unit-y += tests/test-iov$(EXESUF)
 -gcov-files-test-iov-y = iov.c
 +gcov-files-test-iov-y = util/iov.c
  check-unit-y += tests/test-aio$(EXESUF)
  gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c
  gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c
  check-unit-y += tests/test-thread-pool$(EXESUF)
  gcov-files-test-thread-pool-y = thread-pool.c
+ gcov-files-test-hbitmap-y = util/hbitmap.c
+ check-unit-y += tests/test-hbitmap$(EXESUF)
  
  check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
  
@@@ -57,13 -59,11 +59,13 @@@ gcov-files-i386-y += hw/hd-geometry.
  check-qtest-i386-y += tests/rtc-test$(EXESUF)
  check-qtest-x86_64-y = $(check-qtest-i386-y)
  gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c
 +gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
  check-qtest-sparc-y = tests/m48t59-test$(EXESUF)
  check-qtest-sparc64-y = tests/m48t59-test$(EXESUF)
  gcov-files-sparc-y += hw/m48t59.c
 +gcov-files-sparc64-y += hw/m48t59.c
  check-qtest-arm-y = tests/tmp105-test$(EXESUF)
 -qcov-files-arm-y += hw/tmp105.c
 +gcov-files-arm-y += hw/tmp105.c
  
  GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
  
@@@ -88,6 -88,7 +90,7 @@@ tests/test-coroutine$(EXESUF): tests/te
  tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a
  tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a
  tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a
+ tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o libqemuutil.a libqemustub.a
  
  tests/test-qapi-types.c tests/test-qapi-types.h :\
  $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py