%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 */