/* -*- linux-c -*- */
/*
 *   Copyright (c) International Business Machines  Corp., 2000
 *
 *   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, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
/*
 * linux/include/linux/evms_snapshot.h
 *
 * EVMS Snapshot Feature kernel header file
 */

#ifndef __EVMS_SNAPSHOT_INCLUDED__
#define __EVMS_SNAPSHOT_INCLUDED__

#define	EVMS_SNAPSHOT_VERSION_MAJOR		2
#define EVMS_SNAPSHOT_VERSION_MINOR		1
#define EVMS_SNAPSHOT_VERSION_PATCHLEVEL	2

#define EVMS_SNAPSHOT_FEATURE_ID	104

#define EVMS_SNAPSHOT_SIGNATURE		0x536e4170 /* SnAp */
#define EVMS_ORIGINAL_SIGNATURE		0x4f724967 /* OrIg */
#define MAX_HASH_CHAIN_ENTRIES		10

/* Status flags */
#define EVMS_SNAPSHOT			0x001
#define EVMS_SNAPSHOT_ORG		0x002
#define EVMS_SNAPSHOT_DISABLED		0x004
#define EVMS_SNAPSHOT_FULL		0x008
#define EVMS_SNAPSHOT_QUIESCED		0x010
#define EVMS_SNAPSHOT_WRITEABLE 	0x020
#define EVMS_SNAPSHOT_ASYNC		0x040
#define EVMS_SNAPSHOT_ROLLBACK		0x080
#define EVMS_SNAPSHOT_ROLLBACK_COMP	0x100
#define EVMS_SNAPSHOT_DISABLED_PENDING	0x200

/* Private ioctl commands */
#define SNAPSHOT_QUERY_PERCENT_FULL	1
#define SNAPSHOT_START_ROLLBACK		2
#define SNAPSHOT_CHECK_STATE		3

/* Chunk states - for async mode */
#define SNAP_CHUNK_COPYING		1	/* Chunk is being copied from org to snap. */
#define SNAP_CHUNK_COPIED		0	/* Chunk has been copied from org to snap. */

#define SNAPSHOT_DEFAULT_CHUNK_SIZE	128	/* sectors == 64k */
#define SNAPSHOT_MIN_CHUNK_SIZE		16	/* 8kB */
#define SNAPSHOT_MAX_CHUNK_SIZE		2048	/* 1MB */
#define SNAPSHOT_CHUNK_BUFFER_SIZE	128	/* copy buffer */

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,9)
#define min(a,b) (((a)<(b))?(a):(b))
#endif

/**
 * struct snapshot_metadata
 *
 * @signature:		0  : EVMS_SNAPSHOT_SIGNATURE
 * @CRC:		4  :
 * @version:		8  : Major, minor, patchlevel
 * @flags:		20 : EVMS_SNAPSHOT_*
 * @original_volume:	24 : Name of volume being snapshotted.
 * @original_size:	152: In sectors.
 * @lba_of_COW_table:	160:
 * @lba_of_first_chunk: 168:
 * @chunk_size:		176: In sectors
 * @total_chunks:	180:
 *
 * On-disk metadata sector for EVMS Snapshot feature.
 */
struct snapshot_metadata {
	u32			signature;
	u32			CRC;
	struct evms_version	version;
	u32			flags;
	u8			original_volume[128];
	u64			original_size;
	u64			lba_of_COW_table;
	u64			lba_of_first_chunk;
	u32			chunk_size;
	u32			total_chunks;
};

/**
 * struct snapshot_hash_entry
 *
 * @org_chunk:		Chunk number, not LBA.
 * @snap_chunk:		Chunk_number, not LBA.
 * @chunk_state:	SNAP_CHUNK_*
 * @chunk_state_lock:	Protects access to chunk_state
 * @snap_io:		In async mode, the control-block for copying this chunk.
 * @next
 * @prev
 *
 * Entries in the snapshot remapping hash-table.
 */
struct snapshot_hash_entry {
	u64				org_chunk;
	u64				snap_chunk;
	u32				chunk_state;
	spinlock_t			chunk_state_lock;
	struct async_snap_io		* snap_io;
	struct snapshot_hash_entry	* next;
	struct snapshot_hash_entry	* prev;
};

/**
 * struct snapshot_volume
 *
 * @logical_node:	Node below us.
 * @exported_node: 	Node above us.
 * @snapshot_org:	The volume being snapshotted.
 * @snapshot_next:	List of volumes snapshotting this original.
 * @snap_semaphore:	On snapshots: protects access to the snapshot
 *			volume structure.
 *			On originals: protects the list of snapshots.
 * @snapshot_map:	Hash table of remapped chunks.
 * @free_hash_list:	List of pre-allocated hash entries.
 * @chunk_size:		In sectors.
 * @chunk_shift:	Shift value for chunk_size.
 * @num_chunks:		In this volume.
 * @next_cow_entry:	Index into current COW table sector.
 * @current_cow_sector:	Logical sector of current COW table.
 * @next_free_chunk:	Index of next free chunk (not LBA!).
 * @hash_table_size:	Size of the hash table for the remap.
 * @flags:		Status flags. EVMS_SNAPSHOT_*
 * @cow_table:		One sector's worth of COW tables.
 * @async_io_thread:	Thread for async copy-on-writes. Only on originals.
 * @chunk_write_list:		Lists and locks attached to the original.
 * @chunk_write_list_lock:
 * @org_pending_io_list:
 * @org_pending_io_list_lock:
 * @snap_pending_io_list:
 * @snap_pending_io_list_lock:
 * @cow_table_write_list:	List and lock attached to the snapshot.
 * @cow_table_write_list_lock:
 * @rollback_thread:	Thread for rollbacks. Only on snapshots.
 * @chunk_data_buffer:	Buffer for copying data during rollbacks.
 *
 * Private data for one snapshot volume or one original volume.
 */
struct snapshot_volume {
	struct evms_logical_node	* logical_node;
	struct evms_logical_node	* exported_node;
	struct snapshot_volume		* snapshot_org;
	struct snapshot_volume		* snapshot_next;
	struct rw_semaphore		snap_semaphore;
	struct snapshot_hash_entry	** snapshot_map;
	struct snapshot_hash_entry	* free_hash_list;
	u32				chunk_size;
	u32				chunk_shift;
	u32				num_chunks;
	u32				next_cow_entry;
	u64				current_cow_sector;
	u32				next_free_chunk;
	u32				hash_table_size;
	u32				flags;
	u64				cow_table[64];
	struct evms_thread		* async_io_thread;
	struct list_head		chunk_write_list;
	spinlock_t			chunk_write_list_lock;
	struct list_head		org_pending_io_list;
	spinlock_t			org_pending_io_list_lock;
	struct list_head		snap_pending_io_list;
	spinlock_t			snap_pending_io_list_lock;
	struct list_head		cow_table_write_list;
	spinlock_t			cow_table_write_list_lock;
#ifdef SNAPSHOT_DEBUG
	atomic_t			cow_table_writes;
	atomic_t			cow_table_overlaps;
#endif
	struct evms_thread		* rollback_thread;
	u8				* chunk_data_buffer;
};

/**
 * struct snap_io_buffer
 *
 * @bh:			A pointer to the embedded buffer_head at the end.
 * @buffer_private:	Private data associated with this buffer.
 * @buffer_next:	List of snap_io_buffer's for one async_[org|snap]_io.
 * @copy_next:		List of buffers that will write the data that this
 *			buffer just read.
 * @chunk_write_list:	List for the thread to use to drive writes to the
 *			snapshot as part of a copy.
 * @_bh:		An embedded buffer_head. The b_private field will
 *			always point back at the snap_io_buffer.
 *
 * A wrapper around a buffer_head, to allow for the buffer to exist on the
 * variety of lists used by snapshotting.
 */
struct snap_io_buffer {
	struct buffer_head	* bh;
	void			* buffer_private;
	struct snap_io_buffer	* buffer_next;
	struct snap_io_buffer	* copy_next;
	struct list_head	chunk_write_list;
	struct buffer_head	_bh;
};

#define CHUNK_WRITE_ENTRY(lh)	list_entry((lh), \
					struct snap_io_buffer, \
					chunk_write_list)

/**
 * struct async_snap_io
 *
 * @snap_volume:	Snapshot volume that this chunk belongs to.
 * @hash_table_entry:	Hash table entry that this chunk belongs to.
 * @org_io:		Parent async I/O structure that contains list
 *			of read buffers.
 * @pending_reads:	List of pending read requests to the snapshot.
 * @pending_writes:	List of pending write requests to the snapshot.
 * @copy_buffers:	List of buffers to use to write this chunk to the
 *			snapshot.
 * @cow_table_buffer:	Buffer for writing the cow table to disk.
 * @snap_io_list_next:	List of async_snap_io's for the parent async_org_io.
 * @snap_pending_io_list: List of async_snap_io's to be processed by the thread.
 *			For each of these, the thread will process the contents
 *			of the pending_[reads|writes] lists.
 * @cow_write_list:	List of cow table writes to be processed by the thread.
 *			For each of these, the thread will process the
 *			cow_table_buffer.
 * @write_count:	Number of buffers remaining to write for this chunk
 *			(equal to the length of the copy_buffers list).
 * @dev:		Copy of the b_rdev field for this volume. Needed in
 *			order to tell EVMS about pending I/Os.
 *
 * Control structure that handles writing a single chunk to the snapshot during
 * a copy-on-write.
 */
struct async_snap_io {
	struct snapshot_volume		* snap_volume;
	struct snapshot_hash_entry	* hash_table_entry;
	struct async_org_io		* org_io;
	struct buffer_head		* pending_reads;
	struct buffer_head		* pending_writes;
	struct snap_io_buffer		* copy_buffers;
	struct snap_io_buffer		* cow_table_buffer;
	struct async_snap_io		* snap_io_list_next;
	struct list_head		snap_pending_io_list;
	struct list_head		cow_write_list;
	atomic_t			write_count;
	kdev_t				dev;
};

#define SNAP_PENDING_IO_ENTRY(lh)	list_entry((lh), \
						struct async_snap_io, \
						snap_pending_io_list)
#define COW_WRITE_ENTRY(lh)		list_entry((lh), \
						struct async_snap_io, \
						cow_write_list)

/**
 * struct async_org_io
 *
 * @org_volume:		Original volume that this chunk belongs to.
 * @pending_writes:	List of pending write requests to the original.
 * @pending_writes_lock:Protect the pending_writes list.
 * @copy_buffers:	List ob buffers to use to read this chunk from the
 *			original.
 * @snap_io_list:	List of async_snap_io's that will write this chunk to
 *			the snapshots.
 * @org_pending_io_list:List of async_org_io's to be processed by the thread.
 *			For each of these, the thread will process the contents
 *			of the pending_writes list.
 * @copy_count:		Number of snapshots remaining to write this chunk.
 * @ref_count:		= copy_count + 1. Needed to determine when the entire
 *			async I/O structure can be deallocated.
 * @dev:		Copy of the b_rdev field for this volume. Needed in
 *			order to tell EVMS about pending I/Os.
 */
struct async_org_io {
	struct snapshot_volume	* org_volume;
	struct buffer_head	* pending_writes;
	spinlock_t		pending_writes_lock;
	struct snap_io_buffer	* copy_buffers;
	struct async_snap_io	* snap_io_list;
	struct list_head	org_pending_io_list;
	atomic_t		copy_count;
	atomic_t		ref_count;
#ifdef SNAPSHOT_DEBUG
	struct async_org_io	* debug_next_org_io;
#endif
	kdev_t			dev;
};

#define ORG_PENDING_IO_ENTRY(lh)	list_entry((lh), \
						struct async_org_io, \
						org_pending_io_list)

/* Debugging code */
#ifdef SNAPSHOT_DEBUG

#define DEBUG_CHECK_SNAP_IO(async_snap_io)			\
	do {							\
		if ( (async_snap_io)->pending_reads ||		\
		     (async_snap_io)->pending_writes ) {	\
			BUG();					\
		}						\
	} while (0);

#define DEBUG_REMOVE_ORG_IO_FROM_LIST(async_org_io)				\
	do {									\
		struct async_org_io ** p_org_io;				\
		unsigned long flags;						\
		if ((async_org_io)->pending_writes) {				\
			BUG();							\
		}								\
		spin_lock_irqsave(&debug_async_org_io_list_lock, flags);	\
		for ( p_org_io = &debug_async_org_io_list; *p_org_io;		\
		      p_org_io = &(*p_org_io)->debug_next_org_io ) {		\
			if ( *p_org_io == (async_org_io) ) {			\
				*p_org_io = (async_org_io)->debug_next_org_io;	\
				break;						\
			}							\
		}								\
		(async_org_io)->debug_next_org_io = NULL;			\
		spin_unlock_irqrestore(&debug_async_org_io_list_lock, flags);	\
	} while (0);

#define DEBUG_ADD_ORG_IO_TO_LIST(async_org_io)					\
	do {									\
		unsigned long flags;						\
		spin_lock_irqsave(&debug_async_org_io_list_lock, flags);	\
		(async_org_io)->debug_next_org_io = debug_async_org_io_list;	\
		debug_async_org_io_list = (async_org_io);			\
		spin_unlock_irqrestore(&debug_async_org_io_list_lock, flags);	\
	} while (0);

#define DEBUG_INC_COW_TABLE_OVERLAPS(snap_volume)	\
	atomic_inc(&(snap_volume)->cow_table_overlaps)

#define DEBUG_INC_COW_TABLE_WRITES(snap_volume)		\
	atomic_inc(&(snap_volume)->cow_table_writes)

#else /* SNAPSHOT_DEBUG */

#define DEBUG_CHECK_SNAP_IO(async_snap_io)
#define DEBUG_REMOVE_ORG_IO_FROM_LIST(async_org_io)
#define DEBUG_ADD_ORG_IO_TO_LIST(async_org_io)
#define DEBUG_INC_COW_TABLE_OVERLAPS(snap_volume)
#define DEBUG_INC_COW_TABLE_WRITES(snap_volume)

#endif /* SNAPSHOT_DEBUG */

#endif /* __EVMS_SNAPSHOT_INCLUDED__ */

