Whamcloud - gitweb
b=3869,1742
[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_snap.h>
40 #include <linux/lustre_smfs.h>
41
42 #include "smfs_internal.h"
43 #define SNAPTABLE_SIZE(size) (sizeof(struct snap_table) + size * sizeof(struct snap)) 
44 static int smfs_init_snaptabe(struct super_block *sb)
45 {
46         struct snap_info         *snap_info = S2SNAPI(sb);      
47         struct snap_table        *snap_table = NULL;       
48         struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
49         int                      rc = 0, size, table_size, vallen, i;
50  
51         ENTRY;
52
53         init_MUTEX(&snap_info->sntbl_sema);
54         /*Initialized table */
55         /*get the maxsize of snaptable*/
56         vallen = sizeof(int);
57         rc = snapops->fs_get_snap_info(sb, NULL, MAX_SNAPTABLE_COUNT,
58                                        strlen(MAX_SNAPTABLE_COUNT), &size, 
59                                        &vallen);
60         if (size == 0) {
61                 CERROR("the Max snaptable count should not be zero\n");
62                 RETURN(-EINVAL);
63         }
64         
65         table_size = SNAPTABLE_SIZE(size);
66
67         OBD_ALLOC(snap_info->sntbl, table_size);
68
69         if (!snap_info->sntbl) {
70                 CERROR("No MEM\n");
71                 RETURN(-ENOMEM);
72         }
73         snap_table = snap_info->sntbl;
74          
75         snap_table->sntbl_magic = cpu_to_le32((__u32)SNAPTABLE_MAGIC); 
76         snap_table->sntbl_max_count = size;
77         for (i = 0; i < snap_table->sntbl_max_count; i++) {
78                 /*init sn_index to -1*/ 
79                 snap_table->sntbl_items[i].sn_index = -1;
80         }
81         /*get snaptable info*/
82         rc = snapops->fs_get_snap_info(sb, NULL, SNAPTABLE_INFO, 
83                                        strlen(SNAPTABLE_INFO), 
84                                        snap_table, &table_size);       
85         if (rc < 0) {
86                 if (rc == -ENOATTR) {
87                         snap_table->sntbl_count = 0;
88                         CDEBUG(D_INFO, "No snaptable here\n");
89                         RETURN(0);
90                 } else {
91                         CERROR("Can not retrive the snaptable from this filesystem\n");
92                         OBD_FREE(snap_table, table_size);
93                         RETURN(rc); 
94                 }
95         } 
96         if (le32_to_cpu(snap_table->sntbl_magic) != SNAPTABLE_MAGIC) {
97                 CERROR("On disk snaptable is not right \n");
98                 OBD_FREE(snap_table, table_size);
99                 RETURN(-EIO);
100         }
101         RETURN(rc);
102 }
103 #define COWED_NAME_LEN       (7 + 8 + 1) 
104 static int smfs_init_cowed_dir(struct super_block *sb, struct dentry* cowed_dir)  
105 {
106         struct snap_info *snap_info = S2SNAPI(sb);      
107         struct dentry    *dentry = NULL;
108         struct lvfs_run_ctxt saved;
109         char   name[COWED_NAME_LEN];
110         int    rc = 0;
111         ENTRY;
112          
113         sprintf(name, ".cowed_%08x", (__u32)cowed_dir->d_inode->i_ino);
114         push_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
115         dentry = simple_mkdir(cowed_dir, name, 0777, 1);
116         pop_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
117         if (IS_ERR(dentry)) {
118                 rc = PTR_ERR(dentry);
119                 CERROR("create cowed directory: rc = %d\n", rc);
120                 RETURN(rc);
121         }
122         snap_info->sn_cowed_dentry = dentry;
123         RETURN(rc);
124 }
125 int smfs_start_cow(struct super_block *sb)
126 {
127         struct smfs_super_info *smfs_info = S2SMI(sb);
128         int rc = 0;
129
130         ENTRY;
131         OBD_ALLOC(smfs_info->smsi_snap_info, sizeof(struct snap_info));
132      
133         if (!smfs_info->smsi_snap_info) 
134                 RETURN(-ENOMEM);
135         
136         /*init snap fsfilt operations*/
137         if (!S2SNAPI(sb)->snap_cache_fsfilt) {
138                 char *snap_cache_ftype = NULL;
139                 int   tmp = strlen(S2SMI(sb)->smsi_cache_ftype) + strlen("_snap");
140                 
141                 OBD_ALLOC(snap_cache_ftype, tmp + 1);  
142                 sprintf(snap_cache_ftype, "%s_snap", S2SMI(sb)->smsi_cache_ftype);
143                 S2SNAPI(sb)->snap_cache_fsfilt = fsfilt_get_ops(snap_cache_ftype);
144                 OBD_FREE(snap_cache_ftype, tmp + 1);
145                 if (!S2SNAPI(sb)->snap_cache_fsfilt) {
146                         CERROR("Can not get %s fsfilt ops needed by snap\n",
147                                snap_cache_ftype);
148                         RETURN(-EINVAL);
149                 }
150         }
151         if (!S2SNAPI(sb)->snap_fsfilt) {
152                 char *snap_ftype = NULL;
153                 int   tmp = strlen(S2SMI(sb)->smsi_ftype) + strlen("_snap");
154                 
155                 OBD_ALLOC(snap_ftype, tmp + 1);  
156                 sprintf(snap_ftype, "%s_snap", S2SMI(sb)->smsi_ftype);
157                 S2SNAPI(sb)->snap_fsfilt = fsfilt_get_ops(snap_ftype);
158                 OBD_FREE(snap_ftype, tmp + 1);
159                 if (!S2SNAPI(sb)->snap_fsfilt) {
160                         CERROR("Can not get %s fsfilt ops needed by snap\n",
161                                snap_ftype);
162                         RETURN(-EINVAL);
163                 }
164         }
165         rc = smfs_init_snaptabe(sb); 
166         if (rc) {
167                 CERROR("can not init snaptable rc=%d\n", rc);
168                 RETURN(rc);
169         }
170         /*init cowed dir to put the primary cowed inode
171          *FIXME-WANGDI, later the s_root may not be the 
172          *snap dir, we can indicate any dir to be cowed*/
173         rc = smfs_init_cowed_dir(sb, sb->s_root);
174         RETURN(rc);
175 }
176 EXPORT_SYMBOL(smfs_start_cow);
177 int smfs_stop_cow(struct super_block *sb)
178 {
179         struct snap_info       *snap_info = S2SNAPI(sb);        
180         struct snap_table      *snap_table = snap_info->sntbl;  
181         int rc = 0, table_size;
182         ENTRY;
183
184         l_dput(snap_info->sn_cowed_dentry);
185          
186         if (snap_info->snap_fsfilt) 
187                 fsfilt_put_ops(snap_info->snap_fsfilt);
188         if (snap_info->snap_cache_fsfilt)
189                 fsfilt_put_ops(snap_info->snap_cache_fsfilt);
190
191         if (snap_table) {
192                 table_size =  SNAPTABLE_SIZE(snap_table->sntbl_max_count);
193                 OBD_FREE(snap_info->sntbl, table_size);
194         }
195         if (snap_info) 
196                OBD_FREE(snap_info, sizeof(*snap_info)); 
197         
198         RETURN(rc);
199 }
200 EXPORT_SYMBOL(smfs_stop_cow);
201
202 int smfs_cow_init(struct super_block *sb)
203 {
204         struct smfs_super_info *smfs_info = S2SMI(sb);
205         int rc = 0;
206
207         SMFS_SET_COW(smfs_info);
208       
209         RETURN(rc);
210 }
211
212 int smfs_cow_cleanup(struct super_block *sb)
213 {
214         ENTRY;
215         SMFS_CLEAN_COW(S2SMI(sb));
216         RETURN(0);
217 }
218
219 /*FIXME Note indirect and primary inode 
220 * should be recorgnized here*/
221 int smfs_init_snap_inode_info(struct inode *inode, int flags)
222 {
223         int vallen, rc = 0;
224         ENTRY;
225
226         if (SMFS_DO_COW(S2SMI(inode->i_sb)) &&
227             (flags & SM_DO_COW)) {
228                 struct snap_inode_info *sni_info = I2SNAPI(inode);
229                 struct fsfilt_operations *snapops = I2SNAPOPS(inode);
230                 
231                 sni_info->sn_flags = flags;
232                 vallen = sizeof(sni_info->sn_gen);
233
234                 rc = snapops->fs_get_snap_info(NULL, inode, SNAP_GENERATION,
235                                                strlen(SNAP_GENERATION),
236                                                &sni_info->sn_gen, &vallen);               
237         } 
238         RETURN(rc);                                              
239          
240 }
241 /* latest snap: returns 
242    -  the index of the latest snapshot before NOW
243    -  hence it returns 0 in case all the volume snapshots lie in the future
244    -  this is the index where a COW will land (will be created) 
245 */
246 void snap_last(struct super_block *sb, struct snap *snap)
247 {
248         struct snap_info *snap_info = S2SNAPI(sb);
249         struct snap_table *table = snap_info->sntbl;
250         time_t now = CURRENT_TIME;
251         int i ;
252
253         ENTRY;
254         /* start at the highest index in the superblock snaptime array */ 
255         if (table->sntbl_count == 0) {
256                memset(snap, 0, sizeof(struct snap)); 
257         } else {
258                 i = table->sntbl_count - 1;
259                 snap->sn_index = table->sntbl_items[i].sn_index;
260                 snap->sn_time = table->sntbl_items[i].sn_time;
261                 snap->sn_gen = table->sntbl_items[i].sn_gen;
262         }
263         CDEBUG(D_INFO, "index: %d, time[i]: %ld, now: %ld\n",
264                snap->sn_index, snap->sn_time, now);
265         EXIT;
266         return;
267 }
268
269 static int inline get_index_of_item(struct snap_table *table, char *name)
270 {
271         int count = table->sntbl_count;
272         int i, j;
273         ENTRY;
274         
275         for (i = 0; i < table->sntbl_max_count; i++) { 
276                 if (!strcmp(name, table->sntbl_items[i].sn_name)) {
277                         CERROR("Duplicate name %s in snaptable\n", name); 
278                         RETURN(-EINVAL);
279                 }       
280         }
281
282         for (i = 0; i < table->sntbl_max_count; i++) {
283                 int found = 0;
284                 for (j = 0; j < (count + 1); j++) {
285                         if (table->sntbl_items[j].sn_index == i) {
286                                 found = 1;
287                                 break;  
288                         }
289                 }
290                 if (!found)
291                         RETURN(i);
292         }
293         CERROR("snaptable Full\n");
294         RETURN(-ENOSPC);
295 }
296
297 int smfs_add_snap_item(struct super_block *sb, char *name)
298 {
299         struct snap_info *snap_info = S2SNAPI(sb);
300         struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
301         struct snap_table *snap_table = snap_info->sntbl;
302         struct snap      *snap_item;
303         int    table_size, count = 0, index = 0, rc = 0;
304
305         count = snap_table->sntbl_count; 
306         /* XXX Is down this sema necessary*/
307         down_interruptible(&snap_info->sntbl_sema);
308         snap_item = &snap_table->sntbl_items[count];
309
310         /*add item in snap_table set generation*/
311         snap_item->sn_time = CURRENT_TIME;
312         /* find table index */
313         index = get_index_of_item(snap_table, name);
314         if (index < 0) 
315                 GOTO(exit, rc = index);
316         
317         snap_item->sn_index = index;
318         snap_item->sn_flags = 0;
319         snap_item->sn_gen = snap_table->sntbl_generation + 1; 
320         memcpy(snap_item->sn_name, name, SNAP_MAX_NAMELEN);
321         /* Wrote the whole snap_table to disk */
322         table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count); 
323         
324         rc = snapops->fs_set_snap_info(sb, NULL, SNAPTABLE_INFO, 
325                                        strlen(SNAPTABLE_INFO),
326                                        snap_table, &table_size);
327         if (rc) {
328                 CERROR("Set snaptable error rc=%d\n", rc);
329                 GOTO(exit, rc);
330         }
331         snap_table->sntbl_count++;
332         snap_table->sntbl_generation++;
333 exit:
334         up(&snap_info->sntbl_sema);
335         RETURN(rc);
336 }
337 EXPORT_SYMBOL(smfs_add_snap_item);
338 /*
339  * Note: this function should be differnet with snap_do_cow.
340  * In smfs_do_cow, we check the EA for whether do cow for that inode.
341  * In smfs_needs_cow, we check whether we do need to do cow. 
342  */
343 int smfs_needs_cow(struct inode *inode)
344 {
345         struct smfs_inode_info  *smi_info = I2SMI(inode); 
346         struct snap_inode_info *snap_info = NULL;
347         struct snap snap;
348         int index = -1;
349         ENTRY;
350
351         snap_info = &(smi_info->sm_sninfo);
352         
353         snap_last(inode->i_sb, &snap);
354         /* decision .... if the snapshot is more recent than the object,
355          * then any change to the object should cause a COW.
356          */
357         if (snap_info->sn_gen < snap.sn_gen ) 
358                 index = snap.sn_index;
359
360         CDEBUG(D_INFO, "snap_needs_cow, ino %lu , get index %d\n",
361                inode->i_ino, index);
362
363         RETURN(index);
364 } /* snap_needs_cow */
365
366 static int link_cowed_inode(struct inode *inode)
367 {
368         struct snap_info *snap_info = S2SNAPI(inode->i_sb);     
369         struct dentry *cowed_dir = NULL;
370         char fidname[LL_FID_NAMELEN];
371         int fidlen = 0, rc = 0;
372         struct dentry *dchild = NULL;
373         struct dentry *tmp = NULL;
374         unsigned mode;
375
376         cowed_dir = snap_info->sn_cowed_dentry;
377         
378         fidlen = ll_fid2str(fidname, inode->i_ino, inode->i_generation);
379
380         down(&cowed_dir->d_inode->i_sem);
381         dchild = ll_lookup_one_len(fidname, cowed_dir, fidlen);
382         if (IS_ERR(dchild)) {
383                 rc = PTR_ERR(dchild);
384                 if (rc != -EPERM && rc != -EACCES)
385                         CERROR("child lookup error %d\n", rc);
386                 GOTO(out_lock, rc);
387         }
388         if (dchild->d_inode != NULL) {
389                 CERROR("re-cowed file %s?\n", dchild->d_name.name);
390                 LASSERT(dchild->d_inode == inode);
391                 GOTO(out_dput, rc = 0);
392         }
393         tmp = pre_smfs_dentry(NULL, inode, cowed_dir);
394         /* link() is semanticaly-wrong for S_IFDIR, so we set S_IFREG
395          * for linking and return real mode back then -bzzz */
396         mode = inode->i_mode;
397         inode->i_mode = S_IFREG;
398         rc = vfs_link(tmp, cowed_dir->d_inode, dchild);
399         post_smfs_dentry(tmp);
400         if (rc) {
401                 CERROR("error linking cowed inode %s to COWED: rc = %d\n",
402                         fidname, rc);
403         } 
404         inode->i_mode = mode;
405         if ((mode & S_IFMT) == S_IFDIR) {
406                 dchild->d_inode->i_nlink++;
407                 cowed_dir->d_inode->i_nlink++;
408         }
409         mark_inode_dirty(dchild->d_inode);
410 out_dput:
411         dput(dchild);
412 out_lock:       
413         up(&cowed_dir->d_inode->i_sem);
414         RETURN(rc);
415 }
416 /*
417  * Make a copy of the data and plug a redirector in between if there
418  * is no redirector yet.
419  */
420 int snap_do_cow(struct inode *inode, struct dentry *dparent, int del)
421 {
422         struct snap_info *snap_info = S2SNAPI(inode->i_sb);     
423         struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
424         struct snap snap;
425         struct inode *ind = NULL;
426
427         ENTRY;
428
429         if (!snapops || !snapops->fs_create_indirect) 
430                 RETURN(-EINVAL);
431
432         snap_last(inode->i_sb, &snap);
433         ind = snapops->fs_create_indirect(inode, snap.sn_index, snap.sn_gen, 
434                                           dparent->d_inode, del);
435         if(!ind)
436                 RETURN(-EINVAL);
437         if (!SMFS_DO_INODE_COWED(inode)) {
438                 /*insert the inode to cowed inode*/
439                 SMFS_SET_INODE_COWED(inode); 
440                 link_cowed_inode(inode); 
441         }
442         
443         I2SMI(ind)->sm_sninfo.sn_flags = 0;
444         I2SMI(ind)->sm_sninfo.sn_gen = snap.sn_gen;
445         
446         iput(ind);
447         RETURN(0);
448 }
449 /*Dir inode will do cow*/
450 int smfs_cow_create(struct inode *dir, struct dentry *dentry,
451                     void *data1, void *data2)
452 {
453         int rc = 0;
454         struct dentry *dparent;
455         ENTRY;
456
457         if (smfs_needs_cow(dir) != -1) {
458                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
459                 LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
460                 dparent = dentry->d_parent->d_parent;
461                 if ((snap_do_cow(dir, dparent, 0))) {
462                         CERROR("Do cow error\n");
463                         RETURN(-EINVAL);
464                 }
465         }
466         RETURN(rc);
467 }
468
469 int smfs_cow_setattr(struct inode *dir, struct dentry *dentry,
470                      void *data1, void *data2)
471 {
472         int rc = 0;
473         ENTRY;
474         if (smfs_needs_cow(dir) != -1) {
475                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
476                 if ((snap_do_cow(dir, dentry->d_parent, 0))) {
477                         CERROR("Do cow error\n");
478                         RETURN(-EINVAL);
479                 }
480         }
481         RETURN(rc);
482 }
483
484 int smfs_cow_link(struct inode *dir, struct dentry *dentry,
485                   void *data1, void *data2)
486 {
487         int rc = 0;
488         struct dentry *dparent;
489         ENTRY;
490  
491         if (smfs_needs_cow(dir) != -1) {
492                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
493                 LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
494                 dparent = dentry->d_parent->d_parent;
495                 if ((snap_do_cow(dir, dparent, 0))) {
496                         CERROR("Do cow error\n");
497                         RETURN(-EINVAL);
498                 }
499                 if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 0))) {
500                         CERROR("Do cow error\n");
501                         RETURN(-EINVAL);
502                 }
503         }
504         RETURN(rc);
505 }
506
507 int smfs_cow_unlink(struct inode *dir, struct dentry *dentry,
508                     void *data1, void *data2)
509 {
510         struct dentry *dparent;
511         int rc = 0;
512         ENTRY;
513
514         if (smfs_needs_cow(dir) != -1) {
515                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
516                 LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
517                 dparent = dentry->d_parent->d_parent;
518                 if ((snap_do_cow(dir, dparent, 0))) {
519                         CERROR("Do cow error\n");
520                         RETURN(-EINVAL);
521                 }
522                 if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 1))) {
523                         CERROR("Do cow error\n");
524                         RETURN(-EINVAL);
525                 }
526         
527         }
528         RETURN(rc);
529 }
530
531 int smfs_cow_rename(struct inode *dir, struct dentry *dentry, 
532                     void *data1, void *data2)
533 {
534         struct inode *new_dir = (struct inode *)data1;
535         struct dentry *new_dentry = (struct dentry *)data2;
536         struct dentry *dparent;
537         int rc = 0;
538         ENTRY;
539        
540         LASSERT(new_dir);
541         LASSERT(new_dentry); 
542         if (smfs_needs_cow(dir) != -1) {
543                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n", dir->i_ino);
544                 LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
545                 dparent = dentry->d_parent->d_parent;
546                 if ((snap_do_cow(dir, dparent, 0))) {
547                         CERROR("Do cow error\n");
548                         RETURN(-EINVAL);
549                 }
550                 if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 0))) {
551                         CERROR("Do cow error\n");
552                         RETURN(-EINVAL);
553                 }
554         }
555         if (smfs_needs_cow(new_dir) != -1) {
556                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n", new_dir->i_ino);
557                 LASSERT(new_dentry->d_parent && new_dentry->d_parent->d_parent);
558                 dparent = new_dentry->d_parent->d_parent;
559                 if ((new_dir != dir) && (snap_do_cow(new_dir, dparent, 0))){
560                         CERROR("Do cow error\n");
561                         RETURN(-EINVAL);
562                 }
563                 if (new_dentry->d_inode && new_dentry->d_inode->i_nlink == 1) {
564                         if ((snap_do_cow(new_dentry->d_inode, 
565                                          new_dentry->d_parent, 0))) {
566                                 CERROR("Do cow error\n");
567                                 RETURN(-EINVAL);
568                         }
569                 }
570         } 
571         RETURN(rc);
572 }
573
574 int smfs_cow_write(struct inode *inode, struct dentry *dentry, void *data1,
575                    void *data2)
576 {
577         struct snap_info *snap_info = S2SNAPI(inode->i_sb); 
578         struct snap_table *table = snap_info->sntbl; 
579         long   blocks[2]={-1,-1};
580         int  index = 0, i, rc = 0;
581         size_t count;
582         loff_t pos;
583
584         ENTRY;
585
586         LASSERT(data1);
587         LASSERT(data2);
588         
589         count = *(size_t *)data1;
590         pos = *(loff_t*)data2;
591  
592         down(&inode->i_sem);
593         
594         if (smfs_needs_cow(inode) != -1 ) {
595                 CDEBUG(D_INFO, "snap_needs_cow for ino %lu \n",inode->i_ino);
596                 snap_do_cow(inode, dentry->d_parent, 0);
597         }
598         
599         CDEBUG(D_INFO, "write offset %lld count %u \n", pos, count);
600         
601         if(pos & (PAGE_CACHE_SIZE - 1)){
602                 blocks[0] = pos >> inode->i_sb->s_blocksize_bits;
603         }
604         pos += count - 1;
605         if((pos + 1) & (PAGE_CACHE_SIZE - 1)){
606                 blocks[1] = pos >> inode->i_sb->s_blocksize_bits;
607         }
608
609         if (blocks[0] == blocks[1]) 
610                 blocks[1] = -1;
611         
612         for (i = 0; i < 2; i++) {
613                 int slot = 0;
614                 if (blocks[i] == -1) 
615                         continue;
616                 /*Find the nearest page in snaptable and copy back it*/
617                 for (slot = table->sntbl_count - 1; slot >= 0; slot--) {
618                         struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
619                         struct inode *cache_inode = NULL;
620                         int result = 0;
621
622                         index = table->sntbl_items[slot].sn_index;
623                         cache_inode = snapops->fs_get_indirect(inode, NULL, index);
624
625                         if (!cache_inode)  continue;
626
627                         CDEBUG(D_INFO, "find cache_ino %lu\n", cache_inode->i_ino);
628                 
629                         result = snapops->fs_copy_block(inode, cache_inode, blocks[i]);
630                         if (result == 1) {
631                                 iput(cache_inode);
632                                 result = 0;
633                                 break;
634                         }
635                         if (result < 0) {
636                                 iput(cache_inode);
637                                 up(&inode->i_sem);
638                                 GOTO(exit, rc = result);
639                         }
640                         iput(cache_inode);
641                 }
642         }
643 exit:
644         up(&inode->i_sem); 
645         RETURN(rc);
646 }
647 EXPORT_SYMBOL(smfs_cow_write);
648
649 struct inode *smfs_cow_get_ind(struct inode *inode, int index)
650 {
651         struct snap_info *snap_info = S2SNAPI(inode->i_sb);
652         struct fsfilt_operations *snapops = snap_info->snap_fsfilt; 
653         struct snap_table *table = snap_info->sntbl;
654         long block=(index << PAGE_CACHE_SHIFT) >> inode->i_sb->s_blocksize_bits;
655         int slot;
656
657         ENTRY; 
658         for (slot = table->sntbl_count - 1; slot >= 0; slot--) {
659                 struct address_space_operations *aops = inode->i_mapping->a_ops;
660                 struct inode *cache_inode = NULL;
661                 int index = 0;
662
663                 index = table->sntbl_items[slot].sn_index;
664                 cache_inode = snapops->fs_get_indirect(inode, NULL, index);
665                                                                                                                                                                                                      
666                 if (!cache_inode )  continue;
667                                                                                                                                                                                                      
668                 if (aops->bmap(cache_inode->i_mapping, block))
669                        RETURN(cache_inode); 
670                 iput(cache_inode);
671         }
672
673         RETURN(NULL);
674 }
675 EXPORT_SYMBOL(smfs_cow_get_ind);
676 typedef int (*cow_funcs)(struct inode *dir, struct dentry *dentry, 
677                          void *new_dir, void *new_dentry);
678
679 static cow_funcs smfs_cow_funcs[REINT_MAX + 1] = {
680         [REINT_SETATTR] smfs_cow_setattr,
681         [REINT_CREATE]  smfs_cow_create,
682         [REINT_LINK]    smfs_cow_link,
683         [REINT_UNLINK]  smfs_cow_unlink,
684         [REINT_RENAME]  smfs_cow_rename,
685         [REINT_WRITE]   smfs_cow_write,
686 };
687
688 int smfs_cow(struct inode *dir, struct dentry *dentry, void *new_dir, 
689              void *new_dentry, int op)
690 {
691         return smfs_cow_funcs[op](dir, dentry, new_dir, new_dentry);
692 }
693