mirror of
https://github.com/qemu/qemu.git
synced 2024-11-27 13:53:45 +08:00
blockjob: Introduce reference count and fix reference to job->bs
Add reference count to block job, meanwhile move the ownership of the reference to job->bs from the caller (which is released in two completion callbacks) to the block job itself. It is necessary for block_job_complete_sync to work, because block job shouldn't live longer than its bs, as asserted in bdrv_delete. Now block_job_complete_sync can be simplified. Signed-off-by: Fam Zheng <famz@redhat.com> Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 1446765200-3054-6-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
b976ea3cf5
commit
18930ba3d1
@ -742,7 +742,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
|
||||
if (!s->dirty_bitmap) {
|
||||
g_free(s->replaces);
|
||||
block_job_release(bs);
|
||||
block_job_unref(&s->common);
|
||||
return;
|
||||
}
|
||||
|
||||
|
28
blockdev.c
28
blockdev.c
@ -283,32 +283,6 @@ typedef struct {
|
||||
BlockDriverState *bs;
|
||||
} BDRVPutRefBH;
|
||||
|
||||
static void bdrv_put_ref_bh(void *opaque)
|
||||
{
|
||||
BDRVPutRefBH *s = opaque;
|
||||
|
||||
bdrv_unref(s->bs);
|
||||
qemu_bh_delete(s->bh);
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a BDS reference in a BH
|
||||
*
|
||||
* It is not safe to use bdrv_unref() from a callback function when the callers
|
||||
* still need the BlockDriverState. In such cases we schedule a BH to release
|
||||
* the reference.
|
||||
*/
|
||||
static void bdrv_put_ref_bh_schedule(BlockDriverState *bs)
|
||||
{
|
||||
BDRVPutRefBH *s;
|
||||
|
||||
s = g_new(BDRVPutRefBH, 1);
|
||||
s->bh = qemu_bh_new(bdrv_put_ref_bh, s);
|
||||
s->bs = bs;
|
||||
qemu_bh_schedule(s->bh);
|
||||
}
|
||||
|
||||
static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
|
||||
{
|
||||
if (!strcmp(buf, "ignore")) {
|
||||
@ -2741,8 +2715,6 @@ static void block_job_cb(void *opaque, int ret)
|
||||
} else {
|
||||
block_job_event_completed(bs->job, msg);
|
||||
}
|
||||
|
||||
bdrv_put_ref_bh_schedule(bs);
|
||||
}
|
||||
|
||||
void qmp_block_stream(const char *device,
|
||||
|
25
blockjob.c
25
blockjob.c
@ -60,6 +60,7 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
||||
job->cb = cb;
|
||||
job->opaque = opaque;
|
||||
job->busy = true;
|
||||
job->refcnt = 1;
|
||||
bs->job = job;
|
||||
|
||||
/* Only set speed when necessary to avoid NotSupported error */
|
||||
@ -68,7 +69,7 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
||||
|
||||
block_job_set_speed(job, speed, &local_err);
|
||||
if (local_err) {
|
||||
block_job_release(bs);
|
||||
block_job_unref(job);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
@ -76,15 +77,21 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
||||
return job;
|
||||
}
|
||||
|
||||
void block_job_release(BlockDriverState *bs)
|
||||
void block_job_ref(BlockJob *job)
|
||||
{
|
||||
BlockJob *job = bs->job;
|
||||
++job->refcnt;
|
||||
}
|
||||
|
||||
bs->job = NULL;
|
||||
bdrv_op_unblock_all(bs, job->blocker);
|
||||
error_free(job->blocker);
|
||||
g_free(job->id);
|
||||
g_free(job);
|
||||
void block_job_unref(BlockJob *job)
|
||||
{
|
||||
if (--job->refcnt == 0) {
|
||||
job->bs->job = NULL;
|
||||
bdrv_op_unblock_all(job->bs, job->blocker);
|
||||
bdrv_unref(job->bs);
|
||||
error_free(job->blocker);
|
||||
g_free(job->id);
|
||||
g_free(job);
|
||||
}
|
||||
}
|
||||
|
||||
void block_job_completed(BlockJob *job, int ret)
|
||||
@ -93,7 +100,7 @@ void block_job_completed(BlockJob *job, int ret)
|
||||
|
||||
assert(bs->job == job);
|
||||
job->cb(job->opaque, ret);
|
||||
block_job_release(bs);
|
||||
block_job_unref(job);
|
||||
}
|
||||
|
||||
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
|
@ -130,6 +130,9 @@ struct BlockJob {
|
||||
|
||||
/** The opaque value that is passed to the completion function. */
|
||||
void *opaque;
|
||||
|
||||
/** Reference count of the block job */
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -174,12 +177,21 @@ void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns);
|
||||
void block_job_yield(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_release:
|
||||
* block_job_ref:
|
||||
* @bs: The block device.
|
||||
*
|
||||
* Release job resources when an error occurred or job completed.
|
||||
* Grab a reference to the block job. Should be paired with block_job_unref.
|
||||
*/
|
||||
void block_job_release(BlockDriverState *bs);
|
||||
void block_job_ref(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_unref:
|
||||
* @bs: The block device.
|
||||
*
|
||||
* Release reference to the block job and release resources if it is the last
|
||||
* reference.
|
||||
*/
|
||||
void block_job_unref(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_completed:
|
||||
|
@ -645,9 +645,6 @@ static void common_block_job_cb(void *opaque, int ret)
|
||||
if (ret < 0) {
|
||||
error_setg_errno(cbi->errp, -ret, "Block job failed");
|
||||
}
|
||||
|
||||
/* Drop this block job's reference */
|
||||
bdrv_unref(cbi->bs);
|
||||
}
|
||||
|
||||
static void run_block_job(BlockJob *job, Error **errp)
|
||||
|
Loading…
Reference in New Issue
Block a user