Merge remote-tracking branch 'origin/master' into threadpool
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 31 Oct 2012 09:42:51 +0000 (10:42 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 31 Oct 2012 09:42:51 +0000 (10:42 +0100)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1  2 
Makefile
block/Makefile.objs
iov.c
osdep.c
qemu-timer.c
qmp.c
trace-events
vl.c

diff --combined Makefile
+++ b/Makefile
@@@ -8,6 -8,17 +8,17 @@@ ifneq ($(wildcard config-host.mak),
  # Put the all: rule here so that config-host.mak can contain dependencies.
  all:
  include config-host.mak
+ # Check that we're not trying to do an out-of-tree build from
+ # a tree that's been used for an in-tree build.
+ ifneq ($(realpath $(SRC_PATH)),$(realpath .))
+ ifneq ($(wildcard $(SRC_PATH)/config-host.mak),)
+ $(error This is an out of tree build but your source tree ($(SRC_PATH)) \
+ seems to have been used for an in-tree build. You can fix this by running \
+ "make distclean && rm -rf *-linux-user *-softmmu" in your source tree)
+ endif
+ endif
  include $(SRC_PATH)/rules.mak
  config-host.mak: $(SRC_PATH)/configure
        @echo $@ is out-of-date, running configure
@@@ -160,7 -171,8 +171,7 @@@ endi
  qemu-img.o: qemu-img-cmds.h
  
  tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
 -      qemu-timer-common.o main-loop.o notify.o \
 -      iohandler.o cutils.o iov.o async.o error.o
 +      main-loop.o iohandler.o error.o
  tools-obj-$(CONFIG_POSIX) += compatfd.o
  
  qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
@@@ -169,7 -181,7 +180,7 @@@ qemu-io$(EXESUF): qemu-io.o cmd.o $(too
  
  qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
  
 -vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) $(tools-obj-y) qemu-timer-common.o libcacard/vscclient.o
 +vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o
        $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS),"  LINK  $@")
  
  fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
@@@ -212,7 -224,7 +223,7 @@@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH
  QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
  $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
  
 -qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
 +qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
  
  QEMULIBS=libuser libdis libdis-user
  
diff --combined block/Makefile.objs
@@@ -2,18 -2,14 +2,19 @@@ block-obj-y += raw.o cow.o qcow.o vdi.
  block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
  block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
  block-obj-y += qed-check.o
 -block-obj-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
 -block-obj-$(CONFIG_WIN32) += raw-win32.o
 +block-obj-y += parallels.o blkdebug.o blkverify.o
 +block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
  block-obj-$(CONFIG_POSIX) += raw-posix.o
 +block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 +
 +ifeq ($(CONFIG_POSIX),y)
 +block-obj-y += nbd.o sheepdog.o
  block-obj-$(CONFIG_LIBISCSI) += iscsi.o
  block-obj-$(CONFIG_CURL) += curl.o
  block-obj-$(CONFIG_RBD) += rbd.o
  block-obj-$(CONFIG_GLUSTERFS) += gluster.o
 +endif
  
  common-obj-y += stream.o
  common-obj-y += commit.o
+ common-obj-y += mirror.o
diff --combined iov.c
--- 1/iov.c
--- 2/iov.c
+++ b/iov.c
@@@ -229,105 -229,25 +229,128 @@@ void iov_hexdump(const struct iovec *io
      }
  }
  
+ unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt,
+                  const struct iovec *iov, unsigned int iov_cnt,
+                  size_t offset, size_t bytes)
+ {
+     size_t len;
+     unsigned int i, j;
+     for (i = 0, j = 0; i < iov_cnt && j < dst_iov_cnt && bytes; i++) {
+         if (offset >= iov[i].iov_len) {
+             offset -= iov[i].iov_len;
+             continue;
+         }
+         len = MIN(bytes, iov[i].iov_len - offset);
+         dst_iov[j].iov_base = iov[i].iov_base + offset;
+         dst_iov[j].iov_len = len;
+         j++;
+         bytes -= len;
+         offset = 0;
+     }
+     assert(offset == 0);
+     return j;
+ }
++
 +/* io vectors */
 +
 +void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
 +{
 +    qiov->iov = g_malloc(alloc_hint * sizeof(struct iovec));
 +    qiov->niov = 0;
 +    qiov->nalloc = alloc_hint;
 +    qiov->size = 0;
 +}
 +
 +void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov)
 +{
 +    int i;
 +
 +    qiov->iov = iov;
 +    qiov->niov = niov;
 +    qiov->nalloc = -1;
 +    qiov->size = 0;
 +    for (i = 0; i < niov; i++)
 +        qiov->size += iov[i].iov_len;
 +}
 +
 +void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
 +{
 +    assert(qiov->nalloc != -1);
 +
 +    if (qiov->niov == qiov->nalloc) {
 +        qiov->nalloc = 2 * qiov->nalloc + 1;
 +        qiov->iov = g_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
 +    }
 +    qiov->iov[qiov->niov].iov_base = base;
 +    qiov->iov[qiov->niov].iov_len = len;
 +    qiov->size += len;
 +    ++qiov->niov;
 +}
 +
 +/*
 + * Concatenates (partial) iovecs from src to the end of dst.
 + * It starts copying after skipping `soffset' bytes at the
 + * beginning of src and adds individual vectors from src to
 + * dst copies up to `sbytes' bytes total, or up to the end
 + * of src if it comes first.  This way, it is okay to specify
 + * very large value for `sbytes' to indicate "up to the end
 + * of src".
 + * Only vector pointers are processed, not the actual data buffers.
 + */
 +void qemu_iovec_concat(QEMUIOVector *dst,
 +                       QEMUIOVector *src, size_t soffset, size_t sbytes)
 +{
 +    int i;
 +    size_t done;
 +    struct iovec *siov = src->iov;
 +    assert(dst->nalloc != -1);
 +    assert(src->size >= soffset);
 +    for (i = 0, done = 0; done < sbytes && i < src->niov; i++) {
 +        if (soffset < siov[i].iov_len) {
 +            size_t len = MIN(siov[i].iov_len - soffset, sbytes - done);
 +            qemu_iovec_add(dst, siov[i].iov_base + soffset, len);
 +            done += len;
 +            soffset = 0;
 +        } else {
 +            soffset -= siov[i].iov_len;
 +        }
 +    }
 +    /* return done; */
 +}
 +
 +void qemu_iovec_destroy(QEMUIOVector *qiov)
 +{
 +    assert(qiov->nalloc != -1);
 +
 +    qemu_iovec_reset(qiov);
 +    g_free(qiov->iov);
 +    qiov->nalloc = 0;
 +    qiov->iov = NULL;
 +}
 +
 +void qemu_iovec_reset(QEMUIOVector *qiov)
 +{
 +    assert(qiov->nalloc != -1);
 +
 +    qiov->niov = 0;
 +    qiov->size = 0;
 +}
 +
 +size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
 +                         void *buf, size_t bytes)
 +{
 +    return iov_to_buf(qiov->iov, qiov->niov, offset, buf, bytes);
 +}
 +
 +size_t qemu_iovec_from_buf(QEMUIOVector *qiov, size_t offset,
 +                           const void *buf, size_t bytes)
 +{
 +    return iov_from_buf(qiov->iov, qiov->niov, offset, buf, bytes);
 +}
 +
 +size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset,
 +                         int fillc, size_t bytes)
 +{
 +    return iov_memset(qiov->iov, qiov->niov, offset, fillc, bytes);
 +}
diff --combined osdep.c
+++ b/osdep.c
@@@ -88,7 -88,6 +88,6 @@@ static int qemu_dup_flags(int fd, int f
      int ret;
      int serrno;
      int dup_flags;
-     int setfl_flags;
  
  #ifdef F_DUPFD_CLOEXEC
      ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
      }
  
      /* Set/unset flags that we can with fcntl */
-     setfl_flags = O_APPEND | O_ASYNC | O_NONBLOCK;
- #ifdef O_NOATIME
-     setfl_flags |= O_NOATIME;
- #endif
- #ifdef O_DIRECT
-     setfl_flags |= O_DIRECT;
- #endif
-     dup_flags &= ~setfl_flags;
-     dup_flags |= (flags & setfl_flags);
-     if (fcntl(ret, F_SETFL, dup_flags) == -1) {
+     if (fcntl(ret, F_SETFL, flags) == -1) {
          goto fail;
      }
  
@@@ -144,11 -134,6 +134,11 @@@ fail
      errno = serrno;
      return -1;
  }
 +
 +static int qemu_parse_fdset(const char *param)
 +{
 +    return qemu_parse_fd(param);
 +}
  #endif
  
  /*
@@@ -409,28 -394,3 +399,28 @@@ bool fips_get_state(void
  {
      return fips_enabled;
  }
 +
 +
 +static int default_fdset_get_fd(int64_t fdset_id, int flags)
 +{
 +    return -1;
 +}
 +QEMU_WEAK_ALIAS(monitor_fdset_get_fd, default_fdset_get_fd);
 +
 +static int default_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
 +{
 +    return -1;
 +}
 +QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add);
 +
 +static int default_fdset_dup_fd_remove(int dup_fd)
 +{
 +    return -1;
 +}
 +QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove);
 +
 +static int default_fdset_dup_fd_find(int dup_fd)
 +{
 +    return -1;
 +}
 +QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_find, default_fdset_dup_fd_find);
diff --combined qemu-timer.c
@@@ -430,11 -430,9 +430,11 @@@ void qemu_unregister_clock_reset_notifi
  
  void init_clocks(void)
  {
 -    rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
 -    vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
 -    host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
 +    if (!rt_clock) {
 +        rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
 +        vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
 +        host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
 +    }
  }
  
  uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts)
@@@ -496,12 -494,12 +496,12 @@@ static int dynticks_start_timer(struct 
      memset(&ev, 0, sizeof(ev));
      ev.sigev_value.sival_int = 0;
      ev.sigev_notify = SIGEV_SIGNAL;
- #ifdef SIGEV_THREAD_ID
+ #ifdef CONFIG_SIGEV_THREAD_ID
      if (qemu_signalfd_available()) {
          ev.sigev_notify = SIGEV_THREAD_ID;
          ev._sigev_un._tid = qemu_get_thread_id();
      }
- #endif /* SIGEV_THREAD_ID */
+ #endif /* CONFIG_SIGEV_THREAD_ID */
      ev.sigev_signo = SIGALRM;
  
      if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
@@@ -747,10 -745,6 +747,10 @@@ int init_timer_alarm(void
      struct qemu_alarm_timer *t = NULL;
      int i, err = -1;
  
 +    if (alarm_timer) {
 +        return 0;
 +    }
 +
      for (i = 0; alarm_timers[i].name; i++) {
          t = &alarm_timers[i];
  
diff --combined qmp.c
--- 1/qmp.c
--- 2/qmp.c
+++ b/qmp.c
@@@ -85,7 -85,11 +85,11 @@@ void qmp_quit(Error **err
  
  void qmp_stop(Error **errp)
  {
-     vm_stop(RUN_STATE_PAUSED);
+     if (runstate_check(RUN_STATE_INMIGRATE)) {
+         autostart = 0;
+     } else {
+         vm_stop(RUN_STATE_PAUSED);
+     }
  }
  
  void qmp_system_reset(Error **errp)
@@@ -144,10 -148,7 +148,7 @@@ void qmp_cont(Error **errp
  {
      Error *local_err = NULL;
  
-     if (runstate_check(RUN_STATE_INMIGRATE)) {
-         error_set(errp, QERR_MIGRATION_EXPECTED);
-         return;
-     } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
+     if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
                 runstate_check(RUN_STATE_SHUTDOWN)) {
          error_set(errp, QERR_RESET_REQUIRED);
          return;
          return;
      }
  
-     vm_start();
+     if (runstate_check(RUN_STATE_INMIGRATE)) {
+         autostart = 1;
+     } else {
+         vm_start();
+     }
  }
  
  void qmp_system_wakeup(Error **errp)
@@@ -466,12 -471,11 +471,12 @@@ DevicePropertyInfoList *qmp_device_list
      return prop_list;
  }
  
 -CpuDefinitionInfoList GCC_WEAK *arch_query_cpu_definitions(Error **errp)
 +static CpuDefinitionInfoList *default_arch_query_cpu_definitions(Error **errp)
  {
      error_set(errp, QERR_NOT_SUPPORTED);
      return NULL;
  }
 +QEMU_WEAK_ALIAS(arch_query_cpu_definitions, default_arch_query_cpu_definitions);
  
  CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
  {
diff --combined trace-events
@@@ -77,10 -77,18 +77,18 @@@ stream_start(void *bs, void *base, voi
  commit_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
  commit_start(void *bs, void *base, void *top, void *s, void *co, void *opaque) "bs %p base %p top %p s %p co %p opaque %p"
  
+ # block/mirror.c
+ mirror_start(void *bs, void *s, void *co, void *opaque) "bs %p s %p co %p opaque %p"
+ mirror_before_flush(void *s) "s %p"
+ mirror_before_drain(void *s, int64_t cnt) "s %p dirty count %"PRId64
+ mirror_before_sleep(void *s, int64_t cnt, int synced) "s %p dirty count %"PRId64" synced %d"
+ mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_num %"PRId64" nb_sectors %d"
  # blockdev.c
  qmp_block_job_cancel(void *job) "job %p"
  qmp_block_job_pause(void *job) "job %p"
  qmp_block_job_resume(void *job) "job %p"
+ qmp_block_job_complete(void *job) "job %p"
  block_job_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
  qmp_block_stream(void *bs, void *job) "bs %p job %p"
  
@@@ -90,11 -98,6 +98,11 @@@ virtio_blk_rw_complete(void *req, int r
  virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
  virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
  
 +# thread-pool.c
 +thread_pool_submit(void *req, void *opaque) "req %p opaque %p"
 +thread_pool_complete(void *req, void *opaque, int ret) "req %p opaque %p ret %d"
 +thread_pool_cancel(void *req, void *opaque) "req %p opaque %p"
 +
  # posix-aio-compat.c
  paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
  paio_complete(void *acb, void *opaque, int ret) "acb %p opaque %p ret %d"
@@@ -292,7 -295,7 +300,7 @@@ usb_uhci_mmio_writew(uint32_t addr, uin
  usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%08x"
  usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%08x"
  usb_uhci_queue_add(uint32_t token) "token 0x%x"
- usb_uhci_queue_del(uint32_t token) "token 0x%x"
+ usb_uhci_queue_del(uint32_t token, const char *reason) "token 0x%x: %s"
  usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x"
  usb_uhci_packet_link_async(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x"
  usb_uhci_packet_unlink_async(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x"
diff --combined vl.c
--- 1/vl.c
--- 2/vl.c
+++ b/vl.c
@@@ -203,7 -203,6 +203,6 @@@ CharDriverState *serial_hds[MAX_SERIAL_
  CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
  CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
  int win2k_install_hack = 0;
- int usb_enabled = 0;
  int singlestep = 0;
  int smp_cpus = 1;
  int max_cpus = 0;
@@@ -341,7 -340,7 +340,7 @@@ static const RunStateTransition runstat
      { RUN_STATE_DEBUG, RUN_STATE_RUNNING },
  
      { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING },
-     { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH },
+     { RUN_STATE_INMIGRATE, RUN_STATE_PAUSED },
  
      { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED },
      { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE },
@@@ -790,6 -789,89 +789,89 @@@ static int parse_sandbox(QemuOpts *opts
      return 0;
  }
  
+ /*********QEMU USB setting******/
+ bool usb_enabled(bool default_usb)
+ {
+     QemuOpts *mach_opts;
+     mach_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+     if (mach_opts) {
+         return qemu_opt_get_bool(mach_opts, "usb", default_usb);
+     }
+     return default_usb;
+ }
+ #ifndef _WIN32
+ static int parse_add_fd(QemuOpts *opts, void *opaque)
+ {
+     int fd, dupfd, flags;
+     int64_t fdset_id;
+     const char *fd_opaque = NULL;
+     fd = qemu_opt_get_number(opts, "fd", -1);
+     fdset_id = qemu_opt_get_number(opts, "set", -1);
+     fd_opaque = qemu_opt_get(opts, "opaque");
+     if (fd < 0) {
+         qerror_report(ERROR_CLASS_GENERIC_ERROR,
+                       "fd option is required and must be non-negative");
+         return -1;
+     }
+     if (fd <= STDERR_FILENO) {
+         qerror_report(ERROR_CLASS_GENERIC_ERROR,
+                       "fd cannot be a standard I/O stream");
+         return -1;
+     }
+     /*
+      * All fds inherited across exec() necessarily have FD_CLOEXEC
+      * clear, while qemu sets FD_CLOEXEC on all other fds used internally.
+      */
+     flags = fcntl(fd, F_GETFD);
+     if (flags == -1 || (flags & FD_CLOEXEC)) {
+         qerror_report(ERROR_CLASS_GENERIC_ERROR,
+                       "fd is not valid or already in use");
+         return -1;
+     }
+     if (fdset_id < 0) {
+         qerror_report(ERROR_CLASS_GENERIC_ERROR,
+                       "set option is required and must be non-negative");
+         return -1;
+     }
+ #ifdef F_DUPFD_CLOEXEC
+     dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+ #else
+     dupfd = dup(fd);
+     if (dupfd != -1) {
+         qemu_set_cloexec(dupfd);
+     }
+ #endif
+     if (dupfd == -1) {
+         qerror_report(ERROR_CLASS_GENERIC_ERROR,
+                       "Error duplicating fd: %s", strerror(errno));
+         return -1;
+     }
+     /* add the duplicate fd, and optionally the opaque string, to the fd set */
+     monitor_fdset_add_fd(dupfd, true, fdset_id, fd_opaque ? true : false,
+                          fd_opaque, NULL);
+     return 0;
+ }
+ static int cleanup_add_fd(QemuOpts *opts, void *opaque)
+ {
+     int fd;
+     fd = qemu_opt_get_number(opts, "fd", -1);
+     close(fd);
+     return 0;
+ }
+ #endif
  /***********************************************************/
  /* QEMU Block devices */
  
@@@ -1077,8 -1159,9 +1159,9 @@@ static int usb_device_add(const char *d
      const char *p;
      USBDevice *dev = NULL;
  
-     if (!usb_enabled)
+     if (!usb_enabled(false)) {
          return -1;
+     }
  
      /* drivers with .usbdevice_name entry in USBDeviceInfo */
      dev = usbdevice_create(devname);
@@@ -1114,8 -1197,9 +1197,9 @@@ static int usb_device_del(const char *d
      if (strstart(devname, "host:", &p))
          return usb_host_device_close(p);
  
-     if (!usb_enabled)
+     if (!usb_enabled(false)) {
          return -1;
+     }
  
      p = strchr(devname, '.');
      if (!p)
@@@ -2357,6 -2441,11 +2441,6 @@@ static void free_and_trace(gpointer mem
      free(mem);
  }
  
 -int qemu_init_main_loop(void)
 -{
 -    return main_loop_init();
 -}
 -
  int main(int argc, char **argv, char **envp)
  {
      int i;
                  }
                  break;
              case QEMU_OPTION_usb:
-                 usb_enabled = 1;
+                 machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+                 if (machine_opts) {
+                     qemu_opt_set_bool(machine_opts, "usb", true);
+                 }
                  break;
              case QEMU_OPTION_usbdevice:
-                 usb_enabled = 1;
+                 machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+                 if (machine_opts) {
+                     qemu_opt_set_bool(machine_opts, "usb", true);
+                 }
                  add_device_config(DEV_USB, optarg);
                  break;
              case QEMU_OPTION_device:
                      exit(0);
                  }
                  break;
+             case QEMU_OPTION_add_fd:
+ #ifndef _WIN32
+                 opts = qemu_opts_parse(qemu_find_opts("add-fd"), optarg, 0);
+                 if (!opts) {
+                     exit(0);
+                 }
+ #else
+                 error_report("File descriptor passing is disabled on this "
+                              "platform");
+                 exit(1);
+ #endif
+                 break;
              default:
                  os_parse_cmd_args(popt->index, optarg);
              }
      }
      loc_set_none();
  
 +    qemu_init_cpu_loop();
 +    if (qemu_init_main_loop()) {
 +        fprintf(stderr, "qemu_init_main_loop failed\n");
 +        exit(1);
 +    }
 +
      if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
          exit(1);
      }
  
+ #ifndef _WIN32
+     if (qemu_opts_foreach(qemu_find_opts("add-fd"), parse_add_fd, NULL, 1)) {
+         exit(1);
+     }
+     if (qemu_opts_foreach(qemu_find_opts("add-fd"), cleanup_add_fd, NULL, 1)) {
+         exit(1);
+     }
+ #endif
      if (machine == NULL) {
          fprintf(stderr, "No machine found.\n");
          exit(1);
  
      configure_accelerator();
  
 -    qemu_init_cpu_loop();
 -    if (qemu_init_main_loop()) {
 -        fprintf(stderr, "qemu_init_main_loop failed\n");
 -        exit(1);
 -    }
 -
      machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
      if (machine_opts) {
          kernel_filename = qemu_opt_get(machine_opts, "kernel");
      current_machine = machine;
  
      /* init USB devices */
-     if (usb_enabled) {
+     if (usb_enabled(false)) {
          if (foreach_device_config(DEV_USB, usb_parse) < 0)
              exit(1);
      }