block: Replace in_use with operation blocker
This drops BlockDriverState.in_use with op_blockers:
  - Call bdrv_op_block_all in place of bdrv_set_in_use(bs, 1).
  - Call bdrv_op_unblock_all in place of bdrv_set_in_use(bs, 0).
  - Check bdrv_op_is_blocked() in place of bdrv_in_use(bs).
    The specific types are used, e.g. in place of starting block backup,
    bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP, ...).
    There is one exception in block_job_create, where
    bdrv_op_blocker_is_empty() is used, because we don't know the operation
    type here. This doesn't matter because in a few commits away we will drop
    the check and move it to callers that _do_ know the type.
  - Check bdrv_op_blocker_is_empty() in place of assert(!bs->in_use).
Note: there is only bdrv_op_block_all and bdrv_op_unblock_all callers at
this moment. So although the checks are specific to op types, this
changes can still be seen as identical logic with previously with
in_use. The difference is error message are improved because of blocker
error info.
Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Jeff Cody <jcody@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									fbe40ff780
								
							
						
					
					
						commit
						3718d8ab65
					
				| 
						 | 
				
			
			@ -59,6 +59,7 @@ typedef struct BlkMigDevState {
 | 
			
		|||
    unsigned long *aio_bitmap;
 | 
			
		||||
    int64_t completed_sectors;
 | 
			
		||||
    BdrvDirtyBitmap *dirty_bitmap;
 | 
			
		||||
    Error *blocker;
 | 
			
		||||
} BlkMigDevState;
 | 
			
		||||
 | 
			
		||||
typedef struct BlkMigBlock {
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +362,8 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
 | 
			
		|||
        bmds->completed_sectors = 0;
 | 
			
		||||
        bmds->shared_base = block_mig_state.shared_base;
 | 
			
		||||
        alloc_aio_bitmap(bmds);
 | 
			
		||||
        bdrv_set_in_use(bs, 1);
 | 
			
		||||
        error_setg(&bmds->blocker, "block device is in use by migration");
 | 
			
		||||
        bdrv_op_block_all(bs, bmds->blocker);
 | 
			
		||||
        bdrv_ref(bs);
 | 
			
		||||
 | 
			
		||||
        block_mig_state.total_sector_sum += sectors;
 | 
			
		||||
| 
						 | 
				
			
			@ -599,7 +601,8 @@ static void blk_mig_cleanup(void)
 | 
			
		|||
    blk_mig_lock();
 | 
			
		||||
    while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
 | 
			
		||||
        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
 | 
			
		||||
        bdrv_set_in_use(bmds->bs, 0);
 | 
			
		||||
        bdrv_op_unblock_all(bmds->bs, bmds->blocker);
 | 
			
		||||
        error_free(bmds->blocker);
 | 
			
		||||
        bdrv_unref(bmds->bs);
 | 
			
		||||
        g_free(bmds->aio_bitmap);
 | 
			
		||||
        g_free(bmds);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								block.c
								
								
								
								
							
							
						
						
									
										24
									
								
								block.c
								
								
								
								
							| 
						 | 
				
			
			@ -1949,7 +1949,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
 | 
			
		|||
    bs_dest->refcnt             = bs_src->refcnt;
 | 
			
		||||
 | 
			
		||||
    /* job */
 | 
			
		||||
    bs_dest->in_use             = bs_src->in_use;
 | 
			
		||||
    bs_dest->job                = bs_src->job;
 | 
			
		||||
 | 
			
		||||
    /* keep the same entry in bdrv_states */
 | 
			
		||||
| 
						 | 
				
			
			@ -1992,7 +1991,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
 | 
			
		|||
    assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
 | 
			
		||||
    assert(bs_new->job == NULL);
 | 
			
		||||
    assert(bs_new->dev == NULL);
 | 
			
		||||
    assert(bs_new->in_use == 0);
 | 
			
		||||
    assert(bdrv_op_blocker_is_empty(bs_new));
 | 
			
		||||
    assert(bs_new->io_limits_enabled == false);
 | 
			
		||||
    assert(!throttle_have_timer(&bs_new->throttle_state));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2011,7 +2010,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
 | 
			
		|||
    /* Check a few fields that should remain attached to the device */
 | 
			
		||||
    assert(bs_new->dev == NULL);
 | 
			
		||||
    assert(bs_new->job == NULL);
 | 
			
		||||
    assert(bs_new->in_use == 0);
 | 
			
		||||
    assert(bdrv_op_blocker_is_empty(bs_new));
 | 
			
		||||
    assert(bs_new->io_limits_enabled == false);
 | 
			
		||||
    assert(!throttle_have_timer(&bs_new->throttle_state));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2056,7 +2055,7 @@ static void bdrv_delete(BlockDriverState *bs)
 | 
			
		|||
{
 | 
			
		||||
    assert(!bs->dev);
 | 
			
		||||
    assert(!bs->job);
 | 
			
		||||
    assert(!bs->in_use);
 | 
			
		||||
    assert(bdrv_op_blocker_is_empty(bs));
 | 
			
		||||
    assert(!bs->refcnt);
 | 
			
		||||
    assert(QLIST_EMPTY(&bs->dirty_bitmaps));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2238,7 +2237,8 @@ int bdrv_commit(BlockDriverState *bs)
 | 
			
		|||
        return -ENOTSUP;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bdrv_in_use(bs) || bdrv_in_use(bs->backing_hd)) {
 | 
			
		||||
    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, NULL) ||
 | 
			
		||||
        bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, NULL)) {
 | 
			
		||||
        return -EBUSY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3500,8 +3500,9 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
 | 
			
		|||
        return -ENOTSUP;
 | 
			
		||||
    if (bs->read_only)
 | 
			
		||||
        return -EACCES;
 | 
			
		||||
    if (bdrv_in_use(bs))
 | 
			
		||||
    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) {
 | 
			
		||||
        return -EBUSY;
 | 
			
		||||
    }
 | 
			
		||||
    ret = drv->bdrv_truncate(bs, offset);
 | 
			
		||||
    if (ret == 0) {
 | 
			
		||||
        ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
 | 
			
		||||
| 
						 | 
				
			
			@ -5401,17 +5402,6 @@ bool bdrv_op_blocker_is_empty(BlockDriverState *bs)
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bdrv_set_in_use(BlockDriverState *bs, int in_use)
 | 
			
		||||
{
 | 
			
		||||
    assert(bs->in_use != in_use);
 | 
			
		||||
    bs->in_use = in_use;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bdrv_in_use(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    return bs->in_use;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bdrv_iostatus_enable(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    bs->iostatus_enabled = true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								blockdev.c
								
								
								
								
							
							
						
						
									
										19
									
								
								blockdev.c
								
								
								
								
							| 
						 | 
				
			
			@ -1334,8 +1334,8 @@ static void external_snapshot_prepare(BlkTransactionState *common,
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bdrv_in_use(state->old_bs)) {
 | 
			
		||||
        error_set(errp, QERR_DEVICE_IN_USE, device);
 | 
			
		||||
    if (bdrv_op_is_blocked(state->old_bs,
 | 
			
		||||
                           BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1557,8 +1557,7 @@ exit:
 | 
			
		|||
 | 
			
		||||
static void eject_device(BlockDriverState *bs, int force, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    if (bdrv_in_use(bs)) {
 | 
			
		||||
        error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
 | 
			
		||||
    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (!bdrv_dev_has_removable_media(bs)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1760,14 +1759,16 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 | 
			
		|||
{
 | 
			
		||||
    const char *id = qdict_get_str(qdict, "id");
 | 
			
		||||
    BlockDriverState *bs;
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
 | 
			
		||||
    bs = bdrv_find(id);
 | 
			
		||||
    if (!bs) {
 | 
			
		||||
        qerror_report(QERR_DEVICE_NOT_FOUND, id);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if (bdrv_in_use(bs)) {
 | 
			
		||||
        qerror_report(QERR_DEVICE_IN_USE, id);
 | 
			
		||||
    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
 | 
			
		||||
        error_report("%s", error_get_pretty(local_err));
 | 
			
		||||
        error_free(local_err);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2023,8 +2024,7 @@ void qmp_drive_backup(const char *device, const char *target,
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bdrv_in_use(bs)) {
 | 
			
		||||
        error_set(errp, QERR_DEVICE_IN_USE, device);
 | 
			
		||||
    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2157,8 +2157,7 @@ void qmp_drive_mirror(const char *device, const char *target,
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bdrv_in_use(bs)) {
 | 
			
		||||
        error_set(errp, QERR_DEVICE_IN_USE, device);
 | 
			
		||||
    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								blockjob.c
								
								
								
								
							
							
						
						
									
										14
									
								
								blockjob.c
								
								
								
								
							| 
						 | 
				
			
			@ -41,14 +41,16 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
 | 
			
		|||
{
 | 
			
		||||
    BlockJob *job;
 | 
			
		||||
 | 
			
		||||
    if (bs->job || bdrv_in_use(bs)) {
 | 
			
		||||
    if (bs->job || !bdrv_op_blocker_is_empty(bs)) {
 | 
			
		||||
        error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    bdrv_ref(bs);
 | 
			
		||||
    bdrv_set_in_use(bs, 1);
 | 
			
		||||
 | 
			
		||||
    job = g_malloc0(driver->instance_size);
 | 
			
		||||
    error_setg(&job->blocker, "block device is in use by block job: %s",
 | 
			
		||||
               BlockJobType_lookup[driver->job_type]);
 | 
			
		||||
    bdrv_op_block_all(bs, job->blocker);
 | 
			
		||||
 | 
			
		||||
    job->driver        = driver;
 | 
			
		||||
    job->bs            = bs;
 | 
			
		||||
    job->cb            = cb;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,8 +65,9 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
 | 
			
		|||
        block_job_set_speed(job, speed, &local_err);
 | 
			
		||||
        if (local_err) {
 | 
			
		||||
            bs->job = NULL;
 | 
			
		||||
            bdrv_op_unblock_all(bs, job->blocker);
 | 
			
		||||
            error_free(job->blocker);
 | 
			
		||||
            g_free(job);
 | 
			
		||||
            bdrv_set_in_use(bs, 0);
 | 
			
		||||
            error_propagate(errp, local_err);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -79,8 +82,9 @@ void block_job_completed(BlockJob *job, int ret)
 | 
			
		|||
    assert(bs->job == job);
 | 
			
		||||
    job->cb(job->opaque, ret);
 | 
			
		||||
    bs->job = NULL;
 | 
			
		||||
    bdrv_op_unblock_all(bs, job->blocker);
 | 
			
		||||
    error_free(job->blocker);
 | 
			
		||||
    g_free(job);
 | 
			
		||||
    bdrv_set_in_use(bs, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,6 +70,9 @@ struct VirtIOBlockDataPlane {
 | 
			
		|||
                                             queue */
 | 
			
		||||
 | 
			
		||||
    unsigned int num_reqs;
 | 
			
		||||
 | 
			
		||||
    /* Operation blocker on BDS */
 | 
			
		||||
    Error *blocker;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Raise an interrupt to signal guest, if necessary */
 | 
			
		||||
| 
						 | 
				
			
			@ -350,6 +353,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
 | 
			
		|||
{
 | 
			
		||||
    VirtIOBlockDataPlane *s;
 | 
			
		||||
    int fd;
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
 | 
			
		||||
    *dataplane = NULL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -372,9 +376,10 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
 | 
			
		|||
    /* If dataplane is (re-)enabled while the guest is running there could be
 | 
			
		||||
     * block jobs that can conflict.
 | 
			
		||||
     */
 | 
			
		||||
    if (bdrv_in_use(blk->conf.bs)) {
 | 
			
		||||
        error_setg(errp,
 | 
			
		||||
                   "cannot start dataplane thread while device is in use");
 | 
			
		||||
    if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) {
 | 
			
		||||
        error_report("cannot start dataplane thread: %s",
 | 
			
		||||
                      error_get_pretty(local_err));
 | 
			
		||||
        error_free(local_err);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -406,8 +411,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
 | 
			
		|||
    }
 | 
			
		||||
    s->ctx = iothread_get_aio_context(s->iothread);
 | 
			
		||||
 | 
			
		||||
    /* Prevent block operations that conflict with data plane thread */
 | 
			
		||||
    bdrv_set_in_use(blk->conf.bs, 1);
 | 
			
		||||
    error_setg(&s->blocker, "block device is in use by data plane");
 | 
			
		||||
    bdrv_op_block_all(blk->conf.bs, s->blocker);
 | 
			
		||||
 | 
			
		||||
    *dataplane = s;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -420,7 +425,8 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    virtio_blk_data_plane_stop(s);
 | 
			
		||||
    bdrv_set_in_use(s->blk->conf.bs, 0);
 | 
			
		||||
    bdrv_op_unblock_all(s->blk->conf.bs, s->blocker);
 | 
			
		||||
    error_free(s->blocker);
 | 
			
		||||
    object_unref(OBJECT(s->iothread));
 | 
			
		||||
    g_free(s);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -472,8 +472,6 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs);
 | 
			
		|||
 | 
			
		||||
void bdrv_ref(BlockDriverState *bs);
 | 
			
		||||
void bdrv_unref(BlockDriverState *bs);
 | 
			
		||||
void bdrv_set_in_use(BlockDriverState *bs, int in_use);
 | 
			
		||||
int bdrv_in_use(BlockDriverState *bs);
 | 
			
		||||
 | 
			
		||||
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
 | 
			
		||||
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -358,7 +358,6 @@ struct BlockDriverState {
 | 
			
		|||
    QTAILQ_ENTRY(BlockDriverState) device_list;
 | 
			
		||||
    QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;
 | 
			
		||||
    int refcnt;
 | 
			
		||||
    int in_use; /* users other than guest access, eg. block migration */
 | 
			
		||||
 | 
			
		||||
    QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -106,6 +106,9 @@ struct BlockJob {
 | 
			
		|||
    /** The completion function that will be called when the job completes.  */
 | 
			
		||||
    BlockDriverCompletionFunc *cb;
 | 
			
		||||
 | 
			
		||||
    /** Block other operations when block job is running */
 | 
			
		||||
    Error *blocker;
 | 
			
		||||
 | 
			
		||||
    /** The opaque value that is passed to the completion function.  */
 | 
			
		||||
    void *opaque;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue