Diff for /qemu/block.c between versions 1.1.1.18 and 1.1.1.19

version 1.1.1.18, 2018/04/24 18:24:07 version 1.1.1.19, 2018/04/24 18:34:00
Line 23 Line 23
  */   */
 #include "config-host.h"  #include "config-host.h"
 #include "qemu-common.h"  #include "qemu-common.h"
   #include "trace.h"
 #include "monitor.h"  #include "monitor.h"
 #include "block_int.h"  #include "block_int.h"
 #include "module.h"  #include "module.h"
Line 69  static BlockDriverState *bs_snapshots; Line 70  static BlockDriverState *bs_snapshots;
 /* If non-zero, use only whitelisted block drivers */  /* If non-zero, use only whitelisted block drivers */
 static int use_bdrv_whitelist;  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
   
   /* 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
   
       return strchr(path, ':') != NULL;
   }
   
 int path_is_absolute(const char *path)  int path_is_absolute(const char *path)
 {  {
     const char *p;      const char *p;
Line 214  int bdrv_create_file(const char* filenam Line 248  int bdrv_create_file(const char* filenam
   
     drv = bdrv_find_protocol(filename);      drv = bdrv_find_protocol(filename);
     if (drv == NULL) {      if (drv == NULL) {
         drv = bdrv_find_format("file");          return -ENOENT;
     }      }
   
     return bdrv_create(drv, filename, options);      return bdrv_create(drv, filename, options);
Line 243  void get_tmp_filename(char *filename, in Line 277  void get_tmp_filename(char *filename, in
 }  }
 #endif  #endif
   
 #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  
   
 /*  /*
  * Detect host devices. By convention, /dev/cdrom[N] is always   * Detect host devices. By convention, /dev/cdrom[N] is always
  * recognized as a host CDROM.   * recognized as a host CDROM.
Line 306  BlockDriver *bdrv_find_protocol(const ch Line 320  BlockDriver *bdrv_find_protocol(const ch
         return drv1;          return drv1;
     }      }
   
 #ifdef _WIN32      if (!path_has_protocol(filename)) {
      if (is_windows_drive(filename) ||  
          is_windows_drive_prefix(filename))  
          return bdrv_find_format("file");  
 #endif  
   
     p = strchr(filename, ':');  
     if (!p) {  
         return bdrv_find_format("file");          return bdrv_find_format("file");
     }      }
       p = strchr(filename, ':');
       assert(p != NULL);
     len = p - filename;      len = p - filename;
     if (len > sizeof(protocol) - 1)      if (len > sizeof(protocol) - 1)
         len = sizeof(protocol) - 1;          len = sizeof(protocol) - 1;
Line 602  int bdrv_open(BlockDriverState *bs, cons Line 611  int bdrv_open(BlockDriverState *bs, cons
         BlockDriver *back_drv = NULL;          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)) {
         if (bs->backing_format[0] != '\0')              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);              back_drv = bdrv_find_format(bs->backing_format);
           }
   
         /* backing files always opened read-only */          /* backing files always opened read-only */
         back_flags =          back_flags =
Line 628  int bdrv_open(BlockDriverState *bs, cons Line 645  int bdrv_open(BlockDriverState *bs, cons
         /* call the change callback */          /* call the change callback */
         bs->media_changed = 1;          bs->media_changed = 1;
         if (bs->change_cb)          if (bs->change_cb)
             bs->change_cb(bs->change_opaque);              bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
     }      }
   
     return 0;      return 0;
Line 667  void bdrv_close(BlockDriverState *bs) Line 684  void bdrv_close(BlockDriverState *bs)
         /* call the change callback */          /* call the change callback */
         bs->media_changed = 1;          bs->media_changed = 1;
         if (bs->change_cb)          if (bs->change_cb)
             bs->change_cb(bs->change_opaque);              bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
     }      }
 }  }
   
Line 735  int bdrv_check(BlockDriverState *bs, Bdr Line 752  int bdrv_check(BlockDriverState *bs, Bdr
     return bs->drv->bdrv_check(bs, res);      return bs->drv->bdrv_check(bs, res);
 }  }
   
   #define COMMIT_BUF_SECTORS 2048
   
 /* commit COW file into the raw image */  /* commit COW file into the raw image */
 int bdrv_commit(BlockDriverState *bs)  int bdrv_commit(BlockDriverState *bs)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     BlockDriver *backing_drv;      BlockDriver *backing_drv;
     int64_t i, total_sectors;      int64_t sector, total_sectors;
     int n, j, ro, open_flags;      int n, ro, open_flags;
     int ret = 0, rw_ret = 0;      int ret = 0, rw_ret = 0;
     unsigned char sector[BDRV_SECTOR_SIZE];      uint8_t *buf;
     char filename[1024];      char filename[1024];
     BlockDriverState *bs_rw, *bs_ro;      BlockDriverState *bs_rw, *bs_ro;
   
Line 789  int bdrv_commit(BlockDriverState *bs) Line 808  int bdrv_commit(BlockDriverState *bs)
     }      }
   
     total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;      total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
     for (i = 0; i < total_sectors;) {      buf = qemu_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) {  
                     ret = -EIO;  
                     goto ro_cleanup;  
                 }  
   
                 if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {      for (sector = 0; sector < total_sectors; sector += n) {
                     ret = -EIO;          if (drv->bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n)) {
                     goto ro_cleanup;  
                 }              if (bdrv_read(bs, sector, buf, n) != 0) {
                 i++;                  ret = -EIO;
             }                  goto ro_cleanup;
         } else {              }
             i += n;  
               if (bdrv_write(bs->backing_hd, sector, buf, n) != 0) {
                   ret = -EIO;
                   goto ro_cleanup;
               }
         }          }
     }      }
   
Line 821  int bdrv_commit(BlockDriverState *bs) Line 838  int bdrv_commit(BlockDriverState *bs)
         bdrv_flush(bs->backing_hd);          bdrv_flush(bs->backing_hd);
   
 ro_cleanup:  ro_cleanup:
       qemu_free(buf);
   
     if (ro) {      if (ro) {
         /* re-open as RO */          /* re-open as RO */
Line 928  static void set_dirty_bitmap(BlockDriver Line 946  static void set_dirty_bitmap(BlockDriver
         bit = start % (sizeof(unsigned long) * 8);          bit = start % (sizeof(unsigned long) * 8);
         val = bs->dirty_bitmap[idx];          val = bs->dirty_bitmap[idx];
         if (dirty) {          if (dirty) {
             if (!(val & (1 << bit))) {              if (!(val & (1UL << bit))) {
                 bs->dirty_count++;                  bs->dirty_count++;
                 val |= 1 << bit;                  val |= 1UL << bit;
             }              }
         } else {          } else {
             if (val & (1 << bit)) {              if (val & (1UL << bit)) {
                 bs->dirty_count--;                  bs->dirty_count--;
                 val &= ~(1 << bit);                  val &= ~(1UL << bit);
             }              }
         }          }
         bs->dirty_bitmap[idx] = val;          bs->dirty_bitmap[idx] = val;
Line 1114  int bdrv_truncate(BlockDriverState *bs,  Line 1132  int bdrv_truncate(BlockDriverState *bs, 
         return -ENOTSUP;          return -ENOTSUP;
     if (bs->read_only)      if (bs->read_only)
         return -EACCES;          return -EACCES;
       if (bdrv_in_use(bs))
           return -EBUSY;
     ret = drv->bdrv_truncate(bs, offset);      ret = drv->bdrv_truncate(bs, offset);
     if (ret == 0) {      if (ret == 0) {
         ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);          ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
           if (bs->change_cb) {
               bs->change_cb(bs->change_opaque, CHANGE_SIZE);
           }
     }      }
     return ret;      return ret;
 }  }
Line 1348  int bdrv_enable_write_cache(BlockDriverS Line 1371  int bdrv_enable_write_cache(BlockDriverS
   
 /* XXX: no longer used */  /* XXX: no longer used */
 void bdrv_set_change_cb(BlockDriverState *bs,  void bdrv_set_change_cb(BlockDriverState *bs,
                         void (*change_cb)(void *opaque), void *opaque)                          void (*change_cb)(void *opaque, int reason),
                           void *opaque)
 {  {
     bs->change_cb = change_cb;      bs->change_cb = change_cb;
     bs->change_opaque = opaque;      bs->change_opaque = opaque;
Line 1393  int bdrv_set_key(BlockDriverState *bs, c Line 1417  int bdrv_set_key(BlockDriverState *bs, c
         /* call the change callback now, we skipped it on open */          /* call the change callback now, we skipped it on open */
         bs->media_changed = 1;          bs->media_changed = 1;
         if (bs->change_cb)          if (bs->change_cb)
             bs->change_cb(bs->change_opaque);              bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
     }      }
     return ret;      return ret;
 }  }
Line 1451  const char *bdrv_get_device_name(BlockDr Line 1475  const char *bdrv_get_device_name(BlockDr
     return bs->device_name;      return bs->device_name;
 }  }
   
 void bdrv_flush(BlockDriverState *bs)  int bdrv_flush(BlockDriverState *bs)
 {  {
     if (bs->open_flags & BDRV_O_NO_FLUSH) {      if (bs->open_flags & BDRV_O_NO_FLUSH) {
         return;          return 0;
       }
   
       if (bs->drv && bs->drv->bdrv_flush) {
           return bs->drv->bdrv_flush(bs);
     }      }
   
     if (bs->drv && bs->drv->bdrv_flush)      /*
         bs->drv->bdrv_flush(bs);       * 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_flush_all(void)  void bdrv_flush_all(void)
Line 1484  int bdrv_has_zero_init(BlockDriverState  Line 1521  int bdrv_has_zero_init(BlockDriverState 
     return 1;      return 1;
 }  }
   
   int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
   {
       if (!bs->drv) {
           return -ENOMEDIUM;
       }
       if (!bs->drv->bdrv_discard) {
           return 0;
       }
       return bs->drv->bdrv_discard(bs, sector_num, nb_sectors);
   }
   
 /*  /*
  * Returns true iff the specified sector is present in the disk image. Drivers   * Returns true iff the specified sector is present in the disk image. Drivers
  * not implementing the functionality are assumed to not support backing files,   * not implementing the functionality are assumed to not support backing files,
Line 1897  int bdrv_snapshot_list(BlockDriverState  Line 1945  int bdrv_snapshot_list(BlockDriverState 
     return -ENOTSUP;      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
   
 char *get_human_readable_size(char *buf, int buf_size, int64_t size)  char *get_human_readable_size(char *buf, int buf_size, int64_t size)
Line 1981  BlockDriverAIOCB *bdrv_aio_readv(BlockDr Line 2045  BlockDriverAIOCB *bdrv_aio_readv(BlockDr
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     BlockDriverAIOCB *ret;      BlockDriverAIOCB *ret;
   
       trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
   
     if (!drv)      if (!drv)
         return NULL;          return NULL;
     if (bdrv_check_request(bs, sector_num, nb_sectors))      if (bdrv_check_request(bs, sector_num, nb_sectors))
Line 1998  BlockDriverAIOCB *bdrv_aio_readv(BlockDr Line 2064  BlockDriverAIOCB *bdrv_aio_readv(BlockDr
     return ret;      return ret;
 }  }
   
   typedef struct BlockCompleteData {
       BlockDriverCompletionFunc *cb;
       void *opaque;
       BlockDriverState *bs;
       int64_t sector_num;
       int nb_sectors;
   } BlockCompleteData;
   
   static void block_complete_cb(void *opaque, int ret)
   {
       BlockCompleteData *b = opaque;
   
       if (b->bs->dirty_bitmap) {
           set_dirty_bitmap(b->bs, b->sector_num, b->nb_sectors, 1);
       }
       b->cb(b->opaque, ret);
       qemu_free(b);
   }
   
   static BlockCompleteData *blk_dirty_cb_alloc(BlockDriverState *bs,
                                                int64_t sector_num,
                                                int nb_sectors,
                                                BlockDriverCompletionFunc *cb,
                                                void *opaque)
   {
       BlockCompleteData *blkdata = qemu_mallocz(sizeof(BlockCompleteData));
   
       blkdata->bs = bs;
       blkdata->cb = cb;
       blkdata->opaque = opaque;
       blkdata->sector_num = sector_num;
       blkdata->nb_sectors = nb_sectors;
   
       return blkdata;
   }
   
 BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,  BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                   QEMUIOVector *qiov, int nb_sectors,                                    QEMUIOVector *qiov, int nb_sectors,
                                   BlockDriverCompletionFunc *cb, void *opaque)                                    BlockDriverCompletionFunc *cb, void *opaque)
 {  {
     BlockDriver *drv = bs->drv;      BlockDriver *drv = bs->drv;
     BlockDriverAIOCB *ret;      BlockDriverAIOCB *ret;
       BlockCompleteData *blk_cb_data;
   
       trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
   
     if (!drv)      if (!drv)
         return NULL;          return NULL;
Line 2013  BlockDriverAIOCB *bdrv_aio_writev(BlockD Line 2118  BlockDriverAIOCB *bdrv_aio_writev(BlockD
         return NULL;          return NULL;
   
     if (bs->dirty_bitmap) {      if (bs->dirty_bitmap) {
         set_dirty_bitmap(bs, sector_num, nb_sectors, 1);          blk_cb_data = blk_dirty_cb_alloc(bs, sector_num, nb_sectors, cb,
                                            opaque);
           cb = &block_complete_cb;
           opaque = blk_cb_data;
     }      }
   
     ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,      ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
Line 2062  static void multiwrite_cb(void *opaque,  Line 2170  static void multiwrite_cb(void *opaque, 
 {  {
     MultiwriteCB *mcb = opaque;      MultiwriteCB *mcb = opaque;
   
       trace_multiwrite_cb(mcb, ret);
   
     if (ret < 0 && !mcb->error) {      if (ret < 0 && !mcb->error) {
         mcb->error = ret;          mcb->error = ret;
     }      }
Line 2202  int bdrv_aio_multiwrite(BlockDriverState Line 2312  int bdrv_aio_multiwrite(BlockDriverState
     // Check for mergable requests      // Check for mergable requests
     num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);      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       * Run the aio requests. As soon as one request can't be submitted
      * successfully, fail all requests that are not yet submitted (we must       * successfully, fail all requests that are not yet submitted (we must
Line 2223  int bdrv_aio_multiwrite(BlockDriverState Line 2335  int bdrv_aio_multiwrite(BlockDriverState
      */       */
     mcb->num_requests = 1;      mcb->num_requests = 1;
   
       // Run the aio requests
     for (i = 0; i < num_reqs; i++) {      for (i = 0; i < num_reqs; i++) {
         mcb->num_requests++;          mcb->num_requests++;
         acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,          acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
Line 2233  int bdrv_aio_multiwrite(BlockDriverState Line 2346  int bdrv_aio_multiwrite(BlockDriverState
             // submitted yet. Otherwise we'll wait for the submitted AIOs to              // submitted yet. Otherwise we'll wait for the submitted AIOs to
             // complete and report the error in the callback.              // complete and report the error in the callback.
             if (i == 0) {              if (i == 0) {
                   trace_bdrv_aio_multiwrite_earlyfail(mcb);
                 goto fail;                  goto fail;
             } else {              } else {
                   trace_bdrv_aio_multiwrite_latefail(mcb, i);
                 multiwrite_cb(mcb, -EIO);                  multiwrite_cb(mcb, -EIO);
                 break;                  break;
             }              }
Line 2643  int bdrv_get_dirty(BlockDriverState *bs, Line 2758  int bdrv_get_dirty(BlockDriverState *bs,
   
     if (bs->dirty_bitmap &&      if (bs->dirty_bitmap &&
         (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {          (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
         return bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &          return !!(bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
             (1 << (chunk % (sizeof(unsigned long) * 8)));              (1UL << (chunk % (sizeof(unsigned long) * 8))));
     } else {      } else {
         return 0;          return 0;
     }      }
Line 2660  int64_t bdrv_get_dirty_count(BlockDriver Line 2775  int64_t bdrv_get_dirty_count(BlockDriver
 {  {
     return bs->dirty_count;      return bs->dirty_count;
 }  }
   
   void bdrv_set_in_use(BlockDriverState *bs, int in_use)
   {
       assert(bs->in_use != in_use);
       bs->in_use = in_use;
   }
   
   int bdrv_in_use(BlockDriverState *bs)
   {
       return bs->in_use;
   }
   
   int bdrv_img_create(const char *filename, const char *fmt,
                       const char *base_filename, const char *base_fmt,
                       char *options, uint64_t img_size, int flags)
   {
       QEMUOptionParameter *param = NULL, *create_options = NULL;
       QEMUOptionParameter *backing_fmt, *backing_file;
       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
       if (get_option_parameter(param, BLOCK_OPT_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.18  
changed lines
  Added in v.1.1.1.19


unix.superglobalmegacorp.com