#include <linux/blkdev.h>
#include <linux/device-mapper.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
#include <linux/list.h>
#include <linux/list_bl.h>
#include <linux/mempool.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/log2.h>
#include <linux/dm-kcopyd.h>
#include "dm.h"
#include "dm-exception-store.h"
#define DM_MSG_PREFIX …
static const char dm_snapshot_merge_target_name[] = …;
#define dm_target_is_snapshot_merge(ti) …
#define MIN_IOS …
#define DM_TRACKED_CHUNK_HASH_SIZE …
#define DM_TRACKED_CHUNK_HASH(x) …
struct dm_exception_table { … };
struct dm_snapshot { … };
#define RUNNING_MERGE …
#define SHUTDOWN_MERGE …
#define DEFAULT_COW_THRESHOLD …
static unsigned int cow_threshold = …;
module_param_named(snapshot_cow_threshold, cow_threshold, uint, 0644);
MODULE_PARM_DESC(…) …;
DECLARE_DM_KCOPYD_THROTTLE_WITH_MODULE_PARM(…) …;
struct dm_dev *dm_snap_origin(struct dm_snapshot *s)
{ … }
EXPORT_SYMBOL(…);
struct dm_dev *dm_snap_cow(struct dm_snapshot *s)
{ … }
EXPORT_SYMBOL(…);
static sector_t chunk_to_sector(struct dm_exception_store *store,
chunk_t chunk)
{ … }
static int bdev_equal(struct block_device *lhs, struct block_device *rhs)
{ … }
struct dm_snap_pending_exception { … };
static struct kmem_cache *exception_cache;
static struct kmem_cache *pending_cache;
struct dm_snap_tracked_chunk { … };
static void init_tracked_chunk(struct bio *bio)
{ … }
static bool is_bio_tracked(struct bio *bio)
{ … }
static void track_chunk(struct dm_snapshot *s, struct bio *bio, chunk_t chunk)
{ … }
static void stop_tracking_chunk(struct dm_snapshot *s, struct bio *bio)
{ … }
static int __chunk_is_tracked(struct dm_snapshot *s, chunk_t chunk)
{ … }
static void __check_for_conflicting_io(struct dm_snapshot *s, chunk_t chunk)
{ … }
struct origin { … };
struct dm_origin { … };
#define ORIGIN_HASH_SIZE …
#define ORIGIN_MASK …
static struct list_head *_origins;
static struct list_head *_dm_origins;
static struct rw_semaphore _origins_lock;
static DECLARE_WAIT_QUEUE_HEAD(_pending_exceptions_done);
static DEFINE_SPINLOCK(_pending_exceptions_done_spinlock);
static uint64_t _pending_exceptions_done_count;
static int init_origin_hash(void)
{ … }
static void exit_origin_hash(void)
{ … }
static unsigned int origin_hash(struct block_device *bdev)
{ … }
static struct origin *__lookup_origin(struct block_device *origin)
{ … }
static void __insert_origin(struct origin *o)
{ … }
static struct dm_origin *__lookup_dm_origin(struct block_device *origin)
{ … }
static void __insert_dm_origin(struct dm_origin *o)
{ … }
static void __remove_dm_origin(struct dm_origin *o)
{ … }
static int __find_snapshots_sharing_cow(struct dm_snapshot *snap,
struct dm_snapshot **snap_src,
struct dm_snapshot **snap_dest,
struct dm_snapshot **snap_merge)
{ … }
static int __validate_exception_handover(struct dm_snapshot *snap)
{ … }
static void __insert_snapshot(struct origin *o, struct dm_snapshot *s)
{ … }
static int register_snapshot(struct dm_snapshot *snap)
{ … }
static void reregister_snapshot(struct dm_snapshot *s)
{ … }
static void unregister_snapshot(struct dm_snapshot *s)
{ … }
static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk);
struct dm_exception_table_lock { … };
static void dm_exception_table_lock_init(struct dm_snapshot *s, chunk_t chunk,
struct dm_exception_table_lock *lock)
{ … }
static void dm_exception_table_lock(struct dm_exception_table_lock *lock)
{ … }
static void dm_exception_table_unlock(struct dm_exception_table_lock *lock)
{ … }
static int dm_exception_table_init(struct dm_exception_table *et,
uint32_t size, unsigned int hash_shift)
{ … }
static void dm_exception_table_exit(struct dm_exception_table *et,
struct kmem_cache *mem)
{ … }
static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk)
{ … }
static void dm_remove_exception(struct dm_exception *e)
{ … }
static struct dm_exception *dm_lookup_exception(struct dm_exception_table *et,
chunk_t chunk)
{ … }
static struct dm_exception *alloc_completed_exception(gfp_t gfp)
{ … }
static void free_completed_exception(struct dm_exception *e)
{ … }
static struct dm_snap_pending_exception *alloc_pending_exception(struct dm_snapshot *s)
{ … }
static void free_pending_exception(struct dm_snap_pending_exception *pe)
{ … }
static void dm_insert_exception(struct dm_exception_table *eh,
struct dm_exception *new_e)
{ … }
static int dm_add_exception(void *context, chunk_t old, chunk_t new)
{ … }
static uint32_t __minimum_chunk_size(struct origin *o)
{ … }
static int calc_max_buckets(void)
{ … }
static int init_hash_tables(struct dm_snapshot *s)
{ … }
static void merge_shutdown(struct dm_snapshot *s)
{ … }
static struct bio *__release_queued_bios_after_merge(struct dm_snapshot *s)
{ … }
static int __remove_single_exception_chunk(struct dm_snapshot *s,
chunk_t old_chunk)
{ … }
static void flush_bios(struct bio *bio);
static int remove_single_exception_chunk(struct dm_snapshot *s)
{ … }
static int origin_write_extent(struct dm_snapshot *merging_snap,
sector_t sector, unsigned int chunk_size);
static void merge_callback(int read_err, unsigned long write_err,
void *context);
static uint64_t read_pending_exceptions_done_count(void)
{ … }
static void increment_pending_exceptions_done_count(void)
{ … }
static void snapshot_merge_next_chunks(struct dm_snapshot *s)
{ … }
static void error_bios(struct bio *bio);
static void merge_callback(int read_err, unsigned long write_err, void *context)
{ … }
static void start_merge(struct dm_snapshot *s)
{ … }
static void stop_merge(struct dm_snapshot *s)
{ … }
static int parse_snapshot_features(struct dm_arg_set *as, struct dm_snapshot *s,
struct dm_target *ti)
{ … }
static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{ … }
static void __free_exceptions(struct dm_snapshot *s)
{ … }
static void __handover_exceptions(struct dm_snapshot *snap_src,
struct dm_snapshot *snap_dest)
{ … }
static void snapshot_dtr(struct dm_target *ti)
{ … }
static void account_start_copy(struct dm_snapshot *s)
{ … }
static void account_end_copy(struct dm_snapshot *s)
{ … }
static bool wait_for_in_progress(struct dm_snapshot *s, bool unlock_origins)
{ … }
static void flush_bios(struct bio *bio)
{ … }
static int do_origin(struct dm_dev *origin, struct bio *bio, bool limit);
static void retry_origin_bios(struct dm_snapshot *s, struct bio *bio)
{ … }
static void error_bios(struct bio *bio)
{ … }
static void __invalidate_snapshot(struct dm_snapshot *s, int err)
{ … }
static void invalidate_snapshot(struct dm_snapshot *s, int err)
{ … }
static void pending_complete(void *context, int success)
{ … }
static void complete_exception(struct dm_snap_pending_exception *pe)
{ … }
static void copy_callback(int read_err, unsigned long write_err, void *context)
{ … }
static void start_copy(struct dm_snap_pending_exception *pe)
{ … }
static void full_bio_end_io(struct bio *bio)
{ … }
static void start_full_bio(struct dm_snap_pending_exception *pe,
struct bio *bio)
{ … }
static struct dm_snap_pending_exception *
__lookup_pending_exception(struct dm_snapshot *s, chunk_t chunk)
{ … }
static struct dm_snap_pending_exception *
__insert_pending_exception(struct dm_snapshot *s,
struct dm_snap_pending_exception *pe, chunk_t chunk)
{ … }
static struct dm_snap_pending_exception *
__find_pending_exception(struct dm_snapshot *s,
struct dm_snap_pending_exception *pe, chunk_t chunk)
{ … }
static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
struct bio *bio, chunk_t chunk)
{ … }
static void zero_callback(int read_err, unsigned long write_err, void *context)
{ … }
static void zero_exception(struct dm_snapshot *s, struct dm_exception *e,
struct bio *bio, chunk_t chunk)
{ … }
static bool io_overlaps_chunk(struct dm_snapshot *s, struct bio *bio)
{ … }
static int snapshot_map(struct dm_target *ti, struct bio *bio)
{ … }
static int snapshot_merge_map(struct dm_target *ti, struct bio *bio)
{ … }
static int snapshot_end_io(struct dm_target *ti, struct bio *bio,
blk_status_t *error)
{ … }
static void snapshot_merge_presuspend(struct dm_target *ti)
{ … }
static int snapshot_preresume(struct dm_target *ti)
{ … }
static void snapshot_resume(struct dm_target *ti)
{ … }
static uint32_t get_origin_minimum_chunksize(struct block_device *bdev)
{ … }
static void snapshot_merge_resume(struct dm_target *ti)
{ … }
static void snapshot_status(struct dm_target *ti, status_type_t type,
unsigned int status_flags, char *result, unsigned int maxlen)
{ … }
static int snapshot_iterate_devices(struct dm_target *ti,
iterate_devices_callout_fn fn, void *data)
{ … }
static void snapshot_io_hints(struct dm_target *ti, struct queue_limits *limits)
{ … }
static int __origin_write(struct list_head *snapshots, sector_t sector,
struct bio *bio)
{ … }
static int do_origin(struct dm_dev *origin, struct bio *bio, bool limit)
{ … }
static int origin_write_extent(struct dm_snapshot *merging_snap,
sector_t sector, unsigned int size)
{ … }
static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{ … }
static void origin_dtr(struct dm_target *ti)
{ … }
static int origin_map(struct dm_target *ti, struct bio *bio)
{ … }
static void origin_resume(struct dm_target *ti)
{ … }
static void origin_postsuspend(struct dm_target *ti)
{ … }
static void origin_status(struct dm_target *ti, status_type_t type,
unsigned int status_flags, char *result, unsigned int maxlen)
{ … }
static int origin_iterate_devices(struct dm_target *ti,
iterate_devices_callout_fn fn, void *data)
{ … }
static struct target_type origin_target = …;
static struct target_type snapshot_target = …;
static struct target_type merge_target = …;
static int __init dm_snapshot_init(void)
{ … }
static void __exit dm_snapshot_exit(void)
{ … }
module_init(…) …;
module_exit(dm_snapshot_exit);
MODULE_DESCRIPTION(…) …;
MODULE_AUTHOR(…) …;
MODULE_LICENSE(…) …;
MODULE_ALIAS(…) …;
MODULE_ALIAS(…) …;