Commit 18930ba3 authored by Fam Zheng's avatar Fam Zheng Committed by Kevin Wolf
Browse files

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: default avatarFam Zheng <famz@redhat.com>
Signed-off-by: default avatarJohn Snow <jsnow@redhat.com>
Message-id: 1446765200-3054-6-git-send-email-jsnow@redhat.com
Signed-off-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent b976ea3c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;
    }

+0 −28
Original line number Diff line number Diff line
@@ -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,
+16 −9
Original line number Diff line number Diff line
@@ -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,16 +77,22 @@ 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);
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)
+15 −3
Original line number Diff line number Diff line
@@ -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.
 *
 * Grab a reference to the block job. Should be paired with block_job_unref.
 */
void block_job_ref(BlockJob *job);

/**
 * block_job_unref:
 * @bs: The block device.
 *
 * Release job resources when an error occurred or job completed.
 * Release reference to the block job and release resources if it is the last
 * reference.
 */
void block_job_release(BlockDriverState *bs);
void block_job_unref(BlockJob *job);

/**
 * block_job_completed:
+0 −3
Original line number Diff line number Diff line
@@ -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)