%PDF- %PDF-
Direktori : /usr/src/blksnap-6.3.0.73/ |
Current File : //usr/src/blksnap-6.3.0.73/diff_area.h |
/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __BLK_SNAP_DIFF_AREA_H #define __BLK_SNAP_DIFF_AREA_H #include <linux/slab.h> #include <linux/uio.h> #include <linux/kref.h> #include <linux/list.h> #include <linux/spinlock.h> #include <linux/blkdev.h> #include <linux/xarray.h> #include "event_queue.h" #ifdef STANDALONE_BDEVFILTER #include "log_histogram.h" #endif struct diff_storage; struct chunk; /** * struct diff_area - Discribes the difference area for one original device. * @kref: * The reference counter. The &struct diff_area can be shared between * the &struct tracker and &struct snapimage. * @orig_bdev: * A pointer to the structure of an opened block device. * @diff_storage: * Pointer to difference storage for storing difference data. * @chunk_shift: * Power of 2 used to specify the chunk size. This allows to set different chunk sizes for * huge and small block devices. * @chunk_count: * Count of chunks. The number of chunks into which the block device * is divided. * @chunk_map: * A map of chunks. * @in_memory: * A sign that difference storage is not prepared and all differences are * stored in RAM. * @chunk_map_lock: * This spinlock guarantees consistency of maps and linked lists of chunk * caches. * @read_cache_queue: * Queue for the read cache. * @read_cache_count: * The number of chunks in the read cache. * @write_cache_queue: * Queue for the write cache. * @write_cache_count: * The number of chunks in the write cache. * @cache_release_work: * The workqueue work item. This worker limits the number of chunks * that store their data in RAM. * @free_diff_buffers_lock: * This spinlock guarantees consistency of the linked lists of * free difference buffers. * @free_diff_buffers: * Linked list of free difference buffers allows to reduce the number * of buffer allocation and release operations. * @free_diff_buffers_count: * The number of free difference buffers in the linked list. * @corrupt_flag: * The flag is set if an error occurred in the operation of the data * saving mechanism in the diff area. In this case, an error will be * generated when reading from the snapshot image. * * The &struct diff_area is created for each block device in the snapshot. * It is used to save the differences between the original block device and * the snapshot image. That is, when writing data to the original device, * the differences are copied as chunks to the difference storage. * Reading and writing from the snapshot image is also performed using * &struct diff_area. * * The xarray has a limit on the maximum size. This can be especially * noticeable on 32-bit systems. This creates a limit in the size of * supported disks. * * For example, for a 256 TiB disk with a block size of 65536 bytes, the * number of elements in the chunk map will be equal to 2 with a power of 32. * Therefore, the number of chunks into which the block device is divided is * limited. * * To provide high performance, a read cache and a write cache for chunks are * used. The cache algorithm is the simplest. If the data of the chunk was * read to the difference buffer, then the buffer is not released immediately, * but is placed at the end of the queue. The worker thread checks the number * of chunks in the queue and releases a difference buffer for the first chunk * in the queue, but only if the binary semaphore of the chunk is not locked. * If the read thread accesses the chunk from the cache again, it returns * back to the end of the queue. * * The linked list of difference buffers allows to have a certain number of * "hot" buffers. This allows to reduce the number of allocations and releases * of memory. * * */ struct diff_area { struct kref kref; #if defined(HAVE_BDEV_FILE_OPEN) struct file *orig_bdev_file; #elif defined(HAVE_BDEV_HANDLE) struct bdev_handle *orig_bdev_handler; #endif struct block_device *orig_bdev; struct diff_storage *diff_storage; unsigned long chunk_shift; unsigned long chunk_count; struct xarray chunk_map; spinlock_t chunk_map_lock; #ifdef CONFIG_BLK_SNAP_ALLOW_DIFF_STORAGE_IN_MEMORY bool in_memory; #endif struct list_head read_cache_queue; atomic_t read_cache_count; struct list_head write_cache_queue; atomic_t write_cache_count; struct work_struct cache_release_work; spinlock_t free_diff_buffers_lock; struct list_head free_diff_buffers; atomic_t free_diff_buffers_count; atomic_t corrupt_flag; #ifdef STANDALONE_BDEVFILTER atomic64_t stat_processed; atomic64_t stat_copied; atomic64_t stat_image_read; atomic64_t stat_image_written; struct log_histogram read_hg; struct log_histogram redirect_hg; #endif }; struct diff_area *diff_area_new(dev_t dev_id, struct diff_storage *diff_storage); void diff_area_free(struct kref *kref); static inline struct diff_area *diff_area_get(struct diff_area *diff_area) { kref_get(&diff_area->kref); return diff_area; }; static inline void diff_area_put(struct diff_area *diff_area) { if (likely(diff_area)) kref_put(&diff_area->kref, diff_area_free); }; void diff_area_set_corrupted(struct diff_area *diff_area, int err_code); static inline bool diff_area_is_corrupted(struct diff_area *diff_area) { return !!atomic_read(&diff_area->corrupt_flag); }; static inline sector_t diff_area_chunk_sectors(struct diff_area *diff_area) { return (sector_t)(1ull << (diff_area->chunk_shift - SECTOR_SHIFT)); }; int diff_area_copy(struct diff_area *diff_area, sector_t sector, sector_t count, const bool is_nowait); int diff_area_wait(struct diff_area *diff_area, sector_t sector, sector_t count, const bool is_nowait); /** * struct diff_area_image_ctx - The context for processing an io request to * the snapshot image. * @diff_area: * Pointer to &struct diff_area for the current snapshot image. * @is_write: * Distinguishes between the behavior of reading or writing when * processing a request. * @chunk: * Current chunk. */ struct diff_area_image_ctx { struct diff_area *diff_area; struct chunk *chunk; bool is_write; bool in_chunk_map; }; static inline void diff_area_image_ctx_init(struct diff_area_image_ctx *io_ctx, struct diff_area *diff_area, bool is_write) { io_ctx->diff_area = diff_area; io_ctx->is_write = is_write; io_ctx->chunk = NULL; }; void diff_area_image_ctx_done(struct diff_area_image_ctx *io_ctx); blk_status_t diff_area_image_io(struct diff_area_image_ctx *io_ctx, const struct bio_vec *bvec, sector_t *pos); /** * */ void diff_area_throttling_io(struct diff_area *diff_area); #ifdef BLK_SNAP_DEBUG_SECTOR_STATE /** * */ int diff_area_get_sector_state(struct diff_area *diff_area, sector_t sector, unsigned int *chunk_state); int diff_area_get_sector_image(struct diff_area *diff_area, sector_t pos, void *buf); #endif #endif /* __BLK_SNAP_DIFF_AREA_H */