| /* | 
 |  * snapshot_access block driver | 
 |  * | 
 |  * Copyright (c) 2022 Virtuozzo International GmbH. | 
 |  * | 
 |  * Author: | 
 |  *  Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com> | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or modify | 
 |  * it under the terms of the GNU General Public License as published by | 
 |  * the Free Software Foundation; either version 2 of the License, or | 
 |  * (at your option) any later version. | 
 |  * | 
 |  * This program is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |  * GNU General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU General Public License | 
 |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | 
 |  */ | 
 |  | 
 | #include "qemu/osdep.h" | 
 |  | 
 | #include "system/block-backend.h" | 
 | #include "qemu/cutils.h" | 
 | #include "block/block_int.h" | 
 |  | 
 | static int coroutine_fn GRAPH_RDLOCK | 
 | snapshot_access_co_preadv_part(BlockDriverState *bs, | 
 |                                int64_t offset, int64_t bytes, | 
 |                                QEMUIOVector *qiov, size_t qiov_offset, | 
 |                                BdrvRequestFlags flags) | 
 | { | 
 |     if (flags) { | 
 |         return -ENOTSUP; | 
 |     } | 
 |  | 
 |     return bdrv_co_preadv_snapshot(bs->file, offset, bytes, qiov, qiov_offset); | 
 | } | 
 |  | 
 | static int coroutine_fn GRAPH_RDLOCK | 
 | snapshot_access_co_block_status(BlockDriverState *bs, | 
 |                                 bool want_zero, int64_t offset, | 
 |                                 int64_t bytes, int64_t *pnum, | 
 |                                 int64_t *map, BlockDriverState **file) | 
 | { | 
 |     return bdrv_co_snapshot_block_status(bs->file->bs, want_zero, offset, | 
 |                                          bytes, pnum, map, file); | 
 | } | 
 |  | 
 | static int coroutine_fn GRAPH_RDLOCK | 
 | snapshot_access_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | 
 | { | 
 |     return bdrv_co_pdiscard_snapshot(bs->file->bs, offset, bytes); | 
 | } | 
 |  | 
 | static int coroutine_fn | 
 | snapshot_access_co_pwrite_zeroes(BlockDriverState *bs, | 
 |                                  int64_t offset, int64_t bytes, | 
 |                                  BdrvRequestFlags flags) | 
 | { | 
 |     return -ENOTSUP; | 
 | } | 
 |  | 
 | static coroutine_fn int | 
 | snapshot_access_co_pwritev_part(BlockDriverState *bs, | 
 |                                 int64_t offset, int64_t bytes, | 
 |                                 QEMUIOVector *qiov, size_t qiov_offset, | 
 |                                 BdrvRequestFlags flags) | 
 | { | 
 |     return -ENOTSUP; | 
 | } | 
 |  | 
 |  | 
 | static void GRAPH_RDLOCK snapshot_access_refresh_filename(BlockDriverState *bs) | 
 | { | 
 |     pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), | 
 |             bs->file->bs->filename); | 
 | } | 
 |  | 
 | static int snapshot_access_open(BlockDriverState *bs, QDict *options, int flags, | 
 |                                 Error **errp) | 
 | { | 
 |     bdrv_open_child(NULL, options, "file", bs, &child_of_bds, | 
 |                     BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY, | 
 |                     false, errp); | 
 |  | 
 |     GRAPH_RDLOCK_GUARD_MAINLOOP(); | 
 |  | 
 |     if (!bs->file) { | 
 |         return -EINVAL; | 
 |     } | 
 |  | 
 |     bs->total_sectors = bs->file->bs->total_sectors; | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | static void snapshot_access_child_perm(BlockDriverState *bs, BdrvChild *c, | 
 |                                 BdrvChildRole role, | 
 |                                 BlockReopenQueue *reopen_queue, | 
 |                                 uint64_t perm, uint64_t shared, | 
 |                                 uint64_t *nperm, uint64_t *nshared) | 
 | { | 
 |     /* | 
 |      * Currently, we don't need any permissions. If bs->file provides | 
 |      * snapshot-access API, we can use it. | 
 |      */ | 
 |     *nperm = 0; | 
 |     *nshared = BLK_PERM_ALL; | 
 | } | 
 |  | 
 | static BlockDriver bdrv_snapshot_access_drv = { | 
 |     .format_name = "snapshot-access", | 
 |  | 
 |     .bdrv_open                  = snapshot_access_open, | 
 |  | 
 |     .bdrv_co_preadv_part        = snapshot_access_co_preadv_part, | 
 |     .bdrv_co_pwritev_part       = snapshot_access_co_pwritev_part, | 
 |     .bdrv_co_pwrite_zeroes      = snapshot_access_co_pwrite_zeroes, | 
 |     .bdrv_co_pdiscard           = snapshot_access_co_pdiscard, | 
 |     .bdrv_co_block_status       = snapshot_access_co_block_status, | 
 |  | 
 |     .bdrv_refresh_filename      = snapshot_access_refresh_filename, | 
 |  | 
 |     .bdrv_child_perm            = snapshot_access_child_perm, | 
 | }; | 
 |  | 
 | static void snapshot_access_init(void) | 
 | { | 
 |     bdrv_register(&bdrv_snapshot_access_drv); | 
 | } | 
 |  | 
 | block_init(snapshot_access_init); |