/* * dm-snapshot.c * * Copyright (C) 2001-2002 Sistina Software (UK) Limited. * * This file is released under the GPL. */#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/mempool.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/log2.h>#include <linux/dm-kcopyd.h>#include <linux/workqueue.h>#include"dm-exception-store.h"#define DM_MSG_PREFIX"snapshots"/* * The percentage increment we will wake up users at */#define WAKE_UP_PERCENT 5/* * kcopyd priority of snapshot operations */#define SNAPSHOT_COPY_PRIORITY 2/* * Reserve 1MB for each snapshot initially (with minimum of 1 page). */#define SNAPSHOT_PAGES (((1UL << 20) >> PAGE_SHIFT) ? : 1)/* * The size of the mempool used to track chunks in use. */#define MIN_IOS 256#define DM_TRACKED_CHUNK_HASH_SIZE 16#define DM_TRACKED_CHUNK_HASH(x) ((unsigned long)(x) & \ (DM_TRACKED_CHUNK_HASH_SIZE - 1))struct exception_table {uint32_t hash_mask;unsigned hash_shift;struct list_head *table;};struct dm_snapshot {struct rw_semaphore lock;struct dm_dev *origin;/* List of snapshots per Origin */struct list_head list;/* You can't use a snapshot if this is 0 (e.g. if full) */int valid;/* Origin writes don't trigger exceptions until this is set */int active;
mempool_t *pending_pool;
atomic_t pending_exceptions_count;struct exception_table pending;struct exception_table complete;/* * pe_lock protects all pending_exception operations and access * as well as the snapshot_bios list. */
spinlock_t pe_lock;/* The on disk metadata handler */struct dm_exception_store *store;struct dm_kcopyd_client *kcopyd_client;/* Queue of snapshot writes for ksnapd to flush */struct bio_list queued_bios;struct work_struct queued_bios_work;/* Chunks with outstanding reads */
mempool_t *tracked_chunk_pool;
spinlock_t tracked_chunk_lock;struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];};static struct workqueue_struct *ksnapd;static voidflush_queued_bios(struct work_struct *work);static sector_t chunk_to_sector(struct dm_exception_store *store,
chunk_t chunk){return chunk << store->chunk_shift;}static intbdev_equal(struct block_device *lhs,struct block_device *rhs){/* * There is only ever one i