--- /dev/null
+#ifndef __LINUX_SNAPFS_H
+#define __LINUX_SNAPFS_H
+/* maximum number of snapshot tables we maintain in the kernel */
+#define SNAP_MAX_TABLES 32
+#define SNAP_MAX_NAMELEN 64
+
+/* ioctls for manipulating snapshots 40 - 60 */
+#define IOC_SNAP_TYPE 'f'
+#define IOC_SNAP_MIN_NR 41
+
+#define IOC_SNAP_SETTABLE _IOWR('f', 41, long)
+#define IOC_SNAP_PRINTTABLE _IOWR('f', 42, long)
+#define IOC_SNAP_GETINDEXFROMNAME _IOWR('f', 43, long)
+#define IOC_SNAP_GET_NEXT_INO _IOWR('f', 44, long)
+#define IOC_SNAP_GET_INO_INFO _IOWR('f', 45, long)
+
+#define IOC_SNAP_ADD _IOWR('f', 46, long)
+#define IOC_SNAP_DELETE _IOWR('f', 47, long)
+#define IOC_SNAP_RESTORE _IOWR('f', 48, long)
+#define IOC_SNAP_DEBUG _IOWR('f', 49, long)
+#define IOC_SNAP_DEVFAIL _IOWR('f', 50, long)
+#define IOC_SNAP_SHOW_DOTSNAP _IOWR('f', 51, long)
+
+#define IOC_SNAP_MAX_NR 51
+
+
+struct snap {
+ time_t time;
+ unsigned int index;
+ unsigned int gen;
+ unsigned int flags;
+ char name[SNAP_MAX_NAMELEN];
+};
+
+/* snap ioctl data for table fiddling */
+struct snap_table_data {
+ int tblcmd_no; /* which table */
+ unsigned long dev;
+ unsigned int tblcmd_count; /* how many snaps */
+ struct snap tblcmd_snaps[0]; /* sorted times! */
+};
+
+/* we have just a single snapshot control device
+ it contains a list of all the snap_current info's
+*/
+#define SNAPDEV_NAME "/dev/snapconf"
+#define SNAP_PSDEV_MINOR 240
+#define SNAP_PSDEV_MAJOR 10
+
+#ifdef __KERNEL__
+
+#if 0
+#include <linux/lustre_lib.h>
+#else
+#include "snapfs_support.h"
+#endif
+/* What we use to point to IDs in the obdmd data for snapshots. If we use
+ * obd_id (8 bytes) instead of ino_t (4 bytes), we halve the number of
+ * available snapshot slots (14 in 56 bytes vs. 7 in 56 bytes until we
+ * increase the size of OBD_OBDMDSZ).
+ */
+typedef ino_t snap_id;
+
+
+/* maximum number of snapshots per device
+ must fit in "o_obdmd" area of struct obdo */
+//#define OBD_OBDMDSZ 54
+//#define SNAP_MAX ((OBD_OBDMDSZ - sizeof(uint32_t))/sizeof(snap_id))
+
+#define SNAP_MAX 50
+
+
+/* if time is 0 this designates the "current" snapshot, i.e.
+ the head of the tree
+*/
+
+/* sysctl.c */
+extern int init_snapfs_proc_sys(void);
+extern void cleanup_spapfs_proc_sys(void);
+extern int snap_print_entry;
+extern int snap_debug_level;
+extern int snap_inodes;
+extern long snap_kmemory;
+extern int snap_stack;
+
+/* snap cache information: this morally equals the superblock of a
+ snap_current_fs. However, that superblock is the one of the "cache"
+ device holding the inodes, hence we store this info in the hash of
+ mountpoints hanging of our control device.
+*/
+struct snap_cache {
+ struct list_head cache_chain;
+
+ kdev_t cache_dev;
+ struct super_block *cache_sb; /* the _real_ device */
+
+ struct list_head cache_clone_list;
+ int cache_snap_tableno;
+
+ struct filter_fs *cache_filter;
+
+ char cache_type;
+ char cache_show_dotsnap;
+};
+
+/* this is the snap_clone_info for the sb of snap_clone_fs */
+struct snap_clone_info {
+ struct snap_cache *clone_cache;
+ struct list_head clone_list_entry;
+ int clone_index;
+};
+
+/*
+ * it is important that things like inode, super and file operations
+ * for intermezzo are not defined statically. If methods are NULL
+ * the VFS takes special action based on that. Given that different
+ * cache types have NULL ops at different slots, we must install opeation
+ * talbes for InterMezzo with NULL's in the same spot
+ */
+
+struct filter_ops {
+ /* operations on the file store */
+ struct super_operations filter_sops;
+
+ struct inode_operations filter_dir_iops;
+ struct inode_operations filter_file_iops;
+ struct inode_operations filter_sym_iops;
+
+ struct file_operations filter_dir_fops;
+ struct file_operations filter_file_fops;
+ struct file_operations filter_sym_fops;
+
+ struct address_space_operations filter_file_aops;
+ struct dentry_operations filter_dentry_ops;
+};
+
+
+struct cache_ops {
+ /* operations on the file store */
+ struct super_operations *cache_sops;
+
+ struct inode_operations *cache_dir_iops;
+ struct inode_operations *cache_file_iops;
+ struct inode_operations *cache_sym_iops;
+
+ struct file_operations *cache_dir_fops;
+ struct file_operations *cache_file_fops;
+ struct file_operations *cache_sym_fops;
+
+ struct address_space_operations *cache_file_aops;
+ struct dentry_operations *cache_dentry_ops;
+};
+
+
+#define SNAP_OP_NOOP 0
+#define SNAP_OP_CREATE 1
+#define SNAP_OP_MKDIR 2
+#define SNAP_OP_UNLINK 3
+#define SNAP_OP_RMDIR 4
+#define SNAP_OP_CLOSE 5
+#define SNAP_OP_SYMLINK 6
+#define SNAP_OP_RENAME 7
+#define SNAP_OP_SETATTR 8
+#define SNAP_OP_LINK 9
+#define SNAP_OP_OPEN 10
+#define SNAP_OP_MKNOD 11
+#define SNAP_OP_WRITE 12
+#define SNAP_OP_RELEASE 13
+
+struct journal_ops {
+ void *(*trans_start)(struct inode *, int op);
+ void (*trans_commit)(void *handle);
+};
+
+struct snap_control_device {
+ struct list_head snap_dev_list;
+};
+
+#define D_MAXLEN 1024
+
+#define SNAPSHOT_UNUSED_FLAG (1 << 0)
+#define SNAPSHOT_GOOD_FLAG (1 << 1)
+#define SNAPSHOT_DELETING_FLAG (1 << 2)
+#define SNAPSHOT_BAD_FLAG (1 << 3)
+
+struct snap_disk {
+ __u64 time;
+ __u32 gen;
+ __u32 index;
+ __u32 flags;
+ char name[SNAP_MAX_NAMELEN];
+};
+/* snap ioctl data for attach: current always in first slot of this array */
+struct snap_obd_data {
+ int snap_dev; /* which device contains the data */
+ unsigned int snap_index;/* which snapshot is ours */
+ unsigned int snap_table;/* which table do we use */
+};
+
+struct snap_table {
+ struct semaphore tbl_sema;
+ spinlock_t tbl_lock;
+ unsigned int tbl_count; /* how many snapshots exist in this table*/
+ unsigned int generation;
+ struct snap snap_items[SNAP_MAX];
+};
+#define DISK_SNAPTABLE_ATTR "Snaptable"
+#define DISK_SNAP_TABLE_MAGIC 0x1976
+struct snap_disk_table {
+ unsigned int magic;
+ unsigned int count;
+ unsigned int generation;
+ struct snap_disk snap_items[SNAP_MAX];
+};
+
+struct snap_iterdata {
+ kdev_t dev; /* snap current device number */
+ int index;
+ int tableno;
+ time_t time;
+};
+
+struct snap_ioc_data {
+ kdev_t dev;
+ char name[SNAP_MAX_NAMELEN];
+};
+
+struct snap_ino_list_data{
+ kdev_t dev;
+ ino_t ino;
+};
+struct filter_inode_info {
+ int flags; /* the flags indicated inode type */
+ int generation; /*the inode generation*/
+};
+/* dotsnap.c */
+extern int currentfs_is_under_dotsnap(struct dentry *de);
+
+/* cache.c */
+inline void snap_free_cache(struct snap_cache *cache);
+struct snap_cache *snap_find_cache(kdev_t dev);
+
+/* snaptable.c */
+extern struct snap_table snap_tables[SNAP_MAX_TABLES];
+void snap_last(struct snap_cache *info, struct snap *snap);
+int snap_index2slot(struct snap_table *snap_table, int snap_index);
+int snap_needs_cow(struct inode *);
+int snapfs_read_snaptable(struct snap_cache *cache, int tableno);
+/* snap.c */
+int snap_is_redirector(struct inode *inode);
+struct inode *snap_redirect(struct inode *inode, struct super_block *clone_sb);
+int snap_do_cow(struct inode *inode, ino_t parent_ino, int del);
+
+int snap_iterate(struct super_block *sb,
+ int (*repeat)(struct inode *inode, void *priv),
+ struct inode **start, void *priv, int flag);
+
+struct inode *snap_get_indirect(struct inode *pri, int *table, int slot);
+int snap_destroy_indirect(struct inode *pri, int index, struct inode *next_ind);
+int snap_restore_indirect(struct inode *pri, int index );
+int snap_migrate_data(struct inode *dst, struct inode *src);
+int snap_set_indirect(struct inode *pri, ino_t ind_ino,
+ int index, ino_t parent_ino);
+
+/* inode.c */
+extern struct super_operations currentfs_super_ops;
+void cleanup_filter_info_cache(void);
+int init_filter_info_cache(void);
+void init_filter_data(struct inode *inode, struct snapshot_operations *snapops,
+ int flag);
+
+/* dir.c */
+extern struct inode_operations currentfs_dir_iops;
+extern struct file_operations currentfs_dir_fops;
+extern struct address_space_operations currentfs_file_aops;
+
+/* file.c */
+extern struct inode_operations currentfs_file_iops;
+extern struct file_operations currentfs_file_fops;
+
+/* symlink.c */
+extern struct inode_operations currentfs_sym_iops;
+extern struct file_operations currentfs_sym_fops;
+
+extern struct dentry_operations currentfs_dentry_ops;
+
+
+
+#define FILTER_DID_SUPER_OPS 0x1
+#define FILTER_DID_INODE_OPS 0x2
+#define FILTER_DID_FILE_OPS 0x4
+#define FILTER_DID_DENTRY_OPS 0x8
+#define FILTER_DID_DEV_OPS 0x10
+#define FILTER_DID_SYMLINK_OPS 0x20
+#define FILTER_DID_DIR_OPS 0x40
+#define FILTER_DID_SNAPSHOT_OPS 0x80
+#define FILTER_DID_JOURNAL_OPS 0x100
+
+struct filter_fs {
+ int o_flags;
+ struct filter_ops o_fops;
+ struct cache_ops o_caops;
+ struct journal_ops *o_trops;
+ struct snapshot_operations *o_snapops;
+};
+
+#define FILTER_FS_TYPES 3
+#define FILTER_FS_EXT2 0
+#define FILTER_FS_EXT3 1
+#define FILTER_FS_REISER 2
+extern struct filter_fs filter_oppar[FILTER_FS_TYPES];
+
+struct filter_fs *filter_get_filter_fs(const char *cache_type);
+inline struct super_operations *filter_c2usops(struct filter_fs *cache);
+inline struct inode_operations *filter_c2ufiops(struct filter_fs *cache);
+inline struct inode_operations *filter_c2udiops(struct filter_fs *cache);
+inline struct inode_operations *filter_c2usiops(struct filter_fs *cache);
+inline struct super_operations *filter_c2csops(struct filter_fs *cache);
+inline struct inode_operations *filter_c2cfiops(struct filter_fs *cache);
+inline struct inode_operations *filter_c2cdiops(struct filter_fs *cache);
+inline struct inode_operations *filter_c2csiops(struct filter_fs *cache);
+inline struct file_operations *filter_c2cffops(struct filter_fs *cache);
+inline struct file_operations *filter_c2cdfops(struct filter_fs *cache);
+inline struct file_operations *filter_c2csfops(struct filter_fs *cache);
+inline struct dentry_operations *filter_c2cdops(struct filter_fs *cache);
+inline struct dentry_operations *filter_c2udops(struct filter_fs *cache);
+inline struct address_space_operations *filter_c2cfaops(struct filter_fs *cache);
+/* for snapfs */
+inline struct snapshot_operations *filter_c2csnapops(struct filter_fs *cache);
+
+void filter_setup_file_ops(struct filter_fs *cache,
+ struct inode *inode,
+ struct inode_operations *filter_iops,
+ struct file_operations *filter_fops,
+ struct address_space_operations *filter_aops);
+
+void filter_setup_dir_ops(struct filter_fs *cache,
+ struct inode *inode,
+ struct inode_operations *filter_iops,
+ struct file_operations *filter_fops);
+
+void filter_setup_symlink_ops(struct filter_fs *cache,
+ struct inode *inode,
+ struct inode_operations *filter_iops,
+ struct file_operations *filter_fops);
+
+void filter_setup_dentry_ops(struct filter_fs *cache,
+ struct dentry_operations *cache_dop,
+ struct dentry_operations *filter_dop);
+void filter_setup_super_ops(struct filter_fs *cache,
+ struct super_operations *cache_sops,
+ struct super_operations *filter_sops);
+/* for snapfs */
+void filter_setup_snapshot_ops(struct filter_fs *cache,
+ struct snapshot_operations *cache_snapops);
+void filter_setup_journal_ops(struct filter_fs *cache,
+ struct journal_ops *cache_journal_ops);
+
+static inline void* snap_trans_start(struct snap_cache *cache,
+ struct inode *inode, int op)
+{
+ if( cache->cache_filter->o_trops )
+ return cache->cache_filter->o_trops->trans_start(inode, op);
+ return NULL;
+};
+static inline void snap_trans_commit(struct snap_cache *cache, void *handle)
+{
+ if( cache->cache_filter->o_trops )
+ cache->cache_filter->o_trops->trans_commit(handle);
+};
+
+static inline void snapfs_cpy_attrs(struct inode *dst, struct inode *src)
+{
+ dst->i_mtime = src->i_mtime;
+ dst->i_ctime = src->i_ctime;
+ dst->i_atime = src->i_atime;
+ dst->i_size = src->i_size;
+ dst->i_blksize = src->i_blksize;
+ dst->i_blocks = src->i_blocks;
+ dst->i_generation = src->i_generation;
+ dst->i_uid = src->i_uid;
+ dst->i_gid = src->i_gid;
+ dst->i_mode = src->i_mode;
+}
+#ifdef SNAP_DEBUG
+extern unsigned int snap_debug_failcode;
+#ifdef CONFIG_LOOP_DISCARD
+#define BLKDEV_FAIL(dev,fail) loop_discard_io(dev,fail)
+#else
+#define BLKDEV_FAIL(dev,fail) set_device_ro(dev, 1)
+#endif
+
+static inline void snap_debug_device_fail(dev_t dev, unsigned short opcode, unsigned short pos)
+{
+ unsigned int failcode = (opcode<<16) | pos;
+
+ if( failcode == snap_debug_failcode && !is_read_only(dev)){
+ printk(KERN_EMERG "set block device %s into fail mode\n", bdevname(dev));
+ BLKDEV_FAIL(dev, 1);
+ }
+}
+#else
+#define snap_debug_device_fail(args...) do{}while(0)
+#endif
+
+extern int snap_debug_level;
+extern int snap_print_entry;
+
+#endif /*_KERNEL_*/
+#endif /* __LINUX_SNAPFS_H */
--- /dev/null
+/*Got these defination from lustre*/
+#define S_SNAP (1 << 0)
+
+#define D_TRACE (1 << 0) /* ENTRY/EXIT markers */
+#define D_INODE (1 << 1)
+#define D_SUPER (1 << 2)
+#define D_EXT2 (1 << 3) /* anything from ext2_debug */
+#define D_MALLOC (1 << 4) /* print malloc, free information */
+#define D_CACHE (1 << 5) /* cache-related items */
+#define D_INFO (1 << 6) /* general information */
+#define D_IOCTL (1 << 7) /* ioctl related information */
+#define D_BLOCKS (1 << 8) /* ext2 block allocation */
+#define D_NET (1 << 9) /* network communications */
+#define D_WARNING (1 << 10) /* CWARN(...) == CDEBUG (D_WARNING, ...) */
+#define D_BUFFS (1 << 11)
+#define D_OTHER (1 << 12)
+#define D_DENTRY (1 << 13)
+#define D_PAGE (1 << 15) /* bulk page handling */
+#define D_DLMTRACE (1 << 16)
+#define D_ERROR (1 << 17) /* CERROR(...) == CDEBUG (D_ERROR, ...) */
+#define D_EMERG (1 << 18) /* CEMERG(...) == CDEBUG (D_EMERG, ...) */
+#define D_HA (1 << 19) /* recovery and failover */
+#define D_RPCTRACE (1 << 20) /* for distributed debugging */
+#define D_VFSTRACE (1 << 21)
+#define D_SNAP (1 << 22)
+
+#ifdef __KERNEL__
+# include <linux/sched.h> /* THREAD_SIZE */
+#else
+# ifndef THREAD_SIZE /* x86_64 has THREAD_SIZE in userspace */
+# define THREAD_SIZE 8192
+# endif
+#endif
+
+# include <linux/vmalloc.h>
+# define snap_debug_msg(mask, file, fn, line, stack, format, a...) \
+ printk("%02x (@%lu %s:%s,l. %d %d %lu): " format, \
+ (mask), (long)time(0), file, fn, line, \
+ getpid() , stack, ## a);
+
+#define LUSTRE_TRACE_SIZE (THREAD_SIZE >> 5)
+
+#ifdef __KERNEL__
+# ifdef __ia64__
+# define CDEBUG_STACK (THREAD_SIZE - \
+ ((unsigned long)__builtin_dwarf_cfa() & \
+ (THREAD_SIZE - 1)))
+# else
+# define CDEBUG_STACK (THREAD_SIZE - \
+ ((unsigned long)__builtin_frame_address(0) & \
+ (THREAD_SIZE - 1)))
+# endif
+
+#define CHECK_STACK(stack) \
+ do { \
+ if ((stack) > 3*THREAD_SIZE/4 && (stack) > snap_stack) { \
+ printk( "maximum lustre stack %u\n", \
+ snap_stack = (stack)); \
+ } \
+ } while (0)
+#else /* __KERNEL__ */
+#define CHECK_STACK(stack) do { } while(0)
+#define CDEBUG_STACK (0L)
+#endif /* __KERNEL__ */
+
+#if 1
+#define CDEBUG(mask, format, a...) \
+do { \
+ CHECK_STACK(CDEBUG_STACK); \
+ if (!(mask) || ((mask) & (D_ERROR | D_EMERG | D_WARNING)) || \
+ (snap_debug_level & (mask))) \
+ printk(format, ## a); \
+} while (0)
+
+#define CWARN(format, a...) CDEBUG(D_WARNING, format, ## a)
+#define CERROR(format, a...) CDEBUG(D_ERROR, format, ## a)
+#define CEMERG(format, a...) CDEBUG(D_EMERG, format, ## a)
+
+#define GOTO(label, rc) \
+do { \
+ long GOTO__ret = (long)(rc); \
+ CDEBUG(D_TRACE,"Process leaving via %s (rc=%lu : %ld : %lx)\n", \
+ #label, (unsigned long)GOTO__ret, (signed long)GOTO__ret,\
+ (signed long)GOTO__ret); \
+ goto label; \
+} while (0)
+
+#define RETURN(rc) \
+do { \
+ typeof(rc) RETURN__ret = (rc); \
+ CDEBUG(D_TRACE, "Process %d leaving %s (rc=%lu : %ld : %lx)\n", \
+ current->pid, __FUNCTION__, (long)RETURN__ret, \
+ (long)RETURN__ret, (long)RETURN__ret); \
+ return RETURN__ret; \
+} while (0)
+
+#define ENTRY \
+do { \
+ CDEBUG(D_TRACE, "Process %d enter %s\n", \
+ current->pid, __FUNCTION__); \
+} while (0)
+
+#define EXIT \
+do { \
+ CDEBUG(D_TRACE, "Process %d leaving %s \n", \
+ current->pid, __FUNCTION__); \
+} while(0)
+#else
+#define CDEBUG(mask, format, a...) do { } while (0)
+#define CWARN(format, a...) do { } while (0)
+#define CERROR(format, a...) printk("<3>" format, ## a)
+#define CEMERG(format, a...) printk("<0>" format, ## a)
+#define GOTO(label, rc) do { (void)(rc); goto label; } while (0)
+#define RETURN(rc) return (rc)
+#define ENTRY do { } while (0)
+#define EXIT do { } while (0)
+#endif
+
+#define SNAP_ALLOC(ptr, size) \
+do { \
+ if (size <= 4096) { \
+ ptr = kmalloc((unsigned long) size, GFP_KERNEL); \
+ CDEBUG(D_MALLOC, "Proc %d %s:%d kmalloced: %d at %x.\n",\
+ current->pid, __FUNCTION__, __LINE__, \
+ (int) size, (int) ptr); \
+ } else { \
+ ptr = vmalloc((unsigned long) size); \
+ CDEBUG(D_MALLOC, "Proc %d %s:%d vmalloced: %d at %x.\n",\
+ current->pid, __FUNCTION__, __LINE__, \
+ (int) size, (int) ptr); \
+ } \
+ if (ptr == 0) { \
+ printk("kernel malloc returns 0 at %s:%d\n", \
+ __FILE__, __LINE__); \
+ } else { \
+ memset(ptr, 0, size); \
+ snap_kmemory += size; \
+ } \
+} while (0)
+
+#define SNAP_FREE(ptr,size) \
+do { \
+ snap_kmemory -= size; \
+ if (size <= 4096) { \
+ CDEBUG(D_MALLOC, "Proc %d %s:%d kfreed: %d at %x.\n", \
+ current->pid, __FUNCTION__, __LINE__, \
+ (int) size, (int) ptr); \
+ kfree((ptr)); \
+ } else { \
+ CDEBUG(D_MALLOC, "Proc %d %s:%d vfreed: %d at %x.\n", \
+ current->pid, __FUNCTION__, __LINE__, \
+ (int) size, (int) ptr); \
+ vfree((ptr)); \
+ } \
+} while (0)
+