Commit 4172a003 authored by sochin.jiang's avatar sochin.jiang Committed by Max Reitz
Browse files

fix: avoid an infinite loop or a dangling pointer problem in img_commit



img_commit could fall into an infinite loop calling run_block_job() if
its blockjob fails on any I/O error, fix this already known problem.

Signed-off-by: default avatarsochin.jiang <sochin.jiang@huawei.com>
Message-id: 1497509253-28941-1-git-send-email-sochin.jiang@huawei.com
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent f5a5ca79
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -139,7 +139,7 @@ static void block_job_resume(BlockJob *job)
    block_job_enter(job);
}

static void block_job_ref(BlockJob *job)
void block_job_ref(BlockJob *job)
{
    ++job->refcnt;
}
@@ -148,7 +148,7 @@ static void block_job_attached_aio_context(AioContext *new_context,
                                           void *opaque);
static void block_job_detach_aio_context(void *opaque);

static void block_job_unref(BlockJob *job)
void block_job_unref(BlockJob *job)
{
    if (--job->refcnt == 0) {
        BlockDriverState *bs = blk_bs(job->blk);
+18 −0
Original line number Diff line number Diff line
@@ -320,6 +320,24 @@ void block_job_iostatus_reset(BlockJob *job);
 */
BlockJobTxn *block_job_txn_new(void);

/**
 * block_job_ref:
 *
 * Add a reference to BlockJob refcnt, it will be decreased with
 * block_job_unref, and then be freed if it comes to be the last
 * reference.
 */
void block_job_ref(BlockJob *job);

/**
 * block_job_unref:
 *
 * Release a reference that was previously acquired with block_job_ref
 * or block_job_create. If it's the last reference to the object, it will be
 * freed.
 */
void block_job_unref(BlockJob *job);

/**
 * block_job_txn_unref:
 *
+13 −7
Original line number Diff line number Diff line
@@ -887,23 +887,29 @@ static void common_block_job_cb(void *opaque, int ret)
static void run_block_job(BlockJob *job, Error **errp)
{
    AioContext *aio_context = blk_get_aio_context(job->blk);
    int ret = 0;

    /* FIXME In error cases, the job simply goes away and we access a dangling
     * pointer below. */
    aio_context_acquire(aio_context);
    block_job_ref(job);
    do {
        aio_poll(aio_context, true);
        qemu_progress_print(job->len ?
                            ((float)job->offset / job->len * 100.f) : 0.0f, 0);
    } while (!job->ready);
    } while (!job->ready && !job->completed);

    block_job_complete_sync(job, errp);
    if (!job->completed) {
        ret = block_job_complete_sync(job, errp);
    } else {
        ret = job->ret;
    }
    block_job_unref(job);
    aio_context_release(aio_context);

    /* A block job may finish instantaneously without publishing any progress,
     * so just signal completion here */
    /* publish completion progress only when success */
    if (!ret) {
        qemu_progress_print(100.f, 0);
    }
}

static int img_commit(int argc, char **argv)
{