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