Diff for /qemu/block.c between versions 1.1.1.10 and 1.1.1.22

version 1.1.1.10, 2018/04/24 17:06:50 version 1.1.1.22, 2018/04/24 19:17:20
Line 22 Line 22
  * THE SOFTWARE.   * THE SOFTWARE.
  */   */
 #include "config-host.h"  #include "config-host.h"
 #ifdef _BSD  
 /* include native header before sys-queue.h */  
 #include <sys/queue.h>  
 #endif  
   
 #include "qemu-common.h"  #include "qemu-common.h"
 #include "console.h"  #include "trace.h"
   #include "monitor.h"
 #include "block_int.h"  #include "block_int.h"
   #include "module.h"
   #include "qjson.h"
   #include "qemu-coroutine.h"
   #include "qmp-commands.h"
   
 #ifdef _BSD  #ifdef CONFIG_BSD
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/ioctl.h>  #include <sys/ioctl.h>
   #include <sys/queue.h>
   #ifndef __DragonFly__
 #include <sys/disk.h>  #include <sys/disk.h>
 #endif  #endif
   #endif
   
 #define SECTOR_BITS 9  #ifdef _WIN32
 #define SECTOR_SIZE (1 << SECTOR_BITS)  #include <windows.h>
   #endif
 static AIOPool vectored_aio_pool;  
   
 typedef struct BlockDriverAIOCBSync {  #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
     BlockDriverAIOCB common;  
     QEMUBH *bh;  
     int ret;  
 } BlockDriverAIOCBSync;  
   
 static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,  static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
         int64_t sector_num, uint8_t *buf, int nb_sectors,  static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
           int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);          BlockDriverCompletionFunc *cb, void *opaque);
 static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,  static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
         int64_t sector_num, const uint8_t *buf, int nb_sectors,          int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);          BlockDriverCompletionFunc *cb, void *opaque);
 static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);  static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
 static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,                                           int64_t sector_num, int nb_sectors,
                         uint8_t *buf, int nb_sectors);                                           QEMUIOVector *iov);
 static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,  static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
                          const uint8_t *buf, int nb_sectors);                                           int64_t sector_num, int nb_sectors,
                                            QEMUIOVector *iov);
   static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
       int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
   static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
       int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
   static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
                                                  int64_t sector_num,
                                                  QEMUIOVector *qiov,
                                                  int nb_sectors,
                                                  BlockDriverCompletionFunc *cb,
                                                  void *opaque,
                                                  bool is_write);
   static void coroutine_fn bdrv_co_do_rw(void *opaque);
   
   static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
       QTAILQ_HEAD_INITIALIZER(bdrv_states);
   
   static QLIST_HEAD(, BlockDriver) bdrv_drivers =
       QLIST_HEAD_INITIALIZER(bdrv_drivers);
   
   /* The device to use for VM snapshots */
   static BlockDriverState *bs_snapshots;
   
   /* If non-zero, use only whitelisted block drivers */
   static int use_bdrv_whitelist;
   
   #ifdef _WIN32
   static int is_windows_drive_prefix(const char *filename)
   {
       return (((filename[0] >= 'a' && filename[0] <= 'z') ||
                (filename[0] >= 'A' && filename[0] <= 'Z')) &&
               filename[1] == ':');
   }
   
   int is_windows_drive(const char *filename)
   {
       if (is_windows_drive_prefix(filename) &&
           filename[2] == '\0')
           return 1;
       if (strstart(filename, "\\\\.\\", NULL) ||
           strstart(filename, "//./", NULL))
           return 1;
       return 0;
   }
   #endif
   
 BlockDriverState *bdrv_first;  /* check if the path starts with "<protocol>:" */
   static int path_has_protocol(const char *path)
   {
   #ifdef _WIN32
       if (is_windows_drive(path) ||
           is_windows_drive_prefix(path)) {
           return 0;
       }
   #endif
   
 static BlockDriver *first_drv;      return strchr(path, ':') != NULL;
   }
   
 int path_is_absolute(const char *path)  int path_is_absolute(const char *path)
 {  {
Line 129  void path_combine(char *dest, int dest_s Line 182  void path_combine(char *dest, int dest_s
     }      }
 }  }
   
   void bdrv_register(BlockDriver *bdrv)
 static void bdrv_register(BlockDriver *bdrv)  
 {  {
     if (!bdrv->bdrv_aio_read) {      /* Block drivers without coroutine functions need emulation */
         /* add AIO emulation layer */      if (!bdrv->bdrv_co_readv) {
         bdrv->bdrv_aio_read = bdrv_aio_read_em;          bdrv->bdrv_co_readv = bdrv_co_readv_em;
         bdrv->bdrv_aio_write = bdrv_aio_write_em;          bdrv->bdrv_co_writev = bdrv_co_writev_em;
         bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em;  
         bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync);          /* bdrv_co_readv_em()/brdv_co_writev_em() work in terms of aio, so if
     } else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) {           * the block driver lacks aio we need to emulate that too.
         /* add synchronous IO emulation layer */           */
         bdrv->bdrv_read = bdrv_read_em;          if (!bdrv->bdrv_aio_readv) {
         bdrv->bdrv_write = bdrv_write_em;              /* add AIO emulation layer */
     }              bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
     aio_pool_init(&bdrv->aio_pool, bdrv->aiocb_size, bdrv->bdrv_aio_cancel);              bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
     bdrv->next = first_drv;          }
     first_drv = bdrv;      }
   
       QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
 }  }
   
 /* create a new block device (by default it is empty) */  /* create a new block device (by default it is empty) */
 BlockDriverState *bdrv_new(const char *device_name)  BlockDriverState *bdrv_new(const char *device_name)
 {  {
     BlockDriverState **pbs, *bs;      BlockDriverState *bs;
   
     bs = qemu_mallocz(sizeof(BlockDriverState));      bs = g_malloc0(sizeof(BlockDriverState));
     pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);      pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
     if (device_name[0] != '\0') {      if (device_name[0] != '\0') {
         /* insert at the end */          QTAILQ_INSERT_TAIL(&bdrv_states, bs, list);
         pbs = &bdrv_first;  
         while (*pbs != NULL)  
             pbs = &(*pbs)->next;  
         *pbs = bs;  
     }      }
       bdrv_iostatus_disable(bs);
     return bs;      return bs;
 }  }
   
 BlockDriver *bdrv_find_format(const char *format_name)  BlockDriver *bdrv_find_format(const char *format_name)
 {  {
     BlockDriver *drv1;      BlockDriver *drv1;
     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {      QLIST_FOREACH(drv1, &bdrv_drivers, list) {
         if (!strcmp(drv1->format_name, format_name))          if (!strcmp(drv1->format_name, format_name)) {
             return drv1;              return drv1;
           }
     }      }
     return NULL;      return NULL;
 }  }
   
 int bdrv_create(BlockDriver *drv,  static int bdrv_is_whitelisted(BlockDriver *drv)
                 const char *filename, int64_t size_in_sectors,  {
                 const char *backing_file, int flags)      static const char *whitelist[] = {
           CONFIG_BDRV_WHITELIST
       };
       const char **p;
   
       if (!whitelist[0])
           return 1;               /* no whitelist, anything goes */
   
       for (p = whitelist; *p; p++) {
           if (!strcmp(drv->format_name, *p)) {
               return 1;
           }
       }
       return 0;
   }
   
   BlockDriver *bdrv_find_whitelisted_format(const char *format_name)
   {
       BlockDriver *drv = bdrv_find_format(format_name);
       return drv && bdrv_is_whitelisted(drv) ? drv : NULL;
   }
   
   int bdrv_create(BlockDriver *drv, const char* filename,
       QEMUOptionParameter *options)
 {  {
     if (!drv->bdrv_create)      if (!drv->bdrv_create)
         return -ENOTSUP;          return -ENOTSUP;
     return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);  
       return drv->bdrv_create(filename, options);
   }
   
   int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
   {
       BlockDriver *drv;
   
       drv = bdrv_find_protocol(filename);
       if (drv == NULL) {
           return -ENOENT;
       }
   
       return bdrv_create(drv, filename, options);
 }  }
   
 #ifdef _WIN32  #ifdef _WIN32
Line 207  void get_tmp_filename(char *filename, in Line 295  void get_tmp_filename(char *filename, in
 }  }
 #endif  #endif
   
 #ifdef _WIN32  /*
 static int is_windows_drive_prefix(const char *filename)   * Detect host devices. By convention, /dev/cdrom[N] is always
    * recognized as a host CDROM.
    */
   static BlockDriver *find_hdev_driver(const char *filename)
 {  {
     return (((filename[0] >= 'a' && filename[0] <= 'z') ||      int score_max = 0, score;
              (filename[0] >= 'A' && filename[0] <= 'Z')) &&      BlockDriver *drv = NULL, *d;
             filename[1] == ':');  
 }  
   
 static int is_windows_drive(const char *filename)      QLIST_FOREACH(d, &bdrv_drivers, list) {
 {          if (d->bdrv_probe_device) {
     if (is_windows_drive_prefix(filename) &&              score = d->bdrv_probe_device(filename);
         filename[2] == '\0')              if (score > score_max) {
         return 1;                  score_max = score;
     if (strstart(filename, "\\\\.\\", NULL) ||                  drv = d;
         strstart(filename, "//./", NULL))              }
         return 1;          }
     return 0;      }
   
       return drv;
 }  }
 #endif  
   
 static BlockDriver *find_protocol(const char *filename)  BlockDriver *bdrv_find_protocol(const char *filename)
 {  {
     BlockDriver *drv1;      BlockDriver *drv1;
     char protocol[128];      char protocol[128];
     int len;      int len;
     const char *p;      const char *p;
   
 #ifdef _WIN32      /* TODO Drivers without bdrv_file_open must be specified explicitly */
     if (is_windows_drive(filename) ||  
         is_windows_drive_prefix(filename))      /*
         return &bdrv_raw;       * XXX(hch): we really should not let host device detection
 #endif       * override an explicit protocol specification, but moving this
        * later breaks access to device names with colons in them.
        * Thanks to the brain-dead persistent naming schemes on udev-
        * based Linux systems those actually are quite common.
        */
       drv1 = find_hdev_driver(filename);
       if (drv1) {
           return drv1;
       }
   
       if (!path_has_protocol(filename)) {
           return bdrv_find_format("file");
       }
     p = strchr(filename, ':');      p = strchr(filename, ':');
     if (!p)      assert(p != NULL);
         return &bdrv_raw;  
     len = p - filename;      len = p - filename;
     if (len > sizeof(protocol) - 1)      if (len > sizeof(protocol) - 1)
         len = sizeof(protocol) - 1;          len = sizeof(protocol) - 1;
     memcpy(protocol, filename, len);      memcpy(protocol, filename, len);
     protocol[len] = '\0';      protocol[len] = '\0';
     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {      QLIST_FOREACH(drv1, &bdrv_drivers, list) {
         if (drv1->protocol_name &&          if (drv1->protocol_name &&
             !strcmp(drv1->protocol_name, protocol))              !strcmp(drv1->protocol_name, protocol)) {
             return drv1;              return drv1;
           }
     }      }
     return NULL;      return NULL;
 }  }
   
 /* XXX: force raw format if block or character device ? It would  static int find_image_format(const char *filename, BlockDriver **pdrv)
    simplify the BSD case */  
 static BlockDriver *find_image_format(const char *filename)  
 {  {
     int ret, score, score_max;      int ret, score, score_max;
     BlockDriver *drv1, *drv;      BlockDriver *drv1, *drv;
     uint8_t buf[2048];      uint8_t buf[2048];
     BlockDriverState *bs;      BlockDriverState *bs;
   
     /* detect host devices. By convention, /dev/cdrom[N] is always      ret = bdrv_file_open(&bs, filename, 0);
        recognized as a host CDROM */      if (ret < 0) {
     if (strstart(filename, "/dev/cdrom", NULL))          *pdrv = NULL;
         return &bdrv_host_device;          return ret;
 #ifdef _WIN32  
     if (is_windows_drive(filename))  
         return &bdrv_host_device;  
 #else  
     {  
         struct stat st;  
         if (stat(filename, &st) >= 0 &&  
             (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {  
             return &bdrv_host_device;  
         }  
     }      }
 #endif  
   
     drv = find_protocol(filename);      /* Return the raw BlockDriver * to scsi-generic devices or empty drives */
     /* no need to test disk image formats for vvfat */      if (bs->sg || !bdrv_is_inserted(bs)) {
     if (drv == &bdrv_vvfat)          bdrv_delete(bs);
         return drv;          drv = bdrv_find_format("raw");
           if (!drv) {
               ret = -ENOENT;
           }
           *pdrv = drv;
           return ret;
       }
   
     ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);  
     if (ret < 0)  
         return NULL;  
     ret = bdrv_pread(bs, 0, buf, sizeof(buf));      ret = bdrv_pread(bs, 0, buf, sizeof(buf));
     bdrv_delete(bs);      bdrv_delete(bs);
     if (ret < 0) {      if (ret < 0) {
         return NULL;          *pdrv = NULL;
           return ret;
     }      }
   
     score_max = 0;      score_max = 0;
     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {      drv = NULL;
       QLIST_FOREACH(drv1, &bdrv_drivers, list) {
         if (drv1->bdrv_probe) {          if (drv1->bdrv_probe) {
             score = drv1->bdrv_probe(buf, ret, filename);              score = drv1->bdrv_probe(buf, ret, filename);
             if (score > score_max) {              if (score > score_max) {
Line 305  static BlockDriver *find_image_format(co Line 399  static BlockDriver *find_image_format(co
             }              }
         }          }
     }      }
     return drv;      if (!drv) {
           ret = -ENOENT;
       }
       *pdrv = drv;
       return ret;
   }
   
   /**
    * Set the current 'total_sectors' value
    */
   static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
   {
       BlockDriver *drv = bs->drv;
   
       /* Do not attempt drv->bdrv_getlength() on scsi-generic devices */
       if (bs->sg)
           return 0;
   
       /* query actual device if possible, otherwise just trust the hint */
       if (drv->bdrv_getlength) {
           int64_t length = drv->bdrv_getlength(bs);
           if (length < 0) {
               return length;
           }
           hint = length >> BDRV_SECTOR_BITS;
       }
   
       bs->total_sectors = hint;
       return 0;
 }  }
   
   /**
    * Set open flags for a given cache mode
    *
    * Return 0 on success, -1 if the cache mode was invalid.
    */
   int bdrv_parse_cache_flags(const char *mode, int *flags)
   {
       *flags &= ~BDRV_O_CACHE_MASK;
   
       if (!strcmp(mode, "off") || !strcmp(mode, "none")) {
           *flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
       } else if (!strcmp(mode, "directsync")) {
           *flags |= BDRV_O_NOCACHE;
       } else if (!strcmp(mode, "writeback")) {
           *flags |= BDRV_O_CACHE_WB;
       } else if (!strcmp(mode, "unsafe")) {
           *flags |= BDRV_O_CACHE_WB;
           *flags |= BDRV_O_NO_FLUSH;
       } else if (!strcmp(mode, "writethrough")) {
           /* this is the default */
       } else {
           return -1;
       }
   
       return 0;
   }
   
   /*
    * Common part for opening disk images and files
    */
   static int bdrv_open_common(BlockDriverState *bs, const char *filename,
       int flags, BlockDriver *drv)
   {
       int ret, open_flags;
   
       assert(drv != NULL);
   
       trace_bdrv_open_common(bs, filename, flags, drv->format_name);
   
       bs->file = NULL;
       bs->total_sectors = 0;
       bs->encrypted = 0;
       bs->valid_key = 0;
       bs->sg = 0;
       bs->open_flags = flags;
       bs->growable = 0;
       bs->buffer_alignment = 512;
   
       pstrcpy(bs->filename, sizeof(bs->filename), filename);
       bs->backing_file[0] = '\0';
   
       if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
           return -ENOTSUP;
       }
   
       bs->drv = drv;
       bs->opaque = g_malloc0(drv->instance_size);
   
       bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
   
       /*
        * Clear flags that are internal to the block layer before opening the
        * image.
        */
       open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
   
       /*
        * Snapshots should be writable.
        */
       if (bs->is_temporary) {
           open_flags |= BDRV_O_RDWR;
       }
   
       bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
   
       /* Open the image, either directly or using a protocol */
       if (drv->bdrv_file_open) {
           ret = drv->bdrv_file_open(bs, filename, open_flags);
       } else {
           ret = bdrv_file_open(&bs->file, filename, open_flags);
           if (ret >= 0) {
               ret = drv->bdrv_open(bs, open_flags);
           }
       }
   
       if (ret < 0) {
           goto free_and_fail;
       }
   
       ret = refresh_total_sectors(bs, bs->total_sectors);
       if (ret < 0) {
           goto free_and_fail;
       }
   
   #ifndef _WIN32
       if (bs->is_temporary) {
           unlink(filename);
       }
   #endif
       return 0;
   
   free_and_fail:
       if (bs->file) {
           bdrv_delete(bs->file);
           bs->file = NULL;
       }
       g_free(bs->opaque);
       bs->opaque = NULL;
       bs->drv = NULL;
       return ret;
   }
   
   /*
    * Opens a file using a protocol (file, host_device, nbd, ...)
    */
 int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)  int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
 {  {
     BlockDriverState *bs;      BlockDriverState *bs;
       BlockDriver *drv;
     int ret;      int ret;
   
       drv = bdrv_find_protocol(filename);
       if (!drv) {
           return -ENOENT;
       }
   
     bs = bdrv_new("");      bs = bdrv_new("");
     ret = bdrv_open2(bs, filename, flags | BDRV_O_FILE, NULL);      ret = bdrv_open_common(bs, filename, flags, drv);
     if (ret < 0) {      if (ret < 0) {
         bdrv_delete(bs);          bdrv_delete(bs);
         return ret;          return ret;
Line 324  int bdrv_file_open(BlockDriverState **pb Line 567  int bdrv_file_open(BlockDriverState **pb
     return 0;      return 0;
 }  }
   
 int bdrv_open(BlockDriverState *bs, const char *filename, int flags)  /*
 {   * Opens a disk image (raw, qcow2, vmdk, ...)
     return bdrv_open2(bs, filename, flags, NULL);   */
 }  int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
                 BlockDriver *drv)
 int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,  
                BlockDriver *drv)  
 {  {
     int ret, open_flags;      int ret;
     char tmp_filename[PATH_MAX];      char tmp_filename[PATH_MAX];
     char backing_filename[PATH_MAX];  
   
     bs->read_only = 0;  
     bs->is_temporary = 0;  
     bs->encrypted = 0;  
     bs->valid_key = 0;  
   
     if (flags & BDRV_O_SNAPSHOT) {      if (flags & BDRV_O_SNAPSHOT) {
         BlockDriverState *bs1;          BlockDriverState *bs1;
         int64_t total_size;          int64_t total_size;
         int is_protocol = 0;          int is_protocol = 0;
           BlockDriver *bdrv_qcow2;
           QEMUOptionParameter *options;
           char backing_filename[PATH_MAX];
   
         /* if snapshot, we create a temporary backing file and open it          /* if snapshot, we create a temporary backing file and open it
            instead of opening 'filename' directly */             instead of opening 'filename' directly */
   
         /* if there is a backing file, use it */          /* if there is a backing file, use it */
         bs1 = bdrv_new("");          bs1 = bdrv_new("");
         ret = bdrv_open(bs1, filename, 0);          ret = bdrv_open(bs1, filename, 0, drv);
         if (ret < 0) {          if (ret < 0) {
             bdrv_delete(bs1);              bdrv_delete(bs1);
             return ret;              return ret;
         }          }
         total_size = bdrv_getlength(bs1) >> SECTOR_BITS;          total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
   
         if (bs1->drv && bs1->drv->protocol_name)          if (bs1->drv && bs1->drv->protocol_name)
             is_protocol = 1;              is_protocol = 1;
Line 369  int bdrv_open2(BlockDriverState *bs, con Line 607  int bdrv_open2(BlockDriverState *bs, con
         if (is_protocol)          if (is_protocol)
             snprintf(backing_filename, sizeof(backing_filename),              snprintf(backing_filename, sizeof(backing_filename),
                      "%s", filename);                       "%s", filename);
         else          else if (!realpath(filename, backing_filename))
             realpath(filename, backing_filename);              return -errno;
   
           bdrv_qcow2 = bdrv_find_format("qcow2");
           options = parse_option_parameters("", bdrv_qcow2->create_options, NULL);
   
         ret = bdrv_create(&bdrv_qcow2, tmp_filename,          set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size);
                           total_size, backing_filename, 0);          set_option_parameter(options, BLOCK_OPT_BACKING_FILE, backing_filename);
           if (drv) {
               set_option_parameter(options, BLOCK_OPT_BACKING_FMT,
                   drv->format_name);
           }
   
           ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
           free_option_parameters(options);
         if (ret < 0) {          if (ret < 0) {
             return ret;              return ret;
         }          }
   
         filename = tmp_filename;          filename = tmp_filename;
           drv = bdrv_qcow2;
         bs->is_temporary = 1;          bs->is_temporary = 1;
     }      }
   
     pstrcpy(bs->filename, sizeof(bs->filename), filename);      /* Find the right image format driver */
     if (flags & BDRV_O_FILE) {      if (!drv) {
         drv = find_protocol(filename);          ret = find_image_format(filename, &drv);
     } else if (!drv) {  
         drv = find_image_format(filename);  
     }      }
   
     if (!drv) {      if (!drv) {
         ret = -ENOENT;  
         goto unlink_and_fail;          goto unlink_and_fail;
     }      }
     bs->drv = drv;  
     bs->opaque = qemu_mallocz(drv->instance_size);      /* Open the image */
     /* Note: for compatibility, we open disk image files as RDWR, and      ret = bdrv_open_common(bs, filename, flags, drv);
        RDONLY as fallback */  
     if (!(flags & BDRV_O_FILE))  
         open_flags = BDRV_O_RDWR | (flags & BDRV_O_CACHE_MASK);  
     else  
         open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);  
     ret = drv->bdrv_open(bs, filename, open_flags);  
     if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE)) {  
         ret = drv->bdrv_open(bs, filename, open_flags & ~BDRV_O_RDWR);  
         bs->read_only = 1;  
     }  
     if (ret < 0) {      if (ret < 0) {
         qemu_free(bs->opaque);          goto unlink_and_fail;
         bs->opaque = NULL;  
         bs->drv = NULL;  
     unlink_and_fail:  
         if (bs->is_temporary)  
             unlink(filename);  
         return ret;  
     }  
     if (drv->bdrv_getlength) {  
         bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;  
     }  
 #ifndef _WIN32  
     if (bs->is_temporary) {  
         unlink(filename);  
     }      }
 #endif  
     if (bs->backing_file[0] != '\0') {      /* If there is a backing file, use it */
         /* if there is a backing file, use it */      if ((flags & BDRV_O_NO_BACKING) == 0 && bs->backing_file[0] != '\0') {
           char backing_filename[PATH_MAX];
           int back_flags;
           BlockDriver *back_drv = NULL;
   
         bs->backing_hd = bdrv_new("");          bs->backing_hd = bdrv_new("");
         path_combine(backing_filename, sizeof(backing_filename),  
                      filename, bs->backing_file);          if (path_has_protocol(bs->backing_file)) {
         ret = bdrv_open(bs->backing_hd, backing_filename, open_flags);              pstrcpy(backing_filename, sizeof(backing_filename),
                       bs->backing_file);
           } else {
               path_combine(backing_filename, sizeof(backing_filename),
                            filename, bs->backing_file);
           }
   
           if (bs->backing_format[0] != '\0') {
               back_drv = bdrv_find_format(bs->backing_format);
           }
   
           /* backing files always opened read-only */
           back_flags =
               flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
   
           ret = bdrv_open(bs->backing_hd, backing_filename, back_flags, back_drv);
         if (ret < 0) {          if (ret < 0) {
             bdrv_close(bs);              bdrv_close(bs);
             return ret;              return ret;
         }          }
           if (bs->is_temporary) {
               bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR);
           } else {
               /* base image inherits from "parent" */
               bs->backing_hd->keep_read_only = bs->keep_read_only;
           }
     }      }
   
     /* call the change callback */      if (!bdrv_key_required(bs)) {
     bs->media_changed = 1;          bdrv_dev_change_media_cb(bs, true);
     if (bs->change_cb)      }
         bs->change_cb(bs->change_opaque);  
   
     return 0;      return 0;
   
   unlink_and_fail:
       if (bs->is_temporary) {
           unlink(filename);
       }
       return ret;
 }  }
   
 void bdrv_close(BlockDriverState *bs)  void bdrv_close(BlockDriverState *bs)
 {  {
     if (bs->drv) {      if (bs->drv) {
         if (bs->backing_hd)          if (bs == bs_snapshots) {
               bs_snapshots = NULL;
           }
           if (bs->backing_hd) {
             bdrv_delete(bs->backing_hd);              bdrv_delete(bs->backing_hd);
               bs->backing_hd = NULL;
           }
         bs->drv->bdrv_close(bs);          bs->drv->bdrv_close(bs);
         qemu_free(bs->opaque);          g_free(bs->opaque);
 #ifdef _WIN32  #ifdef _WIN32
         if (bs->is_temporary) {          if (bs->is_temporary) {
             unlink(bs->filename);              unlink(bs->filename);
Line 456  void bdrv_close(BlockDriverState *bs) Line 716  void bdrv_close(BlockDriverState *bs)
         bs->opaque = NULL;          bs->opaque = NULL;
         bs->drv = NULL;          bs->drv = NULL;
   
         /* call the change callback */          if (bs->file != NULL) {
         bs->media_changed = 1;              bdrv_close(bs->file);
         if (bs->change_cb)          }
             bs->change_cb(bs->change_opaque);  
           bdrv_dev_change_media_cb(bs, false);
     }      }
 }  }
   
 void bdrv_delete(BlockDriverState *bs)  void bdrv_close_all(void)
 {  {
     BlockDriverState **pbs;      BlockDriverState *bs;
   
     pbs = &bdrv_first;      QTAILQ_FOREACH(bs, &bdrv_states, list) {
     while (*pbs != bs && *pbs != NULL)          bdrv_close(bs);
         pbs = &(*pbs)->next;      }
     if (*pbs == bs)  }
         *pbs = bs->next;  
   
     bdrv_close(bs);  /* make a BlockDriverState anonymous by removing from bdrv_state list.
     qemu_free(bs);     Also, NULL terminate the device_name to prevent double remove */
   void bdrv_make_anon(BlockDriverState *bs)
   {
       if (bs->device_name[0] != '\0') {
           QTAILQ_REMOVE(&bdrv_states, bs, list);
       }
       bs->device_name[0] = '\0';
 }  }
   
 /* commit COW file into the raw image */  void bdrv_delete(BlockDriverState *bs)
 int bdrv_commit(BlockDriverState *bs)  
 {  {
     BlockDriver *drv = bs->drv;      assert(!bs->dev);
     int64_t i, total_sectors;  
     int n, j;      /* remove from list, if necessary */
     unsigned char sector[512];      bdrv_make_anon(bs);
   
       bdrv_close(bs);
       if (bs->file != NULL) {
           bdrv_delete(bs->file);
       }
   
       assert(bs != bs_snapshots);
       g_free(bs);
   }
   
   int bdrv_attach_dev(BlockDriverState *bs, void *dev)
   /* TODO change to DeviceState *dev when all users are qdevified */
   {
       if (bs->dev) {
           return -EBUSY;
       }
       bs->dev = dev;
       bdrv_iostatus_reset(bs);
       return 0;
   }
   
   /* TODO qdevified devices don't use this, remove when devices are qdevified */
   void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
   {
       if (bdrv_attach_dev(bs, dev) < 0) {
           abort();
       }
   }
   
   void bdrv_detach_dev(BlockDriverState *bs, void *dev)
   /* TODO change to DeviceState *dev when all users are qdevified */
   {
       assert(bs->dev == dev);
       bs->dev = NULL;
       bs->dev_ops = NULL;
       bs->dev_opaque = NULL;
       bs->buffer_alignment = 512;
   }
   
   /* TODO change to return DeviceState * when all users are qdevified */
   void *bdrv_get_attached_dev(BlockDriverState *bs)
   {
       return bs->dev;
   }
   
   void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
                         void *opaque)
   {
       bs->dev_ops = ops;
       bs->dev_opaque = opaque;
       if (bdrv_dev_has_removable_media(bs) && bs == bs_snapshots) {
           bs_snapshots = NULL;
       }
   }
   
   static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
   {
       if (bs->dev_ops && bs->dev_ops->change_media_cb) {
           bs->dev_ops->change_media_cb(bs->dev_opaque, load);
       }
   }
   
   bool bdrv_dev_has_removable_media(BlockDriverState *bs)
   {
       return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
   }
   
   void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
   {
       if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
           bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
       }
   }
   
   bool bdrv_dev_is_tray_open(BlockDriverState *bs)
   {
       if (bs->dev_ops && bs->dev_ops->is_tray_open) {
           return bs->dev_ops->is_tray_open(bs->dev_opaque);
       }
       return false;
   }
   
   static void bdrv_dev_resize_cb(BlockDriverState *bs)
   {
       if (bs->dev_ops && bs->dev_ops->resize_cb) {
           bs->dev_ops->resize_cb(bs->dev_opaque);
       }
   }
   
   bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
   {
       if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
           return bs->dev_ops->is_medium_locked(bs->dev_opaque);
       }
       return false;
   }
   
   /*
    * Run consistency checks on an image
    *
    * Returns 0 if the check could be completed (it doesn't mean that the image is
    * free of errors) or -errno when an internal error occurred. The results of the
    * check are stored in res.
    */
   int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res)
   {
       if (bs->drv->bdrv_check == NULL) {
           return -ENOTSUP;
       }
   
       memset(res, 0, sizeof(*res));
       return bs->drv->bdrv_check(bs, res);
   }
   
   #define COMMIT_BUF_SECTORS 2048
   
   /* commit COW file into the raw image */
   int bdrv_commit(BlockDriverState *bs)
   {
       BlockDriver *drv = bs->drv;
       BlockDriver *backing_drv;
       int64_t sector, total_sectors;
       int n, ro, open_flags;
       int ret = 0, rw_ret = 0;
       uint8_t *buf;
       char filename[1024];
       BlockDriverState *bs_rw, *bs_ro;
   
     if (!drv)      if (!drv)
         return -ENOMEDIUM;          return -ENOMEDIUM;
       
       if (!bs->backing_hd) {
           return -ENOTSUP;
       }
   
     if (bs->read_only) {      if (bs->backing_hd->keep_read_only) {
         return -EACCES;          return -EACCES;
     }      }
   
     if (!bs->backing_hd) {      backing_drv = bs->backing_hd->drv;
         return -ENOTSUP;      ro = bs->backing_hd->read_only;
       strncpy(filename, bs->backing_hd->filename, sizeof(filename));
       open_flags =  bs->backing_hd->open_flags;
   
       if (ro) {
           /* re-open as RW */
           bdrv_delete(bs->backing_hd);
           bs->backing_hd = NULL;
           bs_rw = bdrv_new("");
           rw_ret = bdrv_open(bs_rw, filename, open_flags | BDRV_O_RDWR,
               backing_drv);
           if (rw_ret < 0) {
               bdrv_delete(bs_rw);
               /* try to re-open read-only */
               bs_ro = bdrv_new("");
               ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR,
                   backing_drv);
               if (ret < 0) {
                   bdrv_delete(bs_ro);
                   /* drive not functional anymore */
                   bs->drv = NULL;
                   return ret;
               }
               bs->backing_hd = bs_ro;
               return rw_ret;
           }
           bs->backing_hd = bs_rw;
     }      }
   
     total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;      total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
     for (i = 0; i < total_sectors;) {      buf = g_malloc(COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
         if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {  
             for(j = 0; j < n; j++) {  
                 if (bdrv_read(bs, i, sector, 1) != 0) {  
                     return -EIO;  
                 }  
   
                 if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {      for (sector = 0; sector < total_sectors; sector += n) {
                     return -EIO;          if (drv->bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n)) {
                 }  
                 i++;              if (bdrv_read(bs, sector, buf, n) != 0) {
             }                  ret = -EIO;
         } else {                  goto ro_cleanup;
             i += n;              }
   
               if (bdrv_write(bs->backing_hd, sector, buf, n) != 0) {
                   ret = -EIO;
                   goto ro_cleanup;
               }
           }
       }
   
       if (drv->bdrv_make_empty) {
           ret = drv->bdrv_make_empty(bs);
           bdrv_flush(bs);
       }
   
       /*
        * Make sure all data we wrote to the backing device is actually
        * stable on disk.
        */
       if (bs->backing_hd)
           bdrv_flush(bs->backing_hd);
   
   ro_cleanup:
       g_free(buf);
   
       if (ro) {
           /* re-open as RO */
           bdrv_delete(bs->backing_hd);
           bs->backing_hd = NULL;
           bs_ro = bdrv_new("");
           ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR,
               backing_drv);
           if (ret < 0) {
               bdrv_delete(bs_ro);
               /* drive not functional anymore */
               bs->drv = NULL;
               return ret;
         }          }
           bs->backing_hd = bs_ro;
           bs->backing_hd->keep_read_only = 0;
     }      }
   
     if (drv->bdrv_make_empty)      return ret;
         return drv->bdrv_make_empty(bs);  }
   
   void bdrv_commit_all(void)
   {
       BlockDriverState *bs;
   
     return 0;      QTAILQ_FOREACH(bs, &bdrv_states, list) {
           bdrv_commit(bs);
       }
   }
   
   /*
    * Return values:
    * 0        - success
    * -EINVAL  - backing format specified, but no file
    * -ENOSPC  - can't update the backing file because no space is left in the
    *            image file header
    * -ENOTSUP - format driver doesn't support changing the backing file
    */
   int bdrv_change_backing_file(BlockDriverState *bs,
       const char *backing_file, const char *backing_fmt)
   {
       BlockDriver *drv = bs->drv;
   
       if (drv->bdrv_change_backing_file != NULL) {
           return drv->bdrv_change_backing_file(bs, backing_file, backing_fmt);
       } else {
           return -ENOTSUP;
       }
 }  }
   
 static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,  static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
Line 533  static int bdrv_check_byte_request(Block Line 1013  static int bdrv_check_byte_request(Block
   
     len = bdrv_getlength(bs);      len = bdrv_getlength(bs);
   
     if ((offset + size) > len)      if (offset < 0)
           return -EIO;
   
       if ((offset > len) || (len - offset < size))
         return -EIO;          return -EIO;
   
     return 0;      return 0;
Line 542  static int bdrv_check_byte_request(Block Line 1025  static int bdrv_check_byte_request(Block
 static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,  static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
                               int nb_sectors)                                int nb_sectors)
 {  {
     int64_t offset;      return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
                                      nb_sectors * BDRV_SECTOR_SIZE);
   }
   
     /* Deal with byte accesses */  typedef struct RwCo {
     if (sector_num < 0)      BlockDriverState *bs;
         offset = -sector_num;      int64_t sector_num;
     else      int nb_sectors;
         offset = sector_num * 512;      QEMUIOVector *qiov;
       bool is_write;
       int ret;
   } RwCo;
   
   static void coroutine_fn bdrv_rw_co_entry(void *opaque)
   {
       RwCo *rwco = opaque;
   
       if (!rwco->is_write) {
           rwco->ret = bdrv_co_do_readv(rwco->bs, rwco->sector_num,
                                        rwco->nb_sectors, rwco->qiov);
       } else {
           rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num,
                                         rwco->nb_sectors, rwco->qiov);
       }
   }
   
     return bdrv_check_byte_request(bs, offset, nb_sectors * 512);  /*
    * Process a synchronous request using coroutines
    */
   static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
                         int nb_sectors, bool is_write)
   {
       QEMUIOVector qiov;
       struct iovec iov = {
           .iov_base = (void *)buf,
           .iov_len = nb_sectors * BDRV_SECTOR_SIZE,
       };
       Coroutine *co;
       RwCo rwco = {
           .bs = bs,
           .sector_num = sector_num,
           .nb_sectors = nb_sectors,
           .qiov = &qiov,
           .is_write = is_write,
           .ret = NOT_DONE,
       };
   
       qemu_iovec_init_external(&qiov, &iov, 1);
   
       if (qemu_in_coroutine()) {
           /* Fast-path if already in coroutine context */
           bdrv_rw_co_entry(&rwco);
       } else {
           co = qemu_coroutine_create(bdrv_rw_co_entry);
           qemu_coroutine_enter(co, &rwco);
           while (rwco.ret == NOT_DONE) {
               qemu_aio_wait();
           }
       }
       return rwco.ret;
 }  }
   
 /* return < 0 if error. See bdrv_write() for the return codes */  /* return < 0 if error. See bdrv_write() for the return codes */
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,  int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors)                uint8_t *buf, int nb_sectors)
 {  {
     BlockDriver *drv = bs->drv;      return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false);
   }
   
     if (!drv)  static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
         return -ENOMEDIUM;                               int nb_sectors, int dirty)
     if (bdrv_check_request(bs, sector_num, nb_sectors))  {
         return -EIO;      int64_t start, end;
       unsigned long val, idx, bit;
   
     if (drv->bdrv_pread) {      start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
         int ret, len;      end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
         len = nb_sectors * 512;  
         ret = drv->bdrv_pread(bs, sector_num * 512, buf, len);      for (; start <= end; start++) {
         if (ret < 0)          idx = start / (sizeof(unsigned long) * 8);
             return ret;          bit = start % (sizeof(unsigned long) * 8);
         else if (ret != len)          val = bs->dirty_bitmap[idx];
             return -EINVAL;          if (dirty) {
         else {              if (!(val & (1UL << bit))) {
             bs->rd_bytes += (unsigned) len;                  bs->dirty_count++;
             bs->rd_ops ++;                  val |= 1UL << bit;
             return 0;              }
         }          } else {
     } else {              if (val & (1UL << bit)) {
         return drv->bdrv_read(bs, sector_num, buf, nb_sectors);                  bs->dirty_count--;
                   val &= ~(1UL << bit);
               }
           }
           bs->dirty_bitmap[idx] = val;
     }      }
 }  }
   
Line 591  int bdrv_read(BlockDriverState *bs, int6 Line 1131  int bdrv_read(BlockDriverState *bs, int6
 int bdrv_write(BlockDriverState *bs, int64_t sector_num,  int bdrv_write(BlockDriverState *bs, int64_t sector_num,
                const uint8_t *buf, int nb_sectors)                 const uint8_t *buf, int nb_sectors)
 {  {
     BlockDriver *drv = bs->drv;      return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true);
     if (!bs->drv)  
         return -ENOMEDIUM;  
     if (bs->read_only)  
         return -EACCES;  
     if (bdrv_check_request(bs, sector_num, nb_sectors))  
         return -EIO;  
   
     if (drv->bdrv_pwrite) {  
         int ret, len, count = 0;  
         len = nb_sectors * 512;  
         do {  
             ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len - count);  
             if (ret < 0) {  
                 printf("bdrv_write ret=%d\n", ret);  
                 return ret;  
             }  
             count += ret;  
             buf += ret;  
         } while (count != len);  
         bs->wr_bytes += (unsigned) len;  
         bs->wr_ops ++;  
         return 0;  
     }  
     return drv->bdrv_write(bs, sector_num, buf, nb_sectors);  
 }  }
   
 static int bdrv_pread_em(BlockDriverState *bs, int64_t offset,  int bdrv_pread(BlockDriverState *bs, int64_t offset,
                          uint8_t *buf, int count1)                 void *buf, int count1)
 {  {
     uint8_t tmp_buf[SECTOR_SIZE];      uint8_t tmp_buf[BDRV_SECTOR_SIZE];
     int len, nb_sectors, count;      int len, nb_sectors, count;
     int64_t sector_num;      int64_t sector_num;
       int ret;
   
     count = count1;      count = count1;
     /* first read to align to sector start */      /* first read to align to sector start */
     len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);      len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1);
     if (len > count)      if (len > count)
         len = count;          len = count;
     sector_num = offset >> SECTOR_BITS;      sector_num = offset >> BDRV_SECTOR_BITS;
     if (len > 0) {      if (len > 0) {
         if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)          if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
             return -EIO;              return ret;
         memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len);          memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len);
         count -= len;          count -= len;
         if (count == 0)          if (count == 0)
             return count1;              return count1;
Line 643  static int bdrv_pread_em(BlockDriverStat Line 1160  static int bdrv_pread_em(BlockDriverStat
     }      }
   
     /* read the sectors "in place" */      /* read the sectors "in place" */
     nb_sectors = count >> SECTOR_BITS;      nb_sectors = count >> BDRV_SECTOR_BITS;
     if (nb_sectors > 0) {      if (nb_sectors > 0) {
         if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)          if ((ret = bdrv_read(bs, sector_num, buf, nb_sectors)) < 0)
             return -EIO;              return ret;
         sector_num += nb_sectors;          sector_num += nb_sectors;
         len = nb_sectors << SECTOR_BITS;          len = nb_sectors << BDRV_SECTOR_BITS;
         buf += len;          buf += len;
         count -= len;          count -= len;
     }      }
   
     /* add data from the last sector */      /* add data from the last sector */
     if (count > 0) {      if (count > 0) {
         if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)          if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
             return -EIO;              return ret;
         memcpy(buf, tmp_buf, count);          memcpy(buf, tmp_buf, count);
     }      }
     return count1;      return count1;
 }  }
   
 static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset,  int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
                           const uint8_t *buf, int count1)                  const void *buf, int count1)
 {  {
     uint8_t tmp_buf[SECTOR_SIZE];      uint8_t tmp_buf[BDRV_SECTOR_SIZE];
     int len, nb_sectors, count;      int len, nb_sectors, count;
     int64_t sector_num;      int64_t sector_num;
       int ret;
   
     count = count1;      count = count1;
     /* first write to align to sector start */      /* first write to align to sector start */
     len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);      len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1);
     if (len > count)      if (len > count)
         len = count;          len = count;
     sector_num = offset >> SECTOR_BITS;      sector_num = offset >> BDRV_SECTOR_BITS;
     if (len > 0) {      if (len > 0) {
         if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)          if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
             return -EIO;              return ret;
         memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len);          memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
         if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)          if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
             return -EIO;              return ret;
         count -= len;          count -= len;
         if (count == 0)          if (count == 0)
             return count1;              return count1;
Line 689  static int bdrv_pwrite_em(BlockDriverSta Line 1207  static int bdrv_pwrite_em(BlockDriverSta
     }      }
   
     /* write the sectors "in place" */      /* write the sectors "in place" */
     nb_sectors = count >> SECTOR_BITS;      nb_sectors = count >> BDRV_SECTOR_BITS;
     if (nb_sectors > 0) {      if (nb_sectors > 0) {
         if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)          if ((ret = bdrv_write(bs, sector_num, buf, nb_sectors)) < 0)
             return -EIO;              return ret;
         sector_num += nb_sectors;          sector_num += nb_sectors;
         len = nb_sectors << SECTOR_BITS;          len = nb_sectors << BDRV_SECTOR_BITS;
         buf += len;          buf += len;
         count -= len;          count -= len;
     }      }
   
     /* add data from the last sector */      /* add data from the last sector */
     if (count > 0) {      if (count > 0) {
         if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)          if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
             return -EIO;              return ret;
         memcpy(tmp_buf, buf, count);          memcpy(tmp_buf, buf, count);
         if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)          if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
             return -EIO;              return ret;
     }      }
     return count1;      return count1;
 }  }
   
 /**  /*
  * Read with byte offsets (needed only for file protocols)   * 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_pread(BlockDriverState *bs, int64_t offset,  int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
                void *buf1, int count1)      const void *buf, int count)
   {
       int ret;
   
       ret = bdrv_pwrite(bs, offset, buf, count);
       if (ret < 0) {
           return ret;
       }
   
       /* No flush needed for cache modes that use O_DSYNC */
       if ((bs->open_flags & BDRV_O_CACHE_WB) != 0) {
           bdrv_flush(bs);
       }
   
       return 0;
   }
   
   /*
    * Handle a read request in coroutine context
    */
   static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
       int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
   
     if (!drv)      if (!drv) {
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (bdrv_check_byte_request(bs, offset, count1))      }
       if (bdrv_check_request(bs, sector_num, nb_sectors)) {
         return -EIO;          return -EIO;
       }
   
     if (!drv->bdrv_pread)      return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
         return bdrv_pread_em(bs, offset, buf1, count1);  
     return drv->bdrv_pread(bs, offset, buf1, count1);  
 }  }
   
 /**  int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
  * Write with byte offsets (needed only for file protocols)      int nb_sectors, QEMUIOVector *qiov)
   {
       trace_bdrv_co_readv(bs, sector_num, nb_sectors);
   
       return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov);
   }
   
   /*
    * Handle a write request in coroutine context
  */   */
 int bdrv_pwrite(BlockDriverState *bs, int64_t offset,  static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
                 const void *buf1, int count1)      int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
       int ret;
   
     if (!drv)      if (!bs->drv) {
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (bdrv_check_byte_request(bs, offset, count1))      }
       if (bs->read_only) {
           return -EACCES;
       }
       if (bdrv_check_request(bs, sector_num, nb_sectors)) {
         return -EIO;          return -EIO;
       }
   
       ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
   
       if (bs->dirty_bitmap) {
           set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
       }
   
       if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
           bs->wr_highest_sector = sector_num + nb_sectors - 1;
       }
   
       return ret;
   }
   
   int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
       int nb_sectors, QEMUIOVector *qiov)
   {
       trace_bdrv_co_writev(bs, sector_num, nb_sectors);
   
     if (!drv->bdrv_pwrite)      return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov);
         return bdrv_pwrite_em(bs, offset, buf1, count1);  
     return drv->bdrv_pwrite(bs, offset, buf1, count1);  
 }  }
   
 /**  /**
Line 752  int bdrv_pwrite(BlockDriverState *bs, in Line 1324  int bdrv_pwrite(BlockDriverState *bs, in
 int bdrv_truncate(BlockDriverState *bs, int64_t offset)  int bdrv_truncate(BlockDriverState *bs, int64_t offset)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
       int ret;
     if (!drv)      if (!drv)
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (!drv->bdrv_truncate)      if (!drv->bdrv_truncate)
         return -ENOTSUP;          return -ENOTSUP;
     return drv->bdrv_truncate(bs, offset);      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);
           bdrv_dev_resize_cb(bs);
       }
       return ret;
   }
   
   /**
    * Length of a allocated file in bytes. Sparse files are counted by actual
    * allocated space. Return < 0 if error or unknown.
    */
   int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
   {
       BlockDriver *drv = bs->drv;
       if (!drv) {
           return -ENOMEDIUM;
       }
       if (drv->bdrv_get_allocated_file_size) {
           return drv->bdrv_get_allocated_file_size(bs);
       }
       if (bs->file) {
           return bdrv_get_allocated_file_size(bs->file);
       }
       return -ENOTSUP;
 }  }
   
 /**  /**
Line 767  int64_t bdrv_getlength(BlockDriverState  Line 1368  int64_t bdrv_getlength(BlockDriverState 
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     if (!drv)      if (!drv)
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (!drv->bdrv_getlength) {  
         /* legacy mode */      if (bs->growable || bdrv_dev_has_removable_media(bs)) {
         return bs->total_sectors * SECTOR_SIZE;          if (drv->bdrv_getlength) {
               return drv->bdrv_getlength(bs);
           }
     }      }
     return drv->bdrv_getlength(bs);      return bs->total_sectors * BDRV_SECTOR_SIZE;
 }  }
   
 /* return 0 as number of sectors if no device present or error */  /* return 0 as number of sectors if no device present or error */
Line 782  void bdrv_get_geometry(BlockDriverState  Line 1385  void bdrv_get_geometry(BlockDriverState 
     if (length < 0)      if (length < 0)
         length = 0;          length = 0;
     else      else
         length = length >> SECTOR_BITS;          length = length >> BDRV_SECTOR_BITS;
     *nb_sectors_ptr = length;      *nb_sectors_ptr = length;
 }  }
   
Line 797  struct partition { Line 1400  struct partition {
         uint8_t end_cyl;            /* end cylinder */          uint8_t end_cyl;            /* end cylinder */
         uint32_t start_sect;        /* starting sector counting from 0 */          uint32_t start_sect;        /* starting sector counting from 0 */
         uint32_t nr_sects;          /* nr of sectors in partition */          uint32_t nr_sects;          /* nr of sectors in partition */
 } __attribute__((packed));  } QEMU_PACKED;
   
 /* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */  /* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
 static int guess_disk_lchs(BlockDriverState *bs,  static int guess_disk_lchs(BlockDriverState *bs,
                            int *pcylinders, int *pheads, int *psectors)                             int *pcylinders, int *pheads, int *psectors)
 {  {
     uint8_t buf[512];      uint8_t buf[BDRV_SECTOR_SIZE];
     int ret, i, heads, sectors, cylinders;      int ret, i, heads, sectors, cylinders;
     struct partition *p;      struct partition *p;
     uint32_t nr_sects;      uint32_t nr_sects;
Line 910  void bdrv_set_geometry_hint(BlockDriverS Line 1513  void bdrv_set_geometry_hint(BlockDriverS
     bs->secs = secs;      bs->secs = secs;
 }  }
   
 void bdrv_set_type_hint(BlockDriverState *bs, int type)  
 {  
     bs->type = type;  
     bs->removable = ((type == BDRV_TYPE_CDROM ||  
                       type == BDRV_TYPE_FLOPPY));  
 }  
   
 void bdrv_set_translation_hint(BlockDriverState *bs, int translation)  void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
 {  {
     bs->translation = translation;      bs->translation = translation;
Line 930  void bdrv_get_geometry_hint(BlockDriverS Line 1526  void bdrv_get_geometry_hint(BlockDriverS
     *psecs = bs->secs;      *psecs = bs->secs;
 }  }
   
 int bdrv_get_type_hint(BlockDriverState *bs)  /* Recognize floppy formats */
 {  typedef struct FDFormat {
     return bs->type;      FDriveType drive;
       uint8_t last_sect;
       uint8_t max_track;
       uint8_t max_head;
   } FDFormat;
   
   static const FDFormat fd_formats[] = {
       /* First entry is default format */
       /* 1.44 MB 3"1/2 floppy disks */
       { FDRIVE_DRV_144, 18, 80, 1, },
       { FDRIVE_DRV_144, 20, 80, 1, },
       { FDRIVE_DRV_144, 21, 80, 1, },
       { FDRIVE_DRV_144, 21, 82, 1, },
       { FDRIVE_DRV_144, 21, 83, 1, },
       { FDRIVE_DRV_144, 22, 80, 1, },
       { FDRIVE_DRV_144, 23, 80, 1, },
       { FDRIVE_DRV_144, 24, 80, 1, },
       /* 2.88 MB 3"1/2 floppy disks */
       { FDRIVE_DRV_288, 36, 80, 1, },
       { FDRIVE_DRV_288, 39, 80, 1, },
       { FDRIVE_DRV_288, 40, 80, 1, },
       { FDRIVE_DRV_288, 44, 80, 1, },
       { FDRIVE_DRV_288, 48, 80, 1, },
       /* 720 kB 3"1/2 floppy disks */
       { FDRIVE_DRV_144,  9, 80, 1, },
       { FDRIVE_DRV_144, 10, 80, 1, },
       { FDRIVE_DRV_144, 10, 82, 1, },
       { FDRIVE_DRV_144, 10, 83, 1, },
       { FDRIVE_DRV_144, 13, 80, 1, },
       { FDRIVE_DRV_144, 14, 80, 1, },
       /* 1.2 MB 5"1/4 floppy disks */
       { FDRIVE_DRV_120, 15, 80, 1, },
       { FDRIVE_DRV_120, 18, 80, 1, },
       { FDRIVE_DRV_120, 18, 82, 1, },
       { FDRIVE_DRV_120, 18, 83, 1, },
       { FDRIVE_DRV_120, 20, 80, 1, },
       /* 720 kB 5"1/4 floppy disks */
       { FDRIVE_DRV_120,  9, 80, 1, },
       { FDRIVE_DRV_120, 11, 80, 1, },
       /* 360 kB 5"1/4 floppy disks */
       { FDRIVE_DRV_120,  9, 40, 1, },
       { FDRIVE_DRV_120,  9, 40, 0, },
       { FDRIVE_DRV_120, 10, 41, 1, },
       { FDRIVE_DRV_120, 10, 42, 1, },
       /* 320 kB 5"1/4 floppy disks */
       { FDRIVE_DRV_120,  8, 40, 1, },
       { FDRIVE_DRV_120,  8, 40, 0, },
       /* 360 kB must match 5"1/4 better than 3"1/2... */
       { FDRIVE_DRV_144,  9, 80, 0, },
       /* end */
       { FDRIVE_DRV_NONE, -1, -1, 0, },
   };
   
   void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,
                                      int *max_track, int *last_sect,
                                      FDriveType drive_in, FDriveType *drive)
   {
       const FDFormat *parse;
       uint64_t nb_sectors, size;
       int i, first_match, match;
   
       bdrv_get_geometry_hint(bs, nb_heads, max_track, last_sect);
       if (*nb_heads != 0 && *max_track != 0 && *last_sect != 0) {
           /* User defined disk */
       } else {
           bdrv_get_geometry(bs, &nb_sectors);
           match = -1;
           first_match = -1;
           for (i = 0; ; i++) {
               parse = &fd_formats[i];
               if (parse->drive == FDRIVE_DRV_NONE) {
                   break;
               }
               if (drive_in == parse->drive ||
                   drive_in == FDRIVE_DRV_NONE) {
                   size = (parse->max_head + 1) * parse->max_track *
                       parse->last_sect;
                   if (nb_sectors == size) {
                       match = i;
                       break;
                   }
                   if (first_match == -1) {
                       first_match = i;
                   }
               }
           }
           if (match == -1) {
               if (first_match == -1) {
                   match = 1;
               } else {
                   match = first_match;
               }
               parse = &fd_formats[match];
           }
           *nb_heads = parse->max_head + 1;
           *max_track = parse->max_track;
           *last_sect = parse->last_sect;
           *drive = parse->drive;
       }
 }  }
   
 int bdrv_get_translation_hint(BlockDriverState *bs)  int bdrv_get_translation_hint(BlockDriverState *bs)
Line 940  int bdrv_get_translation_hint(BlockDrive Line 1634  int bdrv_get_translation_hint(BlockDrive
     return bs->translation;      return bs->translation;
 }  }
   
 int bdrv_is_removable(BlockDriverState *bs)  void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
                          BlockErrorAction on_write_error)
 {  {
     return bs->removable;      bs->on_read_error = on_read_error;
       bs->on_write_error = on_write_error;
 }  }
   
 int bdrv_is_read_only(BlockDriverState *bs)  BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read)
 {  {
     return bs->read_only;      return is_read ? bs->on_read_error : bs->on_write_error;
   }
   
   int bdrv_is_read_only(BlockDriverState *bs)
   {
       return bs->read_only;
 }  }
   
 int bdrv_is_sg(BlockDriverState *bs)  int bdrv_is_sg(BlockDriverState *bs)
Line 955  int bdrv_is_sg(BlockDriverState *bs) Line 1656  int bdrv_is_sg(BlockDriverState *bs)
     return bs->sg;      return bs->sg;
 }  }
   
 /* XXX: no longer used */  int bdrv_enable_write_cache(BlockDriverState *bs)
 void bdrv_set_change_cb(BlockDriverState *bs,  
                         void (*change_cb)(void *opaque), void *opaque)  
 {  {
     bs->change_cb = change_cb;      return bs->enable_write_cache;
     bs->change_opaque = opaque;  
 }  }
   
 int bdrv_is_encrypted(BlockDriverState *bs)  int bdrv_is_encrypted(BlockDriverState *bs)
Line 989  int bdrv_set_key(BlockDriverState *bs, c Line 1687  int bdrv_set_key(BlockDriverState *bs, c
         if (!bs->encrypted)          if (!bs->encrypted)
             return 0;              return 0;
     }      }
     if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)      if (!bs->encrypted) {
         return -1;          return -EINVAL;
       } else if (!bs->drv || !bs->drv->bdrv_set_key) {
           return -ENOMEDIUM;
       }
     ret = bs->drv->bdrv_set_key(bs, key);      ret = bs->drv->bdrv_set_key(bs, key);
     bs->valid_key = (ret == 0);      if (ret < 0) {
           bs->valid_key = 0;
       } else if (!bs->valid_key) {
           bs->valid_key = 1;
           /* call the change callback now, we skipped it on open */
           bdrv_dev_change_media_cb(bs, true);
       }
     return ret;      return ret;
 }  }
   
Line 1010  void bdrv_iterate_format(void (*it)(void Line 1717  void bdrv_iterate_format(void (*it)(void
 {  {
     BlockDriver *drv;      BlockDriver *drv;
   
     for (drv = first_drv; drv != NULL; drv = drv->next) {      QLIST_FOREACH(drv, &bdrv_drivers, list) {
         it(opaque, drv->format_name);          it(opaque, drv->format_name);
     }      }
 }  }
Line 1019  BlockDriverState *bdrv_find(const char * Line 1726  BlockDriverState *bdrv_find(const char *
 {  {
     BlockDriverState *bs;      BlockDriverState *bs;
   
     for (bs = bdrv_first; bs != NULL; bs = bs->next) {      QTAILQ_FOREACH(bs, &bdrv_states, list) {
         if (!strcmp(name, bs->device_name))          if (!strcmp(name, bs->device_name)) {
             return bs;              return bs;
           }
     }      }
     return NULL;      return NULL;
 }  }
   
   BlockDriverState *bdrv_next(BlockDriverState *bs)
   {
       if (!bs) {
           return QTAILQ_FIRST(&bdrv_states);
       }
       return QTAILQ_NEXT(bs, list);
   }
   
 void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), void *opaque)  void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), void *opaque)
 {  {
     BlockDriverState *bs;      BlockDriverState *bs;
   
     for (bs = bdrv_first; bs != NULL; bs = bs->next) {      QTAILQ_FOREACH(bs, &bdrv_states, list) {
         it(opaque, bs);          it(opaque, bs);
     }      }
 }  }
Line 1040  const char *bdrv_get_device_name(BlockDr Line 1756  const char *bdrv_get_device_name(BlockDr
     return bs->device_name;      return bs->device_name;
 }  }
   
 void bdrv_flush(BlockDriverState *bs)  
 {  
     if (bs->drv->bdrv_flush)  
         bs->drv->bdrv_flush(bs);  
     if (bs->backing_hd)  
         bdrv_flush(bs->backing_hd);  
 }  
   
 void bdrv_flush_all(void)  void bdrv_flush_all(void)
 {  {
     BlockDriverState *bs;      BlockDriverState *bs;
   
     for (bs = bdrv_first; bs != NULL; bs = bs->next)      QTAILQ_FOREACH(bs, &bdrv_states, list) {
         if (bs->drv && !bdrv_is_read_only(bs) &&           if (!bdrv_is_read_only(bs) && bdrv_is_inserted(bs)) {
             (!bdrv_is_removable(bs) || bdrv_is_inserted(bs)))  
             bdrv_flush(bs);              bdrv_flush(bs);
           }
       }
   }
   
   int bdrv_has_zero_init(BlockDriverState *bs)
   {
       assert(bs->drv);
   
       if (bs->drv->bdrv_has_zero_init) {
           return bs->drv->bdrv_has_zero_init(bs);
       }
   
       return 1;
 }  }
   
 /*  /*
Line 1085  int bdrv_is_allocated(BlockDriverState * Line 1805  int bdrv_is_allocated(BlockDriverState *
     return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);      return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);
 }  }
   
 void bdrv_info(void)  void bdrv_mon_event(const BlockDriverState *bdrv,
                       BlockMonEventAction action, int is_read)
   {
       QObject *data;
       const char *action_str;
   
       switch (action) {
       case BDRV_ACTION_REPORT:
           action_str = "report";
           break;
       case BDRV_ACTION_IGNORE:
           action_str = "ignore";
           break;
       case BDRV_ACTION_STOP:
           action_str = "stop";
           break;
       default:
           abort();
       }
   
       data = qobject_from_jsonf("{ 'device': %s, 'action': %s, 'operation': %s }",
                                 bdrv->device_name,
                                 action_str,
                                 is_read ? "read" : "write");
       monitor_protocol_event(QEVENT_BLOCK_IO_ERROR, data);
   
       qobject_decref(data);
   }
   
   BlockInfoList *qmp_query_block(Error **errp)
 {  {
       BlockInfoList *head = NULL, *cur_item = NULL;
     BlockDriverState *bs;      BlockDriverState *bs;
   
     for (bs = bdrv_first; bs != NULL; bs = bs->next) {      QTAILQ_FOREACH(bs, &bdrv_states, list) {
         term_printf("%s:", bs->device_name);          BlockInfoList *info = g_malloc0(sizeof(*info));
         term_printf(" type=");  
         switch(bs->type) {          info->value = g_malloc0(sizeof(*info->value));
         case BDRV_TYPE_HD:          info->value->device = g_strdup(bs->device_name);
             term_printf("hd");          info->value->type = g_strdup("unknown");
             break;          info->value->locked = bdrv_dev_is_medium_locked(bs);
         case BDRV_TYPE_CDROM:          info->value->removable = bdrv_dev_has_removable_media(bs);
             term_printf("cdrom");  
             break;          if (bdrv_dev_has_removable_media(bs)) {
         case BDRV_TYPE_FLOPPY:              info->value->has_tray_open = true;
             term_printf("floppy");              info->value->tray_open = bdrv_dev_is_tray_open(bs);
             break;          }
         }  
         term_printf(" removable=%d", bs->removable);          if (bdrv_iostatus_is_enabled(bs)) {
         if (bs->removable) {              info->value->has_io_status = true;
             term_printf(" locked=%d", bs->locked);              info->value->io_status = bs->iostatus;
         }          }
   
         if (bs->drv) {          if (bs->drv) {
             term_printf(" file=");              info->value->has_inserted = true;
             term_print_filename(bs->filename);              info->value->inserted = g_malloc0(sizeof(*info->value->inserted));
             if (bs->backing_file[0] != '\0') {              info->value->inserted->file = g_strdup(bs->filename);
                 term_printf(" backing_file=");              info->value->inserted->ro = bs->read_only;
                 term_print_filename(bs->backing_file);              info->value->inserted->drv = g_strdup(bs->drv->format_name);
             }              info->value->inserted->encrypted = bs->encrypted;
             term_printf(" ro=%d", bs->read_only);              if (bs->backing_file[0]) {
             term_printf(" drv=%s", bs->drv->format_name);                  info->value->inserted->has_backing_file = true;
             term_printf(" encrypted=%d", bdrv_is_encrypted(bs));                  info->value->inserted->backing_file = g_strdup(bs->backing_file);
               }
           }
   
           /* XXX: waiting for the qapi to support GSList */
           if (!cur_item) {
               head = cur_item = info;
         } else {          } else {
             term_printf(" [not inserted]");              cur_item->next = info;
               cur_item = info;
         }          }
         term_printf("\n");  
     }      }
   
       return head;
   }
   
   /* Consider exposing this as a full fledged QMP command */
   static BlockStats *qmp_query_blockstat(const BlockDriverState *bs, Error **errp)
   {
       BlockStats *s;
   
       s = g_malloc0(sizeof(*s));
   
       if (bs->device_name[0]) {
           s->has_device = true;
           s->device = g_strdup(bs->device_name);
       }
   
       s->stats = g_malloc0(sizeof(*s->stats));
       s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ];
       s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE];
       s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ];
       s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE];
       s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE;
       s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH];
       s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE];
       s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ];
       s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH];
   
       if (bs->file) {
           s->has_parent = true;
           s->parent = qmp_query_blockstat(bs->file, NULL);
       }
   
       return s;
 }  }
   
 /* The "info blockstats" command. */  BlockStatsList *qmp_query_blockstats(Error **errp)
 void bdrv_info_stats (void)  
 {  {
       BlockStatsList *head = NULL, *cur_item = NULL;
     BlockDriverState *bs;      BlockDriverState *bs;
   
     for (bs = bdrv_first; bs != NULL; bs = bs->next) {      QTAILQ_FOREACH(bs, &bdrv_states, list) {
         term_printf ("%s:"          BlockStatsList *info = g_malloc0(sizeof(*info));
                      " rd_bytes=%" PRIu64          info->value = qmp_query_blockstat(bs, NULL);
                      " wr_bytes=%" PRIu64  
                      " rd_operations=%" PRIu64          /* XXX: waiting for the qapi to support GSList */
                      " wr_operations=%" PRIu64          if (!cur_item) {
                      "\n",              head = cur_item = info;
                      bs->device_name,          } else {
                      bs->rd_bytes, bs->wr_bytes,              cur_item->next = info;
                      bs->rd_ops, bs->wr_ops);              cur_item = info;
           }
     }      }
   
       return head;
 }  }
   
 const char *bdrv_get_encrypted_filename(BlockDriverState *bs)  const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
Line 1155  const char *bdrv_get_encrypted_filename( Line 1948  const char *bdrv_get_encrypted_filename(
 void bdrv_get_backing_filename(BlockDriverState *bs,  void bdrv_get_backing_filename(BlockDriverState *bs,
                                char *filename, int filename_size)                                 char *filename, int filename_size)
 {  {
     if (!bs->backing_hd) {      pstrcpy(filename, filename_size, bs->backing_file);
         pstrcpy(filename, filename_size, "");  
     } else {  
         pstrcpy(filename, filename_size, bs->backing_file);  
     }  
 }  }
   
 int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,  int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
Line 1170  int bdrv_write_compressed(BlockDriverSta Line 1959  int bdrv_write_compressed(BlockDriverSta
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (!drv->bdrv_write_compressed)      if (!drv->bdrv_write_compressed)
         return -ENOTSUP;          return -ENOTSUP;
       if (bdrv_check_request(bs, sector_num, nb_sectors))
           return -EIO;
   
       if (bs->dirty_bitmap) {
           set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
       }
   
     return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);      return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
 }  }
   
Line 1184  int bdrv_get_info(BlockDriverState *bs,  Line 1980  int bdrv_get_info(BlockDriverState *bs, 
     return drv->bdrv_get_info(bs, bdi);      return drv->bdrv_get_info(bs, bdi);
 }  }
   
 int bdrv_put_buffer(BlockDriverState *bs, const uint8_t *buf, int64_t pos, int size)  int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
                         int64_t pos, int size)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     if (!drv)      if (!drv)
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (!drv->bdrv_put_buffer)      if (drv->bdrv_save_vmstate)
         return -ENOTSUP;          return drv->bdrv_save_vmstate(bs, buf, pos, size);
     return drv->bdrv_put_buffer(bs, buf, pos, size);      if (bs->file)
           return bdrv_save_vmstate(bs->file, buf, pos, size);
       return -ENOTSUP;
 }  }
   
 int bdrv_get_buffer(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size)  int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
                         int64_t pos, int size)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     if (!drv)      if (!drv)
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (!drv->bdrv_get_buffer)      if (drv->bdrv_load_vmstate)
         return -ENOTSUP;          return drv->bdrv_load_vmstate(bs, buf, pos, size);
     return drv->bdrv_get_buffer(bs, buf, pos, size);      if (bs->file)
           return bdrv_load_vmstate(bs->file, buf, pos, size);
       return -ENOTSUP;
   }
   
   void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
   {
       BlockDriver *drv = bs->drv;
   
       if (!drv || !drv->bdrv_debug_event) {
           return;
       }
   
       return drv->bdrv_debug_event(bs, event);
   
 }  }
   
 /**************************************************************/  /**************************************************************/
 /* handling of snapshots */  /* handling of snapshots */
   
   int bdrv_can_snapshot(BlockDriverState *bs)
   {
       BlockDriver *drv = bs->drv;
       if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
           return 0;
       }
   
       if (!drv->bdrv_snapshot_create) {
           if (bs->file != NULL) {
               return bdrv_can_snapshot(bs->file);
           }
           return 0;
       }
   
       return 1;
   }
   
   int bdrv_is_snapshot(BlockDriverState *bs)
   {
       return !!(bs->open_flags & BDRV_O_SNAPSHOT);
   }
   
   BlockDriverState *bdrv_snapshots(void)
   {
       BlockDriverState *bs;
   
       if (bs_snapshots) {
           return bs_snapshots;
       }
   
       bs = NULL;
       while ((bs = bdrv_next(bs))) {
           if (bdrv_can_snapshot(bs)) {
               bs_snapshots = bs;
               return bs;
           }
       }
       return NULL;
   }
   
 int bdrv_snapshot_create(BlockDriverState *bs,  int bdrv_snapshot_create(BlockDriverState *bs,
                          QEMUSnapshotInfo *sn_info)                           QEMUSnapshotInfo *sn_info)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     if (!drv)      if (!drv)
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (!drv->bdrv_snapshot_create)      if (drv->bdrv_snapshot_create)
         return -ENOTSUP;          return drv->bdrv_snapshot_create(bs, sn_info);
     return drv->bdrv_snapshot_create(bs, sn_info);      if (bs->file)
           return bdrv_snapshot_create(bs->file, sn_info);
       return -ENOTSUP;
 }  }
   
 int bdrv_snapshot_goto(BlockDriverState *bs,  int bdrv_snapshot_goto(BlockDriverState *bs,
                        const char *snapshot_id)                         const char *snapshot_id)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
       int ret, open_ret;
   
     if (!drv)      if (!drv)
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (!drv->bdrv_snapshot_goto)      if (drv->bdrv_snapshot_goto)
         return -ENOTSUP;          return drv->bdrv_snapshot_goto(bs, snapshot_id);
     return drv->bdrv_snapshot_goto(bs, snapshot_id);  
       if (bs->file) {
           drv->bdrv_close(bs);
           ret = bdrv_snapshot_goto(bs->file, snapshot_id);
           open_ret = drv->bdrv_open(bs, bs->open_flags);
           if (open_ret < 0) {
               bdrv_delete(bs->file);
               bs->drv = NULL;
               return open_ret;
           }
           return ret;
       }
   
       return -ENOTSUP;
 }  }
   
 int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)  int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
Line 1234  int bdrv_snapshot_delete(BlockDriverStat Line 2105  int bdrv_snapshot_delete(BlockDriverStat
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     if (!drv)      if (!drv)
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (!drv->bdrv_snapshot_delete)      if (drv->bdrv_snapshot_delete)
         return -ENOTSUP;          return drv->bdrv_snapshot_delete(bs, snapshot_id);
     return drv->bdrv_snapshot_delete(bs, snapshot_id);      if (bs->file)
           return bdrv_snapshot_delete(bs->file, snapshot_id);
       return -ENOTSUP;
 }  }
   
 int bdrv_snapshot_list(BlockDriverState *bs,  int bdrv_snapshot_list(BlockDriverState *bs,
Line 1245  int bdrv_snapshot_list(BlockDriverState  Line 2118  int bdrv_snapshot_list(BlockDriverState 
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     if (!drv)      if (!drv)
         return -ENOMEDIUM;          return -ENOMEDIUM;
     if (!drv->bdrv_snapshot_list)      if (drv->bdrv_snapshot_list)
         return -ENOTSUP;          return drv->bdrv_snapshot_list(bs, psn_info);
     return drv->bdrv_snapshot_list(bs, psn_info);      if (bs->file)
           return bdrv_snapshot_list(bs->file, psn_info);
       return -ENOTSUP;
   }
   
   int bdrv_snapshot_load_tmp(BlockDriverState *bs,
           const char *snapshot_name)
   {
       BlockDriver *drv = bs->drv;
       if (!drv) {
           return -ENOMEDIUM;
       }
       if (!bs->read_only) {
           return -EINVAL;
       }
       if (drv->bdrv_snapshot_load_tmp) {
           return drv->bdrv_snapshot_load_tmp(bs, snapshot_name);
       }
       return -ENOTSUP;
 }  }
   
 #define NB_SUFFIXES 4  #define NB_SUFFIXES 4
Line 1323  char *bdrv_snapshot_dump(char *buf, int  Line 2214  char *bdrv_snapshot_dump(char *buf, int 
     return buf;      return buf;
 }  }
   
   
 /**************************************************************/  /**************************************************************/
 /* async I/Os */  /* async I/Os */
   
 typedef struct VectorTranslationState {  BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
     QEMUIOVector *iov;                                   QEMUIOVector *qiov, int nb_sectors,
     uint8_t *bounce;                                   BlockDriverCompletionFunc *cb, void *opaque)
     int is_write;  
     BlockDriverAIOCB *aiocb;  
     BlockDriverAIOCB *this_aiocb;  
 } VectorTranslationState;  
   
 static void bdrv_aio_cancel_vector(BlockDriverAIOCB *acb)  
 {  {
     VectorTranslationState *s = acb->opaque;      trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
   
     bdrv_aio_cancel(s->aiocb);      return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
                                    cb, opaque, false);
 }  }
   
 static void bdrv_aio_rw_vector_cb(void *opaque, int ret)  BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                     QEMUIOVector *qiov, int nb_sectors,
                                     BlockDriverCompletionFunc *cb, void *opaque)
 {  {
     VectorTranslationState *s = opaque;      trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
   
     if (!s->is_write) {      return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
         qemu_iovec_from_buffer(s->iov, s->bounce, s->iov->size);                                   cb, opaque, true);
     }  
     qemu_vfree(s->bounce);  
     s->this_aiocb->cb(s->this_aiocb->opaque, ret);  
     qemu_aio_release(s->this_aiocb);  
 }  }
   
 static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,  
                                             int64_t sector_num,  
                                             QEMUIOVector *iov,  
                                             int nb_sectors,  
                                             BlockDriverCompletionFunc *cb,  
                                             void *opaque,  
                                             int is_write)  
   
   typedef struct MultiwriteCB {
       int error;
       int num_requests;
       int num_callbacks;
       struct {
           BlockDriverCompletionFunc *cb;
           void *opaque;
           QEMUIOVector *free_qiov;
           void *free_buf;
       } callbacks[];
   } MultiwriteCB;
   
   static void multiwrite_user_cb(MultiwriteCB *mcb)
 {  {
     VectorTranslationState *s = qemu_mallocz(sizeof(*s));      int i;
     BlockDriverAIOCB *aiocb = qemu_aio_get_pool(&vectored_aio_pool, bs,  
                                                 cb, opaque);      for (i = 0; i < mcb->num_callbacks; i++) {
           mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
     s->this_aiocb = aiocb;          if (mcb->callbacks[i].free_qiov) {
     s->iov = iov;              qemu_iovec_destroy(mcb->callbacks[i].free_qiov);
     s->bounce = qemu_memalign(512, nb_sectors * 512);          }
     s->is_write = is_write;          g_free(mcb->callbacks[i].free_qiov);
     if (is_write) {          qemu_vfree(mcb->callbacks[i].free_buf);
         qemu_iovec_to_buffer(s->iov, s->bounce);  
         s->aiocb = bdrv_aio_write(bs, sector_num, s->bounce, nb_sectors,  
                                   bdrv_aio_rw_vector_cb, s);  
     } else {  
         s->aiocb = bdrv_aio_read(bs, sector_num, s->bounce, nb_sectors,  
                                  bdrv_aio_rw_vector_cb, s);  
     }      }
     return aiocb;  
 }  }
   
 BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,  static void multiwrite_cb(void *opaque, int ret)
                                  QEMUIOVector *iov, int nb_sectors,  
                                  BlockDriverCompletionFunc *cb, void *opaque)  
 {  {
     if (bdrv_check_request(bs, sector_num, nb_sectors))      MultiwriteCB *mcb = opaque;
         return NULL;  
       trace_multiwrite_cb(mcb, ret);
   
       if (ret < 0 && !mcb->error) {
           mcb->error = ret;
       }
   
     return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors,      mcb->num_requests--;
                               cb, opaque, 0);      if (mcb->num_requests == 0) {
           multiwrite_user_cb(mcb);
           g_free(mcb);
       }
 }  }
   
 BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,  static int multiwrite_req_compare(const void *a, const void *b)
                                   QEMUIOVector *iov, int nb_sectors,  
                                   BlockDriverCompletionFunc *cb, void *opaque)  
 {  {
     if (bdrv_check_request(bs, sector_num, nb_sectors))      const BlockRequest *req1 = a, *req2 = b;
         return NULL;  
   
     return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors,      /*
                               cb, opaque, 1);       * Note that we can't simply subtract req2->sector from req1->sector
        * here as that could overflow the return value.
        */
       if (req1->sector > req2->sector) {
           return 1;
       } else if (req1->sector < req2->sector) {
           return -1;
       } else {
           return 0;
       }
 }  }
   
 BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,  /*
                                 uint8_t *buf, int nb_sectors,   * Takes a bunch of requests and tries to merge them. Returns the number of
                                 BlockDriverCompletionFunc *cb, void *opaque)   * requests that remain after merging.
    */
   static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
       int num_reqs, MultiwriteCB *mcb)
 {  {
     BlockDriver *drv = bs->drv;      int i, outidx;
     BlockDriverAIOCB *ret;  
   
     if (!drv)      // Sort requests by start sector
         return NULL;      qsort(reqs, num_reqs, sizeof(*reqs), &multiwrite_req_compare);
     if (bdrv_check_request(bs, sector_num, nb_sectors))  
         return NULL;      // Check if adjacent requests touch the same clusters. If so, combine them,
       // filling up gaps with zero sectors.
       outidx = 0;
       for (i = 1; i < num_reqs; i++) {
           int merge = 0;
           int64_t oldreq_last = reqs[outidx].sector + reqs[outidx].nb_sectors;
   
           // This handles the cases that are valid for all block drivers, namely
           // exactly sequential writes and overlapping writes.
           if (reqs[i].sector <= oldreq_last) {
               merge = 1;
           }
   
           // The block driver may decide that it makes sense to combine requests
           // even if there is a gap of some sectors between them. In this case,
           // the gap is filled with zeros (therefore only applicable for yet
           // unused space in format like qcow2).
           if (!merge && bs->drv->bdrv_merge_requests) {
               merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]);
           }
   
           if (reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1 > IOV_MAX) {
               merge = 0;
           }
   
           if (merge) {
               size_t size;
               QEMUIOVector *qiov = g_malloc0(sizeof(*qiov));
               qemu_iovec_init(qiov,
                   reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1);
   
               // Add the first request to the merged one. If the requests are
               // overlapping, drop the last sectors of the first request.
               size = (reqs[i].sector - reqs[outidx].sector) << 9;
               qemu_iovec_concat(qiov, reqs[outidx].qiov, size);
   
               // We might need to add some zeros between the two requests
               if (reqs[i].sector > oldreq_last) {
                   size_t zero_bytes = (reqs[i].sector - oldreq_last) << 9;
                   uint8_t *buf = qemu_blockalign(bs, zero_bytes);
                   memset(buf, 0, zero_bytes);
                   qemu_iovec_add(qiov, buf, zero_bytes);
                   mcb->callbacks[i].free_buf = buf;
               }
   
               // Add the second request
               qemu_iovec_concat(qiov, reqs[i].qiov, reqs[i].qiov->size);
   
     ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque);              reqs[outidx].nb_sectors = qiov->size >> 9;
               reqs[outidx].qiov = qiov;
   
     if (ret) {              mcb->callbacks[i].free_qiov = reqs[outidx].qiov;
         /* Update stats even though technically transfer has not happened. */          } else {
         bs->rd_bytes += (unsigned) nb_sectors * SECTOR_SIZE;              outidx++;
         bs->rd_ops ++;              reqs[outidx].sector     = reqs[i].sector;
               reqs[outidx].nb_sectors = reqs[i].nb_sectors;
               reqs[outidx].qiov       = reqs[i].qiov;
           }
     }      }
   
     return ret;      return outidx + 1;
 }  }
   
 BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,  /*
                                  const uint8_t *buf, int nb_sectors,   * Submit multiple AIO write requests at once.
                                  BlockDriverCompletionFunc *cb, void *opaque)   *
    * On success, the function returns 0 and all requests in the reqs array have
    * been submitted. In error case this function returns -1, and any of the
    * requests may or may not be submitted yet. In particular, this means that the
    * callback will be called for some of the requests, for others it won't. The
    * caller must check the error field of the BlockRequest to wait for the right
    * callbacks (if error != 0, no callback will be called).
    *
    * The implementation may modify the contents of the reqs array, e.g. to merge
    * requests. However, the fields opaque and error are left unmodified as they
    * are used to signal failure for a single request to the caller.
    */
   int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriverAIOCB *acb;
     BlockDriverAIOCB *ret;      MultiwriteCB *mcb;
       int i;
   
     if (!drv)      /* don't submit writes if we don't have a medium */
         return NULL;      if (bs->drv == NULL) {
     if (bs->read_only)          for (i = 0; i < num_reqs; i++) {
         return NULL;              reqs[i].error = -ENOMEDIUM;
     if (bdrv_check_request(bs, sector_num, nb_sectors))          }
         return NULL;          return -1;
       }
   
     ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);      if (num_reqs == 0) {
           return 0;
       }
   
     if (ret) {      // Create MultiwriteCB structure
         /* Update stats even though technically transfer has not happened. */      mcb = g_malloc0(sizeof(*mcb) + num_reqs * sizeof(*mcb->callbacks));
         bs->wr_bytes += (unsigned) nb_sectors * SECTOR_SIZE;      mcb->num_requests = 0;
         bs->wr_ops ++;      mcb->num_callbacks = num_reqs;
   
       for (i = 0; i < num_reqs; i++) {
           mcb->callbacks[i].cb = reqs[i].cb;
           mcb->callbacks[i].opaque = reqs[i].opaque;
       }
   
       // Check for mergable requests
       num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);
   
       trace_bdrv_aio_multiwrite(mcb, mcb->num_callbacks, num_reqs);
   
       /*
        * Run the aio requests. As soon as one request can't be submitted
        * successfully, fail all requests that are not yet submitted (we must
        * return failure for all requests anyway)
        *
        * num_requests cannot be set to the right value immediately: If
        * bdrv_aio_writev fails for some request, num_requests would be too high
        * and therefore multiwrite_cb() would never recognize the multiwrite
        * request as completed. We also cannot use the loop variable i to set it
        * when the first request fails because the callback may already have been
        * called for previously submitted requests. Thus, num_requests must be
        * incremented for each request that is submitted.
        *
        * The problem that callbacks may be called early also means that we need
        * to take care that num_requests doesn't become 0 before all requests are
        * submitted - multiwrite_cb() would consider the multiwrite request
        * completed. A dummy request that is "completed" by a manual call to
        * multiwrite_cb() takes care of this.
        */
       mcb->num_requests = 1;
   
       // Run the aio requests
       for (i = 0; i < num_reqs; i++) {
           mcb->num_requests++;
           acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
               reqs[i].nb_sectors, multiwrite_cb, mcb);
   
           if (acb == NULL) {
               // We can only fail the whole thing if no request has been
               // submitted yet. Otherwise we'll wait for the submitted AIOs to
               // complete and report the error in the callback.
               if (i == 0) {
                   trace_bdrv_aio_multiwrite_earlyfail(mcb);
                   goto fail;
               } else {
                   trace_bdrv_aio_multiwrite_latefail(mcb, i);
                   multiwrite_cb(mcb, -EIO);
                   break;
               }
           }
     }      }
   
     return ret;      /* Complete the dummy request */
       multiwrite_cb(mcb, 0);
   
       return 0;
   
   fail:
       for (i = 0; i < mcb->num_callbacks; i++) {
           reqs[i].error = -EIO;
       }
       g_free(mcb);
       return -1;
 }  }
   
 void bdrv_aio_cancel(BlockDriverAIOCB *acb)  void bdrv_aio_cancel(BlockDriverAIOCB *acb)
Line 1461  void bdrv_aio_cancel(BlockDriverAIOCB *a Line 2484  void bdrv_aio_cancel(BlockDriverAIOCB *a
 /**************************************************************/  /**************************************************************/
 /* async block device emulation */  /* async block device emulation */
   
   typedef struct BlockDriverAIOCBSync {
       BlockDriverAIOCB common;
       QEMUBH *bh;
       int ret;
       /* vector translation state */
       QEMUIOVector *qiov;
       uint8_t *bounce;
       int is_write;
   } BlockDriverAIOCBSync;
   
   static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
   {
       BlockDriverAIOCBSync *acb =
           container_of(blockacb, BlockDriverAIOCBSync, common);
       qemu_bh_delete(acb->bh);
       acb->bh = NULL;
       qemu_aio_release(acb);
   }
   
   static AIOPool bdrv_em_aio_pool = {
       .aiocb_size         = sizeof(BlockDriverAIOCBSync),
       .cancel             = bdrv_aio_cancel_em,
   };
   
 static void bdrv_aio_bh_cb(void *opaque)  static void bdrv_aio_bh_cb(void *opaque)
 {  {
     BlockDriverAIOCBSync *acb = opaque;      BlockDriverAIOCBSync *acb = opaque;
   
       if (!acb->is_write)
           qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size);
       qemu_vfree(acb->bounce);
     acb->common.cb(acb->common.opaque, acb->ret);      acb->common.cb(acb->common.opaque, acb->ret);
       qemu_bh_delete(acb->bh);
       acb->bh = NULL;
     qemu_aio_release(acb);      qemu_aio_release(acb);
 }  }
   
 static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,  static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
         int64_t sector_num, uint8_t *buf, int nb_sectors,                                              int64_t sector_num,
         BlockDriverCompletionFunc *cb, void *opaque)                                              QEMUIOVector *qiov,
                                               int nb_sectors,
                                               BlockDriverCompletionFunc *cb,
                                               void *opaque,
                                               int is_write)
   
 {  {
     BlockDriverAIOCBSync *acb;      BlockDriverAIOCBSync *acb;
     int ret;  
   
     acb = qemu_aio_get(bs, cb, opaque);      acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
       acb->is_write = is_write;
       acb->qiov = qiov;
       acb->bounce = qemu_blockalign(bs, qiov->size);
   
     if (!acb->bh)      if (!acb->bh)
         acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);          acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
     ret = bdrv_read(bs, sector_num, buf, nb_sectors);  
     acb->ret = ret;      if (is_write) {
           qemu_iovec_to_buffer(acb->qiov, acb->bounce);
           acb->ret = bs->drv->bdrv_write(bs, sector_num, acb->bounce, nb_sectors);
       } else {
           acb->ret = bs->drv->bdrv_read(bs, sector_num, acb->bounce, nb_sectors);
       }
   
     qemu_bh_schedule(acb->bh);      qemu_bh_schedule(acb->bh);
   
     return &acb->common;      return &acb->common;
 }  }
   
 static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,  static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, const uint8_t *buf, int nb_sectors,          int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque)          BlockDriverCompletionFunc *cb, void *opaque)
 {  {
     BlockDriverAIOCBSync *acb;      return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
     int ret;  
   
     acb = qemu_aio_get(bs, cb, opaque);  
     if (!acb->bh)  
         acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);  
     ret = bdrv_write(bs, sector_num, buf, nb_sectors);  
     acb->ret = ret;  
     qemu_bh_schedule(acb->bh);  
     return &acb->common;  
 }  }
   
 static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)  static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
           int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
           BlockDriverCompletionFunc *cb, void *opaque)
 {  {
     BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;      return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
     qemu_bh_cancel(acb->bh);  
     qemu_aio_release(acb);  
 }  }
   
 /**************************************************************/  
 /* sync block device emulation */  
   
 static void bdrv_rw_em_cb(void *opaque, int ret)  typedef struct BlockDriverAIOCBCoroutine {
       BlockDriverAIOCB common;
       BlockRequest req;
       bool is_write;
       QEMUBH* bh;
   } BlockDriverAIOCBCoroutine;
   
   static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb)
 {  {
     *(int *)opaque = ret;      qemu_aio_flush();
 }  }
   
 #define NOT_DONE 0x7fffffff  static AIOPool bdrv_em_co_aio_pool = {
       .aiocb_size         = sizeof(BlockDriverAIOCBCoroutine),
       .cancel             = bdrv_aio_co_cancel_em,
   };
   
 static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,  static void bdrv_co_em_bh(void *opaque)
                         uint8_t *buf, int nb_sectors)  
 {  {
     int async_ret;      BlockDriverAIOCBCoroutine *acb = opaque;
     BlockDriverAIOCB *acb;  
   
     async_ret = NOT_DONE;      acb->common.cb(acb->common.opaque, acb->req.error);
     acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors,      qemu_bh_delete(acb->bh);
                         bdrv_rw_em_cb, &async_ret);      qemu_aio_release(acb);
     if (acb == NULL)  }
         return -1;  
   
     while (async_ret == NOT_DONE) {  /* Invoke bdrv_co_do_readv/bdrv_co_do_writev */
         qemu_aio_wait();  static void coroutine_fn bdrv_co_do_rw(void *opaque)
   {
       BlockDriverAIOCBCoroutine *acb = opaque;
       BlockDriverState *bs = acb->common.bs;
   
       if (!acb->is_write) {
           acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
               acb->req.nb_sectors, acb->req.qiov);
       } else {
           acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
               acb->req.nb_sectors, acb->req.qiov);
     }      }
   
     return async_ret;      acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
       qemu_bh_schedule(acb->bh);
 }  }
   
 static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,  static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
                          const uint8_t *buf, int nb_sectors)                                                 int64_t sector_num,
                                                  QEMUIOVector *qiov,
                                                  int nb_sectors,
                                                  BlockDriverCompletionFunc *cb,
                                                  void *opaque,
                                                  bool is_write)
   {
       Coroutine *co;
       BlockDriverAIOCBCoroutine *acb;
   
       acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
       acb->req.sector = sector_num;
       acb->req.nb_sectors = nb_sectors;
       acb->req.qiov = qiov;
       acb->is_write = is_write;
   
       co = qemu_coroutine_create(bdrv_co_do_rw);
       qemu_coroutine_enter(co, acb);
   
       return &acb->common;
   }
   
   static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque)
 {  {
     int async_ret;      BlockDriverAIOCBCoroutine *acb = opaque;
     BlockDriverAIOCB *acb;      BlockDriverState *bs = acb->common.bs;
   
     async_ret = NOT_DONE;      acb->req.error = bdrv_co_flush(bs);
     acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors,      acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
                          bdrv_rw_em_cb, &async_ret);      qemu_bh_schedule(acb->bh);
     if (acb == NULL)  }
         return -1;  
     while (async_ret == NOT_DONE) {  BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
         qemu_aio_wait();          BlockDriverCompletionFunc *cb, void *opaque)
     }  {
     return async_ret;      trace_bdrv_aio_flush(bs, opaque);
   
       Coroutine *co;
       BlockDriverAIOCBCoroutine *acb;
   
       acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
       co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
       qemu_coroutine_enter(co, acb);
   
       return &acb->common;
   }
   
   static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque)
   {
       BlockDriverAIOCBCoroutine *acb = opaque;
       BlockDriverState *bs = acb->common.bs;
   
       acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors);
       acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
       qemu_bh_schedule(acb->bh);
   }
   
   BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
           int64_t sector_num, int nb_sectors,
           BlockDriverCompletionFunc *cb, void *opaque)
   {
       Coroutine *co;
       BlockDriverAIOCBCoroutine *acb;
   
       trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque);
   
       acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
       acb->req.sector = sector_num;
       acb->req.nb_sectors = nb_sectors;
       co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
       qemu_coroutine_enter(co, acb);
   
       return &acb->common;
 }  }
   
 void bdrv_init(void)  void bdrv_init(void)
 {  {
     aio_pool_init(&vectored_aio_pool, sizeof(BlockDriverAIOCB),      module_call_init(MODULE_INIT_BLOCK);
                   bdrv_aio_cancel_vector);  }
   
     bdrv_register(&bdrv_raw);  void bdrv_init_with_whitelist(void)
     bdrv_register(&bdrv_host_device);  {
 #ifndef _WIN32      use_bdrv_whitelist = 1;
     bdrv_register(&bdrv_cow);      bdrv_init();
 #endif  
     bdrv_register(&bdrv_qcow);  
     bdrv_register(&bdrv_vmdk);  
     bdrv_register(&bdrv_cloop);  
     bdrv_register(&bdrv_dmg);  
     bdrv_register(&bdrv_bochs);  
     bdrv_register(&bdrv_vpc);  
     bdrv_register(&bdrv_vvfat);  
     bdrv_register(&bdrv_qcow2);  
     bdrv_register(&bdrv_parallels);  
     bdrv_register(&bdrv_nbd);  
 }  
   
 void aio_pool_init(AIOPool *pool, int aiocb_size,  
                    void (*cancel)(BlockDriverAIOCB *acb))  
 {  
     pool->aiocb_size = aiocb_size;  
     pool->cancel = cancel;  
     pool->free_aiocb = NULL;  
 }  }
   
 void *qemu_aio_get_pool(AIOPool *pool, BlockDriverState *bs,  void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
                         BlockDriverCompletionFunc *cb, void *opaque)                     BlockDriverCompletionFunc *cb, void *opaque)
 {  {
     BlockDriverAIOCB *acb;      BlockDriverAIOCB *acb;
   
Line 1592  void *qemu_aio_get_pool(AIOPool *pool, B Line 2707  void *qemu_aio_get_pool(AIOPool *pool, B
         acb = pool->free_aiocb;          acb = pool->free_aiocb;
         pool->free_aiocb = acb->next;          pool->free_aiocb = acb->next;
     } else {      } else {
         acb = qemu_mallocz(pool->aiocb_size);          acb = g_malloc0(pool->aiocb_size);
         acb->pool = pool;          acb->pool = pool;
     }      }
     acb->bs = bs;      acb->bs = bs;
Line 1601  void *qemu_aio_get_pool(AIOPool *pool, B Line 2716  void *qemu_aio_get_pool(AIOPool *pool, B
     return acb;      return acb;
 }  }
   
 void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,  
                    void *opaque)  
 {  
     return qemu_aio_get_pool(&bs->drv->aio_pool, bs, cb, opaque);  
 }  
   
 void qemu_aio_release(void *p)  void qemu_aio_release(void *p)
 {  {
     BlockDriverAIOCB *acb = (BlockDriverAIOCB *)p;      BlockDriverAIOCB *acb = (BlockDriverAIOCB *)p;
Line 1616  void qemu_aio_release(void *p) Line 2725  void qemu_aio_release(void *p)
 }  }
   
 /**************************************************************/  /**************************************************************/
   /* Coroutine block device emulation */
   
   typedef struct CoroutineIOCompletion {
       Coroutine *coroutine;
       int ret;
   } CoroutineIOCompletion;
   
   static void bdrv_co_io_em_complete(void *opaque, int ret)
   {
       CoroutineIOCompletion *co = opaque;
   
       co->ret = ret;
       qemu_coroutine_enter(co->coroutine, NULL);
   }
   
   static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
                                         int nb_sectors, QEMUIOVector *iov,
                                         bool is_write)
   {
       CoroutineIOCompletion co = {
           .coroutine = qemu_coroutine_self(),
       };
       BlockDriverAIOCB *acb;
   
       if (is_write) {
           acb = bs->drv->bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
                                          bdrv_co_io_em_complete, &co);
       } else {
           acb = bs->drv->bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
                                         bdrv_co_io_em_complete, &co);
       }
   
       trace_bdrv_co_io_em(bs, sector_num, nb_sectors, is_write, acb);
       if (!acb) {
           return -EIO;
       }
       qemu_coroutine_yield();
   
       return co.ret;
   }
   
   static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
                                            int64_t sector_num, int nb_sectors,
                                            QEMUIOVector *iov)
   {
       return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, false);
   }
   
   static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
                                            int64_t sector_num, int nb_sectors,
                                            QEMUIOVector *iov)
   {
       return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, true);
   }
   
   static void coroutine_fn bdrv_flush_co_entry(void *opaque)
   {
       RwCo *rwco = opaque;
   
       rwco->ret = bdrv_co_flush(rwco->bs);
   }
   
   int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
   {
       int ret;
   
       if (!bs->drv) {
           return 0;
       }
   
       /* Write back cached data to the OS even with cache=unsafe */
       if (bs->drv->bdrv_co_flush_to_os) {
           ret = bs->drv->bdrv_co_flush_to_os(bs);
           if (ret < 0) {
               return ret;
           }
       }
   
       /* But don't actually force it to the disk with cache=unsafe */
       if (bs->open_flags & BDRV_O_NO_FLUSH) {
           return 0;
       }
   
       if (bs->drv->bdrv_co_flush_to_disk) {
           return bs->drv->bdrv_co_flush_to_disk(bs);
       } else if (bs->drv->bdrv_aio_flush) {
           BlockDriverAIOCB *acb;
           CoroutineIOCompletion co = {
               .coroutine = qemu_coroutine_self(),
           };
   
           acb = bs->drv->bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co);
           if (acb == NULL) {
               return -EIO;
           } else {
               qemu_coroutine_yield();
               return co.ret;
           }
       } else {
           /*
            * Some block drivers always operate in either writethrough or unsafe
            * mode and don't support bdrv_flush therefore. Usually qemu doesn't
            * know how the server works (because the behaviour is hardcoded or
            * depends on server-side configuration), so we can't ensure that
            * everything is safe on disk. Returning an error doesn't work because
            * that would break guests even if the server operates in writethrough
            * mode.
            *
            * Let's hope the user knows what he's doing.
            */
           return 0;
       }
   }
   
   void bdrv_invalidate_cache(BlockDriverState *bs)
   {
       if (bs->drv && bs->drv->bdrv_invalidate_cache) {
           bs->drv->bdrv_invalidate_cache(bs);
       }
   }
   
   void bdrv_invalidate_cache_all(void)
   {
       BlockDriverState *bs;
   
       QTAILQ_FOREACH(bs, &bdrv_states, list) {
           bdrv_invalidate_cache(bs);
       }
   }
   
   int bdrv_flush(BlockDriverState *bs)
   {
       Coroutine *co;
       RwCo rwco = {
           .bs = bs,
           .ret = NOT_DONE,
       };
   
       if (qemu_in_coroutine()) {
           /* Fast-path if already in coroutine context */
           bdrv_flush_co_entry(&rwco);
       } else {
           co = qemu_coroutine_create(bdrv_flush_co_entry);
           qemu_coroutine_enter(co, &rwco);
           while (rwco.ret == NOT_DONE) {
               qemu_aio_wait();
           }
       }
   
       return rwco.ret;
   }
   
   static void coroutine_fn bdrv_discard_co_entry(void *opaque)
   {
       RwCo *rwco = opaque;
   
       rwco->ret = bdrv_co_discard(rwco->bs, rwco->sector_num, rwco->nb_sectors);
   }
   
   int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
                                    int nb_sectors)
   {
       if (!bs->drv) {
           return -ENOMEDIUM;
       } else if (bdrv_check_request(bs, sector_num, nb_sectors)) {
           return -EIO;
       } else if (bs->read_only) {
           return -EROFS;
       } else if (bs->drv->bdrv_co_discard) {
           return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
       } else if (bs->drv->bdrv_aio_discard) {
           BlockDriverAIOCB *acb;
           CoroutineIOCompletion co = {
               .coroutine = qemu_coroutine_self(),
           };
   
           acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors,
                                           bdrv_co_io_em_complete, &co);
           if (acb == NULL) {
               return -EIO;
           } else {
               qemu_coroutine_yield();
               return co.ret;
           }
       } else {
           return 0;
       }
   }
   
   int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
   {
       Coroutine *co;
       RwCo rwco = {
           .bs = bs,
           .sector_num = sector_num,
           .nb_sectors = nb_sectors,
           .ret = NOT_DONE,
       };
   
       if (qemu_in_coroutine()) {
           /* Fast-path if already in coroutine context */
           bdrv_discard_co_entry(&rwco);
       } else {
           co = qemu_coroutine_create(bdrv_discard_co_entry);
           qemu_coroutine_enter(co, &rwco);
           while (rwco.ret == NOT_DONE) {
               qemu_aio_wait();
           }
       }
   
       return rwco.ret;
   }
   
   /**************************************************************/
 /* removable device support */  /* removable device support */
   
 /**  /**
Line 1624  void qemu_aio_release(void *p) Line 2947  void qemu_aio_release(void *p)
 int bdrv_is_inserted(BlockDriverState *bs)  int bdrv_is_inserted(BlockDriverState *bs)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     int ret;  
     if (!drv)      if (!drv)
         return 0;          return 0;
     if (!drv->bdrv_is_inserted)      if (!drv->bdrv_is_inserted)
         return 1;          return 1;
     ret = drv->bdrv_is_inserted(bs);      return drv->bdrv_is_inserted(bs);
     return ret;  
 }  }
   
 /**  /**
  * Return TRUE if the media changed since the last call to this   * Return whether the media changed since the last call to this
  * function. It is currently only used for floppy disks   * function, or -ENOTSUP if we don't know.  Most drivers don't know.
  */   */
 int bdrv_media_changed(BlockDriverState *bs)  int bdrv_media_changed(BlockDriverState *bs)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     int ret;  
   
     if (!drv || !drv->bdrv_media_changed)      if (drv && drv->bdrv_media_changed) {
         ret = -ENOTSUP;          return drv->bdrv_media_changed(bs);
     else      }
         ret = drv->bdrv_media_changed(bs);      return -ENOTSUP;
     if (ret == -ENOTSUP)  
         ret = bs->media_changed;  
     bs->media_changed = 0;  
     return ret;  
 }  }
   
 /**  /**
Line 1658  int bdrv_media_changed(BlockDriverState  Line 2975  int bdrv_media_changed(BlockDriverState 
 void bdrv_eject(BlockDriverState *bs, int eject_flag)  void bdrv_eject(BlockDriverState *bs, int eject_flag)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     int ret;  
   
     if (!drv || !drv->bdrv_eject) {      if (drv && drv->bdrv_eject) {
         ret = -ENOTSUP;          drv->bdrv_eject(bs, eject_flag);
     } else {  
         ret = drv->bdrv_eject(bs, eject_flag);  
     }      }
     if (ret == -ENOTSUP) {  
         if (eject_flag)  
             bdrv_close(bs);  
     }  
 }  
   
 int bdrv_is_locked(BlockDriverState *bs)  
 {  
     return bs->locked;  
 }  }
   
 /**  /**
  * Lock or unlock the media (if it is locked, the user won't be able   * Lock or unlock the media (if it is locked, the user won't be able
  * to eject it manually).   * to eject it manually).
  */   */
 void bdrv_set_locked(BlockDriverState *bs, int locked)  void bdrv_lock_medium(BlockDriverState *bs, bool locked)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
   
     bs->locked = locked;      trace_bdrv_lock_medium(bs, locked);
     if (drv && drv->bdrv_set_locked) {  
         drv->bdrv_set_locked(bs, locked);      if (drv && drv->bdrv_lock_medium) {
           drv->bdrv_lock_medium(bs, locked);
     }      }
 }  }
   
Line 1700  int bdrv_ioctl(BlockDriverState *bs, uns Line 3006  int bdrv_ioctl(BlockDriverState *bs, uns
         return drv->bdrv_ioctl(bs, req, buf);          return drv->bdrv_ioctl(bs, req, buf);
     return -ENOTSUP;      return -ENOTSUP;
 }  }
   
   BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
           unsigned long int req, void *buf,
           BlockDriverCompletionFunc *cb, void *opaque)
   {
       BlockDriver *drv = bs->drv;
   
       if (drv && drv->bdrv_aio_ioctl)
           return drv->bdrv_aio_ioctl(bs, req, buf, cb, opaque);
       return NULL;
   }
   
   void bdrv_set_buffer_alignment(BlockDriverState *bs, int align)
   {
       bs->buffer_alignment = align;
   }
   
   void *qemu_blockalign(BlockDriverState *bs, size_t size)
   {
       return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
   }
   
   void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
   {
       int64_t bitmap_size;
   
       bs->dirty_count = 0;
       if (enable) {
           if (!bs->dirty_bitmap) {
               bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
                       BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
               bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
   
               bs->dirty_bitmap = g_malloc0(bitmap_size);
           }
       } else {
           if (bs->dirty_bitmap) {
               g_free(bs->dirty_bitmap);
               bs->dirty_bitmap = NULL;
           }
       }
   }
   
   int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
   {
       int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
   
       if (bs->dirty_bitmap &&
           (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
           return !!(bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
               (1UL << (chunk % (sizeof(unsigned long) * 8))));
       } else {
           return 0;
       }
   }
   
   void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
                         int nr_sectors)
   {
       set_dirty_bitmap(bs, cur_sector, nr_sectors, 0);
   }
   
   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;
   }
   
   void bdrv_iostatus_enable(BlockDriverState *bs)
   {
       bs->iostatus_enabled = true;
       bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
   }
   
   /* The I/O status is only enabled if the drive explicitly
    * enables it _and_ the VM is configured to stop on errors */
   bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
   {
       return (bs->iostatus_enabled &&
              (bs->on_write_error == BLOCK_ERR_STOP_ENOSPC ||
               bs->on_write_error == BLOCK_ERR_STOP_ANY    ||
               bs->on_read_error == BLOCK_ERR_STOP_ANY));
   }
   
   void bdrv_iostatus_disable(BlockDriverState *bs)
   {
       bs->iostatus_enabled = false;
   }
   
   void bdrv_iostatus_reset(BlockDriverState *bs)
   {
       if (bdrv_iostatus_is_enabled(bs)) {
           bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
       }
   }
   
   /* XXX: Today this is set by device models because it makes the implementation
      quite simple. However, the block layer knows about the error, so it's
      possible to implement this without device models being involved */
   void bdrv_iostatus_set_err(BlockDriverState *bs, int error)
   {
       if (bdrv_iostatus_is_enabled(bs) &&
           bs->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
           assert(error >= 0);
           bs->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
                                            BLOCK_DEVICE_IO_STATUS_FAILED;
       }
   }
   
   void
   bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, int64_t bytes,
           enum BlockAcctType type)
   {
       assert(type < BDRV_MAX_IOTYPE);
   
       cookie->bytes = bytes;
       cookie->start_time_ns = get_clock();
       cookie->type = type;
   }
   
   void
   bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
   {
       assert(cookie->type < BDRV_MAX_IOTYPE);
   
       bs->nr_bytes[cookie->type] += cookie->bytes;
       bs->nr_ops[cookie->type]++;
       bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
   }
   
   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)
   {
       QEMUOptionParameter *param = NULL, *create_options = NULL;
       QEMUOptionParameter *backing_fmt, *backing_file, *size;
       BlockDriverState *bs = NULL;
       BlockDriver *drv, *proto_drv;
       BlockDriver *backing_drv = NULL;
       int ret = 0;
   
       /* Find driver and parse its options */
       drv = bdrv_find_format(fmt);
       if (!drv) {
           error_report("Unknown file format '%s'", fmt);
           ret = -EINVAL;
           goto out;
       }
   
       proto_drv = bdrv_find_protocol(filename);
       if (!proto_drv) {
           error_report("Unknown protocol '%s'", filename);
           ret = -EINVAL;
           goto out;
       }
   
       create_options = append_option_parameters(create_options,
                                                 drv->create_options);
       create_options = append_option_parameters(create_options,
                                                 proto_drv->create_options);
   
       /* Create parameter list with default values */
       param = parse_option_parameters("", create_options, param);
   
       set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
   
       /* Parse -o options */
       if (options) {
           param = parse_option_parameters(options, create_options, param);
           if (param == NULL) {
               error_report("Invalid options for file format '%s'.", fmt);
               ret = -EINVAL;
               goto out;
           }
       }
   
       if (base_filename) {
           if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
                                    base_filename)) {
               error_report("Backing file not supported for file format '%s'",
                            fmt);
               ret = -EINVAL;
               goto out;
           }
       }
   
       if (base_fmt) {
           if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
               error_report("Backing file format not supported for file "
                            "format '%s'", fmt);
               ret = -EINVAL;
               goto out;
           }
       }
   
       backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
       if (backing_file && backing_file->value.s) {
           if (!strcmp(filename, backing_file->value.s)) {
               error_report("Error: Trying to create an image with the "
                            "same filename as the backing file");
               ret = -EINVAL;
               goto out;
           }
       }
   
       backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
       if (backing_fmt && backing_fmt->value.s) {
           backing_drv = bdrv_find_format(backing_fmt->value.s);
           if (!backing_drv) {
               error_report("Unknown backing file format '%s'",
                            backing_fmt->value.s);
               ret = -EINVAL;
               goto out;
           }
       }
   
       // The size for the image must always be specified, with one exception:
       // If we are using a backing file, we can obtain the size from there
       size = get_option_parameter(param, BLOCK_OPT_SIZE);
       if (size && size->value.n == -1) {
           if (backing_file && backing_file->value.s) {
               uint64_t size;
               char buf[32];
   
               bs = bdrv_new("");
   
               ret = bdrv_open(bs, backing_file->value.s, flags, backing_drv);
               if (ret < 0) {
                   error_report("Could not open '%s'", backing_file->value.s);
                   goto out;
               }
               bdrv_get_geometry(bs, &size);
               size *= 512;
   
               snprintf(buf, sizeof(buf), "%" PRId64, size);
               set_option_parameter(param, BLOCK_OPT_SIZE, buf);
           } else {
               error_report("Image creation needs a size parameter");
               ret = -EINVAL;
               goto out;
           }
       }
   
       printf("Formatting '%s', fmt=%s ", filename, fmt);
       print_option_parameters(param);
       puts("");
   
       ret = bdrv_create(drv, filename, param);
   
       if (ret < 0) {
           if (ret == -ENOTSUP) {
               error_report("Formatting or formatting option not supported for "
                            "file format '%s'", fmt);
           } else if (ret == -EFBIG) {
               error_report("The image size is too large for file format '%s'",
                            fmt);
           } else {
               error_report("%s: error while creating %s: %s", filename, fmt,
                            strerror(-ret));
           }
       }
   
   out:
       free_option_parameters(create_options);
       free_option_parameters(param);
   
       if (bs) {
           bdrv_delete(bs);
       }
   
       return ret;
   }

Removed from v.1.1.1.10  
changed lines
  Added in v.1.1.1.22


unix.superglobalmegacorp.com