Revision 212a5a8f
b/block.c | ||
---|---|---|
5094 | 5094 |
return bs->drv->bdrv_amend_options(bs, options); |
5095 | 5095 |
} |
5096 | 5096 |
|
5097 |
ExtSnapshotPerm bdrv_check_ext_snapshot(BlockDriverState *bs) |
|
5097 |
/* Used to recurse on single child block filters. |
|
5098 |
* Single child block filter will store their child in bs->file. |
|
5099 |
*/ |
|
5100 |
bool bdrv_generic_is_first_non_filter(BlockDriverState *bs, |
|
5101 |
BlockDriverState *candidate) |
|
5098 | 5102 |
{ |
5099 |
if (bs->drv->bdrv_check_ext_snapshot) { |
|
5100 |
return bs->drv->bdrv_check_ext_snapshot(bs); |
|
5103 |
if (!bs->drv) { |
|
5104 |
return false; |
|
5105 |
} |
|
5106 |
|
|
5107 |
if (!bs->drv->authorizations[BS_IS_A_FILTER]) { |
|
5108 |
if (bs == candidate) { |
|
5109 |
return true; |
|
5110 |
} else { |
|
5111 |
return false; |
|
5112 |
} |
|
5113 |
} |
|
5114 |
|
|
5115 |
if (!bs->drv->authorizations[BS_FILTER_PASS_DOWN]) { |
|
5116 |
return false; |
|
5101 | 5117 |
} |
5102 | 5118 |
|
5103 |
if (bs->file && bs->file->drv && bs->file->drv->bdrv_check_ext_snapshot) { |
|
5104 |
return bs->file->drv->bdrv_check_ext_snapshot(bs); |
|
5119 |
if (!bs->file) { |
|
5120 |
return false; |
|
5121 |
} |
|
5122 |
|
|
5123 |
return bdrv_recurse_is_first_non_filter(bs->file, candidate); |
|
5124 |
} |
|
5125 |
|
|
5126 |
bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs, |
|
5127 |
BlockDriverState *candidate) |
|
5128 |
{ |
|
5129 |
if (bs->drv && bs->drv->bdrv_recurse_is_first_non_filter) { |
|
5130 |
return bs->drv->bdrv_recurse_is_first_non_filter(bs, candidate); |
|
5105 | 5131 |
} |
5106 | 5132 |
|
5107 |
/* external snapshots are allowed by default */ |
|
5108 |
return EXT_SNAPSHOT_ALLOWED; |
|
5133 |
return bdrv_generic_is_first_non_filter(bs, candidate); |
|
5109 | 5134 |
} |
5110 | 5135 |
|
5111 |
ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs) |
|
5136 |
/* This function checks if the candidate is the first non filter bs down it's |
|
5137 |
* bs chain. Since we don't have pointers to parents it explore all bs chains |
|
5138 |
* from the top. Some filters can choose not to pass down the recursion. |
|
5139 |
*/ |
|
5140 |
bool bdrv_is_first_non_filter(BlockDriverState *candidate) |
|
5112 | 5141 |
{ |
5113 |
return EXT_SNAPSHOT_FORBIDDEN; |
|
5142 |
BlockDriverState *bs; |
|
5143 |
|
|
5144 |
/* walk down the bs forest recursively */ |
|
5145 |
QTAILQ_FOREACH(bs, &bdrv_states, device_list) { |
|
5146 |
bool perm; |
|
5147 |
|
|
5148 |
if (!bs->file) { |
|
5149 |
continue; |
|
5150 |
} |
|
5151 |
|
|
5152 |
perm = bdrv_recurse_is_first_non_filter(bs->file, candidate); |
|
5153 |
|
|
5154 |
/* candidate is the first non filter */ |
|
5155 |
if (perm) { |
|
5156 |
return true; |
|
5157 |
} |
|
5158 |
} |
|
5159 |
|
|
5160 |
return false; |
|
5114 | 5161 |
} |
b/block/blkverify.c | ||
---|---|---|
404 | 404 |
.bdrv_aio_writev = blkverify_aio_writev, |
405 | 405 |
.bdrv_aio_flush = blkverify_aio_flush, |
406 | 406 |
|
407 |
.bdrv_check_ext_snapshot = bdrv_check_ext_snapshot_forbidden,
|
|
407 |
.authorizations = { true, false },
|
|
408 | 408 |
}; |
409 | 409 |
|
410 | 410 |
static void bdrv_blkverify_init(void) |
b/blockdev.c | ||
---|---|---|
1243 | 1243 |
} |
1244 | 1244 |
} |
1245 | 1245 |
|
1246 |
if (bdrv_check_ext_snapshot(state->old_bs) != EXT_SNAPSHOT_ALLOWED) {
|
|
1246 |
if (!bdrv_is_first_non_filter(state->old_bs)) {
|
|
1247 | 1247 |
error_set(errp, QERR_FEATURE_DISABLED, "snapshot"); |
1248 | 1248 |
return; |
1249 | 1249 |
} |
b/include/block/block.h | ||
---|---|---|
287 | 287 |
/* external snapshots */ |
288 | 288 |
|
289 | 289 |
typedef enum { |
290 |
EXT_SNAPSHOT_ALLOWED,
|
|
291 |
EXT_SNAPSHOT_FORBIDDEN,
|
|
292 |
} ExtSnapshotPerm;
|
|
293 |
|
|
294 |
/* return EXT_SNAPSHOT_ALLOWED if external snapshot is allowed |
|
295 |
* return EXT_SNAPSHOT_FORBIDDEN if external snapshot is forbidden
|
|
296 |
*/
|
|
297 |
ExtSnapshotPerm bdrv_check_ext_snapshot(BlockDriverState *bs);
|
|
298 |
/* helper used to forbid external snapshots like in blkverify */
|
|
299 |
ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs);
|
|
290 |
BS_IS_A_FILTER,
|
|
291 |
BS_FILTER_PASS_DOWN,
|
|
292 |
BS_AUTHORIZATION_COUNT,
|
|
293 |
} BsAuthorization; |
|
294 |
|
|
295 |
bool bdrv_generic_is_first_non_filter(BlockDriverState *bs,
|
|
296 |
BlockDriverState *candidate);
|
|
297 |
bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
|
|
298 |
BlockDriverState *candidate);
|
|
299 |
bool bdrv_is_first_non_filter(BlockDriverState *candidate);
|
|
300 | 300 |
|
301 | 301 |
/* async block I/O */ |
302 | 302 |
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector, |
b/include/block/block_int.h | ||
---|---|---|
69 | 69 |
const char *format_name; |
70 | 70 |
int instance_size; |
71 | 71 |
|
72 |
/* if not defined external snapshots are allowed |
|
73 |
* future block filters will query their children to build the response |
|
72 |
/* this table of boolean contains authorizations for the block operations */ |
|
73 |
bool authorizations[BS_AUTHORIZATION_COUNT]; |
|
74 |
/* for snapshots complex block filter like Quorum can implement the |
|
75 |
* following recursive callback instead of BS_IS_A_FILTER. |
|
76 |
* It's purpose is to recurse on the filter children while calling |
|
77 |
* bdrv_recurse_is_first_non_filter on them. |
|
78 |
* For a sample implementation look in the future Quorum block filter. |
|
74 | 79 |
*/ |
75 |
ExtSnapshotPerm (*bdrv_check_ext_snapshot)(BlockDriverState *bs); |
|
80 |
bool (*bdrv_recurse_is_first_non_filter)(BlockDriverState *bs, |
|
81 |
BlockDriverState *candidate); |
|
76 | 82 |
|
77 | 83 |
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); |
78 | 84 |
int (*bdrv_probe_device)(const char *filename); |
Also available in: Unified diff