Whamcloud - gitweb
- landing b_fid.
[fs/lustre-release.git] / lustre / smfs / smfs_cow.c
index f02e7a7..425eb0e 100644 (file)
 
 #include "smfs_internal.h"
 
-#define SNAPTABLE_SIZE(size) (sizeof(struct snap_table) + \
-                              size * sizeof(struct snap)) 
+#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;
@@ -50,7 +53,9 @@ static int smfs_init_snap_super_info(struct smfs_super_info *smfs_info)
 
         ENTRY;
         
-        OBD_ALLOC(smfs_info->smsi_snap_info, sizeof(struct snap_super_info));
+        OBD_ALLOC(smfs_info->smsi_snap_info,
+                  sizeof(struct snap_super_info));
+        
         if (!smfs_info->smsi_snap_info) 
                 GOTO(exit, rc = -ENOMEM);
 
@@ -143,6 +148,7 @@ static struct snap_info *smfs_find_snap_info(struct inode *inode)
         RETURN(NULL);
 }
 
+#if 0
 static int smfs_dotsnap_dir_size(struct inode *inode)
 {
         struct snap_super_info *snap_sinfo = S2SNAPI(inode->i_sb);
@@ -170,13 +176,17 @@ static int smfs_dotsnap_dir_size(struct inode *inode)
         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;
@@ -197,7 +207,8 @@ static int smfs_init_snap_inode_info(struct inode *inode, struct inode *dir, int
                         RETURN(-EIO);
                 }
                 /*init dot_snap inode info*/
-                inode->i_size = (loff_t)smfs_dotsnap_dir_size(inode);
+//              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;
@@ -218,22 +229,24 @@ static int smfs_init_snap_inode_info(struct inode *inode, struct inode *dir, int
 }
 
 #define COWED_NAME_LEN       (7 + 8 + 1) 
-static int smfs_init_cowed_dir(struct snap_info *snap_info, struct dentry* dir)  
+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)dir->d_inode->i_ino);
+        sprintf(name, ".cowed_%08x", (__u32)inode->i_ino);
         /*FIXME-WANGDI: will use simple_mkdir, when integrating snap to lustre*/
-        dentry = smfs_simple_mkdir(dir, name, 0777, 1);
+        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);
 }
 
@@ -268,23 +281,19 @@ static int smfs_init_dotinfo(struct snap_info *snap_info)
 }
 
 static int smfs_init_snap_info(struct smfs_super_info *smb, 
-                               struct snap_info *snap_info, struct dentry *de) 
+                               struct snap_info *snap_info, struct inode *inode) 
 {
         struct snap_table        *snap_table = NULL;       
        struct fsfilt_operations *snapcops;
         int                      rc = 0, size, table_size, vallen, i;
-        struct inode             *root_inode = NULL;
  
         ENTRY;
 
-        root_inode = iget(smb->smsi_sb, de->d_inode->i_ino); 
-        if (!root_inode || is_bad_inode(root_inode))
-                RETURN(-EIO);
         snapcops = smb->smsi_snap_info->snap_cache_fsfilt;
         /*Initialized table */
         /*get the maxsize of snaptable*/
         vallen = sizeof(int);
-        rc = snapcops->fs_get_snap_info(root_inode, MAX_SNAPTABLE_COUNT,
+        rc = snapcops->fs_get_snap_info(I2CI(inode), MAX_SNAPTABLE_COUNT,
                                        strlen(MAX_SNAPTABLE_COUNT), &size, 
                                        &vallen);
         if (size == 0) {
@@ -307,7 +316,7 @@ static int smfs_init_snap_info(struct smfs_super_info *smb,
         for (i = 0; i < snap_table->sntbl_max_count; i++) 
                 snap_table->sntbl_items[i].sn_index = -1;
         /*get snaptable info*/
-        rc = snapcops->fs_get_snap_info(root_inode, SNAPTABLE_INFO, 
+        rc = snapcops->fs_get_snap_info(I2CI(inode), SNAPTABLE_INFO, 
                                         strlen(SNAPTABLE_INFO), 
                                         snap_table, &table_size);       
         if (rc < 0) {
@@ -325,23 +334,21 @@ static int smfs_init_snap_info(struct smfs_super_info *smb,
                 }
         }
         init_MUTEX(&snap_info->sni_sema);
-        snap_info->sni_root_ino = de->d_inode->i_ino;
-        rc = smfs_init_cowed_dir(snap_info, de);
+        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 (root_inode) 
-                iput(root_inode);
         if (rc && snap_table)
                 OBD_FREE(snap_table, table_size);
         RETURN(rc);
 }
 
 static struct snap_info *smfs_create_snap_info(struct smfs_super_info *sinfo, 
-                                               struct dentry *dentry)
+                                               struct inode *inode)
 {
         struct snap_info *snap_info = NULL;
         int rc = 0;
@@ -350,13 +357,13 @@ static struct snap_info *smfs_create_snap_info(struct smfs_super_info *sinfo,
         OBD_ALLOC(snap_info, sizeof(struct snap_info)); 
         if (!snap_info) 
                 RETURN(ERR_PTR(-ENOMEM));  
-        rc = smfs_init_snap_info(sinfo, snap_info, dentry);  
+        rc = smfs_init_snap_info(sinfo, snap_info, inode);  
         if (rc) 
                 GOTO(exit, rc);
        
         /*set cow flags for the snap root inode*/ 
-        I2SMI(dentry->d_inode)->smi_flags |= SM_DO_COW;
-        I2SNAPI(dentry->d_inode)->sn_root_ino = dentry->d_inode->i_ino; 
+        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));
@@ -400,6 +407,40 @@ static int smfs_cow_post_hook(struct inode *inode, void *dentry, void *data1,
         RETURN(rc);                                                                     
 }
 
+int smfs_cow_cleanup(struct smfs_super_info *smb)
+{
+        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;
+
+        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_sinfo->snap_fsfilt) 
+                fsfilt_put_ops(snap_sinfo->snap_fsfilt);
+        if (snap_sinfo->snap_cache_fsfilt)
+                fsfilt_put_ops(snap_sinfo->snap_cache_fsfilt);
+
+        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);
+}
+
 int smfs_cow_init(struct super_block *sb)
 {
         struct smfs_super_info *smfs_info = S2SMI(sb);
@@ -435,7 +476,7 @@ int smfs_cow_init(struct super_block *sb)
         vallen = sizeof(int); 
         rc = sops->fs_get_snap_info(root_inode, SNAP_COUNT, strlen(SNAP_COUNT),
                                     &snap_count, &vallen);
-        if (rc)
+        if (rc < 0)
                 GOTO(exit, rc);       
  
         if (snap_count > 0) {
@@ -451,21 +492,18 @@ int smfs_cow_init(struct super_block *sb)
                 rc = sops->fs_get_snap_info(root_inode, SNAP_ROOT_INO, 
                                             strlen(SNAP_ROOT_INO), snap_root, 
                                             &snap_root_size);
-                if (rc) {
+                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 dentry *tmp = smfs_info->smsi_sb->s_root;
                         struct snap_info *snap_info;                      
-                        struct dentry *dentry;                        
  
                         root_inode = smfs_get_inode(sb, root_ino, NULL, 0);
                         smfs_init_snap_inode_info(root_inode, NULL, 0);
-                        dentry = pre_smfs_dentry(NULL, root_inode, tmp); 
-                        snap_info = smfs_create_snap_info(S2SMI(sb), dentry);
-                        post_smfs_dentry(dentry);
+                        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));
@@ -473,11 +511,11 @@ int smfs_cow_init(struct super_block *sb)
                         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);
 }
 
@@ -508,6 +546,7 @@ int smfs_cleanup_snap_info(struct snap_info *snap_info)
         ENTRY;
 
         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);
@@ -516,40 +555,6 @@ int smfs_cleanup_snap_info(struct snap_info *snap_info)
         RETURN(rc);
 }
 
-int smfs_cow_cleanup(struct smfs_super_info *smb)
-{
-        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;
-
-        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_sinfo->snap_fsfilt) 
-                fsfilt_put_ops(snap_sinfo->snap_fsfilt);
-        if (snap_sinfo->snap_cache_fsfilt)
-                fsfilt_put_ops(snap_sinfo->snap_cache_fsfilt);
-
-        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);
-}
-
 int smfs_snap_test_inode(struct inode *inode, void *args)
 { 
         struct smfs_iget_args *sargs = (struct smfs_iget_args*)args;
@@ -617,7 +622,7 @@ static inline int 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) {
@@ -637,6 +642,7 @@ static struct dentry *smfs_find_snap_root(struct super_block *sb,
 {
         struct dentry *dentry = NULL;
         struct nameidata nd;
+        int error;
         ENTRY;
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
@@ -691,15 +697,17 @@ static int snap_add_item(struct smfs_super_info *smb,
        /* Wrote the whole snap_table to disk */
         table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count); 
          
+        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->sni_sema);
         if (root_inode)
@@ -708,28 +716,71 @@ exit:
 }
 
 static struct snap_info * smfs_find_create_snap_info(struct super_block *sb, 
-                                                     struct dentry *dentry
+                                                     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 == dentry->d_inode->i_ino) {
+                if (snap_info->sni_root_ino == inode->i_ino) {
                         RETURN(snap_info);
                 }      
         } 
 
-        CDEBUG(D_INFO, "create a new  snap info root ino %lu\n", 
-               dentry->d_inode->i_ino);
+        CDEBUG(D_INFO, "create a new  snap info root ino %lu\n", inode->i_ino);
 
-        snap_info = smfs_create_snap_info(S2SMI(sb), dentry);  
+        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);  
 }         
 
@@ -753,7 +804,7 @@ int smfs_add_snap_item(struct super_block *sb, char *path_name, char *name)
                 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);
+        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));
@@ -797,9 +848,9 @@ int smfs_needs_cow(struct inode *inode)
 static int link_cowed_inode(struct inode *inode)
 {
         struct dentry *cowed_dir = NULL;
-        char fidname[LL_FID_NAMELEN];
+        char idname[LL_ID_NAMELEN];
         struct snap_info *snap_info;   
-        int fidlen = 0, rc = 0;
+        int idlen = 0, rc = 0;
         struct dentry *dchild = NULL;
         struct dentry *tmp = NULL;
         unsigned mode;
@@ -812,10 +863,10 @@ static int link_cowed_inode(struct inode *inode)
 
         cowed_dir = snap_info->sni_cowed_dentry;
         
-        fidlen = ll_fid2str(fidname, inode->i_ino, inode->i_generation);
-
         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)
@@ -832,22 +883,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);
 }
 /*
@@ -874,11 +928,13 @@ int snap_do_cow(struct inode *inode, struct dentry *dparent, int del)
                         PTR_ERR(cache_ind));
                RETURN(PTR_ERR(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); 
+        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); 
+                }
         }
         RETURN(0);
 }
@@ -1127,13 +1183,15 @@ static int smfs_dotsnap_lookup(struct inode *dir, struct dentry *dentry,
                                 break;
                         }
                 }
-                if (index != -1) {
+                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);
@@ -1291,12 +1349,12 @@ static int smfs_cow_readdir_pre(struct inode *dir, void *de, void *data1,
                
                 for (i = filp->f_pos - 2; i < table->sntbl_count; i++, 
                      filp->f_pos++) { 
-                        int slot = table->sntbl_count-i;
+                        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;
+                                break;
                          
                 } 
                 RETURN(1); 
@@ -1323,36 +1381,111 @@ static cow_funcs smfs_cow_pre_funcs[HOOK_MAX + 1] = {
         [HOOK_WRITE]    smfs_cow_write_pre,
         [HOOK_READDIR]  smfs_cow_readdir_pre,
 };
-int smfs_cow_lookup_post(struct inode *dir, void *de, void *data1,
-                         void *data2)
+
+static int smfs_revalidate_dotsnap_dentry(struct dentry *dentry, 
+                                          struct inode *dir, int index)
 {
-        struct dentry *dentry = (struct dentry*)de;
-        struct inode *inode = dentry->d_inode; 
-        struct fsfilt_operations *sops = I2SNAPCOPS(inode); 
-        int index = I2SNAPI(dir)->sn_index;
-        ENTRY;
+        struct inode *inode = dentry->d_inode;
+        ENTRY;       
+        if (!inode)
+                RETURN(0);
 
-        LASSERT(inode);
-      
-        if (index > 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->i_ino != I2CI(inode)->i_ino) {
+                
+                if (cache_ind) {
                         struct inode *ind_inode = NULL;
+
+                        LASSERT(cache_ind->i_ino != I2CI(inode)->i_ino);
                         
-                        ind_inode = smfs_get_inode(dir->i_sb, cache_ind->i_ino,
+                        ind_inode = smfs_get_inode(inode->i_sb, cache_ind->i_ino,
                                                    dir, index);
-                        /*replace the ind_inode here*/ 
                         list_del_init(&dentry->d_alias);
                         iput(inode);
-                        d_instantiate(dentry, ind_inode); 
+                        d_instantiate(dentry, ind_inode);                         
+                        iput(cache_ind); 
                 }
         }
-        inode = dentry->d_inode;
+        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;
+}
  
-        smfs_init_snap_inode_info(inode, dir, index);
+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);
 }