Whamcloud - gitweb
- mdc_op_data should not be allocated on stack.
[fs/lustre-release.git] / lustre / smfs / smfs_cow.c
index 5b4f579..9fe77a6 100644 (file)
 #include <linux/lustre_idl.h>
 #include <linux/lustre_fsfilt.h>
 
-#include <linux/lustre_snap.h>
 #include <linux/lustre_smfs.h>
+#include <linux/lustre_snap.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)
+
+#define SNAPTABLE_SIZE(size) (sizeof(struct snap_table) +       \
+                              size * sizeof(struct snap))
+
+int smfs_cleanup_snap_info(struct snap_info *snap_info);
+
+static int smfs_init_snap_super_info(struct smfs_super_info *smfs_info)
+{
+        struct snap_super_info  *snap_sinfo;
+        int rc = 0;
+
+        ENTRY;
+        
+        OBD_ALLOC(smfs_info->smsi_snap_info,
+                  sizeof(struct snap_super_info));
+        
+        if (!smfs_info->smsi_snap_info) 
+                GOTO(exit, rc = -ENOMEM);
+
+        snap_sinfo = smfs_info->smsi_snap_info;
+
+        /*init snap fsfilt operations*/
+        if (!snap_sinfo->snap_cache_fsfilt) {
+                char *snap_cache_ftype = NULL;
+                int   tmp = strlen(smfs_info->smsi_cache_ftype) + strlen("_snap");
+                
+                OBD_ALLOC(snap_cache_ftype, tmp + 1);  
+                sprintf(snap_cache_ftype, "%s_snap", smfs_info->smsi_cache_ftype);
+                snap_sinfo->snap_cache_fsfilt = fsfilt_get_ops(snap_cache_ftype);
+                OBD_FREE(snap_cache_ftype, tmp + 1);
+                if (!snap_sinfo->snap_cache_fsfilt) {
+                        CERROR("Can not get %s fsfilt ops needed by snap\n",
+                               snap_cache_ftype);
+                        GOTO(exit, rc = -EINVAL);
+                }
+        }
+        if (!snap_sinfo->snap_fsfilt) {
+                char *snap_ftype = NULL;
+                int   tmp = strlen(smfs_info->smsi_ftype) + strlen("_snap");
+                
+                OBD_ALLOC(snap_ftype, tmp + 1);  
+                sprintf(snap_ftype, "%s_snap", smfs_info->smsi_ftype);
+                snap_sinfo->snap_fsfilt = fsfilt_get_ops(snap_ftype);
+                OBD_FREE(snap_ftype, tmp + 1);
+                if (!snap_sinfo->snap_fsfilt) {
+                        CERROR("Can not get %s fsfilt ops needed by snap\n",
+                               snap_ftype);
+                        GOTO(exit, rc = -EINVAL);
+                }
+        }
+        INIT_LIST_HEAD(&snap_sinfo->snap_list);
+exit:
+        if (rc && smfs_info->smsi_snap_info)
+                OBD_FREE(snap_sinfo, sizeof(struct snap_super_info));
+        RETURN(rc);
+}
+/*FIXME-wangdi Should remove it when integrated it with lustre*/
+static struct dentry *smfs_simple_mkdir(struct dentry *dir, char *name, 
+                                        int mode, int fix)
+{
+        struct dentry *dchild;
+        int err = 0;
+        
+        dchild = ll_lookup_one_len(name, dir, strlen(name));
+        if (IS_ERR(dchild))
+                GOTO(out_up, dchild);
+        
+        if (dchild->d_inode) {
+                int old_mode = dchild->d_inode->i_mode;
+                if (!S_ISDIR(old_mode))
+                        GOTO(out_err, err = -ENOTDIR);
+                                                                                                                                                                                                     
+                /* Fixup directory permissions if necessary */
+                if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
+                        CWARN("fixing permissions on %s from %o to %o\n",
+                              name, old_mode, mode);
+                        dchild->d_inode->i_mode = (mode & S_IALLUGO) |
+                                                  (old_mode & ~S_IALLUGO);
+                        mark_inode_dirty(dchild->d_inode);
+                }
+                GOTO(out_up, dchild);
+        }
+        err = vfs_mkdir(dir->d_inode, dchild, mode);
+        if (err)
+                GOTO(out_err, err);
+        RETURN(dchild);
+out_err:
+        dput(dchild);
+        dchild = ERR_PTR(err);
+out_up:
+        return dchild;
+
+}
+static struct snap_info *smfs_find_snap_info(struct inode *inode)
+{
+        struct snap_inode_info *snap_iinfo = I2SNAPI(inode);
+        struct snap_super_info *snap_sinfo = S2SNAPI(inode->i_sb);
+        struct snap_info *snap_info = NULL, *tmp; 
+
+        ENTRY;
+        list_for_each_entry_safe(snap_info, tmp, &snap_sinfo->snap_list, 
+                                 sni_list) {
+               if (snap_info->sni_root_ino == snap_iinfo->sn_root_ino)
+                        RETURN(snap_info); 
+        }
+        RETURN(NULL);
+}
+
+#if 0
+static int smfs_dotsnap_dir_size(struct inode *inode)
+{
+        struct snap_super_info *snap_sinfo = S2SNAPI(inode->i_sb);
+        struct fsfilt_operations *snapops = snap_sinfo->snap_cache_fsfilt; 
+        int size = 0, dir_size = 0, blocks, i = 0;
+        struct snap_table *snap_table = NULL; 
+        struct snap_info *snap_info = NULL;
+        ENTRY;
+       
+        snap_info = smfs_find_snap_info(inode);
+        
+        if (!snap_info) {
+                CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+                RETURN(0);                
+        }
+        snap_table = snap_info->sni_table;
+        for (i = 0; i < snap_table->sntbl_count; i++) {
+                char *name = snap_table->sntbl_items[i].sn_name;
+                size += snapops->fs_dir_ent_size(name);
+        }
+        /*FIXME this is only for ext3 dir format, may need fix for other FS*/ 
+        blocks = (size + inode->i_sb->s_blocksize - 1) >> 
+                                inode->i_sb->s_blocksize_bits; 
+        
+        dir_size = blocks * inode->i_sb->s_blocksize; 
+        RETURN(dir_size); 
+
+}
+#endif
+
+static int smfs_init_snap_inode_info(struct inode *inode, struct inode *dir, int index) 
+{
+        int rc = 0;
+        ENTRY;
+
+        if (!inode)
+                RETURN(0);
+
+        if (dir) {
+                I2SNAPI(inode)->sn_flags = I2SNAPI(dir)->sn_flags;
+                I2SNAPI(inode)->sn_gen = I2SNAPI(dir)->sn_gen;
+                I2SNAPI(inode)->sn_root_ino = I2SNAPI(dir)->sn_root_ino;
+                I2SNAPI(inode)->sn_index = I2SNAPI(inode)->sn_index; 
+        } else {
+                I2SNAPI(inode)->sn_flags = 0;
+                I2SNAPI(inode)->sn_gen = 0;
+        }
+        
+        I2SNAPI(inode)->sn_index = index;
+        if (smfs_dotsnap_inode(inode)) {
+                struct snap_info *snap_info;
+
+                snap_info = smfs_find_snap_info(inode);
+                if (!snap_info) {
+                        RETURN(-EIO);
+                }
+                /*init dot_snap inode info*/
+//              inode->i_size = (loff_t)smfs_dotsnap_dir_size(inode);
+                inode->i_size = snap_info->sni_table->sntbl_count;
+                inode->i_nlink = snap_info->sni_table->sntbl_count + 2;
+                inode->i_uid = 0;
+                inode->i_gid = 0;
+        } else if (SMFS_DO_COW(S2SMI(inode->i_sb)) && 
+                   (I2SMI(inode)->smi_flags & SM_DO_COW) &&
+                   smfs_primary_inode(inode)) {
+                struct snap_inode_info *sni_info = I2SNAPI(inode);
+                struct fsfilt_operations *sops = I2SNAPCOPS(inode);
+                int vallen = 0;
+                vallen = sizeof(sni_info->sn_gen);
+                
+                rc = sops->fs_get_snap_info(I2CI(inode), SNAP_GENERATION,
+                                            strlen(SNAP_GENERATION),
+                                            &sni_info->sn_gen, &vallen);               
+        } 
+        RETURN(rc);                                              
+}
+
+#define COWED_NAME_LEN       (7 + 8 + 1) 
+static int smfs_init_cowed_dir(struct snap_info *snap_info, struct inode* inode)  
+{
+        struct dentry    *dentry = NULL;
+        char   name[COWED_NAME_LEN];
+        int    rc = 0;
+        ENTRY;
+         
+        sprintf(name, ".cowed_%08x", (__u32)inode->i_ino);
+        /*FIXME-WANGDI: will use simple_mkdir, when integrating snap to lustre*/
+        dentry = smfs_simple_mkdir(inode->i_sb->s_root, name, 0777, 1);
+        if (IS_ERR(dentry)) {
+                rc = PTR_ERR(dentry);
+                CERROR("create cowed directory: rc = %d\n", rc);
+                RETURN(rc);
+        }
+        snap_info->sni_cowed_dentry = dentry;
+        /*cleanup cowed inode attr for cowed dir*/
+        SMFS_CLEAN_INODE_COWED(dentry->d_inode);
+        RETURN(rc);
+}
+
+static int smfs_init_dotinfo(struct snap_info *snap_info)
+{
+        struct snap_dot_info *dot_info = NULL;
+        int rc = 0;
+        ENTRY;
+
+        if (snap_info->sni_dot_info)
+                RETURN(-EEXIST);
+       
+        OBD_ALLOC(snap_info->sni_dot_info, sizeof(struct snap_dot_info));
+        
+        if (!snap_info->sni_dot_info)
+                RETURN(-ENOMEM); 
+      
+        dot_info = snap_info->sni_dot_info;
+        OBD_ALLOC(dot_info->dot_name,  strlen(DOT_SNAP_NAME) + 1);
+
+        if (!dot_info->dot_name) {
+                OBD_FREE(snap_info->sni_dot_info, sizeof(struct snap_dot_info));
+                RETURN(-ENOMEM); 
+        } 
+        memcpy(dot_info->dot_name, DOT_SNAP_NAME, strlen(DOT_SNAP_NAME));
+        
+        dot_info->dot_name_len = strlen(DOT_SNAP_NAME); 
+        dot_info->dot_snap_enable = 1;
+        
+        RETURN(rc);
+}
+
+static int smfs_init_snap_info(struct smfs_super_info *smb, 
+                               struct snap_info *snap_info, struct inode *inode) 
 {
-        struct snap_info         *snap_info = S2SNAPI(sb);     
         struct snap_table        *snap_table = NULL;       
-       struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
-        int                      rc = 0, size, table_size, vallen;
+       struct fsfilt_operations *snapcops;
+        int                      rc = 0, size, table_size, vallen, i;
  
         ENTRY;
 
-        init_MUTEX(&snap_info->sntbl_sema);
+        snapcops = smb->smsi_snap_info->snap_cache_fsfilt;
         /*Initialized table */
         /*get the maxsize of snaptable*/
         vallen = sizeof(int);
-        rc = snapops->fs_get_snap_info(sb, NULL, MAX_SNAPTABLE_COUNT,
+        rc = snapcops->fs_get_snap_info(I2CI(inode), MAX_SNAPTABLE_COUNT,
                                        strlen(MAX_SNAPTABLE_COUNT), &size, 
                                        &vallen);
         if (size == 0) {
                 CERROR("the Max snaptable count should not be zero\n");
-                RETURN(-EINVAL);
+                GOTO(exit, rc);
         }
-        
         table_size = SNAPTABLE_SIZE(size);
 
-        OBD_ALLOC(snap_info->sntbl, table_size);
+        OBD_ALLOC(snap_info->sni_table, table_size);
 
-        if (!snap_info->sntbl) {
+        if (!snap_info->sni_table) {
                 CERROR("No MEM\n");
                 RETURN(-ENOMEM);
         }
-        snap_table = snap_info->sntbl;
+        snap_table = snap_info->sni_table;
          
         snap_table->sntbl_magic = cpu_to_le32((__u32)SNAPTABLE_MAGIC); 
         snap_table->sntbl_max_count = size;
+        /*init sn_index to -1*/ 
+        for (i = 0; i < snap_table->sntbl_max_count; i++) 
+                snap_table->sntbl_items[i].sn_index = -1;
         /*get snaptable info*/
-
-        rc = snapops->fs_get_snap_info(sb, NULL, SNAPTABLE_INFO, 
-                                       strlen(SNAPTABLE_INFO), 
-                                       snap_table, &table_size);       
+        rc = snapcops->fs_get_snap_info(I2CI(inode), SNAPTABLE_INFO, 
+                                        strlen(SNAPTABLE_INFO), 
+                                        snap_table, &table_size);       
         if (rc < 0) {
-                if (rc == -ENOATTR) {
+                if (rc == -ENODATA) {
                         snap_table->sntbl_count = 0;
-                        CDEBUG(D_INFO, "No snaptable here\n");
-                        RETURN(0);
+                        rc = 0;
                 } else {
                         CERROR("Can not retrive the snaptable from this filesystem\n");
-                        OBD_FREE(snap_table, table_size);
-                        RETURN(rc); 
+                        GOTO(exit, rc);
                 }
-        } 
-        if (le32_to_cpu(snap_table->sntbl_magic) != SNAPTABLE_MAGIC) {
-                CERROR("On disk snaptable is not right \n");
-                OBD_FREE(snap_table, table_size);
-                RETURN(-EIO);
+        } else { 
+                if (le32_to_cpu(snap_table->sntbl_magic) != SNAPTABLE_MAGIC) {
+                        CERROR("On disk snaptable is not right \n");
+                        GOTO(exit, rc = -EIO);
+                }
+        }
+        init_MUTEX(&snap_info->sni_sema);
+        snap_info->sni_root_ino = inode->i_ino;
+        rc = smfs_init_cowed_dir(snap_info, inode);
+        if (rc) {
+                CERROR("Init cowed dir error rc=%d\n", rc);
+                GOTO(exit, rc); 
         }
+        rc = smfs_init_dotinfo(snap_info);
+exit:
+        if (rc && snap_table)
+                OBD_FREE(snap_table, table_size);
         RETURN(rc);
 }
-#define COWED_NAME_LEN       (7 + 8 + 1) 
-static int smfs_init_cowed_dir(struct super_block *sb, struct dentry* cowed_dir)  
+
+static struct snap_info *smfs_create_snap_info(struct smfs_super_info *sinfo, 
+                                               struct inode *inode)
 {
-        struct snap_info *snap_info = S2SNAPI(sb);     
-        struct dentry    *dentry = NULL;
-        struct lvfs_run_ctxt saved;
-        char   name[COWED_NAME_LEN];
-        int    rc = 0;
+        struct snap_info *snap_info = NULL;
+        int rc = 0;
         ENTRY;
-         
-        sprintf(name, ".cowed_%08x", (__u32)cowed_dir->d_inode->i_ino);
-        push_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
-        dentry = simple_mkdir(cowed_dir, name, 0777, 1);
-        pop_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
-        if (IS_ERR(dentry)) {
-                rc = PTR_ERR(dentry);
-                CERROR("create cowed directory: rc = %d\n", rc);
-                RETURN(rc);
+        OBD_ALLOC(snap_info, sizeof(struct snap_info)); 
+        if (!snap_info) 
+                RETURN(ERR_PTR(-ENOMEM));  
+        rc = smfs_init_snap_info(sinfo, snap_info, inode);  
+        if (rc) 
+                GOTO(exit, rc);
+       
+        /*set cow flags for the snap root inode*/ 
+        I2SMI(inode)->smi_flags |= SM_DO_COW;
+        I2SNAPI(inode)->sn_root_ino = inode->i_ino; 
+exit:
+        if (rc) {
+                OBD_FREE(snap_info, sizeof(struct snap_info));
+                snap_info = ERR_PTR(rc);
         }
-        snap_info->sn_cowed_dentry = dentry;
-        RETURN(rc);
+        RETURN(snap_info);
 }
-int smfs_start_cow(struct super_block *sb)
+
+static int smfs_cow_pre(struct inode *dir, void *dentry, void *new_dir, 
+                        void *new_dentry, int op);
+
+static int smfs_cow_post(struct inode *dir, void *dentry, void *new_dir, 
+                         void *new_dentry, int op);
+#define COW_HOOK "cow_hook"
+static int smfs_cow_pre_hook(struct inode *inode, void *dentry, void *data1,
+                             void *data2, int op, void *handle)
 {
-        struct smfs_super_info *smfs_info = S2SMI(sb);
         int rc = 0;
-
         ENTRY;
-        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);
-                }
+        if (smfs_do_cow(inode)) {
+                /*FIXME:WANGDI, get index from the dentry*/
+                #if 0
+                int index = 0;
+                smfs_get_dentry_name_index(dentry, &name, index);       
+                smfs_free_dentry_name(&name);
+                #endif
+                rc = smfs_cow_pre(inode, dentry, data1, data2, op);           
         }
-        rc = smfs_init_snaptabe(sb); 
-        if (rc) {
-                CERROR("can not init snaptable rc=%d\n", rc);
-                RETURN(rc);
+        RETURN(rc);                                                                     
+}
+static int smfs_cow_post_hook(struct inode *inode, void *dentry, void *data1, 
+                              void *data2, int op, void *handle)
+{
+        int rc = 0;
+        ENTRY;
+        if (smfs_do_cow(inode)) {
+                rc = smfs_cow_post(inode, dentry, data1, data2, op);           
         }
-        /*init cowed dir to put the primary cowed inode
-         *FIXME-WANGDI, later the s_root may not be the 
-         *snap dir, we can indicate any dir to be cowed*/
-        rc = smfs_init_cowed_dir(sb, sb->s_root);
-        RETURN(rc);
+        RETURN(rc);                                                                     
 }
-EXPORT_SYMBOL(smfs_start_cow);
-int smfs_stop_cow(struct super_block *sb)
+
+int smfs_cow_cleanup(struct smfs_super_info *smb)
 {
-        struct snap_info       *snap_info = S2SNAPI(sb);       
-        struct snap_table      *snap_table = snap_info->sntbl; 
-        int rc = 0, table_size;
+        struct snap_super_info   *snap_sinfo = smb->smsi_snap_info;
+        struct list_head        *snap_list = &snap_sinfo->snap_list; 
+        struct smfs_hook_ops     *cow_hops;
+        int                      rc = 0; 
         ENTRY;
 
-        l_dput(snap_info->sn_cowed_dentry);
+        while (!list_empty(snap_list)) {
+                struct snap_info *snap_info;
+                
+                snap_info = list_entry(snap_list->next, struct snap_info,
+                                       sni_list); 
+                rc = smfs_cleanup_snap_info(snap_info); 
+                if (rc) 
+                        CERROR("cleanup snap_info error rc=%d\n", rc);
+                list_del(&snap_info->sni_list); 
+                OBD_FREE(snap_info, sizeof(struct snap_info));
+        } 
          
-        if (snap_info->snap_fsfilt) 
-                fsfilt_put_ops(snap_info->snap_fsfilt);
-        if (snap_info->snap_cache_fsfilt)
-                fsfilt_put_ops(snap_info->snap_cache_fsfilt);
+        if (snap_sinfo->snap_fsfilt) 
+                fsfilt_put_ops(snap_sinfo->snap_fsfilt);
+        if (snap_sinfo->snap_cache_fsfilt)
+                fsfilt_put_ops(snap_sinfo->snap_cache_fsfilt);
 
-        if (snap_table) {
-                table_size =  SNAPTABLE_SIZE(snap_table->sntbl_max_count);
-                OBD_FREE(snap_info->sntbl, table_size);
-        }
-        if (snap_info) 
-               OBD_FREE(snap_info, sizeof(*snap_info)); 
-        
+        cow_hops = smfs_unregister_hook_ops(smb, COW_HOOK);
+        smfs_free_hook_ops(cow_hops);
+
+        SMFS_CLEAN_COW(smb);
+        if (snap_sinfo) 
+               OBD_FREE(snap_sinfo, sizeof(struct snap_super_info));
         RETURN(rc);
 }
-EXPORT_SYMBOL(smfs_stop_cow);
 
 int smfs_cow_init(struct super_block *sb)
 {
         struct smfs_super_info *smfs_info = S2SMI(sb);
-        int rc = 0;
+        struct smfs_hook_ops *cow_hops = NULL;
+        struct fsfilt_operations *sops;
+        struct inode *root_inode = smfs_info->smsi_sb->s_root->d_inode; 
+        int snap_count = 0, rc = 0, vallen;
+
+        ENTRY;
 
         SMFS_SET_COW(smfs_info);
       
+        cow_hops = smfs_alloc_hook_ops(COW_HOOK, smfs_cow_pre_hook, 
+                                       smfs_cow_post_hook);
+        if (!cow_hops) {
+                RETURN(-ENOMEM);
+        }
+        rc = smfs_register_hook_ops(smfs_info, cow_hops);
+        if (rc) {
+                smfs_free_hook_ops(cow_hops);
+                RETURN(rc);
+        }
+        
+        rc = smfs_init_snap_super_info(smfs_info);
+        if (rc && cow_hops) {
+                smfs_unregister_hook_ops(smfs_info, cow_hops->smh_name);
+                smfs_free_hook_ops(cow_hops);
+                RETURN(rc);
+        }
+        sops = smfs_info->smsi_snap_info->snap_cache_fsfilt; 
+        
+        vallen = sizeof(int); 
+        rc = sops->fs_get_snap_info(root_inode, SNAP_COUNT, strlen(SNAP_COUNT),
+                                    &snap_count, &vallen);
+        if (rc < 0)
+                GOTO(exit, rc);       
+        if (snap_count > 0) {
+                int snap_root_size = snap_count * sizeof(ino_t);
+                ino_t *snap_root;
+                int i;
+                
+                OBD_ALLOC(snap_root, snap_root_size);
+                
+                if (!snap_root)
+                        GOTO(exit, rc = -ENOMEM); 
+                
+                rc = sops->fs_get_snap_info(root_inode, SNAP_ROOT_INO, 
+                                            strlen(SNAP_ROOT_INO), snap_root, 
+                                            &snap_root_size);
+                if (rc < 0) {
+                        OBD_FREE(snap_root, sizeof(int) * snap_count);
+                        GOTO(exit, rc);
+                }
+                for (i = 0; i < snap_count; i++) {
+                        ino_t root_ino = le32_to_cpu(snap_root[i]);
+                        struct snap_info *snap_info;                      
+                        root_inode = smfs_get_inode(sb, root_ino, NULL, 0);
+                        smfs_init_snap_inode_info(root_inode, NULL, 0);
+                        snap_info = smfs_create_snap_info(S2SMI(sb), root_inode);
+                        iput(root_inode);
+                        if (IS_ERR(snap_info)) {
+                                OBD_FREE(snap_root, sizeof(int) * snap_count);
+                                GOTO(exit, rc = PTR_ERR(snap_info));
+                        }                
+                        list_add(&snap_info->sni_list, 
+                                 &(S2SNAPI(sb)->snap_list));        
+                }
+        }      
+        smfs_info->smsi_snap_info->snap_count = snap_count; 
+exit:
+        if (rc) 
+                smfs_cow_cleanup(smfs_info);
         RETURN(rc);
 }
 
-int smfs_cow_cleanup(struct super_block *sb)
-{
+static int smfs_cleanup_dotinfo(struct snap_info *snap_info)
+{       
+        struct snap_dot_info *dot_info = NULL;
+        int rc = 0;
         ENTRY;
-        SMFS_CLEAN_COW(S2SMI(sb));
-        RETURN(0);
+
+        if (!snap_info->sni_dot_info)
+                RETURN(rc);
+       
+        dot_info = snap_info->sni_dot_info;
+
+        if (dot_info->dot_name) { 
+                OBD_FREE(dot_info->dot_name, dot_info->dot_name_len + 1);
+        }
+        
+        OBD_FREE(dot_info, sizeof(struct snap_dot_info));
+
+        RETURN(rc);
 }
 
-/*FIXME Note indirect and primary inode 
-* should be recorgnized here*/
-int smfs_init_snap_inode_info(struct inode *inode, int flags)
+int smfs_cleanup_snap_info(struct snap_info *snap_info)
 {
-        int vallen, rc = 0;
+        struct snap_table      *snap_table = snap_info->sni_table;
+        int rc = 0, table_size;
         ENTRY;
 
-        if (SMFS_DO_COW(S2SMI(inode->i_sb)) &&
-            (flags & SM_DO_COW)) {
-                struct snap_inode_info *sni_info = I2SNAPI(inode);
-                struct fsfilt_operations *snapops = I2SNAPOPS(inode);
-                
-                sni_info->sn_flags = flags;
-                vallen = sizeof(sni_info->sn_gen);
+        l_dput(snap_info->sni_cowed_dentry);
+        //d_unalloc(snap_info->sni_cowed_dentry);
+        if (snap_table) {
+                table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count);
+                OBD_FREE(snap_info->sni_table, table_size);
+        }
+        smfs_cleanup_dotinfo(snap_info);
+        RETURN(rc);
+}
 
-                rc = snapops->fs_get_snap_info(NULL, inode, SNAP_GENERATION,
-                                               strlen(SNAP_GENERATION),
-                                               &sni_info->sn_gen, &vallen);               
-        } 
-        RETURN(rc);                                              
-         
+int smfs_snap_test_inode(struct inode *inode, void *args)
+{ 
+        struct smfs_iget_args *sargs = (struct smfs_iget_args*)args;
+        struct inode *dir;
+
+        LASSERT(sargs);
+        
+        dir = sargs->s_inode;
+        
+        if (sargs->s_index > 0) { 
+                if (I2SNAPI(inode)->sn_index != sargs->s_index)
+                        return 0;
+        }else {
+                if (dir && I2SNAPI(inode)->sn_index != I2SNAPI(dir)->sn_index)
+                        return 0;
+        }
+        return 1;
 }
 /* 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)
+void snap_last(struct inode *inode, struct snap *snap)
 {
-       struct snap_info *snap_info = S2SNAPI(sb);
-       struct snap_table *table = snap_info->sntbl;
-        time_t now = CURRENT_TIME;
+        time_t now = LTIME_S(CURRENT_TIME);
+       struct snap_table *snap_table;
+        struct snap_info  *snap_info;
        int i ;
 
        ENTRY;
+
+        snap_info = smfs_find_snap_info(inode);
+        if (!snap_info) {
+                CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+                EXIT;
+                return;
+        }
+        snap_table = snap_info->sni_table;
        /* start at the highest index in the superblock snaptime array */ 
-       if (table->sntbl_count == 0) {
+       if (snap_table->sntbl_count == 0) {
                memset(snap, 0, sizeof(struct snap)); 
         } else {
-                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;
+                i = snap_table->sntbl_count - 1;
+                snap->sn_index = snap_table->sntbl_items[i].sn_index;
+                snap->sn_time = snap_table->sntbl_items[i].sn_time;
+                snap->sn_gen = snap_table->sntbl_items[i].sn_gen;
         }
        CDEBUG(D_INFO, "index: %d, time[i]: %ld, now: %ld\n",
               snap->sn_index, snap->sn_time, now);
@@ -263,7 +609,7 @@ void snap_last(struct super_block *sb, struct snap *snap)
        return;
 }
 
-static int inline get_index_of_item(struct snap_table *table, char *name)
+static inline int get_index_of_item(struct snap_table *table, char *name)
 {
        int count = table->sntbl_count;
        int i, j;
@@ -276,7 +622,7 @@ static int inline get_index_of_item(struct snap_table *table, char *name)
                 }      
        }
 
-       for (i = 0; i < table->sntbl_max_count; i++) {
+       for (i = 1; i <= table->sntbl_max_count; i++) {
                int found = 0;
                for (j = 0; j < (count + 1); j++) {
                        if (table->sntbl_items[j].sn_index == i) {
@@ -291,21 +637,53 @@ static int inline get_index_of_item(struct snap_table *table, char *name)
        RETURN(-ENOSPC);
 }
 
-int smfs_add_snap_item(struct super_block *sb, char *name)
+static struct dentry *smfs_find_snap_root(struct super_block *sb, 
+                                          char *path_name)
 {
-       struct snap_info *snap_info = S2SNAPI(sb);
-        struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
-        struct snap_table *snap_table = snap_info->sntbl;
-        struct snap      *snap_item;
-        int    table_size, count = 0, index = 0, rc = 0;
+        struct dentry *dentry = NULL;
+        struct nameidata nd;
+        ENTRY;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+        if (path_init(path_name, LOOKUP_FOLLOW, &nd)) {
+                int error = path_walk(path_name, &nd);
+                if (error) {
+                        path_release(&nd);
+                        RETURN(NULL);
+                }
+        } else {
+                RETURN(NULL);
+        }
+#else
+        if (path_lookup(path_name, LOOKUP_FOLLOW, &nd))
+                RETURN(NULL);
+#endif
+        dentry = dget(nd.dentry); 
+        path_release(&nd);
+        RETURN(dentry); 
+}
+
+static int snap_add_item(struct smfs_super_info *smb, 
+                         struct snap_info *snap_info,
+                         char *name)
+{        
+        struct fsfilt_operations *snapops;
+        struct snap_table        *snap_table = snap_info->sni_table;
+        struct inode             *root_inode = NULL;
+        int                      table_size, count = 0, index = 0, rc = 0;
+               struct  snap             *snap_item;
+        ENTRY;
 
         count = snap_table->sntbl_count; 
+        root_inode = iget(smb->smsi_sb, snap_info->sni_root_ino);
+        if (!root_inode || is_bad_inode(root_inode)) 
+                RETURN(-EIO); 
        /* XXX Is down this sema necessary*/
-       down_interruptible(&snap_info->sntbl_sema);
+       down_interruptible(&snap_info->sni_sema);
         snap_item = &snap_table->sntbl_items[count];
-
+        snapops = smb->smsi_snap_info->snap_cache_fsfilt;
        /*add item in snap_table set generation*/
-       snap_item->sn_time = CURRENT_TIME;
+       snap_item->sn_time = LTIME_S(CURRENT_TIME);
        /* find table index */
        index = get_index_of_item(snap_table, name);
         if (index < 0) 
@@ -317,21 +695,127 @@ int smfs_add_snap_item(struct super_block *sb, char *name)
        memcpy(snap_item->sn_name, name, SNAP_MAX_NAMELEN);
        /* Wrote the whole snap_table to disk */
         table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count); 
-        
-        rc = snapops->fs_set_snap_info(sb, NULL, SNAPTABLE_INFO, 
+         
+        snap_table->sntbl_count++;
+       snap_table->sntbl_generation++;
+        rc = snapops->fs_set_snap_info(root_inode, SNAPTABLE_INFO, 
                                        strlen(SNAPTABLE_INFO),
                                       snap_table, &table_size);
        if (rc) {
+                snap_table->sntbl_count--;
+               snap_table->sntbl_generation--;
                 CERROR("Set snaptable error rc=%d\n", rc);
                 GOTO(exit, rc);
         }
-        snap_table->sntbl_count++;
-       snap_table->sntbl_generation++;
 exit:
-       up(&snap_info->sntbl_sema);
+       up(&snap_info->sni_sema);
+        if (root_inode)
+                iput(root_inode);
        RETURN(rc);
 }
-EXPORT_SYMBOL(smfs_add_snap_item);
+
+static struct snap_info * smfs_find_create_snap_info(struct super_block *sb, 
+                                                     struct inode *inode) 
+{      
+        struct snap_super_info   *snap_sinfo = S2SNAPI(sb);
+        struct fsfilt_operations *sops = snap_sinfo->snap_cache_fsfilt;
+        struct snap_info *snap_info, *tmp;
+        ino_t *snap_root = NULL;
+        int    rino_size, snap_count_size, rc = 0;
+        ENTRY;
+        
+        list_for_each_entry_safe(snap_info, tmp, &snap_sinfo->snap_list, 
+                                 sni_list) {
+                if (snap_info->sni_root_ino == inode->i_ino) {
+                        RETURN(snap_info);
+                }      
+        } 
+
+        CDEBUG(D_INFO, "create a new  snap info root ino %lu\n", inode->i_ino);
+
+        snap_info = smfs_create_snap_info(S2SMI(sb), inode);  
+
+        if (IS_ERR(snap_info))
+                RETURN(snap_info);
+  
+        snap_sinfo->snap_count++;
+
+        rino_size = snap_sinfo->snap_count * sizeof(ino_t);
+
+        OBD_ALLOC(snap_root, rino_size);
+                
+        if (!snap_root)
+                GOTO(exit, rc = -ENOMEM); 
+                
+        rc = sops->fs_get_snap_info(I2CI(inode), SNAP_ROOT_INO, 
+                                    strlen(SNAP_ROOT_INO), snap_root, 
+                                    &rino_size);
+        if (rc < 0) {
+                if (rc == -ENODATA) {
+                        rc = 0;
+                } else {
+                        GOTO(exit, rc);
+                }
+        }
+        snap_root[snap_sinfo->snap_count - 1] = inode->i_ino;
+      
+        snap_count_size = sizeof(int);        
+        rc = sops->fs_set_snap_info(I2CI(inode), SNAP_COUNT, strlen(SNAP_COUNT), 
+                                    &snap_sinfo->snap_count,  &snap_count_size);
+        if (rc) 
+                GOTO(exit, rc);
+       
+        rc = sops->fs_set_snap_info(I2CI(inode), SNAP_ROOT_INO,
+                                    strlen(SNAP_ROOT_INO), snap_root,
+                                    &rino_size); 
+
+        if (rc)
+                GOTO(exit, rc);        
+
+        list_add(&snap_info->sni_list, &snap_sinfo->snap_list);        
+exit: 
+        if (rc) {
+                smfs_cleanup_snap_info(snap_info); 
+                OBD_FREE(snap_info, sizeof(struct snap_info));
+        }
+        if (snap_root)
+                OBD_FREE(snap_root, rino_size); 
+        RETURN(snap_info);  
+}         
+
+int smfs_add_snap_item(struct super_block *sb, char *path_name, char *name)
+{
+        struct dentry  *dentry = NULL;
+        struct snap_info *snap_info;
+        int            rc = 0;        
+        ENTRY;
+                
+        if (!SMFS_DO_COW(S2SMI(sb))) {
+                RETURN(0);
+        }
+
+        if (!path_name || !name) {
+                CERROR("patch_name and snapshot_name is NULL");
+                RETURN(-EINVAL);
+        } 
+        dentry = smfs_find_snap_root(sb, path_name);
+        if (IS_ERR(dentry)) {
+                CERROR("can not find snap_shot root by %s\n", path_name);
+                RETURN(PTR_ERR(dentry)); 
+        }
+        snap_info = smfs_find_create_snap_info(sb, dentry->d_inode);
+        if (IS_ERR(snap_info)) {
+                CERROR("can not find snap_info by %s rc=%lu\n", path_name,
+                        PTR_ERR(snap_info));
+                GOTO(exit, rc = PTR_ERR(snap_info)); 
+        }
+
+        rc = snap_add_item(S2SMI(sb), snap_info, name);
+exit:       
+        dput(dentry); 
+        RETURN(rc); 
+}        
+//EXPORT_SYMBOL(smfs_add_snap_item);
 /*
  * 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.
@@ -347,7 +831,7 @@ int smfs_needs_cow(struct inode *inode)
 
        snap_info = &(smi_info->sm_sninfo);
        
-        snap_last(inode->i_sb, &snap);
+        snap_last(inode, &snap);
        /* decision .... if the snapshot is more recent than the object,
         * then any change to the object should cause a COW.
         */
@@ -362,20 +846,26 @@ int smfs_needs_cow(struct inode *inode)
 
 static int link_cowed_inode(struct inode *inode)
 {
-        struct snap_info *snap_info = S2SNAPI(inode->i_sb);    
         struct dentry *cowed_dir = NULL;
-        char fidname[LL_FID_NAMELEN];
-        int fidlen = 0, rc = 0;
+        char idname[LL_ID_NAMELEN];
+        struct snap_info *snap_info;   
+        int idlen = 0, rc = 0;
         struct dentry *dchild = NULL;
         struct dentry *tmp = NULL;
         unsigned mode;
 
-        cowed_dir = snap_info->sn_cowed_dentry;
-        
-        fidlen = ll_fid2str(fidname, inode->i_ino, inode->i_generation);
+        snap_info = smfs_find_snap_info(inode);
+        if (!snap_info) {
+                CERROR("can not find snap info for inode %p\n", inode);
+                RETURN(-EINVAL);                
+        }
 
+        cowed_dir = snap_info->sni_cowed_dentry;
+        
         down(&cowed_dir->d_inode->i_sem);
-        dchild = ll_lookup_one_len(fidname, cowed_dir, fidlen);
+
+        idlen = ll_id2str(idname, inode->i_ino, inode->i_generation);
+        dchild = lookup_one_len(idname, cowed_dir, idlen);
         if (IS_ERR(dchild)) {
                 rc = PTR_ERR(dchild);
                 if (rc != -EPERM && rc != -EACCES)
@@ -392,22 +882,25 @@ static int link_cowed_inode(struct inode *inode)
          * for linking and return real mode back then -bzzz */
         mode = inode->i_mode;
         inode->i_mode = S_IFREG;
-        rc = vfs_link(tmp, cowed_dir->d_inode, dchild);
+
+        rc = cowed_dir->d_inode->i_op->link(tmp, cowed_dir->d_inode, dchild);         
+
         post_smfs_dentry(tmp);
         if (rc) {
                 CERROR("error linking cowed inode %s to COWED: rc = %d\n",
-                        fidname, rc);
+                        idname, rc);
         } 
         inode->i_mode = mode;
         if ((mode & S_IFMT) == S_IFDIR) {
                 dchild->d_inode->i_nlink++;
                 cowed_dir->d_inode->i_nlink++;
+                mark_inode_dirty(cowed_dir->d_inode);
+                mark_inode_dirty(dchild->d_inode);
         }
-        mark_inode_dirty(dchild->d_inode);
 out_dput:
+        up(&cowed_dir->d_inode->i_sem);
         dput(dchild);
 out_lock:       
-        up(&cowed_dir->d_inode->i_sem);
         RETURN(rc);
 }
 /*
@@ -416,56 +909,57 @@ out_lock:
  */
 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 fsfilt_operations *snapops = I2SNAPCOPS(inode);
         struct snap snap;
-       struct inode *ind = NULL;
-
-       ENTRY;
+       struct inode *cache_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);
-        if (!SMFS_DO_INODE_COWED(inode)) {
-                /*insert the inode to cowed inode*/
-                SMFS_SET_INODE_COWED(inode); 
-                link_cowed_inode(inode); 
+       snap_last(inode, &snap);
+       cache_ind = snapops->fs_create_indirect(I2CI(inode), snap.sn_index, 
+                                          snap.sn_gen, I2CI(dparent->d_inode), 
+                                          del);
+       if(cache_ind && IS_ERR(cache_ind)) {
+                CERROR("Create ind inode %lu index %d gen %d del %d rc%lu\n",
+                        inode->i_ino, snap.sn_index, snap.sn_gen, del,
+                        PTR_ERR(cache_ind));
+               RETURN(PTR_ERR(cache_ind));
+        }
+        if (cache_ind) {
+                iput(cache_ind);
+                if (!SMFS_DO_INODE_COWED(inode)) {
+                        /*insert the inode to cowed inode*/
+                        SMFS_SET_INODE_COWED(inode); 
+                        link_cowed_inode(inode); 
+                }
         }
-        
-        I2SMI(ind)->sm_sninfo.sn_flags = 0;
-        I2SMI(ind)->sm_sninfo.sn_gen = snap.sn_gen;
-        
-        iput(ind);
         RETURN(0);
 }
 /*Dir inode will do cow*/
-int smfs_cow_create(struct inode *dir, struct dentry *dentry,
-                    void *data1, void *data2)
+int smfs_cow_create_pre(struct inode *dir, void *de, void *data1, void *data2)
 {
-        int rc = 0;
         struct dentry *dparent;
+        struct dentry *dentry = (struct dentry *)de;
+        int rc = 0;
         ENTRY;
 
         if (smfs_needs_cow(dir) != -1) {
                CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
                 LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
                 dparent = dentry->d_parent->d_parent;
-               if ((snap_do_cow(dir, dparent, 0))) {
-                       CERROR("Do cow error\n");
+               if ((rc = snap_do_cow(dir, dparent, 0))) {
+                       CERROR("Do cow error %d\n", rc);
                        RETURN(-EINVAL);
                }
        }
         RETURN(rc);
 }
 
-int smfs_cow_setattr(struct inode *dir, struct dentry *dentry,
-                     void *data1, void *data2)
+int smfs_cow_setattr_pre(struct inode *dir, void *de, void *data1, void *data2)
 {
+        struct dentry *dentry = (struct dentry *)de;
         int rc = 0;
         ENTRY;
         if (smfs_needs_cow(dir) != -1) {
@@ -478,11 +972,11 @@ int smfs_cow_setattr(struct inode *dir, struct dentry *dentry,
         RETURN(rc);
 }
 
-int smfs_cow_link(struct inode *dir, struct dentry *dentry,
-                  void *data1, void *data2)
+int smfs_cow_link_pre(struct inode *dir, void *de, void *data1, void *data2)
 {
-        int rc = 0;
         struct dentry *dparent;
+        struct dentry *dentry = (struct dentry *)de;
+        int rc = 0;
         ENTRY;
  
         if (smfs_needs_cow(dir) != -1) {
@@ -501,9 +995,9 @@ int smfs_cow_link(struct inode *dir, struct dentry *dentry,
         RETURN(rc);
 }
 
-int smfs_cow_unlink(struct inode *dir, struct dentry *dentry,
-                    void *data1, void *data2)
+int smfs_cow_unlink_pre(struct inode *dir, void *de, void *data1, void *data2)
 {
+        struct dentry *dentry = (struct dentry *)de; 
         struct dentry *dparent;
         int rc = 0;
         ENTRY;
@@ -525,9 +1019,9 @@ int smfs_cow_unlink(struct inode *dir, struct dentry *dentry,
         RETURN(rc);
 }
 
-int smfs_cow_rename(struct inode *dir, struct dentry *dentry, 
-                    void *data1, void *data2)
+int smfs_cow_rename_pre(struct inode *dir, void *de, void *data1, void *data2)
 {
+        struct dentry *dentry = (struct dentry*)de;
         struct inode *new_dir = (struct inode *)data1;
         struct dentry *new_dentry = (struct dentry *)data2;
         struct dentry *dparent;
@@ -568,20 +1062,30 @@ int smfs_cow_rename(struct inode *dir, struct dentry *dentry,
         RETURN(rc);
 }
 
-int smfs_cow_write(struct inode *inode, struct dentry *dentry, void *data1,
-                   void *data2)
+int smfs_cow_write_pre(struct inode *inode, void *de, void *data1, void *data2)
 {
-        struct snap_info *snap_info = S2SNAPI(inode->i_sb); 
-        struct snap_table *table = snap_info->sntbl; 
+        struct dentry *dentry = (struct dentry*)de;
+        struct snap_info *snap_info = NULL; 
+        struct snap_table *table; 
        long   blocks[2]={-1,-1};
                int  index = 0, i, rc = 0;
-        size_t count = *(size_t *)data1;
-       loff_t pos = *(loff_t*)data2;
+        size_t count;
+       loff_t pos;
 
         ENTRY;
 
-        LASSERT(count);
-        LASSERT(pos);
+        snap_info = smfs_find_snap_info(inode);
+        if (!snap_info) {
+                CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+                RETURN(0);                
+        }
+        table = snap_info->sni_table;
+
+        LASSERT(data1);
+        LASSERT(data2);
+        
+        count = *(size_t *)data1;
+       pos = *(loff_t*)data2;
  
        down(&inode->i_sem);
         
@@ -609,52 +1113,423 @@ int smfs_cow_write(struct inode *inode, struct dentry *dentry, void *data1,
                        continue;
                /*Find the nearest page in snaptable and copy back it*/
                for (slot = table->sntbl_count - 1; slot >= 0; slot--) {
-                        struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
-                       struct inode *cache_inode = NULL;
+                        struct fsfilt_operations *sops = I2SNAPCOPS(inode);
+                       struct inode *cind = NULL;
                                int result = 0;
 
                         index = table->sntbl_items[slot].sn_index;
-                       cache_inode = snapops->fs_get_indirect(inode, NULL, index);
-
-                       if (!cache_inode)  continue;
+                       cind = sops->fs_get_indirect(I2CI(inode), NULL, index);
+                       if (!cind)  continue;
 
-                       CDEBUG(D_INFO, "find cache_ino %lu\n", cache_inode->i_ino);
+                       CDEBUG(D_INFO, "find cache_ino %lu\n", cind->i_ino);
                
-                       result = snapops->fs_copy_block(inode, cache_inode, blocks[i]);
+                       result = sops->fs_copy_block(I2CI(inode), cind, 
+                                                     blocks[i]);
                        if (result == 1) {
-                                       iput(cache_inode);
+                                       iput(cind);
                                result = 0;
                                break;
                        }
                        if (result < 0) {
-                               iput(cache_inode);
+                               iput(cind);
                                up(&inode->i_sem);
                                GOTO(exit, rc = result);
                        }
-                               iput(cache_inode);
+                               iput(cind);
                }
        }
 exit:
         up(&inode->i_sem); 
         RETURN(rc);
 }
-EXPORT_SYMBOL(smfs_cow_write);
+EXPORT_SYMBOL(smfs_cow_write_pre);
+/*lookup inode in dotsnap inode */
+static int smfs_dotsnap_lookup(struct inode *dir, struct dentry *dentry,
+                               struct snap_info *snap_info)
+{ 
+        if (dentry->d_name.len == 1 && 
+            !strcmp(dentry->d_name.name, ".")) {
+                d_add(dentry, iget(dir->i_sb, dir->i_ino));
+        } else if (dentry->d_name.len == 2 && 
+                   !strcmp(dentry->d_name.name, "..")) {
+                struct inode *inode;
+                struct dentry *dparent = dentry->d_parent;                                                                                                                                                                                       
+                if (dparent->d_inode) {
+                        inode = iget(dir->i_sb, dparent->d_inode->i_ino);
+                        if (inode) {
+                                if (!is_bad_inode(inode))
+                                        d_add(dentry, inode);
+                                else
+                                        iput(inode);
+                        }
+                }
+        } else {
+                /*find the name from the snaptable*/
+                struct fsfilt_operations *sops = I2SNAPCOPS(dir);
+                struct snap_table *table; 
+                struct inode *inode;
+                ino_t  cino;
+                int i = 0, index = -1;
+
+                table = snap_info->sni_table;
+                
+                for (i = 0; i < table->sntbl_count; i++) {
+                        char *name = table->sntbl_items[i].sn_name;
+                        if ((dentry->d_name.len == strlen(name)) &&
+                            (memcmp(dentry->d_name.name, name,
+                                    dentry->d_name.len) == 0)) {
+                                index = table->sntbl_items[i].sn_index;
+                                break;
+                        }
+                }
+                if (index == -1) {
+                       CERROR("No such %s in this .snap dir \n", 
+                               dentry->d_name.name);
+                       RETURN(-ENOENT);
+                }
+                cino = sops->fs_get_indirect_ino(S2CSB(dir->i_sb), dir->i_ino,
+                                                 index);
+                if (cino == 0)
+                        cino = dir->i_ino;
+                inode = smfs_get_inode(dir->i_sb, cino, dir, index);
+                if (!inode || is_bad_inode(inode)) {
+                        CERROR("Can not find cino %lu inode\n", cino);
+                        RETURN(-ENOENT); 
+                } 
+                smfs_init_snap_inode_info(inode, dir, index);
+                d_add(dentry, inode);
+        } 
+        RETURN(0);
+}
+int smfs_cow_lookup_pre(struct inode *inode, void *de, void *data1,
+                        void *data2)
+{
+        struct dentry *dentry = (struct dentry*)de;
+        struct snap_info *snap_info;
+        struct snap_dot_info *dot_info;
+        int rc = 0;
+        ENTRY;
+
+        snap_info = smfs_find_snap_info(inode);
+        if (!snap_info) {
+                CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+                RETURN(0);                
+        }
+        
+        dot_info = snap_info->sni_dot_info;
+
+        if (smfs_primary_inode(inode) && 
+            dentry->d_name.len == dot_info->dot_name_len &&
+            memcmp(dentry->d_name.name, dot_info->dot_name, 
+                   strlen(dot_info->dot_name)) == 0) {
+                struct inode *dot_inode = NULL; 
+                
+                dot_inode = smfs_get_inode(inode->i_sb, inode->i_ino, inode,
+                                           DOT_SNAP_INDEX);
+                smfs_init_snap_inode_info(dot_inode, inode, DOT_SNAP_INDEX);
+                d_add(dentry, dot_inode);
+                rc = 1;
+                RETURN(rc);
+        } else if (smfs_dotsnap_inode(inode)) {
+                rc = smfs_dotsnap_lookup(inode, dentry, snap_info);
+                if (rc == 0)
+                        rc = 1;
+                RETURN(rc);                
+        } else {
+                /*HERE: will replace ino in dentry->d_name according to index,
+                 *For iopen, will fix it in integrating snapfs to Lustre*/ 
+#if 0
+                struct fsfilt_operations *snapops = I2SNAPOPS(inode);
+                char *name = (char *)dentry->d_name.name;
+                unsigned long ino, hash, ind_ino; 
+                int len = sizeof(ind_ino);
+                 
+                ino = simple_strtoul(name, 0, 0);         
+
+                ind_ino = snapops->fs_get_indirect_ino(inode->i_sb, ino, index);
+                
+                snprintf(name, strlen(name), "0x%lx", ind_ino);                 
+                
+                hash = init_name_hash();
+                while (len--) {
+                        unsigned char c; 
+                        c = *(const unsigned char *)name++;
+                        if (c == '\0') break;
+                        hash = partial_name_hash(c, hash);
+                }
+                dentry->d_name.hash = end_name_hash(hash);
+#endif     
+        }
+        RETURN(rc);         
+}
+
+struct inode *smfs_cow_get_ind(struct inode *inode, int index)
+{
+        long block=(index << PAGE_CACHE_SHIFT) >> inode->i_sb->s_blocksize_bits;
+        struct fsfilt_operations *sops = I2SNAPCOPS(inode); 
+        struct snap_info *snap_info = NULL;
+        struct snap_table *table = NULL;
+        int slot;
+
+        ENTRY;
+        
+        snap_info = smfs_find_snap_info(inode);
+        if (!snap_info) {
+                CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+                RETURN(NULL);                
+        }
+        
+        table = snap_info->sni_table;        
+
+        for (slot = table->sntbl_count - 1; slot >= 0; slot--) {
+                struct address_space_operations *aops = inode->i_mapping->a_ops;
+                struct inode *cache_inode = NULL;
+                int index = 0;
+
+                index = table->sntbl_items[slot].sn_index;
+                cache_inode = sops->fs_get_indirect(I2CI(inode), NULL, index);
+                                                                                                                                                                                                     
+                if (!cache_inode )  continue;
+                
+                if (aops->bmap(cache_inode->i_mapping, block))
+                       RETURN(cache_inode); 
+                iput(cache_inode);
+        }
+
+        RETURN(NULL);
+}
+EXPORT_SYMBOL(smfs_cow_get_ind);
+
+static int smfs_cow_readdir_pre(struct inode *dir, void *de, void *data1,
+                                void *data2)
+{
+        struct file *filp = (struct file*)de;
+        void *dirent = data1; 
+        filldir_t filldir = (filldir_t)data2;
+        struct snap_info *snap_info = NULL;
+        
+        if (smfs_under_dotsnap_inode(dir))
+                RETURN(0);
+
+        snap_info = smfs_find_snap_info(dir);
+
+        if (!snap_info) {
+                CDEBUG(D_INFO, "can not find snap info for ino %lu\n", 
+                       dir->i_ino);
+                RETURN(-EINVAL);                
+        }
+
+        if (smfs_primary_inode(dir)) {
+                if (filp->f_pos == 0) {
+                        struct snap_dot_info *dot = snap_info->sni_dot_info;
+                        if (filldir(dirent, dot->dot_name, dot->dot_name_len, 
+                                    filp->f_pos, -1, 0)) { 
+                                CERROR("fill .snap error \n");
+                                RETURN(-EINVAL);
+                        }
+                } else {
+                        filp->f_pos -= 1;
+                }
+        } else if (smfs_dotsnap_inode(dir)) {
+                struct snap_table *table = snap_info->sni_table;   
+                int i = 0;
+
+                if (filp->f_pos < 0)
+                       RETURN(-EINVAL);
+        
+                if ((filp->f_pos == 0) && filldir(dirent, ".", 1, 
+                                                  filp->f_pos++, 
+                                                  dir->i_ino, 0) < 0)
+                       RETURN(-EIO);
+                if ((filp->f_pos == 1) && filldir(dirent, "..", 2, 
+                                                  filp->f_pos++, 
+                                                  dir->i_ino, 0) < 0)
+                       RETURN(-EIO); 
+               
+                for (i = filp->f_pos - 2; i < table->sntbl_count; i++, 
+                     filp->f_pos++) { 
+                        int slot = table->sntbl_count - i - 1;
+                        
+                        if (filldir(dirent, table->sntbl_items[slot].sn_name,
+                                    strlen(table->sntbl_items[slot].sn_name),
+                                    filp->f_pos, dir->i_ino, 0))
+                                break;
+                         
+                } 
+                RETURN(1); 
+        }
+        
+        RETURN(0); 
+}
 
-typedef int (*cow_funcs)(struct inode *dir, struct dentry *dentry, 
-                         void *new_dir, void *new_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,
+typedef int (*cow_funcs)(struct inode *dir, void *dentry, void *new_dir, 
+                         void *new_dentry);
+
+static cow_funcs smfs_cow_pre_funcs[HOOK_MAX + 1] = {
+        [HOOK_CREATE]   smfs_cow_create_pre,
+        [HOOK_LOOKUP]   smfs_cow_lookup_pre,
+        [HOOK_LINK]     smfs_cow_link_pre,
+        [HOOK_UNLINK]   smfs_cow_unlink_pre,
+        [HOOK_SYMLINK]  smfs_cow_create_pre,
+        [HOOK_MKDIR]    smfs_cow_create_pre,
+        [HOOK_RMDIR]    smfs_cow_unlink_pre, 
+        [HOOK_MKNOD]    smfs_cow_create_pre,
+        [HOOK_RENAME]   smfs_cow_rename_pre,
+        [HOOK_SETATTR]  smfs_cow_setattr_pre,
+        [HOOK_WRITE]    smfs_cow_write_pre,
+        [HOOK_READDIR]  smfs_cow_readdir_pre,
 };
 
-int smfs_cow(struct inode *dir, struct dentry *dentry, void *new_dir
-             void *new_dentry, int op)
+static int smfs_revalidate_dotsnap_dentry(struct dentry *dentry
+                                          struct inode *dir, int index)
 {
-        return smfs_cow_funcs[op](dir, dentry, new_dir, new_dentry);
+        struct inode *inode = dentry->d_inode;
+        ENTRY;       
+        if (!inode)
+                RETURN(0);
+
+        if (index > 0 && index != DOT_SNAP_INDEX) {
+                struct fsfilt_operations *sops = I2SNAPCOPS(inode); 
+                struct inode *cache_ind = NULL;
+
+                cache_ind = sops->fs_get_indirect(I2CI(inode), NULL, index);
+                
+                if (cache_ind) {
+                        struct inode *ind_inode = NULL;
+
+                        LASSERT(cache_ind->i_ino != I2CI(inode)->i_ino);
+                        
+                        ind_inode = smfs_get_inode(inode->i_sb, cache_ind->i_ino,
+                                                   dir, index);
+                        list_del_init(&dentry->d_alias);
+                        iput(inode);
+                        d_instantiate(dentry, ind_inode);                         
+                        iput(cache_ind); 
+                }
+        }
+        RETURN(0);
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int
+smfs_revalidate_nd(struct dentry *de, struct nameidata *nd)
+{
+        struct inode *inode = de->d_inode;
+        ENTRY;
+
+        if (!inode)
+                RETURN(0);
+        
+        if (smfs_under_dotsnap_inode(inode)) {
+                struct inode *dir = de->d_parent->d_inode;
+                int index = I2SNAPI(inode)->sn_index;
+                
+                smfs_revalidate_dotsnap_dentry(de, dir, index);
+                smfs_init_snap_inode_info(de->d_inode, dir, index);
+        }
+
+        RETURN(0);
+}
+#else
+static int
+smfs_revalidate_it(struct dentry *de, int flags,
+                   struct nameidata *nd,
+                   struct lookup_intent *it)
+{
+        struct inode *inode = de->d_inode;
+        ENTRY;
+
+        if (!inode)
+                RETURN(0);
+        
+        if (smfs_under_dotsnap_inode(inode)) {
+                struct inode *dir = de->d_parent->d_inode;
+                int index = I2SNAPI(inode)->sn_index;
+                
+                smfs_revalidate_dotsnap_dentry(de, dir, index);
+                smfs_init_snap_inode_info(de->d_inode, dir, index);
+        }
+
+        RETURN(0);
+}
+#endif
+
+static int smfs_delete_dentry(struct dentry *dentry)
+{
+        dentry->d_op = NULL; 
+        return 0;
+}
+struct dentry_operations smfs_cow_dops = {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+        .d_revalidate = smfs_revalidate_nd,
+#else
+        .d_revalidate_it = smfs_revalidate_it,
+#endif
+        .d_delete     = smfs_delete_dentry,
+};
+
+int smfs_cow_lookup_post(struct inode *dir, void *de, void *data1,
+                         void *data2)
+{
+        struct dentry *dentry = (struct dentry*)de;
+        struct inode *inode = dentry->d_inode; 
+        ENTRY;
+
+        if (inode && smfs_under_dotsnap_inode(inode)) {
+                int index = I2SNAPI(dir)->sn_index;
+        
+                smfs_revalidate_dotsnap_dentry(dentry, dir, index);
+                smfs_init_snap_inode_info(inode, dir, index);
+        }
+        dentry->d_op = &smfs_cow_dops;  
+        RETURN(0);
+}
+
+static int smfs_cow_readdir_post(struct inode *dir, void *de, void *data1,
+                                 void *data2)
+{
+        struct file *filp = (struct file*)de;
+        
+        if (smfs_primary_inode(dir)) {
+                filp->f_pos += 1;
+        }
+        RETURN(0); 
+}
+
+
+static cow_funcs smfs_cow_post_funcs[HOOK_MAX + 1] = {
+        [HOOK_CREATE]   NULL,
+        [HOOK_LOOKUP]   smfs_cow_lookup_post,
+        [HOOK_LINK]     NULL,
+        [HOOK_UNLINK]   NULL,
+        [HOOK_SYMLINK]  NULL,
+        [HOOK_MKDIR]    NULL,
+        [HOOK_RMDIR]    NULL, 
+        [HOOK_MKNOD]    NULL,
+        [HOOK_RENAME]   NULL,
+        [HOOK_SETATTR]  NULL,
+        [HOOK_WRITE]    NULL,
+        [HOOK_READDIR]  smfs_cow_readdir_post,
+};
+
+static int smfs_cow_pre(struct inode *dir, void *dentry, void *new_dir, 
+                        void *new_dentry, int op)
+{
+        if (smfs_cow_pre_funcs[op]) {
+                return smfs_cow_pre_funcs[op](dir, dentry, new_dir, new_dentry);
+        }
+        return 0;
+}
+
+static int smfs_cow_post(struct inode *dir, void *dentry, void *new_dir, 
+                         void *new_dentry, int op)
+{
+        if (smfs_cow_post_funcs[op]) {
+                return smfs_cow_post_funcs[op](dir, dentry, new_dir, new_dentry);
+        }
+        return 0;
 }