Whamcloud - gitweb
update.snap on smfs
[fs/lustre-release.git] / lustre / smfs / smfs_cow.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2004 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #define DEBUG_SUBSYSTEM S_SM
24
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/pagemap.h>
28 #include <linux/string.h>
29 #include <linux/slab.h>
30 #include <linux/stat.h>
31 #include <linux/unistd.h>
32 #include <linux/smp_lock.h>
33 #include <linux/obd_class.h>
34 #include <linux/obd_support.h>
35 #include <linux/lustre_lib.h>
36 #include <linux/lustre_idl.h>
37 #include <linux/lustre_fsfilt.h>
38
39 #include <linux/lustre_smfs.h>
40 #include <linux/lustre_snap.h>
41
42 #include "smfs_internal.h"
43
44 #define SNAPTABLE_SIZE(size) (sizeof(struct snap_table) + \
45                               size * sizeof(struct snap)) 
46 static int smfs_init_snap_super_info(struct smfs_super_info *smfs_info)
47 {
48         struct snap_super_info  *snap_sinfo;
49         int rc = 0;
50
51         ENTRY;
52         
53         OBD_ALLOC(smfs_info->smsi_snap_info, sizeof(struct snap_super_info));
54         if (!smfs_info->smsi_snap_info) 
55                 GOTO(exit, rc = -ENOMEM);
56
57         snap_sinfo = smfs_info->smsi_snap_info;
58
59         /*init snap fsfilt operations*/
60         if (!snap_sinfo->snap_cache_fsfilt) {
61                 char *snap_cache_ftype = NULL;
62                 int   tmp = strlen(smfs_info->smsi_cache_ftype) + strlen("_snap");
63                 
64                 OBD_ALLOC(snap_cache_ftype, tmp + 1);  
65                 sprintf(snap_cache_ftype, "%s_snap", smfs_info->smsi_cache_ftype);
66                 snap_sinfo->snap_cache_fsfilt = fsfilt_get_ops(snap_cache_ftype);
67                 OBD_FREE(snap_cache_ftype, tmp + 1);
68                 if (!snap_sinfo->snap_cache_fsfilt) {
69                         CERROR("Can not get %s fsfilt ops needed by snap\n",
70                                snap_cache_ftype);
71                         GOTO(exit, rc = -EINVAL);
72                 }
73         }
74         if (!snap_sinfo->snap_fsfilt) {
75                 char *snap_ftype = NULL;
76                 int   tmp = strlen(smfs_info->smsi_ftype) + strlen("_snap");
77                 
78                 OBD_ALLOC(snap_ftype, tmp + 1);  
79                 sprintf(snap_ftype, "%s_snap", smfs_info->smsi_ftype);
80                 snap_sinfo->snap_fsfilt = fsfilt_get_ops(snap_ftype);
81                 OBD_FREE(snap_ftype, tmp + 1);
82                 if (!snap_sinfo->snap_fsfilt) {
83                         CERROR("Can not get %s fsfilt ops needed by snap\n",
84                                snap_ftype);
85                         GOTO(exit, rc = -EINVAL);
86                 }
87         }
88         INIT_LIST_HEAD(&snap_sinfo->snap_list);
89 exit:
90         if (rc && smfs_info->smsi_snap_info)
91                 OBD_FREE(snap_sinfo, sizeof(struct snap_super_info));
92         RETURN(rc);
93 }
94 /*FIXME-wangdi Should remove it when integrated it with lustre*/
95 static struct dentry *smfs_simple_mkdir(struct dentry *dir, char *name, 
96                                         int mode, int fix)
97 {
98         struct dentry *dchild;
99         int err = 0;
100         
101         dchild = ll_lookup_one_len(name, dir, strlen(name));
102         if (IS_ERR(dchild))
103                 GOTO(out_up, dchild);
104         
105         if (dchild->d_inode) {
106                 int old_mode = dchild->d_inode->i_mode;
107                 if (!S_ISDIR(old_mode))
108                         GOTO(out_err, err = -ENOTDIR);
109                                                                                                                                                                                                      
110                 /* Fixup directory permissions if necessary */
111                 if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
112                         CWARN("fixing permissions on %s from %o to %o\n",
113                               name, old_mode, mode);
114                         dchild->d_inode->i_mode = (mode & S_IALLUGO) |
115                                                   (old_mode & ~S_IALLUGO);
116                         mark_inode_dirty(dchild->d_inode);
117                 }
118                 GOTO(out_up, dchild);
119         }
120         err = vfs_mkdir(dir->d_inode, dchild, mode);
121         if (err)
122                 GOTO(out_err, err);
123         RETURN(dchild);
124 out_err:
125         dput(dchild);
126         dchild = ERR_PTR(err);
127 out_up:
128         return dchild;
129
130 }
131 static struct snap_info *smfs_find_snap_info(struct inode *inode)
132 {
133         struct snap_inode_info *snap_iinfo = I2SNAPI(inode);
134         struct snap_super_info *snap_sinfo = S2SNAPI(inode->i_sb);
135         struct snap_info *snap_info = NULL, *tmp; 
136
137         ENTRY;
138         list_for_each_entry_safe(snap_info, tmp, &snap_sinfo->snap_list, 
139                                  sni_list) {
140                if (snap_info->sni_root_ino == snap_iinfo->sn_root_ino)
141                         RETURN(snap_info); 
142         }
143         RETURN(NULL);
144 }
145
146 static int smfs_dotsnap_dir_size(struct inode *inode)
147 {
148         struct snap_super_info *snap_sinfo = S2SNAPI(inode->i_sb);
149         struct fsfilt_operations *snapops = snap_sinfo->snap_cache_fsfilt; 
150         int size = 0, dir_size = 0, blocks, i = 0;
151         struct snap_table *snap_table = NULL; 
152         struct snap_info *snap_info = NULL;
153         ENTRY;
154        
155         snap_info = smfs_find_snap_info(inode);
156         
157         if (!snap_info) {
158                 CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
159                 RETURN(0);                
160         }
161         snap_table = snap_info->sni_table;
162         for (i = 0; i < snap_table->sntbl_count; i++) {
163                 char *name = snap_table->sntbl_items[i].sn_name;
164                 size += snapops->fs_dir_ent_size(name);
165         }
166         /*FIXME this is only for ext3 dir format, may need fix for other FS*/ 
167         blocks = (size + inode->i_sb->s_blocksize - 1) >> 
168                                 inode->i_sb->s_blocksize_bits; 
169         
170         dir_size = blocks * inode->i_sb->s_blocksize; 
171         RETURN(dir_size); 
172
173
174
175 static int smfs_init_snap_inode_info(struct inode *inode, struct inode *dir, int index) 
176 {
177         int rc = 0;
178         ENTRY;
179
180         if (dir) {
181                 I2SNAPI(inode)->sn_flags = I2SNAPI(dir)->sn_flags;
182                 I2SNAPI(inode)->sn_gen = I2SNAPI(dir)->sn_gen;
183                 I2SNAPI(inode)->sn_root_ino = I2SNAPI(dir)->sn_root_ino;
184                 I2SNAPI(inode)->sn_index = I2SNAPI(inode)->sn_index; 
185         } else {
186                 I2SNAPI(inode)->sn_flags = 0;
187                 I2SNAPI(inode)->sn_gen = 0;
188         }
189         
190         I2SNAPI(inode)->sn_index = index;
191  
192         if (smfs_dotsnap_inode(inode)) {
193                 struct snap_info *snap_info;
194
195                 snap_info = smfs_find_snap_info(inode);
196                 if (!snap_info) {
197                         RETURN(-EIO);
198                 }
199                 /*init dot_snap inode info*/
200 //              inode->i_size = (loff_t)smfs_dotsnap_dir_size(inode);
201                 inode->i_size = snap_info->sni_table->sntbl_count;
202                 inode->i_nlink = snap_info->sni_table->sntbl_count + 2;
203                 inode->i_uid = 0;
204                 inode->i_gid = 0;
205         } else if (SMFS_DO_COW(S2SMI(inode->i_sb)) && 
206                    (I2SMI(inode)->smi_flags & SM_DO_COW) &&
207                    smfs_primary_inode(inode)) {
208                 struct snap_inode_info *sni_info = I2SNAPI(inode);
209                 struct fsfilt_operations *sops = I2SNAPCOPS(inode);
210                 int vallen = 0;
211  
212                 vallen = sizeof(sni_info->sn_gen);
213                 
214                 rc = sops->fs_get_snap_info(I2CI(inode), SNAP_GENERATION,
215                                             strlen(SNAP_GENERATION),
216                                             &sni_info->sn_gen, &vallen);               
217         } 
218         RETURN(rc);                                              
219 }
220
221 #define COWED_NAME_LEN       (7 + 8 + 1) 
222 static int smfs_init_cowed_dir(struct snap_info *snap_info, struct dentry* dir)  
223 {
224         struct dentry    *dentry = NULL;
225         char   name[COWED_NAME_LEN];
226         int    rc = 0;
227         ENTRY;
228          
229         sprintf(name, ".cowed_%08x", (__u32)dir->d_inode->i_ino);
230         /*FIXME-WANGDI: will use simple_mkdir, when integrating snap to lustre*/
231         dentry = smfs_simple_mkdir(dir, name, 0777, 1);
232         if (IS_ERR(dentry)) {
233                 rc = PTR_ERR(dentry);
234                 CERROR("create cowed directory: rc = %d\n", rc);
235                 RETURN(rc);
236         }
237         snap_info->sni_cowed_dentry = dentry;
238         RETURN(rc);
239 }
240
241 static int smfs_init_dotinfo(struct snap_info *snap_info)
242 {
243         struct snap_dot_info *dot_info = NULL;
244         int rc = 0;
245         ENTRY;
246
247         if (snap_info->sni_dot_info)
248                 RETURN(-EEXIST);
249        
250         OBD_ALLOC(snap_info->sni_dot_info, sizeof(struct snap_dot_info));
251         
252         if (!snap_info->sni_dot_info)
253                 RETURN(-ENOMEM); 
254       
255         dot_info = snap_info->sni_dot_info;
256  
257         OBD_ALLOC(dot_info->dot_name,  strlen(DOT_SNAP_NAME) + 1);
258
259         if (!dot_info->dot_name) {
260                 OBD_FREE(snap_info->sni_dot_info, sizeof(struct snap_dot_info));
261                 RETURN(-ENOMEM); 
262         } 
263         memcpy(dot_info->dot_name, DOT_SNAP_NAME, strlen(DOT_SNAP_NAME));
264         
265         dot_info->dot_name_len = strlen(DOT_SNAP_NAME); 
266         dot_info->dot_snap_enable = 1;
267         
268         RETURN(rc);
269 }
270
271 static int smfs_init_snap_info(struct smfs_super_info *smb, 
272                                struct snap_info *snap_info, struct dentry *de) 
273 {
274         struct snap_table        *snap_table = NULL;       
275         struct fsfilt_operations *snapcops;
276         int                      rc = 0, size, table_size, vallen, i;
277         struct inode             *root_inode = NULL;
278  
279         ENTRY;
280
281         root_inode = iget(smb->smsi_sb, de->d_inode->i_ino); 
282         if (!root_inode || is_bad_inode(root_inode))
283                 RETURN(-EIO);
284         snapcops = smb->smsi_snap_info->snap_cache_fsfilt;
285         /*Initialized table */
286         /*get the maxsize of snaptable*/
287         vallen = sizeof(int);
288         rc = snapcops->fs_get_snap_info(root_inode, MAX_SNAPTABLE_COUNT,
289                                        strlen(MAX_SNAPTABLE_COUNT), &size, 
290                                        &vallen);
291         if (size == 0) {
292                 CERROR("the Max snaptable count should not be zero\n");
293                 GOTO(exit, rc);
294         }
295         table_size = SNAPTABLE_SIZE(size);
296
297         OBD_ALLOC(snap_info->sni_table, table_size);
298
299         if (!snap_info->sni_table) {
300                 CERROR("No MEM\n");
301                 RETURN(-ENOMEM);
302         }
303         snap_table = snap_info->sni_table;
304          
305         snap_table->sntbl_magic = cpu_to_le32((__u32)SNAPTABLE_MAGIC); 
306         snap_table->sntbl_max_count = size;
307         /*init sn_index to -1*/ 
308         for (i = 0; i < snap_table->sntbl_max_count; i++) 
309                 snap_table->sntbl_items[i].sn_index = -1;
310         /*get snaptable info*/
311         rc = snapcops->fs_get_snap_info(root_inode, SNAPTABLE_INFO, 
312                                         strlen(SNAPTABLE_INFO), 
313                                         snap_table, &table_size);       
314         if (rc < 0) {
315                 if (rc == -ENODATA) {
316                         snap_table->sntbl_count = 0;
317                         rc = 0;
318                 } else {
319                         CERROR("Can not retrive the snaptable from this filesystem\n");
320                         GOTO(exit, rc);
321                 }
322         } else { 
323                 if (le32_to_cpu(snap_table->sntbl_magic) != SNAPTABLE_MAGIC) {
324                         CERROR("On disk snaptable is not right \n");
325                         GOTO(exit, rc = -EIO);
326                 }
327         }
328         init_MUTEX(&snap_info->sni_sema);
329         snap_info->sni_root_ino = de->d_inode->i_ino;
330         rc = smfs_init_cowed_dir(snap_info, de);
331         if (rc) {
332                 CERROR("Init cowed dir error rc=%d\n", rc);
333                 GOTO(exit, rc); 
334         }
335         rc = smfs_init_dotinfo(snap_info);
336 exit:
337         if (root_inode) 
338                 iput(root_inode);
339         if (rc && snap_table)
340                 OBD_FREE(snap_table, table_size);
341         RETURN(rc);
342 }
343
344 static struct snap_info *smfs_create_snap_info(struct smfs_super_info *sinfo, 
345                                                struct dentry *dentry)
346 {
347         struct snap_info *snap_info = NULL;
348         int rc = 0;
349         ENTRY;
350  
351         OBD_ALLOC(snap_info, sizeof(struct snap_info)); 
352         if (!snap_info) 
353                 RETURN(ERR_PTR(-ENOMEM));  
354         rc = smfs_init_snap_info(sinfo, snap_info, dentry);  
355         if (rc) 
356                 GOTO(exit, rc);
357        
358         /*set cow flags for the snap root inode*/ 
359         I2SMI(dentry->d_inode)->smi_flags |= SM_DO_COW;
360         I2SNAPI(dentry->d_inode)->sn_root_ino = dentry->d_inode->i_ino; 
361 exit:
362         if (rc) {
363                 OBD_FREE(snap_info, sizeof(struct snap_info));
364                 snap_info = ERR_PTR(rc);
365         }
366         RETURN(snap_info);
367 }
368
369 static int smfs_cow_pre(struct inode *dir, void *dentry, void *new_dir, 
370                         void *new_dentry, int op);
371
372 static int smfs_cow_post(struct inode *dir, void *dentry, void *new_dir, 
373                          void *new_dentry, int op);
374 #define COW_HOOK "cow_hook"
375 static int smfs_cow_pre_hook(struct inode *inode, void *dentry, void *data1,
376                              void *data2, int op, void *handle)
377 {
378         int rc = 0;
379         ENTRY;
380  
381         if (smfs_do_cow(inode)) {
382                 /*FIXME:WANGDI, get index from the dentry*/
383                 #if 0
384                 int index = 0;
385                 smfs_get_dentry_name_index(dentry, &name, index);       
386                 smfs_free_dentry_name(&name);
387                 #endif
388                 rc = smfs_cow_pre(inode, dentry, data1, data2, op);           
389         }
390         RETURN(rc);                                                                     
391 }
392 static int smfs_cow_post_hook(struct inode *inode, void *dentry, void *data1, 
393                               void *data2, int op, void *handle)
394 {
395         int rc = 0;
396         ENTRY;
397  
398         if (smfs_do_cow(inode)) {
399                 rc = smfs_cow_post(inode, dentry, data1, data2, op);           
400         }
401         RETURN(rc);                                                                     
402 }
403
404 int smfs_cow_init(struct super_block *sb)
405 {
406         struct smfs_super_info *smfs_info = S2SMI(sb);
407         struct smfs_hook_ops *cow_hops = NULL;
408         struct fsfilt_operations *sops;
409         struct inode *root_inode = smfs_info->smsi_sb->s_root->d_inode; 
410         int snap_count = 0, rc = 0, vallen;
411
412         ENTRY;
413
414         SMFS_SET_COW(smfs_info);
415       
416         cow_hops = smfs_alloc_hook_ops(COW_HOOK, smfs_cow_pre_hook, 
417                                        smfs_cow_post_hook);
418         if (!cow_hops) {
419                 RETURN(-ENOMEM);
420         }
421  
422         rc = smfs_register_hook_ops(smfs_info, cow_hops);
423         if (rc) {
424                 smfs_free_hook_ops(cow_hops);
425                 RETURN(rc);
426         }
427         
428         rc = smfs_init_snap_super_info(smfs_info);
429         if (rc && cow_hops) {
430                 smfs_unregister_hook_ops(smfs_info, cow_hops->smh_name);
431                 smfs_free_hook_ops(cow_hops);
432                 RETURN(rc);
433         }
434         sops = smfs_info->smsi_snap_info->snap_cache_fsfilt; 
435         
436         vallen = sizeof(int); 
437         rc = sops->fs_get_snap_info(root_inode, SNAP_COUNT, strlen(SNAP_COUNT),
438                                     &snap_count, &vallen);
439         if (rc)
440                 GOTO(exit, rc);       
441  
442         if (snap_count > 0) {
443                 int snap_root_size = snap_count * sizeof(ino_t);
444                 ino_t *snap_root;
445                 int i;
446                 
447                 OBD_ALLOC(snap_root, snap_root_size);
448                 
449                 if (!snap_root)
450                         GOTO(exit, rc = -ENOMEM); 
451                 
452                 rc = sops->fs_get_snap_info(root_inode, SNAP_ROOT_INO, 
453                                             strlen(SNAP_ROOT_INO), snap_root, 
454                                             &snap_root_size);
455                 if (rc) {
456                         OBD_FREE(snap_root, sizeof(int) * snap_count);
457                         GOTO(exit, rc);
458                 }
459                 for (i = 0; i < snap_count; i++) {
460                         ino_t root_ino = le32_to_cpu(snap_root[i]);
461                         struct dentry *tmp = smfs_info->smsi_sb->s_root;
462                         struct snap_info *snap_info;                      
463                         struct dentry *dentry;                        
464  
465                         root_inode = smfs_get_inode(sb, root_ino, NULL, 0);
466                         smfs_init_snap_inode_info(root_inode, NULL, 0);
467                         dentry = pre_smfs_dentry(NULL, root_inode, tmp); 
468                         snap_info = smfs_create_snap_info(S2SMI(sb), dentry);
469                         post_smfs_dentry(dentry);
470                         if (IS_ERR(snap_info)) {
471                                 OBD_FREE(snap_root, sizeof(int) * snap_count);
472                                 GOTO(exit, rc = PTR_ERR(snap_info));
473                         }                
474                         list_add(&snap_info->sni_list, 
475                                  &(S2SNAPI(sb)->snap_list));        
476                 }
477         }       
478 exit:
479         if (rc) 
480                 smfs_cow_cleanup(smfs_info);
481         
482         RETURN(rc);
483 }
484
485 static int smfs_cleanup_dotinfo(struct snap_info *snap_info)
486 {       
487         struct snap_dot_info *dot_info = NULL;
488         int rc = 0;
489         ENTRY;
490
491         if (!snap_info->sni_dot_info)
492                 RETURN(rc);
493        
494         dot_info = snap_info->sni_dot_info;
495
496         if (dot_info->dot_name) { 
497                 OBD_FREE(dot_info->dot_name, dot_info->dot_name_len + 1);
498         }
499         
500         OBD_FREE(dot_info, sizeof(struct snap_dot_info));
501
502         RETURN(rc);
503 }
504
505 int smfs_cleanup_snap_info(struct snap_info *snap_info)
506 {
507         struct snap_table      *snap_table = snap_info->sni_table;
508         int rc = 0, table_size;
509         ENTRY;
510
511         l_dput(snap_info->sni_cowed_dentry);
512         if (snap_table) {
513                 table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count);
514                 OBD_FREE(snap_info->sni_table, table_size);
515         }
516         smfs_cleanup_dotinfo(snap_info);
517         RETURN(rc);
518 }
519
520 int smfs_cow_cleanup(struct smfs_super_info *smb)
521 {
522         struct snap_super_info   *snap_sinfo = smb->smsi_snap_info;
523         struct list_head         *snap_list = &snap_sinfo->snap_list; 
524         struct smfs_hook_ops     *cow_hops;
525         int                      rc = 0; 
526         ENTRY;
527
528         while (!list_empty(snap_list)) {
529                 struct snap_info *snap_info;
530                 
531                 snap_info = list_entry(snap_list->next, struct snap_info,
532                                        sni_list); 
533                 rc = smfs_cleanup_snap_info(snap_info); 
534                 if (rc) 
535                         CERROR("cleanup snap_info error rc=%d\n", rc);
536                 list_del(&snap_info->sni_list); 
537                 OBD_FREE(snap_info, sizeof(struct snap_info));
538         } 
539          
540         if (snap_sinfo->snap_fsfilt) 
541                 fsfilt_put_ops(snap_sinfo->snap_fsfilt);
542         if (snap_sinfo->snap_cache_fsfilt)
543                 fsfilt_put_ops(snap_sinfo->snap_cache_fsfilt);
544
545         cow_hops = smfs_unregister_hook_ops(smb, COW_HOOK);
546         smfs_free_hook_ops(cow_hops);
547
548         SMFS_CLEAN_COW(smb);
549         if (snap_sinfo) 
550                OBD_FREE(snap_sinfo, sizeof(struct snap_super_info));
551         RETURN(rc);
552 }
553
554 int smfs_snap_test_inode(struct inode *inode, void *args)
555
556         struct smfs_iget_args *sargs = (struct smfs_iget_args*)args;
557         struct inode *dir;
558
559         LASSERT(sargs);
560         
561         dir = sargs->s_inode;
562         
563         if (sargs->s_index > 0) { 
564                 if (I2SNAPI(inode)->sn_index != sargs->s_index)
565                         return 0;
566         }else {
567                 if (dir && I2SNAPI(inode)->sn_index != I2SNAPI(dir)->sn_index)
568                         return 0;
569         }
570         return 1;
571 }
572 /* latest snap: returns 
573    -  the index of the latest snapshot before NOW
574    -  hence it returns 0 in case all the volume snapshots lie in the future
575    -  this is the index where a COW will land (will be created) 
576 */
577 void snap_last(struct inode *inode, struct snap *snap)
578 {
579         time_t now = LTIME_S(CURRENT_TIME);
580         struct snap_table *snap_table;
581         struct snap_info  *snap_info;
582         int i ;
583
584         ENTRY;
585
586         snap_info = smfs_find_snap_info(inode);
587         if (!snap_info) {
588                 CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
589                 EXIT;
590                 return;
591         }
592         snap_table = snap_info->sni_table;
593         /* start at the highest index in the superblock snaptime array */ 
594         if (snap_table->sntbl_count == 0) {
595                memset(snap, 0, sizeof(struct snap)); 
596         } else {
597                 i = snap_table->sntbl_count - 1;
598                 snap->sn_index = snap_table->sntbl_items[i].sn_index;
599                 snap->sn_time = snap_table->sntbl_items[i].sn_time;
600                 snap->sn_gen = snap_table->sntbl_items[i].sn_gen;
601         }
602         CDEBUG(D_INFO, "index: %d, time[i]: %ld, now: %ld\n",
603                snap->sn_index, snap->sn_time, now);
604         EXIT;
605         return;
606 }
607
608 static inline int get_index_of_item(struct snap_table *table, char *name)
609 {
610         int count = table->sntbl_count;
611         int i, j;
612         ENTRY;
613         
614         for (i = 0; i < table->sntbl_max_count; i++) { 
615                 if (!strcmp(name, table->sntbl_items[i].sn_name)) {
616                         CERROR("Duplicate name %s in snaptable\n", name); 
617                         RETURN(-EINVAL);
618                 }       
619         }
620
621         for (i = 1; i <= table->sntbl_max_count; i++) {
622                 int found = 0;
623                 for (j = 0; j < (count + 1); j++) {
624                         if (table->sntbl_items[j].sn_index == i) {
625                                 found = 1;
626                                 break;  
627                         }
628                 }
629                 if (!found)
630                         RETURN(i);
631         }
632         CERROR("snaptable Full\n");
633         RETURN(-ENOSPC);
634 }
635
636 static struct dentry *smfs_find_snap_root(struct super_block *sb, 
637                                           char *path_name)
638 {
639         struct dentry *dentry = NULL;
640         struct nameidata nd;
641         ENTRY;
642
643 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
644         if (path_init(path_name, LOOKUP_FOLLOW, &nd)) {
645                 error = path_walk(path_name, &nd);
646                 if (error) {
647                         path_release(&nd);
648                         RETURN(NULL);
649                 }
650         } else {
651                 RETURN(NULL);
652         }
653 #else
654         if (path_lookup(path_name, LOOKUP_FOLLOW, &nd))
655                 RETURN(NULL);
656                                                                                                                                                                                                      
657 #endif
658         dentry = dget(nd.dentry); 
659         path_release(&nd);
660         RETURN(dentry); 
661 }
662 static int snap_add_item(struct smfs_super_info *smb, 
663                          struct snap_info *snap_info,
664                          char *name)
665 {        
666         struct fsfilt_operations *snapops;
667         struct snap_table        *snap_table = snap_info->sni_table;
668         struct inode             *root_inode = NULL;
669         int                      table_size, count = 0, index = 0, rc = 0;
670         struct  snap             *snap_item;
671         ENTRY;
672
673         count = snap_table->sntbl_count; 
674         root_inode = iget(smb->smsi_sb, snap_info->sni_root_ino);
675         if (!root_inode || is_bad_inode(root_inode)) 
676                 RETURN(-EIO); 
677         /* XXX Is down this sema necessary*/
678         down_interruptible(&snap_info->sni_sema);
679         snap_item = &snap_table->sntbl_items[count];
680         snapops = smb->smsi_snap_info->snap_cache_fsfilt;
681         /*add item in snap_table set generation*/
682         snap_item->sn_time = LTIME_S(CURRENT_TIME);
683         /* find table index */
684         index = get_index_of_item(snap_table, name);
685         if (index < 0) 
686                 GOTO(exit, rc = index);
687         
688         snap_item->sn_index = index;
689         snap_item->sn_flags = 0;
690         snap_item->sn_gen = snap_table->sntbl_generation + 1; 
691         memcpy(snap_item->sn_name, name, SNAP_MAX_NAMELEN);
692         /* Wrote the whole snap_table to disk */
693         table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count); 
694          
695         rc = snapops->fs_set_snap_info(root_inode, SNAPTABLE_INFO, 
696                                        strlen(SNAPTABLE_INFO),
697                                        snap_table, &table_size);
698         if (rc) {
699                 CERROR("Set snaptable error rc=%d\n", rc);
700                 GOTO(exit, rc);
701         }
702         snap_table->sntbl_count++;
703         snap_table->sntbl_generation++;
704 exit:
705         up(&snap_info->sni_sema);
706         if (root_inode)
707                 iput(root_inode);
708         RETURN(rc);
709 }
710
711 static struct snap_info * smfs_find_create_snap_info(struct super_block *sb, 
712                                                      struct dentry *dentry) 
713 {       
714         struct snap_super_info   *snap_sinfo = S2SNAPI(sb);
715         struct snap_info *snap_info, *tmp;
716         ENTRY;
717         
718         list_for_each_entry_safe(snap_info, tmp, &snap_sinfo->snap_list, 
719                                  sni_list) {
720                 if (snap_info->sni_root_ino == dentry->d_inode->i_ino) {
721                         RETURN(snap_info);
722                 }      
723         } 
724
725         CDEBUG(D_INFO, "create a new  snap info root ino %lu\n", 
726                dentry->d_inode->i_ino);
727
728         snap_info = smfs_create_snap_info(S2SMI(sb), dentry);  
729
730         if (IS_ERR(snap_info))
731                 RETURN(snap_info);
732
733         list_add(&snap_info->sni_list, &snap_sinfo->snap_list);        
734         RETURN(snap_info);  
735 }         
736
737 int smfs_add_snap_item(struct super_block *sb, char *path_name, char *name)
738 {
739         struct dentry  *dentry = NULL;
740         struct snap_info *snap_info;
741         int            rc = 0;        
742         ENTRY;
743                 
744         if (!SMFS_DO_COW(S2SMI(sb))) {
745                 RETURN(0);
746         }
747
748         if (!path_name || !name) {
749                 CERROR("patch_name and snapshot_name is NULL");
750                 RETURN(-EINVAL);
751         } 
752         dentry = smfs_find_snap_root(sb, path_name);
753         if (IS_ERR(dentry)) {
754                 CERROR("can not find snap_shot root by %s\n", path_name);
755                 RETURN(PTR_ERR(dentry)); 
756         }
757         snap_info = smfs_find_create_snap_info(sb, dentry);
758         if (IS_ERR(snap_info)) {
759                 CERROR("can not find snap_info by %s rc=%lu\n", path_name,
760                         PTR_ERR(snap_info));
761                 GOTO(exit, rc = PTR_ERR(snap_info)); 
762         }
763
764         rc = snap_add_item(S2SMI(sb), snap_info, name);
765 exit:       
766         dput(dentry); 
767         RETURN(rc); 
768 }        
769 //EXPORT_SYMBOL(smfs_add_snap_item);
770 /*
771  * Note: this function should be differnet with snap_do_cow.
772  * In smfs_do_cow, we check the EA for whether do cow for that inode.
773  * In smfs_needs_cow, we check whether we do need to do cow. 
774  */
775 int smfs_needs_cow(struct inode *inode)
776 {
777         struct smfs_inode_info  *smi_info = I2SMI(inode); 
778         struct snap_inode_info *snap_info = NULL;
779         struct snap snap;
780         int index = -1;
781         ENTRY;
782
783         snap_info = &(smi_info->sm_sninfo);
784         
785         snap_last(inode, &snap);
786         /* decision .... if the snapshot is more recent than the object,
787          * then any change to the object should cause a COW.
788          */
789         if (snap_info->sn_gen < snap.sn_gen ) 
790                 index = snap.sn_index;
791
792         CDEBUG(D_INFO, "snap_needs_cow, ino %lu , get index %d\n",
793                inode->i_ino, index);
794
795         RETURN(index);
796 } /* snap_needs_cow */
797
798 static int link_cowed_inode(struct inode *inode)
799 {
800         struct dentry *cowed_dir = NULL;
801         char fidname[LL_FID_NAMELEN];
802         struct snap_info *snap_info;    
803         int fidlen = 0, rc = 0;
804         struct dentry *dchild = NULL;
805         struct dentry *tmp = NULL;
806         unsigned mode;
807
808         snap_info = smfs_find_snap_info(inode);
809         if (!snap_info) {
810                 CERROR("can not find snap info for inode %p\n", inode);
811                 RETURN(-EINVAL);                
812         }
813
814         cowed_dir = snap_info->sni_cowed_dentry;
815         
816         fidlen = ll_fid2str(fidname, inode->i_ino, inode->i_generation);
817
818         down(&cowed_dir->d_inode->i_sem);
819         dchild = ll_lookup_one_len(fidname, cowed_dir, fidlen);
820         if (IS_ERR(dchild)) {
821                 rc = PTR_ERR(dchild);
822                 if (rc != -EPERM && rc != -EACCES)
823                         CERROR("child lookup error %d\n", rc);
824                 GOTO(out_lock, rc);
825         }
826         if (dchild->d_inode != NULL) {
827                 CERROR("re-cowed file %s?\n", dchild->d_name.name);
828                 LASSERT(dchild->d_inode == inode);
829                 GOTO(out_dput, rc = 0);
830         }
831         tmp = pre_smfs_dentry(NULL, inode, cowed_dir);
832         /* link() is semanticaly-wrong for S_IFDIR, so we set S_IFREG
833          * for linking and return real mode back then -bzzz */
834         mode = inode->i_mode;
835         inode->i_mode = S_IFREG;
836         rc = vfs_link(tmp, cowed_dir->d_inode, dchild);
837         post_smfs_dentry(tmp);
838         if (rc) {
839                 CERROR("error linking cowed inode %s to COWED: rc = %d\n",
840                         fidname, rc);
841         } 
842         inode->i_mode = mode;
843         if ((mode & S_IFMT) == S_IFDIR) {
844                 dchild->d_inode->i_nlink++;
845                 cowed_dir->d_inode->i_nlink++;
846         }
847         mark_inode_dirty(dchild->d_inode);
848 out_dput:
849         dput(dchild);
850 out_lock:       
851         up(&cowed_dir->d_inode->i_sem);
852         RETURN(rc);
853 }
854 /*
855  * Make a copy of the data and plug a redirector in between if there
856  * is no redirector yet.
857  */
858 int snap_do_cow(struct inode *inode, struct dentry *dparent, int del)
859 {
860         struct fsfilt_operations *snapops = I2SNAPCOPS(inode);
861         struct snap snap;
862         struct inode *cache_ind = NULL;
863         ENTRY;
864
865         if (!snapops || !snapops->fs_create_indirect) 
866                 RETURN(-EINVAL);
867
868         snap_last(inode, &snap);
869         cache_ind = snapops->fs_create_indirect(I2CI(inode), snap.sn_index, 
870                                           snap.sn_gen, I2CI(dparent->d_inode), 
871                                           del);
872         if(cache_ind && IS_ERR(cache_ind)) {
873                 CERROR("Create ind inode %lu index %d gen %d del %d rc%lu\n",
874                         inode->i_ino, snap.sn_index, snap.sn_gen, del,
875                         PTR_ERR(cache_ind));
876                 RETURN(PTR_ERR(cache_ind));
877         }
878         iput(cache_ind);
879         if (!SMFS_DO_INODE_COWED(inode)) {
880                 /*insert the inode to cowed inode*/
881                 SMFS_SET_INODE_COWED(inode); 
882                 link_cowed_inode(inode); 
883         }
884         RETURN(0);
885 }
886 /*Dir inode will do cow*/
887 int smfs_cow_create_pre(struct inode *dir, void *de, void *data1, void *data2)
888 {
889         struct dentry *dparent;
890         struct dentry *dentry = (struct dentry *)de;
891         int rc = 0;
892         ENTRY;
893
894         if (smfs_needs_cow(dir) != -1) {
895                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
896                 LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
897                 dparent = dentry->d_parent->d_parent;
898                 if ((rc = snap_do_cow(dir, dparent, 0))) {
899                         CERROR("Do cow error %d\n", rc);
900                         RETURN(-EINVAL);
901                 }
902         }
903         RETURN(rc);
904 }
905
906 int smfs_cow_setattr_pre(struct inode *dir, void *de, void *data1, void *data2)
907 {
908         struct dentry *dentry = (struct dentry *)de;
909         int rc = 0;
910         ENTRY;
911         if (smfs_needs_cow(dir) != -1) {
912                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
913                 if ((snap_do_cow(dir, dentry->d_parent, 0))) {
914                         CERROR("Do cow error\n");
915                         RETURN(-EINVAL);
916                 }
917         }
918         RETURN(rc);
919 }
920
921 int smfs_cow_link_pre(struct inode *dir, void *de, void *data1, void *data2)
922 {
923         struct dentry *dparent;
924         struct dentry *dentry = (struct dentry *)de;
925         int rc = 0;
926         ENTRY;
927  
928         if (smfs_needs_cow(dir) != -1) {
929                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
930                 LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
931                 dparent = dentry->d_parent->d_parent;
932                 if ((snap_do_cow(dir, dparent, 0))) {
933                         CERROR("Do cow error\n");
934                         RETURN(-EINVAL);
935                 }
936                 if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 0))) {
937                         CERROR("Do cow error\n");
938                         RETURN(-EINVAL);
939                 }
940         }
941         RETURN(rc);
942 }
943
944 int smfs_cow_unlink_pre(struct inode *dir, void *de, void *data1, void *data2)
945 {
946         struct dentry *dentry = (struct dentry *)de; 
947         struct dentry *dparent;
948         int rc = 0;
949         ENTRY;
950
951         if (smfs_needs_cow(dir) != -1) {
952                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
953                 LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
954                 dparent = dentry->d_parent->d_parent;
955                 if ((snap_do_cow(dir, dparent, 0))) {
956                         CERROR("Do cow error\n");
957                         RETURN(-EINVAL);
958                 }
959                 if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 1))) {
960                         CERROR("Do cow error\n");
961                         RETURN(-EINVAL);
962                 }
963         
964         }
965         RETURN(rc);
966 }
967
968 int smfs_cow_rename_pre(struct inode *dir, void *de, void *data1, void *data2)
969 {
970         struct dentry *dentry = (struct dentry*)de;
971         struct inode *new_dir = (struct inode *)data1;
972         struct dentry *new_dentry = (struct dentry *)data2;
973         struct dentry *dparent;
974         int rc = 0;
975         ENTRY;
976        
977         LASSERT(new_dir);
978         LASSERT(new_dentry); 
979         if (smfs_needs_cow(dir) != -1) {
980                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n", dir->i_ino);
981                 LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
982                 dparent = dentry->d_parent->d_parent;
983                 if ((snap_do_cow(dir, dparent, 0))) {
984                         CERROR("Do cow error\n");
985                         RETURN(-EINVAL);
986                 }
987                 if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 0))) {
988                         CERROR("Do cow error\n");
989                         RETURN(-EINVAL);
990                 }
991         }
992         if (smfs_needs_cow(new_dir) != -1) {
993                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n", new_dir->i_ino);
994                 LASSERT(new_dentry->d_parent && new_dentry->d_parent->d_parent);
995                 dparent = new_dentry->d_parent->d_parent;
996                 if ((new_dir != dir) && (snap_do_cow(new_dir, dparent, 0))){
997                         CERROR("Do cow error\n");
998                         RETURN(-EINVAL);
999                 }
1000                 if (new_dentry->d_inode && new_dentry->d_inode->i_nlink == 1) {
1001                         if ((snap_do_cow(new_dentry->d_inode, 
1002                                          new_dentry->d_parent, 0))) {
1003                                 CERROR("Do cow error\n");
1004                                 RETURN(-EINVAL);
1005                         }
1006                 }
1007         } 
1008         RETURN(rc);
1009 }
1010
1011 int smfs_cow_write_pre(struct inode *inode, void *de, void *data1, void *data2)
1012 {
1013         struct dentry *dentry = (struct dentry*)de;
1014         struct snap_info *snap_info = NULL; 
1015         struct snap_table *table; 
1016         long   blocks[2]={-1,-1};
1017         int  index = 0, i, rc = 0;
1018         size_t count;
1019         loff_t pos;
1020
1021         ENTRY;
1022
1023         snap_info = smfs_find_snap_info(inode);
1024         if (!snap_info) {
1025                 CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
1026                 RETURN(0);                
1027         }
1028         table = snap_info->sni_table;
1029
1030         LASSERT(data1);
1031         LASSERT(data2);
1032         
1033         count = *(size_t *)data1;
1034         pos = *(loff_t*)data2;
1035  
1036         down(&inode->i_sem);
1037         
1038         if (smfs_needs_cow(inode) != -1 ) {
1039                 CDEBUG(D_INFO, "snap_needs_cow for ino %lu \n",inode->i_ino);
1040                 snap_do_cow(inode, dentry->d_parent, 0);
1041         }
1042         
1043         CDEBUG(D_INFO, "write offset %lld count %u \n", pos, count);
1044         
1045         if(pos & (PAGE_CACHE_SIZE - 1)){
1046                 blocks[0] = pos >> inode->i_sb->s_blocksize_bits;
1047         }
1048         pos += count - 1;
1049         if((pos + 1) & (PAGE_CACHE_SIZE - 1)){
1050                 blocks[1] = pos >> inode->i_sb->s_blocksize_bits;
1051         }
1052
1053         if (blocks[0] == blocks[1]) 
1054                 blocks[1] = -1;
1055         
1056         for (i = 0; i < 2; i++) {
1057                 int slot = 0;
1058                 if (blocks[i] == -1) 
1059                         continue;
1060                 /*Find the nearest page in snaptable and copy back it*/
1061                 for (slot = table->sntbl_count - 1; slot >= 0; slot--) {
1062                         struct fsfilt_operations *sops = I2SNAPCOPS(inode);
1063                         struct inode *cind = NULL;
1064                         int result = 0;
1065
1066                         index = table->sntbl_items[slot].sn_index;
1067                         cind = sops->fs_get_indirect(I2CI(inode), NULL, index);
1068                         if (!cind)  continue;
1069
1070                         CDEBUG(D_INFO, "find cache_ino %lu\n", cind->i_ino);
1071                 
1072                         result = sops->fs_copy_block(I2CI(inode), cind, 
1073                                                      blocks[i]);
1074                         if (result == 1) {
1075                                 iput(cind);
1076                                 result = 0;
1077                                 break;
1078                         }
1079                         if (result < 0) {
1080                                 iput(cind);
1081                                 up(&inode->i_sem);
1082                                 GOTO(exit, rc = result);
1083                         }
1084                         iput(cind);
1085                 }
1086         }
1087 exit:
1088         up(&inode->i_sem); 
1089         RETURN(rc);
1090 }
1091 EXPORT_SYMBOL(smfs_cow_write_pre);
1092 /*lookup inode in dotsnap inode */
1093 static int smfs_dotsnap_lookup(struct inode *dir, struct dentry *dentry,
1094                                struct snap_info *snap_info)
1095
1096         if (dentry->d_name.len == 1 && 
1097             !strcmp(dentry->d_name.name, ".")) {
1098                 d_add(dentry, iget(dir->i_sb, dir->i_ino));
1099         } else if (dentry->d_name.len == 2 && 
1100                    !strcmp(dentry->d_name.name, "..")) {
1101                 struct inode *inode;
1102                 struct dentry *dparent = dentry->d_parent;                                                                                                                                                                                       
1103                 if (dparent->d_inode) {
1104                         inode = iget(dir->i_sb, dparent->d_inode->i_ino);
1105                         if (inode) {
1106                                 if (!is_bad_inode(inode))
1107                                         d_add(dentry, inode);
1108                                 else
1109                                         iput(inode);
1110                         }
1111                 }
1112         } else {
1113                 /*find the name from the snaptable*/
1114                 struct fsfilt_operations *sops = I2SNAPCOPS(dir);
1115                 struct snap_table *table; 
1116                 struct inode *inode;
1117                 ino_t  cino;
1118                 int i = 0, index = -1;
1119
1120                 table = snap_info->sni_table;
1121                 
1122                 for (i = 0; i < table->sntbl_count; i++) {
1123                         char *name = table->sntbl_items[i].sn_name;
1124                         if ((dentry->d_name.len == strlen(name)) &&
1125                             (memcmp(dentry->d_name.name, name,
1126                                     dentry->d_name.len) == 0)) {
1127                                 index = table->sntbl_items[i].sn_index;
1128                                 break;
1129                         }
1130                 }
1131                 if (index == -1) {
1132                        CERROR("No such %s in this .snap dir \n", 
1133                                dentry->d_name.name);
1134                        RETURN(-ENOENT);
1135                 }
1136                 cino = sops->fs_get_indirect_ino(S2CSB(dir->i_sb), dir->i_ino,
1137                                                  index);
1138                 if (cino == 0)
1139                         cino = dir->i_ino;
1140                 inode = smfs_get_inode(dir->i_sb, cino, dir, index);
1141                 if (!inode || is_bad_inode(inode)) {
1142                         CERROR("Can not find cino %lu inode\n", cino);
1143                         RETURN(-ENOENT); 
1144                 } 
1145                 smfs_init_snap_inode_info(inode, dir, index);
1146                 d_add(dentry, inode);
1147         } 
1148         RETURN(0);
1149 }
1150 int smfs_cow_lookup_pre(struct inode *inode, void *de, void *data1,
1151                         void *data2)
1152 {
1153         struct dentry *dentry = (struct dentry*)de;
1154         struct snap_info *snap_info;
1155         struct snap_dot_info *dot_info;
1156         int rc = 0;
1157         ENTRY;
1158
1159         snap_info = smfs_find_snap_info(inode);
1160         if (!snap_info) {
1161                 CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
1162                 RETURN(0);                
1163         }
1164         
1165         dot_info = snap_info->sni_dot_info;
1166
1167         if (smfs_primary_inode(inode) && 
1168             dentry->d_name.len == dot_info->dot_name_len &&
1169             memcmp(dentry->d_name.name, dot_info->dot_name, 
1170                    strlen(dot_info->dot_name)) == 0) {
1171                 struct inode *dot_inode = NULL; 
1172                 
1173                 dot_inode = smfs_get_inode(inode->i_sb, inode->i_ino, inode,
1174                                            DOT_SNAP_INDEX);
1175                 smfs_init_snap_inode_info(dot_inode, inode, DOT_SNAP_INDEX);
1176                 d_add(dentry, dot_inode);
1177                 rc = 1;
1178                 RETURN(rc);
1179         } else if (smfs_dotsnap_inode(inode)) {
1180                 rc = smfs_dotsnap_lookup(inode, dentry, snap_info);
1181                 if (rc == 0)
1182                         rc = 1;
1183                 RETURN(rc);                
1184         } else {
1185                 /*HERE: will replace ino in dentry->d_name according to index,
1186                  *For iopen, will fix it in integrating snapfs to Lustre*/ 
1187 #if 0
1188                 struct fsfilt_operations *snapops = I2SNAPOPS(inode);
1189                 char *name = (char *)dentry->d_name.name;
1190                 unsigned long ino, hash, ind_ino; 
1191                 int len = sizeof(ind_ino);
1192                  
1193                 ino = simple_strtoul(name, 0, 0);         
1194
1195                 ind_ino = snapops->fs_get_indirect_ino(inode->i_sb, ino, index);
1196                 
1197                 snprintf(name, strlen(name), "0x%lx", ind_ino);                 
1198                 
1199                 hash = init_name_hash();
1200                 while (len--) {
1201                         unsigned char c; 
1202                         c = *(const unsigned char *)name++;
1203                         if (c == '\0') break;
1204                         hash = partial_name_hash(c, hash);
1205                 }
1206                 dentry->d_name.hash = end_name_hash(hash);
1207 #endif     
1208         }
1209         RETURN(rc);         
1210 }
1211
1212 struct inode *smfs_cow_get_ind(struct inode *inode, int index)
1213 {
1214         long block=(index << PAGE_CACHE_SHIFT) >> inode->i_sb->s_blocksize_bits;
1215         struct fsfilt_operations *sops = I2SNAPCOPS(inode); 
1216         struct snap_info *snap_info = NULL;
1217         struct snap_table *table = NULL;
1218         int slot;
1219
1220         ENTRY;
1221         
1222         snap_info = smfs_find_snap_info(inode);
1223         if (!snap_info) {
1224                 CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
1225                 RETURN(NULL);                
1226         }
1227         
1228         table = snap_info->sni_table;        
1229
1230         for (slot = table->sntbl_count - 1; slot >= 0; slot--) {
1231                 struct address_space_operations *aops = inode->i_mapping->a_ops;
1232                 struct inode *cache_inode = NULL;
1233                 int index = 0;
1234
1235                 index = table->sntbl_items[slot].sn_index;
1236                 cache_inode = sops->fs_get_indirect(I2CI(inode), NULL, index);
1237                                                                                                                                                                                                      
1238                 if (!cache_inode )  continue;
1239                 
1240                 if (aops->bmap(cache_inode->i_mapping, block))
1241                        RETURN(cache_inode); 
1242                 iput(cache_inode);
1243         }
1244
1245         RETURN(NULL);
1246 }
1247 EXPORT_SYMBOL(smfs_cow_get_ind);
1248
1249 static int smfs_cow_readdir_pre(struct inode *dir, void *de, void *data1,
1250                                 void *data2)
1251 {
1252         struct file *filp = (struct file*)de;
1253         void *dirent = data1; 
1254         filldir_t filldir = (filldir_t)data2;
1255         struct snap_info *snap_info = NULL;
1256         
1257         if (smfs_under_dotsnap_inode(dir))
1258                 RETURN(0);
1259
1260         snap_info = smfs_find_snap_info(dir);
1261
1262         if (!snap_info) {
1263                 CDEBUG(D_INFO, "can not find snap info for ino %lu\n", 
1264                        dir->i_ino);
1265                 RETURN(-EINVAL);                
1266         }
1267
1268         if (smfs_primary_inode(dir)) {
1269                 if (filp->f_pos == 0) {
1270                         struct snap_dot_info *dot = snap_info->sni_dot_info;
1271                         if (filldir(dirent, dot->dot_name, dot->dot_name_len, 
1272                                     filp->f_pos, -1, 0)) { 
1273                                 CERROR("fill .snap error \n");
1274                                 RETURN(-EINVAL);
1275                         }
1276                 } else {
1277                         filp->f_pos -= 1;
1278                 }
1279         } else if (smfs_dotsnap_inode(dir)) {
1280                 struct snap_table *table = snap_info->sni_table;   
1281                 int i = 0;
1282
1283                 if (filp->f_pos < 0)
1284                        RETURN(-EINVAL);
1285         
1286                 if ((filp->f_pos == 0) && filldir(dirent, ".", 1, 
1287                                                   filp->f_pos++, 
1288                                                   dir->i_ino, 0) < 0)
1289                        RETURN(-EIO);
1290                 if ((filp->f_pos == 1) && filldir(dirent, "..", 2, 
1291                                                   filp->f_pos++, 
1292                                                   dir->i_ino, 0) < 0)
1293                        RETURN(-EIO); 
1294                
1295                 for (i = filp->f_pos - 2; i < table->sntbl_count; i++, 
1296                      filp->f_pos++) { 
1297                         int slot = table->sntbl_count - i - 1;
1298                         
1299                         if (filldir(dirent, table->sntbl_items[slot].sn_name,
1300                                     strlen(table->sntbl_items[slot].sn_name),
1301                                     filp->f_pos, dir->i_ino, 0))
1302                                 break;
1303                          
1304                 } 
1305                 RETURN(1); 
1306         }
1307         
1308         RETURN(0); 
1309 }
1310
1311
1312 typedef int (*cow_funcs)(struct inode *dir, void *dentry, void *new_dir, 
1313                          void *new_dentry);
1314
1315 static cow_funcs smfs_cow_pre_funcs[HOOK_MAX + 1] = {
1316         [HOOK_CREATE]   smfs_cow_create_pre,
1317         [HOOK_LOOKUP]   smfs_cow_lookup_pre,
1318         [HOOK_LINK]     smfs_cow_link_pre,
1319         [HOOK_UNLINK]   smfs_cow_unlink_pre,
1320         [HOOK_SYMLINK]  smfs_cow_create_pre,
1321         [HOOK_MKDIR]    smfs_cow_create_pre,
1322         [HOOK_RMDIR]    smfs_cow_unlink_pre, 
1323         [HOOK_MKNOD]    smfs_cow_create_pre,
1324         [HOOK_RENAME]   smfs_cow_rename_pre,
1325         [HOOK_SETATTR]  smfs_cow_setattr_pre,
1326         [HOOK_WRITE]    smfs_cow_write_pre,
1327         [HOOK_READDIR]  smfs_cow_readdir_pre,
1328 };
1329 int smfs_cow_lookup_post(struct inode *dir, void *de, void *data1,
1330                          void *data2)
1331 {
1332         struct dentry *dentry = (struct dentry*)de;
1333         struct inode *inode = dentry->d_inode; 
1334         struct fsfilt_operations *sops = I2SNAPCOPS(inode); 
1335         int index = I2SNAPI(dir)->sn_index;
1336         ENTRY;
1337
1338         LASSERT(inode);
1339       
1340         if (index > 0) {
1341                 struct inode *cache_ind = NULL;
1342
1343                 cache_ind = sops->fs_get_indirect(I2CI(inode), NULL, index);
1344                 if (cache_ind->i_ino != I2CI(inode)->i_ino) {
1345                         struct inode *ind_inode = NULL;
1346                         
1347                         ind_inode = smfs_get_inode(dir->i_sb, cache_ind->i_ino,
1348                                                    dir, index);
1349                         /*replace the ind_inode here*/ 
1350                         list_del_init(&dentry->d_alias);
1351                         iput(inode);
1352                         d_instantiate(dentry, ind_inode); 
1353                 }
1354         }
1355         inode = dentry->d_inode;
1356  
1357         smfs_init_snap_inode_info(inode, dir, index);
1358         
1359         RETURN(0);
1360 }
1361
1362 static int smfs_cow_readdir_post(struct inode *dir, void *de, void *data1,
1363                                  void *data2)
1364 {
1365         struct file *filp = (struct file*)de;
1366         
1367         if (smfs_primary_inode(dir)) {
1368                 filp->f_pos += 1;
1369         }
1370         RETURN(0); 
1371 }
1372
1373
1374 static cow_funcs smfs_cow_post_funcs[HOOK_MAX + 1] = {
1375         [HOOK_CREATE]   NULL,
1376         [HOOK_LOOKUP]   smfs_cow_lookup_post,
1377         [HOOK_LINK]     NULL,
1378         [HOOK_UNLINK]   NULL,
1379         [HOOK_SYMLINK]  NULL,
1380         [HOOK_MKDIR]    NULL,
1381         [HOOK_RMDIR]    NULL, 
1382         [HOOK_MKNOD]    NULL,
1383         [HOOK_RENAME]   NULL,
1384         [HOOK_SETATTR]  NULL,
1385         [HOOK_WRITE]    NULL,
1386         [HOOK_READDIR]  smfs_cow_readdir_post,
1387 };
1388
1389 static int smfs_cow_pre(struct inode *dir, void *dentry, void *new_dir, 
1390                         void *new_dentry, int op)
1391 {
1392         if (smfs_cow_pre_funcs[op]) {
1393                 return smfs_cow_pre_funcs[op](dir, dentry, new_dir, new_dentry);
1394         }
1395         return 0;
1396 }
1397
1398 static int smfs_cow_post(struct inode *dir, void *dentry, void *new_dir, 
1399                          void *new_dentry, int op)
1400 {
1401         if (smfs_cow_post_funcs[op]) {
1402                 return smfs_cow_post_funcs[op](dir, dentry, new_dir, new_dentry);
1403         }
1404         return 0;
1405 }
1406