diff --git a/lnet/utils/debug.c b/lnet/utils/debug.c
index 67d8edc09b5ed0dd8a72c356316f4efc1d021000..9ce7528887980a9d53deb10816b94d6a969d63fc 100644
--- a/lnet/utils/debug.c
+++ b/lnet/utils/debug.c
@@ -545,9 +545,11 @@ static struct mod_paths {
         {"lov", "lustre/lov"},
         {"lmv", "lustre/lmv"},
         {"fsfilt_ext3", "lustre/lvfs"},
+        {"fsfilt_snap_ext3", "lustre/lvfs"},
         {"fsfilt_extN", "lustre/lvfs"},
         {"fsfilt_reiserfs", "lustre/lvfs"},
         {"fsfilt_smfs", "lustre/lvfs"},
+        {"fsfilt_snap_smfs", "lustre/lvfs"},
         {"ptlbd", "lustre/ptlbd"},
         {"mgmt_svc", "lustre/mgmt"},
         {"mgmt_cli", "lustre/mgmt"},
diff --git a/lustre/Makefile.in b/lustre/Makefile.in
index 311435df956720f41ce729c225dc05ec13ac2920..7a9e4600f3cefaecdb3941b738bb8aa983a5f4ee 100644
--- a/lustre/Makefile.in
+++ b/lustre/Makefile.in
@@ -23,6 +23,5 @@ ifeq ($(PATCHLEVEL),4)
 subdir-m += ptlbd
 endif # PATCHLEVEL = 4
 
-@SNAPFS_TRUE@subdir-m += snapfs
 
 @INCLUDE_RULES@
diff --git a/lustre/autoMakefile.am b/lustre/autoMakefile.am
index a664117842937c9287a7b29a812e9258708ff076..a706178ecdcc07185d8b15291b676cab3c6335aa 100644
--- a/lustre/autoMakefile.am
+++ b/lustre/autoMakefile.am
@@ -6,7 +6,7 @@
 AUTOMAKE_OPTIONS = foreign
 
 SUBDIRS = . include portals ldiskfs lvfs obdclass lov ldlm ptlrpc      \
-	obdecho osc mdc lmv  mds obdfilter ost llite cobd ptlbd snapfs smfs cmobd \
+	obdecho osc mdc lmv  mds obdfilter ost llite cobd ptlbd smfs cmobd \
 	liblustre doc utils tests conf scripts
 
 EXTRA_DIST = BUGS FDL Rules.in kernel_patches kernel-tests/Makefile    \
diff --git a/lustre/configure.in b/lustre/configure.in
index d6672708fb16f3731011e974681cb1e1af5c9007..762e4893dbf6b7e419f2006990f70e31e57830a1 100644
--- a/lustre/configure.in
+++ b/lustre/configure.in
@@ -143,8 +143,12 @@ AC_ARG_ENABLE([snapfs],
 	AC_HELP_STRING([--enable-snapfs],
 			[build snapfs]),
 	[],[enable_snapfs='no'])
+
 AC_MSG_RESULT([$enable_snapfs])
 AM_CONDITIONAL(SNAPFS, test x$enable_snapfs = xyes)
+if test x$enable_snapfs = xyes ; then
+	AC_DEFINE(CONFIG_SNAPFS, 1, [enable snap support])
+fi
 
 sinclude(portals/build.m4)
 sinclude(portals/archdep.m4)
@@ -239,9 +243,6 @@ scripts/lustre.spec
 scripts/version_tag.pl
 smfs/Makefile
 smfs/autoMakefile
-snapfs/Makefile
-snapfs/autoMakefile
-snapfs/utils/Makefile
 cmobd/Makefile
 cmobd/autoMakefile
 tests/Makefile
diff --git a/lustre/include/linux/lustre_fsfilt.h b/lustre/include/linux/lustre_fsfilt.h
index 43c3123bdb10030cdc7264e283a91f26a59736dc..204004ea408262b01a5b3c4b2096a10c6aa6a3ca 100644
--- a/lustre/include/linux/lustre_fsfilt.h
+++ b/lustre/include/linux/lustre_fsfilt.h
@@ -58,8 +58,8 @@ struct fsfilt_operations {
         int     (* fs_iocontrol)(struct inode *inode, struct file *file,
                                  unsigned int cmd, unsigned long arg);
         int     (* fs_set_md)(struct inode *inode, void *handle, void *md,
-                              int size);
-        int     (* fs_get_md)(struct inode *inode, void *md, int size);
+                              int size, int flags);
+        int     (* fs_get_md)(struct inode *inode, void *md, int size, int flags);
 
         /* this method is needed to make IO operation fsfilt nature depend. */
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
@@ -126,6 +126,32 @@ struct fsfilt_operations {
                                      char *, int, unsigned long, unsigned long,
                                      unsigned);
         int     (* fs_del_dir_entry)(struct obd_device *, struct dentry *);
+        /*snap operations*/
+        int     (* fs_is_redirector)(struct inode *inode);
+        int     (* fs_is_indirect)(struct inode *inode);
+        
+        struct inode * (* fs_create_indirect)(struct inode *pri, int index,
+                                              unsigned int gen, struct inode *parent,
+                                              int del);
+        struct inode * (* fs_get_indirect)(struct inode *pri, int *table,
+                                          int slot);
+        ino_t   (* fs_get_indirect_ino)(struct inode *pri, int index);
+        int     (* fs_destroy_indirect)(struct inode *pri, int index,
+                                        struct inode *next_ind);
+        int     (* fs_restore_indirect)(struct inode *pri, int index);
+        int     (* fs_iterate)(struct super_block *sb,
+                              int (*repeat)(struct inode *inode, void *priv),
+                              struct inode **start, void *priv, int flag);
+        int     (* fs_copy_block)(struct inode *dst, struct inode *src, int blk);
+        int     (* fs_set_indirect)(struct inode *pri, int index,
+                                    ino_t ind_ino, ino_t parent_ino);
+        int     (* fs_snap_feature)(struct super_block *sb, int feature, int op);
+        int     (* fs_set_snap_info)(struct super_block *sb, struct inode *inode, 
+                                     void* key, __u32 keylen, void *val, 
+                                     __u32 *vallen); 
+        int     (* fs_get_snap_info)(struct super_block *sb, struct inode *inode,
+                                     void* key, __u32 keylen, void *val, 
+                                     __u32 *vallen); 
 };
 
 extern int fsfilt_register_ops(struct fsfilt_operations *fs_ops);
@@ -175,6 +201,10 @@ extern void fsfilt_put_ops(struct fsfilt_operations *fs_ops);
 #define KML_CACHE_LINK          0x39
 #define KML_CACHE_NOOP          0x3f
 
+/*for fsfilt set md ea*/
+#define LMV_EA  1
+#define LOV_EA  0
+
 static inline void *
 fsfilt_start_ops(struct fsfilt_operations *ops, struct inode *inode,
                  int op, struct obd_trans_info *oti, int logs)
@@ -335,19 +365,18 @@ static inline int fsfilt_setup(struct obd_device *obd,
                 return obd->obd_fsops->fs_setup(obd, fs);
         return 0;
 }
-
 static inline int
 fsfilt_set_md(struct obd_device *obd, struct inode *inode,
-              void *handle, void *md, int size)
+              void *handle, void *md, int size, int flags)
 {
-        return obd->obd_fsops->fs_set_md(inode, handle, md, size);
+        return obd->obd_fsops->fs_set_md(inode, handle, md, size, flags);
 }
 
 static inline int
 fsfilt_get_md(struct obd_device *obd, struct inode *inode,
-              void *md, int size)
+              void *md, int size, int flags)
 {
-        return obd->obd_fsops->fs_get_md(inode, md, size);
+        return obd->obd_fsops->fs_get_md(inode, md, size, flags);
 }
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
diff --git a/lustre/include/linux/lustre_smfs.h b/lustre/include/linux/lustre_smfs.h
index dfa3096ccf89d4779447203321b050802f1a4fb2..738eb6fc637a6898221d0a0bfb4a03bb0c3bb5f3 100644
--- a/lustre/include/linux/lustre_smfs.h
+++ b/lustre/include/linux/lustre_smfs.h
@@ -1,9 +1,40 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001-2003 Cluster File Systems, Inc. <info@clusterfs.com>
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   Lustre is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   Lustre 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 Lustre; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   smfs data structures.
+ *   See also lustre_idl.h for wire formats of requests.
+ *
+ */
+
 #ifndef __LUSTRE_SMFS_H
 #define __LUSTRE_SMFS_H
 
+struct snap_inode_info {
+	int sn_flags;		/* the flags indicated inode type */
+	int sn_gen; 	        /*the inode generation*/
+};
+
 struct smfs_inode_info {
         struct inode *smi_inode;
         __u32  smi_flags;
+	struct snap_inode_info sm_sninfo;
 };
 
 struct journal_operations {
@@ -40,6 +71,7 @@ struct mds_kml_pack_info {
         int mpi_size[4];
         int mpi_total_size;
 };
+
 struct smfs_super_info {
         struct super_block       *smsi_sb;
         struct vfsmount          *smsi_mnt;         /* mount the cache kern */
@@ -54,9 +86,10 @@ struct smfs_super_info {
         char                     *smsi_cache_ftype; /* cache file system type */
         char                     *smsi_ftype;       /* file system type */
 	struct obd_export	 *smsi_exp;	    /* file system obd exp */
-        smfs_pack_rec_func   smsi_pack_rec[PACK_MAX]; /* sm_pack_rec type ops */
-        __u32                     smsi_flags;       /* flags */
-        __u32                     smsi_ops_check;
+	struct snap_info	 *smsi_snap_info;    /* snap table cow */
+        smfs_pack_rec_func   	 smsi_pack_rec[PACK_MAX]; /* sm_pack_rec type ops */
+        __u32                    smsi_flags;       /* flags */
+        __u32                    smsi_ops_check;
 };
 
 #define SMFS_FILE_TYPE "smfs"
@@ -104,6 +137,9 @@ struct fs_extent{
                         (inode->i_sb->s_fs_info))->sm_cache_fsfilt)
 #endif
 
+#define I2SNAPOPS(inode) ((S2SMI(inode->i_sb))->smsi_snap_info->snap_cache_fsfilt) 
+
+#define S2SNAPI(sb) (S2SMI(sb)->smsi_snap_info)
 #define F2SMFI(file) ((struct smfs_file_info *)((file->private_data)))
 #define F2CF(file) (((struct smfs_file_info *) ((file->private_data)))->c_file)
 #define SIZE2BLKS(size, inode) ((size + (I2CI(inode)->i_blksize)) >> (I2CI(inode)->i_blkbits))
@@ -113,7 +149,8 @@ struct fs_extent{
 #define SM_INIT_REC             0x2
 #define SM_CACHE_HOOK           0x4
 #define SM_OVER_WRITE           0x8
-#define SM_DIRTY_WRITE         0x10
+#define SM_DIRTY_WRITE          0x10
+#define SM_DO_COW         	0x20
 
 #define SMFS_DO_REC(smfs_info) (smfs_info->smsi_flags & SM_DO_REC)
 #define SMFS_SET_REC(smfs_info) (smfs_info->smsi_flags |= SM_DO_REC)
@@ -143,6 +180,13 @@ struct fs_extent{
 #define SMFS_SET_INODE_DIRTY_WRITE(inode) (I2SMI(inode)->smi_flags |= SM_DIRTY_WRITE)
 #define SMFS_CLEAN_INODE_DIRTY_WRITE(inode) (I2SMI(inode)->smi_flags &= ~SM_DIRTY_WRITE)
 
+#define SMFS_DO_COW(smfs_info) (smfs_info->smsi_flags & SM_DO_COW)
+#define SMFS_SET_COW(smfs_info) (smfs_info->smsi_flags |= SM_DO_COW)
+#define SMFS_CLEAN_COW(smfs_info) (smfs_info->smsi_flags &= ~SM_DO_COW)
+
+#define SMFS_SET_INODE_COW(inode) (I2SMI(inode)->smi_flags |= SM_DO_COW)
+#define SMFS_DO_INODE_COW(inode) (I2SMI(inode)->smi_flags & SM_DO_COW)
+#define SMFS_CLEAN_INODE_COW(inode) (I2SMI(inode)->smi_flags &= ~SM_DO_COW)
 
 #define LVFS_SMFS_BACK_ATTR "lvfs_back_attr"
 
@@ -358,7 +402,6 @@ static inline int lookup_by_path(char *path, int flags, struct nameidata *nd)
 }
 
 /*FIXME there should be more conditions in this check*/
-
 static inline int smfs_do_rec(struct inode *inode)
 {
         struct super_block *sb = inode->i_sb;
@@ -369,6 +412,7 @@ static inline int smfs_do_rec(struct inode *inode)
                 return 1;
         return 0;
 }
+
 static inline int smfs_cache_hook(struct inode *inode)
 {
         struct smfs_super_info  *smfs_info = I2CSB(inode);
@@ -379,6 +423,17 @@ static inline int smfs_cache_hook(struct inode *inode)
         else
                 return 0;
 }
+
+static inline int smfs_do_cow(struct inode *inode)
+{
+        struct super_block *sb = inode->i_sb;
+        struct smfs_super_info *smfs_info = S2SMI(sb);
+
+        if (SMFS_DO_COW(smfs_info) && SMFS_DO_INODE_COW(inode))
+                return 1;
+        return 0;
+}
+
 /* XXX BUG 3188 -- must return to one set of opcodes */
 #define SMFS_TRANS_OP(inode, op)                \
 {                                               \
@@ -398,5 +453,7 @@ extern int smfs_rec_precreate(struct dentry *dentry, int *num, struct obdo *oa);
 extern int smfs_rec_md(struct inode *inode, void * lmm, int lmm_size);
 extern int smfs_rec_unpack(struct smfs_proc_args *args, char *record,
                            char **pbuf, int *opcode);
+	
+int smfs_cow(struct inode *dir, struct dentry *dentry, int op);
 
 #endif /* _LUSTRE_SMFS_H */
diff --git a/lustre/include/linux/lustre_snap.h b/lustre/include/linux/lustre_snap.h
new file mode 100644
index 0000000000000000000000000000000000000000..3962a525ef30ccd30c8558e3f9195eb850af8efa
--- /dev/null
+++ b/lustre/include/linux/lustre_snap.h
@@ -0,0 +1,172 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001-2003 Cluster File Systems, Inc. <info@clusterfs.com>
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   Lustre is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   Lustre 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 Lustre; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * SNAP data structures.
+ * See also lustre_idl.h for wire formats of requests.
+ *
+ */
+/* maximum number of snapshots available for users */
+
+#ifndef __LUSTRE_SNAP_H
+#define __LUSTRE_SNAP_H
+
+#define MAX_SNAPS       20
+#define SNAP_ATTR       "@snap"
+struct snap_ea{
+        int   generation;
+        ino_t prev_ino;
+        ino_t next_ino;
+        ino_t ino[MAX_SNAPS+1]; /* including current snapshot */
+        ino_t parent_ino[MAX_SNAPS+1];
+};
+#define MAX_SNAP_DATA (sizeof(struct snap_ea))
+
+/*
+ * Check if the EA @name is Snap EA or not.
+ * Snap EA includes the SNAP_ATTR, SNAP_NEW_INO_ATTR and DISK_SNAP_META_ATTR
+ */
+
+#define IS_SNAP_EA(name) ( (!strcmp((name), SNAP_ATTR)) || 		\
+			   (!strcmp((name), DISK_SNAP_META_ATTR)))
+
+
+/* file system features */
+#define SNAP_FEATURE_COMPAT_SNAPFS              0x0010
+#define SNAP_FEATURE_COMPAT_BLOCKCOW            0x0020
+
+/* constants for snap_feature operations */
+#define SNAP_CLEAR_FEATURE	0x0
+#define SNAP_SET_FEATURE	0x1
+#define SNAP_HAS_FEATURE	0x2
+
+/* snap flags for inode, within 1 byte range, each occupy 1 bit */
+#define SNAP_INO_MAGIC	0x88		/* magic for snap inode */
+#define SNAP_COW_FLAG	0x01		/* snap redirected inode */
+#define SNAP_DEL_FLAG	0x02		/* snap deleted inode */
+#define SNAP_TABLE_FLAG	0x04		/* snap table inode */
+#define SNAP_PRI_FLAG	0x08		/* primary inode */
+
+/* no snapfs attributes for get_indirect_ino */
+#define ENOSNAPATTR	320
+
+/* constants used by iterator */
+#define SNAP_ITERATE_ALL_INODE          0x0
+#define SNAP_ITERATE_COWED_INODE        0x1
+
+/* constants used by create_indirect */
+#define SNAP_CREATE_IND_NORMAL		0x0
+#define	SNAP_CREATE_IND_DEL_PRI		0x1
+
+/* the data structure represent in the xfs_dinode.pad
+	offset  0:	magic	(1 byte)
+	offset	1:	flag	(1 byte)
+	offset	2:	gen	(4 bytes)
+	offset	6:	unused
+ */
+#define SIZEOF_MAGIC		1
+#define SIZEOF_FLAG		1
+#define SIZEOF_GENERATION	4
+
+#define MAGIC_OFFSET		0
+#define FLAG_OFFSET		1
+#define GENERATION_OFFSET	2
+
+#define SNAP_GET_DINODE_MAGIC(dinode)	\
+		(((__u8*)(dinode)->di_pad)[MAGIC_OFFSET])
+#define SNAP_SET_DINODE_MAGIC(dinode)	\
+		((__u8*)(dinode)->di_pad)[MAGIC_OFFSET] = (SNAP_INO_MAGIC)
+#define SNAP_GET_DINODE_FLAG(dinode)	\
+		(((__u8*)(dinode)->di_pad)[FLAG_OFFSET])
+#define SNAP_SET_DINODE_FLAG(dinode, flag)	\
+		(((__u8*)(dinode)->di_pad)[FLAG_OFFSET] |= (flag))
+#define SNAP_CLEAR_DINODE_FLAG(dinode, flag)	\
+		(((__u8*)(dinode)->di_pad)[FLAG_OFFSET] &= ~(flag))
+#define SNAP_GET_DINODE_GEN(dinode)	\
+		(le32_to_cpu(*(__u32*)(&((__u8*)(dinode)->di_pad)[GENERATION_OFFSET])))
+#define SNAP_SET_DINODE_GEN(dinode, gen)	\
+		*(__u32*)(&((__u8*)(dinode)->di_pad)[GENERATION_OFFSET]) = cpu_to_le32(gen)
+#define SNAP_VERSION(a,b,c)             \
+                (((a & 0xFF) << 16) | ((b & 0xFF) << 8) | (c & 0xFF))
+#define SNAP_VERSION_MAJOR(v)           \
+                ((v >> 16) & 0xFF)
+#define SNAP_VERSION_MINOR(v)           \
+                ((v >> 8) & 0xFF)
+#define SNAP_VERSION_REL(v)             \
+                (v & 0xFF)
+                                                                                                                                                                                                     
+                                                                                                                                                                                                     
+#define EXT3_EA_TRANS_BLOCKS            EXT3_DATA_TRANS_BLOCKS
+#define EXT3_SETMETA_TRANS_BLOCKS       EXT3_DATA_TRANS_BLOCKS
+#define EXT3_NEWINODE_TRANS_BLOCKS      10
+#define SNAP_INSERTLIST_TRANS_BLOCKS    (2 * EXT3_EA_TRANS_BLOCKS + 1)
+#define SNAP_DELETELIST_TRANS_BLOCKS    (2 * EXT3_EA_TRANS_BLOCKS + 2)
+#define SNAP_COPYBLOCK_TRANS_BLOCKS     (EXT3_DATA_TRANS_BLOCKS)
+#define SNAP_MIGRATEDATA_TRANS_BLOCKS   2
+#define SNAP_SETIND_TRANS_BLOCKS        (SNAP_INSERTLIST_TRANS_BLOCKS + 1)
+#define SNAP_ADDORPHAN_TRANS_BLOCKS     2
+#define SNAP_REMOVEORPHAN_TRANS_BLOCKS  1
+#define SNAP_RESTOREORPHAN_TRANS_BLOCKS (EXT3_EA_TRANS_BLOCKS + \
+                                         SNAP_DELETELIST_TRANS_BLOCKS + \
+                                         EXT3_NEWINODE_TRANS_BLOCKS + \
+                                         2 * SNAP_MIGRATEDATA_TRANS_BLOCKS)
+#define SNAP_BIGCOPY_TRANS_BLOCKS       (2 * EXT3_DATA_TRANS_BLOCKS)
+#define SNAP_CREATEIND_TRANS_BLOCKS     (EXT3_NEWINODE_TRANS_BLOCKS + \
+                                         SNAP_MIGRATEDATA_TRANS_BLOCKS + \
+                                         SNAP_SETIND_TRANS_BLOCKS + \
+                                         SNAP_BIGCOPY_TRANS_BLOCKS + 3)
+#define SNAP_MIGRATEBLK_TRANS_BLOCKS    2
+#define SNAP_DESTROY_TRANS_BLOCKS       (SNAP_DELETELIST_TRANS_BLOCKS + \
+                                         EXT3_EA_TRANS_BLOCKS + 2)
+#define SNAP_RESTORE_TRANS_BLOCKS       (EXT3_NEWINODE_TRANS_BLOCKS + \
+                                         2 * SNAP_MIGRATEDATA_TRANS_BLOCKS + 1)
+/*Snap Table*/
+#define SNAP_MAX		32	
+#define SNAP_MAX_TABLES 	32	
+#define SNAP_MAX_NAMELEN	64
+
+#define MAX_SNAPTABLE_COUNT     "MAXSnapCount"
+#define SNAP_TABLE_MAGIC	0x19760218
+#define SNAPTABLE_INFO          "snaptable"
+#define SNAP_GENERATION         "snap_generation"
+struct snap {
+        time_t          sn_time;
+        unsigned int    sn_index;
+        unsigned int    sn_gen;
+        unsigned int    sn_flags;
+        char    name[SNAP_MAX_NAMELEN];
+};
+
+struct snap_table {
+	unsigned int   	sntbl_magic;
+	unsigned int   	sntbl_count;
+	unsigned int   	sntbl_max_count;
+	unsigned int	sntbl_generation;
+	struct  snap  	sntbl_items[0];
+};
+
+struct snap_info {
+        struct fsfilt_operations *snap_fsfilt;  
+        struct fsfilt_operations *snap_cache_fsfilt;  
+	struct semaphore         sntbl_sema;
+	spinlock_t               sntbl_lock;
+        struct snap_table        *sntbl;
+};
+
+#endif /*_LUSTRE_SNAP_H*/
diff --git a/lustre/lvfs/fsfilt_snap_ext3.c b/lustre/lvfs/fsfilt_snap_ext3.c
index 0d68a455d93442ab1205bdd01666b7a2466f46ba..b183bf668ccb525cb02fec3cdbd838b64bfbf1a7 100644
--- a/lustre/lvfs/fsfilt_snap_ext3.c
+++ b/lustre/lvfs/fsfilt_snap_ext3.c
@@ -56,7 +56,7 @@
 #define EXT3_DEL_FL                     0x00200000 /* inode is deleting in snapshot */
 
 #define EXT3_SNAP_ATTR "@snap"
-#define EXT3_SNAP_GENERATION_ATTR "@snap_generation"
+#define EXT3_SNAP_GENERATION "@snap_generation"
 #define EXT3_MAX_SNAPS 20
 #define EXT3_MAX_SNAP_DATA (sizeof(struct snap_ea))
 #define EXT3_SNAP_INDEX EXT3_XATTR_INDEX_LUSTRE
@@ -69,6 +69,8 @@
 
 #define EXT3_FEATURE_COMPAT_SNAPFS             0x0010
 #define EXT3_FEATURE_COMPAT_BLOCKCOW           0x0020
+/*snaptable info for EXT3*/
+#define EXT3_SNAPTABLE_EA       "@snaptable"
                                                                                                                                                                                                      
 /* NOTE: these macros are close dependant on the structure of snap ea */
 #define SNAP_CNT_FROM_SIZE(size)       ((((size)-sizeof(ino_t)*2)/2)/sizeof(ino_t))
@@ -232,7 +234,7 @@ out_unlock:
 	return err;
 }
 
-static int fsfilt_ext3_set_generation(struct inode *inode, unsigned long gen)
+static int ext3_set_generation(struct inode *inode, unsigned long gen)
 {
         handle_t *handle;
         int err = 0;
@@ -243,7 +245,7 @@ static int fsfilt_ext3_set_generation(struct inode *inode, unsigned long gen)
                 RETURN(-EINVAL);
 
         err = ext3_xattr_set(handle, inode, EXT3_SNAP_INDEX, 
-                             EXT3_SNAP_GENERATION_ATTR,
+                             EXT3_SNAP_GENERATION,
                              (char*)&gen, sizeof(int), 0);
         if (err < 0) {
                 CERROR("ino %lu, set_ext_attr err %d\n", inode->i_ino, err);
@@ -253,26 +255,6 @@ static int fsfilt_ext3_set_generation(struct inode *inode, unsigned long gen)
         ext3_journal_stop(handle, inode);
         RETURN(0);
 }
-                                                                                                                                                                                                     
-static int fsfilt_ext3_get_generation(struct inode *inode)
-{
-        int err, gen;
-        ENTRY;
-
-        err = ext3_xattr_get(inode, EXT3_SNAP_INDEX, EXT3_SNAP_GENERATION_ATTR,
-                             (char*)&gen, sizeof(gen));
-        if (err < 0) {
-                if (err == -ENODATA) {
-                        RETURN(0);
-                } else {
-                        CERROR("can not get generation from %lu \n", 
-                               inode->i_ino);
-                        RETURN(err);
-                }
-        }
-
-        RETURN(gen);
-}
 
 /*
  * Copy inode metadata from one inode to another, excluding blocks and size.
@@ -624,7 +606,7 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index,
 	CDEBUG(D_INODE, "got new inode %lu\n", ind->i_ino);
 	ind->i_rdev = pri->i_rdev;
 	ind->i_op = pri->i_op;
-	fsfilt_ext3_set_generation(ind, (unsigned long)gen);
+	ext3_set_generation(ind, (unsigned long)gen);
 	/* If we are deleting the primary inode, we want to ensure that it is
 	 * written to disk with a non-zero link count, otherwise the next iget
 	 * and iput will mark the inode as free (which we don't want, we want
@@ -1455,231 +1437,72 @@ static int fsfilt_ext3_iterate(struct super_block *sb,
 	}
 }
 
-static int find_snap_meta_index(
-	struct table_snap_meta_data *snap_meta,
-	char			    *name)
-{
-	int i;
-
-	/* table max length is null*/
-	for( i = 0; i < TABLE_ITEM_COUNT; i++){
-		/*compare name Max name Length 15*/
-		if (snap_meta->array[i].name[0]){
-			if(!strncmp(snap_meta->array[i].name, name, strlen(name)))
-				return i;
-		}
-	}
-	return -1; /* can not find */
-}
-
-int set_snap_meta_index(
-	struct table_snap_meta_data *snap_meta,
-	char			    *name,
-	int			     size)
+static int fsfilt_ext3_get_snap_info(struct super_block *sb,struct inode *inode,
+                                     void *key, __u32 keylen, void *val, 
+                                     __u32 *vallen) 
 {
-	int i;
-
-	for( i = 0; i < TABLE_ITEM_COUNT; i++){
-		/*compare name Max name Length 15*/
-		if (! snap_meta->array[i].name[0]){
-			strcpy(snap_meta->array[i].name, name);
-			snap_meta->count ++;
-			snap_meta->array[i].start = i * TABLE_ITEM_SIZE + 1;
-			snap_meta->array[i].len	  = size;
-			return i;
-		}
-	}
-	return -1; /* can not find */
-}
-
-static int fsfilt_ext3_get_meta_attr(struct super_block *sb, char* name, 
-                                     char* buf, int *size)
-{
-        struct inode  			*inode;
-	struct buffer_head 		*bh = NULL;
-	struct table_snap_meta_data     *s_attr;
-	unsigned long			map_len = 0,  left_size;
-        int 				i, error = 0, index = 0;
-        ino_t           		ino;
-        ENTRY;        
-	
-	ino = SB_SNAPTABLE_INO(sb);	
-	if (ino == 0){
-		CERROR("No table file \n");
-		RETURN(-ENODATA);
-	} 
-
-	inode = iget(sb, ino);
-        if(!inode || is_bad_inode(inode)){
-                CERROR("unable to get table ino %lu\n", ino);
-                GOTO(out_iput, error = -ENOENT);
-	}
-	/*read the table from the table inode*/
-	bh = ext3_bread(NULL, inode, 0, 0, &error);
-	if (!bh) {
-		CERROR("read table ino %lu, error %d\n", ino, error);
-                GOTO(out_iput, error = -ENODATA);
-	}
-	s_attr = (struct table_snap_meta_data *)(bh->b_data);
-	index = find_snap_meta_index(s_attr, name);
-	if (index < 0) {
-		CDEBUG(D_INFO, "not exit %s meta attr of table ino %lu \n", 
-		       name, inode->i_ino);
-	        GOTO(out_iput, error = 0);
-	}
-	if (!buf || *size < s_attr->array[index].len) {
-		/*return the size of this meta attr */
-		error = s_attr->array[index].len;		
-		GOTO(out_iput, error);
-	}
-	map_len = (s_attr->array[index].len + sb->s_blocksize - 1) 
-                  >> sb->s_blocksize_bits;	
-	left_size = *size;
-	for(i = 0; i < map_len; i++) {
-		struct buffer_head *array_bh = NULL;
-
-		array_bh = ext3_bread(NULL, inode, 
-				      s_attr->array[index].start + i,
-				      0, &error);
-		if (!array_bh) {
-			CERROR("ino %lu read snap attr offset %d error %d \n",
-			       inode->i_ino, (s_attr->array[index].start + i), 
-                               error);
-			GOTO(out_iput, error);
-		}
-		if (left_size >= sb->s_blocksize) 
-			memcpy(buf, array_bh->b_data, sb->s_blocksize);
-		else
-			memcpy(buf, array_bh->b_data, left_size);
-		left_size -= sb->s_blocksize;
-		brelse(array_bh);
-	}
-	*size = s_attr->array[index].len;
-out_iput:
-	brelse(bh);
-	iput(inode);
+        int rc = 0;
+        ENTRY;
 
-	RETURN(error);
+        if (!vallen || !val) {
+                CERROR("val and val_size is 0!\n");
+                RETURN(-EFAULT);
+        }
+        if (keylen >= strlen(MAX_SNAPTABLE_COUNT) 
+            && strcmp(key, MAX_SNAPTABLE_COUNT) == 0) {
+                /*FIXME should get it from the EA_size*/
+               *((__u32 *)val) = EXT3_MAX_SNAPS; 
+               *vallen = sizeof(int);
+               RETURN(rc);
+        } else if (keylen >= strlen(SNAPTABLE_INFO) 
+                   && strcmp(key, SNAPTABLE_INFO) == 0) {
+                rc = ext3_xattr_get(sb->s_root->d_inode, EXT3_SNAP_INDEX, 
+                                    EXT3_SNAPTABLE_EA, val, *vallen); 
+                RETURN(rc);
+        } else if (keylen >= strlen(SNAP_GENERATION) 
+                   && strcmp(key, SNAP_GENERATION) == 0) {
+                
+                rc = ext3_xattr_get(inode, EXT3_SNAP_INDEX,EXT3_SNAP_GENERATION,
+                                    (char *)val, *vallen);
+                RETURN(rc);
+        } 
+        RETURN(-EINVAL);
 } 
 
-static int fsfilt_ext3_set_meta_attr(struct super_block *sb, char* name, 
-			             char* buf, int size)
+static int fsfilt_ext3_set_snap_info(struct super_block *sb,struct inode *inode, 
+                                     void *key, __u32 keylen, void *val, 
+                                     __u32 *vallen)
 {
-        struct inode  			*inode = NULL;
-        handle_t			*handle = NULL;
-	struct	buffer_head 		*bh = NULL;
-	struct table_snap_meta_data     *s_attr = NULL;
-	unsigned long   		ino;
-        int 				i, index = 0, error = 0;
-	unsigned long   		new_len = 0, left_size; 
-        
+        int rc = 0;
         ENTRY;
-		
-	ino = SB_SNAPTABLE_INO(sb);
-      
-	if (ino == 0 && !buf) {
-		CDEBUG(D_INODE, "no table ino \n");
-		RETURN(0);
-	}
-	
-	handle = ext3_journal_start(sb->s_root->d_inode, 
-                                    2 * EXT3_SETMETA_TRANS_BLOCKS);
-	if(!handle)
-		RETURN(-EINVAL);
-
-	if (ino == 0) {
-		/*create table inode update table ino*/
-		inode = ext3_new_inode(handle, sb->s_root->d_inode, (int)S_IFREG, 0);
-		if (!inode)
-			RETURN(-EINVAL);
-		lock_super(sb);
-		ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh);
-		SB_SNAPTABLE_INO(sb) = inode->i_ino;
-		ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);
-		sb->s_dirt = 1;
-		unlock_super(sb);
+        
+        if (!vallen || !val) {
+                CERROR("val and val_size is 0!\n");
+                RETURN(-EFAULT);
+        }
 
-	} else {
-		inode = iget(sb, ino);
-		if (!inode || !inode->i_nlink || is_bad_inode(inode)) {
-			CERROR("unable to get table ino %lu\n", ino);
-			GOTO(exit, error = -ENOENT);
-		}
-	}
-	/*read the table from the table inode,
-	 * If can not find the block just create it*/
-	bh = ext3_bread(handle, inode, 0, 1, &error);
-	if (!bh) {
-		CERROR("read table ino %lu, error %d\n", ino, error);
-		GOTO(exit, error = -ENODATA);
-	}
-	s_attr = (struct table_snap_meta_data *)(bh->b_data);
-	index = find_snap_meta_index(s_attr, name);
-	if (index < 0 && !buf) { 	
-		CDEBUG(D_INODE, "%s meta attr of table ino %lu do not exist\n", 
-		       name, inode->i_ino);
-		brelse(bh);
-	        GOTO(exit, error = 0);
-	}
-	if (!buf) {
-		CDEBUG(D_INODE, "delete the meta attr %s in the table ino %lu",
-		       name, inode->i_ino);
-		/*Here we only delete the entry of the attr
-		 *FIXME, should we also delete the block of 
-		 * this attr
-		 */
-		ext3_journal_get_write_access(handle, bh);
-		memset(s_attr->array[index].name, 0, TABLE_ITEM_NAME_SIZE);
-	        s_attr->array[index].len = 0;
-	        s_attr->count --;
-		ext3_journal_dirty_metadata(handle, bh);
-		brelse(bh);
-		GOTO(exit, error);
-	}
-	new_len = (size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
-	/*find the place to put this attr in that index*/
-	ext3_journal_get_write_access(handle, bh);
-	if (index < 0){
-		index = set_snap_meta_index(s_attr, name, size);
-		if (index < 0){
-			CERROR("table full of ino %lu \n", inode->i_ino);
-		        brelse(bh);
-		        GOTO(exit, error = index);
-		}
-	}
-	s_attr->array[index].len = size;
-	journal_dirty_metadata(handle, bh);
-	brelse(bh);
-	/*put this attr to the snap table*/
-	left_size = size;
-	for(i = 0; i < new_len; i++) {
-		struct buffer_head *array_bh = NULL;
-		
-		array_bh = ext3_bread(handle, inode, 
-				      s_attr->array[index].start + i, 1, &error);
-		if (!array_bh) {
-			CERROR("inode %lu Can not get the block of attr %s\n",  
-				inode->i_ino, name);
-			brelse(array_bh);
-			GOTO(exit, error = -ENOSPC);
-		}
-		ext3_journal_get_write_access(handle, array_bh);
-		if (left_size > inode->i_sb->s_blocksize) 	
-			memcpy(array_bh->b_data, buf, inode->i_sb->s_blocksize);
-		else
-			memcpy(array_bh->b_data, buf, left_size);
-		ext3_journal_dirty_metadata(handle, array_bh);
-		left_size -= inode->i_sb->s_blocksize;
-		brelse(array_bh);
-	}
-exit:
-        if (handle)
-		ext3_journal_stop(handle, sb->s_root->d_inode); 
-	iput(inode);
-	RETURN(error);
+        if (keylen >= strlen(SNAPTABLE_INFO) 
+            && strcmp(key, SNAPTABLE_INFO) == 0) {
+                struct inode *inode = sb->s_root->d_inode;
+                handle_t *handle;
+ 
+                handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
+                if( !handle )
+                        RETURN(-EINVAL);
+                rc = ext3_xattr_set(handle, inode, EXT3_SNAP_INDEX, 
+                                    EXT3_SNAPTABLE_EA, val, *vallen, 0); 
+	        ext3_journal_stop(handle,inode);
+                
+                RETURN(rc);
+        } else if (keylen >= strlen(SNAP_GENERATION) 
+                   && strcmp(key, SNAP_GENERATION) == 0) {
+                rc = ext3_set_generation(inode, *(int*)val);
+                
+                RETURN(rc); 
+        }
+        RETURN(-EINVAL);
 }
 
-
 struct fsfilt_operations fsfilt_ext3_snap_ops = {
         .fs_type                = "ext3_snap",
         .fs_owner               = THIS_MODULE,
@@ -1690,14 +1513,12 @@ struct fsfilt_operations fsfilt_ext3_snap_ops = {
 	.fs_is_redirector	= fsfilt_ext3_is_redirector,
 	.fs_is_indirect		= fsfilt_ext3_is_indirect,
         .fs_get_indirect_ino    = fsfilt_ext3_get_indirect_ino,
-        .fs_set_generation      = fsfilt_ext3_set_generation,
-        .fs_get_generation      = fsfilt_ext3_get_generation,
         .fs_destroy_indirect    = fsfilt_ext3_destroy_indirect,
         .fs_restore_indirect    = fsfilt_ext3_restore_indirect,
         .fs_iterate             = fsfilt_ext3_iterate,
         .fs_copy_block          = fsfilt_ext3_copy_block,
-        .fs_set_meta_attr       = fsfilt_ext3_set_meta_attr,
-        .fs_get_meta_attr       = fsfilt_ext3_get_meta_attr,
+        .fs_set_snap_info       = fsfilt_ext3_set_snap_info,
+        .fs_get_snap_info       = fsfilt_ext3_get_snap_info,
 };
 
 static int __init fsfilt_ext3_snap_init(void)
diff --git a/lustre/lvfs/fsfilt_snap_smfs.c b/lustre/lvfs/fsfilt_snap_smfs.c
index 2d74ae48b2aa0420e0e5f1da0a0446137b4d0f92..bd300f46f9f4a73e2aa6d344369a7793bb98fcf3 100644
--- a/lustre/lvfs/fsfilt_snap_smfs.c
+++ b/lustre/lvfs/fsfilt_snap_smfs.c
@@ -137,7 +137,7 @@ static int fsfilt_smfs_set_indirect(struct inode *inode, int index,
 static int fsfilt_smfs_snap_feature(struct super_block *sb, int feature, 
                                     int op)
 {
-        struct fsfilt_operations *snap_fsfilt = S2SMI(sb)->sm_snap_fsfilt;
+        struct fsfilt_operations *snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt;
         struct super_block       *csb = S2CSB(sb);
         int                      rc = -EIO;
         
@@ -215,50 +215,6 @@ static ino_t fsfilt_smfs_get_indirect_ino(struct inode *inode, int index)
         
         RETURN(rc);
 }
-static int fsfilt_smfs_set_generation(struct inode *inode, 
-                                      unsigned long new_gen)
-{
-        struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
-        struct inode *cache_inode = NULL;
-        int    rc = -EIO;
-        ENTRY;
-
-        if (snap_fsfilt == NULL)
-                RETURN(rc);
-
-        cache_inode = I2CI(inode);
-        if (!cache_inode)
-                RETURN(rc);
-
-        pre_smfs_inode(inode, cache_inode);
-        if (snap_fsfilt->fs_set_generation)
-                rc = snap_fsfilt->fs_set_generation(cache_inode, new_gen);
-        post_smfs_inode(inode, cache_inode);
-        
-        RETURN(rc);
-}
-
-static int fsfilt_smfs_get_generation(struct inode *inode)
-{
-        struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
-        struct inode *cache_inode = NULL;
-        int    rc = -EIO;
-        ENTRY;
-
-        if (snap_fsfilt == NULL)
-                RETURN(rc);
-
-        cache_inode = I2CI(inode);
-        if (!cache_inode)
-                RETURN(rc);
-
-        pre_smfs_inode(inode, cache_inode);
-        if (snap_fsfilt->fs_get_generation)
-                rc = snap_fsfilt->fs_get_generation(cache_inode);
-        post_smfs_inode(inode, cache_inode);
-        
-        RETURN(rc);
-}
 
 static int fsfilt_smfs_destroy_indirect(struct inode *inode, int index,
                                         struct inode *next_ind)
@@ -318,7 +274,7 @@ static int fsfilt_smfs_iterate(struct super_block *sb,
                                int (*repeat)(struct inode *inode, void *priv),
                                struct inode **start, void *priv, int flag)
 {
-        struct fsfilt_operations *snap_fsfilt = S2SMI(sb)->sm_snap_fsfilt;
+        struct fsfilt_operations *snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt;
         struct super_block       *csb = S2CSB(sb);
         int                      rc = -EIO;
         ENTRY;
@@ -366,38 +322,56 @@ static int fsfilt_smfs_copy_block(struct inode *dst, struct inode *src, int blk)
         RETURN(rc); 
 }
 
-static int fsfilt_smfs_set_meta_attr(struct super_block *sb, char *name,
-                                     char *buf, int size)
+static int fsfilt_smfs_set_snap_info(struct super_block *sb,struct inode *inode, 
+                                     void* key, __u32 keylen, void *val, 
+                                     __u32 *vallen)
 {
-        struct fsfilt_operations *snap_fsfilt = S2SMI(sb)->sm_snap_fsfilt;
-        struct super_block       *csb = S2CSB(sb);
+        struct super_block     *csb = NULL;
+        struct inode           *cache_inode = NULL;  
+        struct fsfilt_operations *snap_fsfilt = NULL; 
         int                      rc = -EIO;
         
+        if (sb) {
+                csb = S2CSB(sb);
+                snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt;
+        } else if (inode) {
+                cache_inode = I2CI(inode);
+                snap_fsfilt = I2SNAPOPS(inode);
+        }
+
         if (snap_fsfilt == NULL)
                 RETURN(rc);
-        if (!csb)
-                RETURN(rc);
         
-        if (snap_fsfilt->fs_set_meta_attr)
-                rc = snap_fsfilt->fs_set_meta_attr(csb, name, buf, size);
+        if (snap_fsfilt->fs_set_snap_info)
+                rc = snap_fsfilt->fs_set_snap_info(csb, cache_inode, key, 
+                                                   keylen, val, vallen);
 
         RETURN(rc);
 }
 
-static int fsfilt_smfs_get_meta_attr(struct super_block *sb, char *name,
-                                     char *buf, int *size)
+static int fsfilt_smfs_get_snap_info(struct super_block *sb, struct inode *inode,
+                                     void *key, __u32 keylen, void *val,
+                                     __u32 *vallen)
 {
-        struct fsfilt_operations *snap_fsfilt = S2SMI(sb)->sm_snap_fsfilt;
-        struct super_block       *csb = S2CSB(sb);
+        struct super_block     *csb = NULL;
+        struct inode           *cache_inode = NULL;  
+        struct fsfilt_operations *snap_fsfilt = NULL; 
         int                      rc = -EIO;
         
+        if (sb) {
+                csb = S2CSB(sb);
+                snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt;
+        } else if (inode) {
+                cache_inode = I2CI(inode);
+                snap_fsfilt = I2SNAPOPS(inode);
+        }
+      
         if (snap_fsfilt == NULL)
                 RETURN(rc);
-        if (!csb)
-                RETURN(rc);
-        
-        if (snap_fsfilt->fs_get_meta_attr)
-                rc = snap_fsfilt->fs_get_meta_attr(csb, name, buf, size);
+       
+        if (snap_fsfilt->fs_get_snap_info)
+                rc = snap_fsfilt->fs_get_snap_info(csb, cache_inode, key, 
+                                                   keylen, val, vallen);
 
         RETURN(rc);
 }
@@ -412,14 +386,12 @@ struct fsfilt_operations fsfilt_smfs_snap_ops = {
 	.fs_is_redirector	= fsfilt_smfs_is_redirector,
 	.fs_is_indirect		= fsfilt_smfs_is_indirect,
         .fs_get_indirect_ino    = fsfilt_smfs_get_indirect_ino,
-        .fs_set_generation      = fsfilt_smfs_set_generation,
-        .fs_get_generation      = fsfilt_smfs_get_generation,
         .fs_destroy_indirect    = fsfilt_smfs_destroy_indirect,
         .fs_restore_indirect    = fsfilt_smfs_restore_indirect,
         .fs_iterate             = fsfilt_smfs_iterate,
         .fs_copy_block          = fsfilt_smfs_copy_block,
-        .fs_set_meta_attr       = fsfilt_smfs_set_meta_attr,
-        .fs_get_meta_attr       = fsfilt_smfs_get_meta_attr,
+        .fs_set_snap_info       = fsfilt_smfs_set_snap_info,
+        .fs_get_snap_info       = fsfilt_smfs_get_snap_info,
 };
 
 
diff --git a/lustre/portals/utils/debug.c b/lustre/portals/utils/debug.c
index 67d8edc09b5ed0dd8a72c356316f4efc1d021000..9ce7528887980a9d53deb10816b94d6a969d63fc 100644
--- a/lustre/portals/utils/debug.c
+++ b/lustre/portals/utils/debug.c
@@ -545,9 +545,11 @@ static struct mod_paths {
         {"lov", "lustre/lov"},
         {"lmv", "lustre/lmv"},
         {"fsfilt_ext3", "lustre/lvfs"},
+        {"fsfilt_snap_ext3", "lustre/lvfs"},
         {"fsfilt_extN", "lustre/lvfs"},
         {"fsfilt_reiserfs", "lustre/lvfs"},
         {"fsfilt_smfs", "lustre/lvfs"},
+        {"fsfilt_snap_smfs", "lustre/lvfs"},
         {"ptlbd", "lustre/ptlbd"},
         {"mgmt_svc", "lustre/mgmt"},
         {"mgmt_cli", "lustre/mgmt"},
diff --git a/lustre/smfs/Makefile.in b/lustre/smfs/Makefile.in
index 8dda73547305291def52a4bacd492af9c985b850..8586c583dc51244b6b9207d3785d14b512473563 100644
--- a/lustre/smfs/Makefile.in
+++ b/lustre/smfs/Makefile.in
@@ -1,6 +1,6 @@
 MODULES := smfs
 smfs-objs := super.o options.o inode.o cache.o cache_space.o dir.o ioctl.o
 smfs-objs += sysctl.o file.o symlink.o sm_fs.o kml.o journal.o smfs_llog.o
-smfs-objs += mds_kml.o ost_kml.o
-
+smfs-objs += mds_kml.o ost_kml.o 
+@SNAPFS_TRUE@smfs-objs += smfs_cow.o 
 @INCLUDE_RULES@
diff --git a/lustre/smfs/dir.c b/lustre/smfs/dir.c
index 89acd05095f3477b6d95a70cffbc6c70104dca86..4a3c943f85aa8bcaebb059efee15ed048469b67d 100644
--- a/lustre/smfs/dir.c
+++ b/lustre/smfs/dir.c
@@ -67,7 +67,7 @@ static int smfs_create(struct inode *dir, struct dentry *dentry,
 
         SMFS_CACHE_HOOK_PRE(CACHE_HOOK_CREATE, handle, dir);
 
-         cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry);
+        cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry);
         cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry);
 
         lock_kernel();
@@ -76,6 +76,8 @@ static int smfs_create(struct inode *dir, struct dentry *dentry,
 
         pre_smfs_inode(dir, cache_dir);
 
+        SMFS_PRE_COW(dir, dentry, REINT_CREATE, "create", rc, exit);
+
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
         if (cache_dir && cache_dir->i_op->create)
                 rc = cache_dir->i_op->create(cache_dir, cache_dentry,
@@ -98,6 +100,7 @@ static int smfs_create(struct inode *dir, struct dentry *dentry,
         post_smfs_inode(dir, cache_dir);
 
         /*Do KML post hook*/
+
         SMFS_KML_POST(dir, dentry, NULL, NULL, REINT_CREATE,
                       "create", rc, exit);
         SMFS_CACHE_HOOK_POST(CACHE_HOOK_CREATE, handle, dir, dentry,
@@ -133,7 +136,7 @@ static struct dentry *smfs_lookup(struct inode *dir, struct dentry *dentry,
 
         handle = smfs_trans_start(dir, KML_CACHE_NOOP, NULL);
         if (IS_ERR(handle))
-                       RETURN(ERR_PTR(-ENOSPC));
+                RETURN(ERR_PTR(-ENOSPC));
 
         SMFS_CACHE_HOOK_PRE(CACHE_HOOK_LOOKUP, handle, dir);
 
diff --git a/lustre/smfs/smfs_cow.c b/lustre/smfs/smfs_cow.c
new file mode 100644
index 0000000000000000000000000000000000000000..5b611fbebcbad3cd7eb29f854c405fda5c913d78
--- /dev/null
+++ b/lustre/smfs/smfs_cow.c
@@ -0,0 +1,318 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2004 Cluster File Systems, Inc.
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   Lustre is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   Lustre 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 Lustre; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define DEBUG_SUBSYSTEM S_SM
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/unistd.h>
+#include <linux/smp_lock.h>
+#include <linux/obd_class.h>
+#include <linux/obd_support.h>
+#include <linux/lustre_lib.h>
+#include <linux/lustre_idl.h>
+#include <linux/lustre_fsfilt.h>
+
+#include <linux/lustre_snap.h>
+#include <linux/lustre_smfs.h>
+
+#include "smfs_internal.h"
+#define SNAPTABLE_SIZE(size) (sizeof(struct snap_table) + size * sizeof(struct snap)) 
+static int smfs_init_snaptabe(struct super_block *sb)
+{
+        struct snap_info         *snap_info = S2SNAPI(sb);	
+	struct fsfilt_operations *snapops;
+        int                      rc = 0, size, table_size, vallen;
+        
+        ENTRY;
+
+        init_MUTEX(&snap_info->sntbl_sema);
+        /*Initialized table */
+        /*get the maxsize of snaptable*/
+        vallen = sizeof(int);
+        rc = snapops->fs_get_snap_info(sb, NULL, MAX_SNAPTABLE_COUNT,
+                                       strlen(MAX_SNAPTABLE_COUNT), &size, 
+                                       &vallen);
+        if (size == 0) {
+                CERROR("the Max snaptable count should not be zero\n");
+                RETURN(-EINVAL);
+        }
+        
+        table_size = SNAPTABLE_SIZE(size);
+
+        OBD_ALLOC(snap_info->sntbl, table_size);
+
+        if (!snap_info->sntbl) {
+                CERROR("No MEM\n");
+                RETURN(-ENOMEM);
+        }
+        /*get snaptable info*/
+        rc = snapops->fs_get_snap_info(sb, NULL, SNAPTABLE_INFO, 
+                                       strlen(SNAPTABLE_INFO), 
+                                       snap_info->sntbl, &table_size);       
+       
+        if (rc < 0) {
+                if (rc == -ENOATTR) {
+                        snap_info->sntbl->sntbl_count = 1;
+                        CDEBUG(D_INFO, "No snaptable here\n");
+                        RETURN(0);
+                } else {
+                        CERROR("Can not retrive the snaptable from this filesystem\n");
+                        OBD_FREE(snap_info->sntbl, table_size);
+                        RETURN(rc); 
+                }
+        } 
+        if (le32_to_cpu(snap_info->sntbl->sntbl_magic) != SNAP_TABLE_MAGIC) {
+                CERROR("On disk snaptable is not right \n");
+                OBD_FREE(snap_info->sntbl, table_size);
+                RETURN(-EIO);
+        }
+        snap_info->sntbl->sntbl_max_count = size;
+        
+        return 0;
+}
+
+int smfs_cow_init(struct super_block *sb)
+{
+        struct smfs_super_info *smfs_info = S2SMI(sb);
+        struct inode *inode = sb->s_root->d_inode;
+        int rc = 0;
+
+        SMFS_SET_COW(smfs_info);
+        SMFS_SET_INODE_COW(inode);
+      
+        OBD_ALLOC(smfs_info->smsi_snap_info, sizeof(struct snap_info));
+     
+        if (!smfs_info->smsi_snap_info) 
+                RETURN(-ENOMEM);
+        
+        /*init snap fsfilt operations*/
+        if (!S2SNAPI(sb)->snap_cache_fsfilt) {
+                char *snap_cache_ftype = NULL;
+                int   tmp = strlen(S2SMI(sb)->smsi_cache_ftype) + strlen("_snap");
+                
+                OBD_ALLOC(snap_cache_ftype, tmp + 1);  
+                sprintf(snap_cache_ftype, "%s_snap", S2SMI(sb)->smsi_cache_ftype);
+                S2SNAPI(sb)->snap_cache_fsfilt = fsfilt_get_ops(snap_cache_ftype);
+                OBD_FREE(snap_cache_ftype, tmp + 1);
+                if (!S2SNAPI(sb)->snap_cache_fsfilt) {
+                        CERROR("Can not get %s fsfilt ops needed by snap\n",
+                               snap_cache_ftype);
+                        RETURN(-EINVAL);
+                }
+        }
+        if (!S2SNAPI(sb)->snap_fsfilt) {
+                char *snap_ftype = NULL;
+                int   tmp = strlen(S2SMI(sb)->smsi_ftype) + strlen("_snap");
+                
+                OBD_ALLOC(snap_ftype, tmp + 1);  
+                sprintf(snap_ftype, "%s_snap", S2SMI(sb)->smsi_ftype);
+                S2SNAPI(sb)->snap_fsfilt = fsfilt_get_ops(snap_ftype);
+                OBD_FREE(snap_ftype, tmp + 1);
+                if (!S2SNAPI(sb)->snap_fsfilt) {
+                        CERROR("Can not get %s fsfilt ops needed by snap\n",
+                               snap_ftype);
+                        RETURN(-EINVAL);
+                }
+        }
+        rc = smfs_init_snaptabe(sb); 
+        
+        RETURN(rc);
+}
+
+int smfs_cow_cleanup(struct super_block *sb)
+{
+        struct smfs_super_info *smfs_info = S2SMI(sb);
+        struct snap_info       *snap_info = S2SNAPI(sb);	
+        struct inode *inode = sb->s_root->d_inode;
+        int rc = 0;
+        ENTRY;
+
+        SMFS_CLEAN_COW(smfs_info);
+        SMFS_CLEAN_INODE_COW(inode);
+
+        if (snap_info->sntbl) {
+                int table_size = SNAPTABLE_SIZE(snap_info->sntbl->sntbl_max_count);
+                OBD_FREE(snap_info->sntbl, table_size);
+        }
+        if (snap_info) 
+               OBD_FREE(snap_info, sizeof(*snap_info)); 
+        
+        RETURN(rc);
+}
+
+/* latest snap: returns 
+   -  the index of the latest snapshot before NOW
+   -  hence it returns 0 in case all the volume snapshots lie in the future
+   -  this is the index where a COW will land (will be created) 
+*/
+void snap_last(struct super_block *sb, struct snap *snap)
+{
+	struct snap_info *snap_info = S2SNAPI(sb);
+	struct snap_table *table = snap_info->sntbl;
+        time_t now = CURRENT_TIME;
+	int i ;
+
+	ENTRY;
+	/* start at the highest index in the superblock snaptime array */ 
+	i = table->sntbl_count - 1;
+
+	snap->sn_index = table->sntbl_items[i].sn_index;
+	snap->sn_time = table->sntbl_items[i].sn_time;
+	snap->sn_gen = table->sntbl_items[i].sn_gen;
+	CDEBUG(D_INFO, "index: %d, time[i]: %ld, now: %ld\n",
+	       snap->sn_index, snap->sn_time, now);
+        EXIT;
+	return;
+}
+
+/*
+ * Note: this function should be differnet with snap_do_cow.
+ * In smfs_do_cow, we check the EA for whether do cow for that inode.
+ * In smfs_needs_cow, we check whether we do need to do cow. 
+ */
+int smfs_needs_cow(struct inode *inode)
+{
+	struct smfs_inode_info  *smi_info = I2SMI(inode); 
+        struct snap_inode_info *snap_info = NULL;
+        struct snap snap;
+	int index = -1;
+	ENTRY;
+
+	snap_info = &(smi_info->sm_sninfo);
+	
+        snap_last(inode->i_sb, &snap);
+	/* decision .... if the snapshot is more recent than the object,
+	 * then any change to the object should cause a COW.
+	 */
+	if (snap_info->sn_gen < snap.sn_gen ) 
+		index = snap.sn_index;
+
+	CDEBUG(D_INFO, "snap_needs_cow, ino %lu , get index %d\n",
+	       inode->i_ino, index);
+
+	RETURN(index);
+} /* snap_needs_cow */
+
+/*
+ * Make a copy of the data and plug a redirector in between if there
+ * is no redirector yet.
+ */
+int snap_do_cow(struct inode *inode, struct dentry *dparent, int del)
+{
+        struct snap_info *snap_info = S2SNAPI(inode->i_sb);	
+	struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
+        struct snap snap;
+	struct inode *ind = NULL;
+
+	ENTRY;
+
+	if (!snapops || !snapops->fs_create_indirect) 
+		RETURN(-EINVAL);
+
+	snap_last(inode->i_sb, &snap);
+	ind = snapops->fs_create_indirect(inode, snap.sn_index, snap.sn_gen, 
+                                          dparent->d_inode, del);
+	if(!ind)
+		RETURN(-EINVAL);
+
+        I2SMI(ind)->sm_sninfo.sn_flags = 0;
+        I2SMI(ind)->sm_sninfo.sn_gen = snap.sn_gen;
+        
+        iput(ind);
+        RETURN(0);
+}
+
+int smfs_cow_create(struct inode *dir, struct dentry *dentry)
+{
+        int rc = 0;
+        ENTRY;
+
+        if (smfs_needs_cow(dir) != -1) {
+		CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
+		if ((smfs_cow(dir, dentry->d_parent, 0))) {
+			CERROR("Do cow error\n");
+			RETURN(-EINVAL);
+		}
+	}
+        RETURN(rc);
+}
+
+int smfs_cow_setattr(struct inode *dir, struct dentry *dentry)
+{
+        int rc = 0;
+        ENTRY;
+        
+        RETURN(rc);
+}
+
+int smfs_cow_link(struct inode *dir, struct dentry *dentry)
+{
+        int rc = 0;
+        ENTRY;
+        
+        RETURN(rc);
+}
+
+int smfs_cow_unlink(struct inode *dir, struct dentry *dentry)
+{
+        int rc = 0;
+        ENTRY;
+        
+        RETURN(rc);
+}
+
+int smfs_cow_rename(struct inode *dir, struct dentry *dentry)
+{
+        int rc = 0;
+        ENTRY;
+        
+        RETURN(rc);
+}
+
+int smfs_cow_write(struct inode *dir, struct dentry *dentry)
+{
+        int rc = 0;
+        ENTRY;
+        
+        RETURN(rc);
+}
+
+typedef int (*cow_funcs)(struct inode *dir, struct dentry *dentry);
+
+static cow_funcs smfs_cow_funcs[REINT_MAX + 1] = {
+        [REINT_SETATTR] smfs_cow_setattr,
+        [REINT_CREATE]  smfs_cow_create,
+        [REINT_LINK]    smfs_cow_link,
+        [REINT_UNLINK]  smfs_cow_unlink,
+        [REINT_RENAME]  smfs_cow_rename,
+        [REINT_WRITE]   smfs_cow_write,
+};
+
+int smfs_cow(struct inode *dir, struct dentry *dentry, int op)
+{
+        return smfs_cow_funcs[op](dir, dentry);
+}
+
diff --git a/lustre/smfs/smfs_internal.h b/lustre/smfs/smfs_internal.h
index 2c021003e30f3b9355d2e854ad447d52987308e6..541afbf439e6ac4f0c3e2ff409d332e5ed272500 100644
--- a/lustre/smfs/smfs_internal.h
+++ b/lustre/smfs/smfs_internal.h
@@ -196,7 +196,9 @@ extern int smfs_llog_add_rec(struct smfs_super_info * sinfo, void *data,
 /*ioctl.c*/
 extern int init_smfs_psdev(void);
 extern void smfs_cleanup_psdev(void);
+/*smfs_cow.c */
 
+extern int smfs_cow_init(struct super_block *sb);
 /* cache_space.c */
 extern int do_cache_manage;
 struct cache_purge_queue {
@@ -306,6 +308,21 @@ static inline int get_active_entry(struct inode *dir, __u64 *active_entry)
                         GOTO(label, rc);                                \
         }                                                               \
 }
+#if CONFIG_SNAP
+/*snap macros*/
+#define SMFS_PRE_COW(dir, dentry, op, name, rc, label)                  \
+do {                                                                    \
+        if (smfs_do_cow(dir) && !rc) {                                  \
+                CDEBUG(D_INODE, "Do %s snap post for dir %lu \n",       \
+                              name, dir->i_ino);                        \
+                rc = smfs_cow(dir, dentry, op);                         \
+                if (rc)                                                 \
+                        GOTO(label, rc);                                \
+        }                                                               \
+} while(0)
+#else
+#define SMFS_PRE_COW(dir, dentry, op, name, rc, label)                 
+#endif 
 
 #endif /*__KERNEL*/
 #endif /* __LINUX_SMFS_H */
diff --git a/lustre/smfs/super.c b/lustre/smfs/super.c
index 55d316a4eca12b0e0c6b978ad085c227a3feaa5e..b92eaf75791ba65e481f352bf2c7926c9e80a39f 100644
--- a/lustre/smfs/super.c
+++ b/lustre/smfs/super.c
@@ -46,7 +46,8 @@
 #include "smfs_internal.h"
 
 static char *smfs_options(char *data, char **devstr, char **namestr,
-                          int *kml, int *cache, char **opts, int *iopen_nopriv)
+                          int *kml, int *cache, char **opts, int *iopen_nopriv,
+                          int *cow)
 {
         char *pos;
         struct option *opt_value = NULL;
@@ -70,6 +71,8 @@ static char *smfs_options(char *data, char **devstr, char **namestr,
                 } else if (!strcmp(opt_value->opt, "iopen_nopriv")) {
                         if (iopen_nopriv != NULL)
                                 *iopen_nopriv = 1;
+                } else if (!strcmp(opt_value->opt, "snap")) {
+                                *cow = 1;
                 } else {
                         break;
                 }
@@ -249,7 +252,7 @@ static int smfs_fill_super(struct super_block *sb,
 
         int iopen_nopriv = 0;
         struct inode *root_inode = NULL;
-        int err = 0, do_rec = 0, cache_hook = 0;
+        int err = 0, do_rec = 0, cache_hook = 0, do_cow = 0;
         char *devstr = NULL, *typestr = NULL, *opts = NULL;
 
         ENTRY;
@@ -262,7 +265,7 @@ static int smfs_fill_super(struct super_block *sb,
         /* read and validate passed options. */
         cache_data = smfs_options(data, &devstr, &typestr,
                                   &do_rec, &cache_hook, &opts,
-                                  &iopen_nopriv);
+                                  &iopen_nopriv, &do_cow);
 
         if (*cache_data)
                 CWARN("smfs_fill_super(): options parsing stoped at "
@@ -280,7 +283,7 @@ static int smfs_fill_super(struct super_block *sb,
 
         if (do_rec) smfs_rec_init(sb);
         if (cache_hook) cache_space_hook_init(sb);
-
+        
         dget(S2CSB(sb)->s_root);
         root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
         root_inode = iget(sb, root_ino);
@@ -294,13 +297,9 @@ static int smfs_fill_super(struct super_block *sb,
                 sm_umount_cache(sb);
                 GOTO(out_err, err=-EINVAL);
         }
-
-        sb->s_root = d_alloc_root(root_inode);
-
-        if (!sb->s_root) {
-                sm_umount_cache(sb);
-                GOTO(out_err, err = -EINVAL);
-        }
+#if CONFIG_SNAP
+        if (do_cow) smfs_cow_init(sb);
+#endif
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",