Newer
Older
c->bs->filename);
return ret;
}
return 0;
}
/*
* Return the child that @bs acts as an overlay for, and from which data may be
* copied in COW or COR operations. Usually this is the backing file.
*/
BdrvChild *bdrv_cow_child(BlockDriverState *bs)
{
IO_CODE();
8016
8017
8018
8019
8020
8021
8022
8023
8024
8025
8026
8027
8028
8029
8030
8031
8032
8033
8034
8035
8036
8037
8038
if (!bs || !bs->drv) {
return NULL;
}
if (bs->drv->is_filter) {
return NULL;
}
if (!bs->backing) {
return NULL;
}
assert(bs->backing->role & BDRV_CHILD_COW);
return bs->backing;
}
/*
* If @bs acts as a filter for exactly one of its children, return
* that child.
*/
BdrvChild *bdrv_filter_child(BlockDriverState *bs)
{
BdrvChild *c;
IO_CODE();
8040
8041
8042
8043
8044
8045
8046
8047
8048
8049
8050
8051
8052
8053
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069
8070
if (!bs || !bs->drv) {
return NULL;
}
if (!bs->drv->is_filter) {
return NULL;
}
/* Only one of @backing or @file may be used */
assert(!(bs->backing && bs->file));
c = bs->backing ?: bs->file;
if (!c) {
return NULL;
}
assert(c->role & BDRV_CHILD_FILTERED);
return c;
}
/*
* Return either the result of bdrv_cow_child() or bdrv_filter_child(),
* whichever is non-NULL.
*
* Return NULL if both are NULL.
*/
BdrvChild *bdrv_filter_or_cow_child(BlockDriverState *bs)
{
BdrvChild *cow_child = bdrv_cow_child(bs);
BdrvChild *filter_child = bdrv_filter_child(bs);
IO_CODE();
/* Filter nodes cannot have COW backing files */
assert(!(cow_child && filter_child));
return cow_child ?: filter_child;
}
/*
* Return the primary child of this node: For filters, that is the
* filtered child. For other nodes, that is usually the child storing
* metadata.
* (A generally more helpful description is that this is (usually) the
* child that has the same filename as @bs.)
*
* Drivers do not necessarily have a primary child; for example quorum
* does not.
*/
BdrvChild *bdrv_primary_child(BlockDriverState *bs)
{
BdrvChild *c, *found = NULL;
IO_CODE();
QLIST_FOREACH(c, &bs->children, next) {
if (c->role & BDRV_CHILD_PRIMARY) {
assert(!found);
found = c;
}
}
return found;
}
8103
8104
8105
8106
8107
8108
8109
8110
8111
8112
8113
8114
8115
8116
8117
8118
8119
8120
8121
8122
8123
8124
8125
8126
8127
8128
8129
8130
8131
8132
8133
8134
8135
8136
8137
8138
8139
8140
8141
8142
8143
8144
static BlockDriverState *bdrv_do_skip_filters(BlockDriverState *bs,
bool stop_on_explicit_filter)
{
BdrvChild *c;
if (!bs) {
return NULL;
}
while (!(stop_on_explicit_filter && !bs->implicit)) {
c = bdrv_filter_child(bs);
if (!c) {
/*
* A filter that is embedded in a working block graph must
* have a child. Assert this here so this function does
* not return a filter node that is not expected by the
* caller.
*/
assert(!bs->drv || !bs->drv->is_filter);
break;
}
bs = c->bs;
}
/*
* Note that this treats nodes with bs->drv == NULL as not being
* filters (bs->drv == NULL should be replaced by something else
* anyway).
* The advantage of this behavior is that this function will thus
* always return a non-NULL value (given a non-NULL @bs).
*/
return bs;
}
/*
* Return the first BDS that has not been added implicitly or that
* does not have a filtered child down the chain starting from @bs
* (including @bs itself).
*/
BlockDriverState *bdrv_skip_implicit_filters(BlockDriverState *bs)
{
GLOBAL_STATE_CODE();
return bdrv_do_skip_filters(bs, true);
}
/*
* Return the first BDS that does not have a filtered child down the
* chain starting from @bs (including @bs itself).
*/
BlockDriverState *bdrv_skip_filters(BlockDriverState *bs)
{
IO_CODE();
return bdrv_do_skip_filters(bs, false);
}
/*
* For a backing chain, return the first non-filter backing image of
* the first non-filter image.
*/
BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs)
{
IO_CODE();
return bdrv_skip_filters(bdrv_cow_bs(bdrv_skip_filters(bs)));
}
8168
8169
8170
8171
8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
8184
8185
8186
8187
8188
8189
8190
8191
8192
8193
8194
8195
8196
8197
8198
8199
8200
/**
* Check whether [offset, offset + bytes) overlaps with the cached
* block-status data region.
*
* If so, and @pnum is not NULL, set *pnum to `bsc.data_end - offset`,
* which is what bdrv_bsc_is_data()'s interface needs.
* Otherwise, *pnum is not touched.
*/
static bool bdrv_bsc_range_overlaps_locked(BlockDriverState *bs,
int64_t offset, int64_t bytes,
int64_t *pnum)
{
BdrvBlockStatusCache *bsc = qatomic_rcu_read(&bs->block_status_cache);
bool overlaps;
overlaps =
qatomic_read(&bsc->valid) &&
ranges_overlap(offset, bytes, bsc->data_start,
bsc->data_end - bsc->data_start);
if (overlaps && pnum) {
*pnum = bsc->data_end - offset;
}
return overlaps;
}
/**
* See block_int.h for this function's documentation.
*/
bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum)
{
IO_CODE();
RCU_READ_LOCK_GUARD();
return bdrv_bsc_range_overlaps_locked(bs, offset, 1, pnum);
}
/**
* See block_int.h for this function's documentation.
*/
void bdrv_bsc_invalidate_range(BlockDriverState *bs,
int64_t offset, int64_t bytes)
{
IO_CODE();
RCU_READ_LOCK_GUARD();
if (bdrv_bsc_range_overlaps_locked(bs, offset, bytes, NULL)) {
qatomic_set(&bs->block_status_cache->valid, false);
}
}
/**
* See block_int.h for this function's documentation.
*/
void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes)
{
BdrvBlockStatusCache *new_bsc = g_new(BdrvBlockStatusCache, 1);
BdrvBlockStatusCache *old_bsc;
IO_CODE();
*new_bsc = (BdrvBlockStatusCache) {
.valid = true,
.data_start = offset,
.data_end = offset + bytes,
};
QEMU_LOCK_GUARD(&bs->bsc_modify_lock);
old_bsc = qatomic_rcu_read(&bs->block_status_cache);
qatomic_rcu_set(&bs->block_status_cache, new_bsc);
if (old_bsc) {
g_free_rcu(old_bsc, rcu);
}
}