func: void commit_start(const char *job_id, BlockDriverState *bs,
  
                    BlockDriverState *base, BlockDriverState *top, int64_t speed,
  
                    BlockdevOnError on_error, const char *backing_file_str,
  
                    const char *filter_node_name, Error **errp)
  
  {
  
      CommitBlockJob *s;
  
      BlockReopenQueue *reopen_queue = NULL;
  
      int orig_overlay_flags;
  
      int orig_base_flags;
  
      BlockDriverState *iter;
  
      BlockDriverState *overlay_bs;
  
      BlockDriverState *commit_top_bs = NULL;
  
      Error *local_err = NULL;
  
      int ret;
  
  
  
      assert(top != bs);
  
      if (top == base) {
  
          error_setg(errp, "Invalid files for merge: top and base are the same");
  
          return;
  
  
  
  
      overlay_bs = bdrv_find_overlay(bs, top);
  
  
  
      if (overlay_bs == NULL) {
  
          error_setg(errp, "Could not find overlay image for %s:", top->filename);
  
          return;
  
  
  
  
      s = block_job_create(job_id, &commit_job_driver, bs, 0, BLK_PERM_ALL,
  
                           speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
  
      if (!s) {
  
          return;
  
  
  
  
      orig_base_flags    = bdrv_get_flags(base);
  
      orig_overlay_flags = bdrv_get_flags(overlay_bs);
  
  
  
      /* convert base & overlay_bs to r/w, if necessary */
  
      if (!(orig_base_flags & BDRV_O_RDWR)) {
  
          reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
  
                                           orig_base_flags | BDRV_O_RDWR);
  
  
      if (!(orig_overlay_flags & BDRV_O_RDWR)) {
  
          reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
  
                                           orig_overlay_flags | BDRV_O_RDWR);
  
  
      if (reopen_queue) {
  
          bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
  
          if (local_err != NULL) {
  
              error_propagate(errp, local_err);
  
              goto fail;
  
  
  
  
  
      /* Insert commit_top block node above top, so we can block consistent read
  
       * on the backing chain below it */
  
      commit_top_bs = bdrv_new_open_driver(&bdrv_commit_top, filter_node_name, 0,
  
                                           errp);
  
      if (commit_top_bs == NULL) {
  
          goto fail;
  
  
  
  
  
      commit_top_bs->total_sectors = top->total_sectors;
  
      bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top));
  
  
  
      bdrv_set_backing_hd(commit_top_bs, top, &local_err);
  
      if (local_err) {
  
          bdrv_unref(commit_top_bs);
  
          commit_top_bs = NULL;
  
          error_propagate(errp, local_err);
  
          goto fail;
  
  
      bdrv_set_backing_hd(overlay_bs, commit_top_bs, &local_err);
  
      if (local_err) {
  
          bdrv_unref(commit_top_bs);
  
          commit_top_bs = NULL;
  
          error_propagate(errp, local_err);
  
          goto fail;
  
  
  
  
      s->commit_top_bs = commit_top_bs;
  
      bdrv_unref(commit_top_bs);
  
  
  
      /* Block all nodes between top and base, because they will
  
       * disappear from the chain after this operation. */
  
      assert(bdrv_chain_contains(top, base));
  
      for (iter = top; iter != base; iter = backing_bs(iter)) {
  
          /* XXX BLK_PERM_WRITE needs to be allowed so we don't block ourselves
  
           * at s->base (if writes are blocked for a node, they are also blocked
  
           * for its backing file). The other options would be a second filter
  
           * driver above s->base. */
  
          ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
  
                                   BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE,
  
                                   errp);
  
          if (ret < 0) {
  
              goto fail;
  
  
  
  
  
      ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
  
      if (ret < 0) {
  
          goto fail;
  
  
  
  
      /* overlay_bs must be blocked because it needs to be modified to
  
       * update the backing image string. */
  
      ret = block_job_add_bdrv(&s->common, "overlay of top", overlay_bs,
  
                               BLK_PERM_GRAPH_MOD, BLK_PERM_ALL, errp);
  
      if (ret < 0) {
  
          goto fail;
  
  
  
  
      s->base = blk_new(BLK_PERM_CONSISTENT_READ
  
                        | BLK_PERM_WRITE
  
                        | BLK_PERM_RESIZE,
  
                        BLK_PERM_CONSISTENT_READ
  
                        | BLK_PERM_GRAPH_MOD
  
                        | BLK_PERM_WRITE_UNCHANGED);
  
      ret = blk_insert_bs(s->base, base, errp);
  
      if (ret < 0) {
  
          goto fail;
  
  
  
  
      /* Required permissions are already taken with block_job_add_bdrv() */
  
      s->top = blk_new(0, BLK_PERM_ALL);
  
      ret = blk_insert_bs(s->top, top, errp);
  
      if (ret < 0) {
  
          goto fail;
  
  
  
  
      s->active = bs;
  
  
  
      s->base_flags          = orig_base_flags;
  
      s->orig_overlay_flags  = orig_overlay_flags;
  
  
  
      s->backing_file_str = g_strdup(backing_file_str);
  
  
  
      s->on_error = on_error;
  
  
  
      trace_commit_start(bs, base, top, s);
  
      block_job_start(&s->common);
  
      return;
  
  
  
  fail:
  
      if (s->base) {
  
          blk_unref(s->base);
  
  
      if (s->top) {
  
          blk_unref(s->top);
  
  
      if (commit_top_bs) {
  
          bdrv_set_backing_hd(overlay_bs, top, &error_abort);
  
  
      block_job_early_fail(&s->common);
  