提交 4172a003 编写于 作者: S sochin.jiang 提交者: Max Reitz

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: Nsochin.jiang <sochin.jiang@huawei.com>
Message-id: 1497509253-28941-1-git-send-email-sochin.jiang@huawei.com
Signed-off-by: NMax Reitz <mreitz@redhat.com>
上级 f5a5ca79
......@@ -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);
......
......@@ -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:
*
......
......@@ -887,22 +887,28 @@ 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 */
qemu_progress_print(100.f, 0);
/* publish completion progress only when success */
if (!ret) {
qemu_progress_print(100.f, 0);
}
}
static int img_commit(int argc, char **argv)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册