2005-04-17 02:20:36 +04:00
/*
* dm - snapshot . c
*
* Copyright ( C ) 2001 - 2002 Sistina Software ( UK ) Limited .
*
* This file is released under the GPL .
*/
# ifndef DM_SNAPSHOT_H
# define DM_SNAPSHOT_H
# include "dm.h"
2006-10-03 12:15:30 +04:00
# include "dm-bio-list.h"
2005-04-17 02:20:36 +04:00
# include <linux/blkdev.h>
2006-10-03 12:15:30 +04:00
# include <linux/workqueue.h>
2005-04-17 02:20:36 +04:00
struct exception_table {
uint32_t hash_mask ;
struct list_head * table ;
} ;
/*
* The snapshot code deals with largish chunks of the disk at a
* time . Typically 64 k - 256 k .
*/
/* FIXME: can we get away with limiting these to a uint32_t ? */
typedef sector_t chunk_t ;
/*
* An exception is used where an old chunk of data has been
* replaced by a new one .
*/
struct exception {
struct list_head hash_list ;
chunk_t old_chunk ;
chunk_t new_chunk ;
} ;
/*
* Abstraction to handle the meta / layout of exception stores ( the
* COW device ) .
*/
struct exception_store {
/*
* Destroys this object when you ' ve finished with it .
*/
void ( * destroy ) ( struct exception_store * store ) ;
/*
* The target shouldn ' t read the COW device until this is
* called .
*/
int ( * read_metadata ) ( struct exception_store * store ) ;
/*
* Find somewhere to store the next exception .
*/
int ( * prepare_exception ) ( struct exception_store * store ,
struct exception * e ) ;
/*
* Update the metadata with this exception .
*/
void ( * commit_exception ) ( struct exception_store * store ,
struct exception * e ,
void ( * callback ) ( void * , int success ) ,
void * callback_context ) ;
/*
* The snapshot is invalid , note this in the metadata .
*/
void ( * drop_snapshot ) ( struct exception_store * store ) ;
/*
* Return how full the snapshot is .
*/
void ( * fraction_full ) ( struct exception_store * store ,
sector_t * numerator ,
sector_t * denominator ) ;
struct dm_snapshot * snap ;
void * context ;
} ;
struct dm_snapshot {
struct rw_semaphore lock ;
struct dm_table * table ;
struct dm_dev * origin ;
struct dm_dev * cow ;
/* List of snapshots per Origin */
struct list_head list ;
/* Size of data blocks saved - must be a power of 2 */
chunk_t chunk_size ;
chunk_t chunk_mask ;
chunk_t chunk_shift ;
/* You can't use a snapshot if this is 0 (e.g. if full) */
int valid ;
2006-02-01 14:04:50 +03:00
/* Origin writes don't trigger exceptions until this is set */
int active ;
2005-04-17 02:20:36 +04:00
/* Used for display of table */
char type ;
/* The last percentage we notified */
int last_percent ;
struct exception_table pending ;
struct exception_table complete ;
2006-10-03 12:15:30 +04:00
/*
* pe_lock protects all pending_exception operations and access
* as well as the snapshot_bios list .
*/
spinlock_t pe_lock ;
2005-04-17 02:20:36 +04:00
/* The on disk metadata handler */
struct exception_store store ;
struct kcopyd_client * kcopyd_client ;
2006-10-03 12:15:30 +04:00
/* Queue of snapshot writes for ksnapd to flush */
struct bio_list queued_bios ;
struct work_struct queued_bios_work ;
2005-04-17 02:20:36 +04:00
} ;
/*
* Used by the exception stores to load exceptions hen
* initialising .
*/
int dm_add_exception ( struct dm_snapshot * s , chunk_t old , chunk_t new ) ;
/*
* Constructor and destructor for the default persistent
* store .
*/
2006-10-03 12:15:25 +04:00
int dm_create_persistent ( struct exception_store * store ) ;
2005-04-17 02:20:36 +04:00
2006-10-03 12:15:25 +04:00
int dm_create_transient ( struct exception_store * store ) ;
2005-04-17 02:20:36 +04:00
/*
* Return the number of sectors in the device .
*/
static inline sector_t get_dev_size ( struct block_device * bdev )
{
return bdev - > bd_inode - > i_size > > SECTOR_SHIFT ;
}
static inline chunk_t sector_to_chunk ( struct dm_snapshot * s , sector_t sector )
{
return ( sector & ~ s - > chunk_mask ) > > s - > chunk_shift ;
}
static inline sector_t chunk_to_sector ( struct dm_snapshot * s , chunk_t chunk )
{
return chunk < < s - > chunk_shift ;
}
static inline int bdev_equal ( struct block_device * lhs , struct block_device * rhs )
{
/*
* There is only ever one instance of a particular block
* device so we can compare pointers safely .
*/
return lhs = = rhs ;
}
# endif