Whamcloud - gitweb
file pers.c was initially added on branch b_cray_portals_merge.
[fs/lustre-release.git] / lustre / snapfs / dir.c
1 /*
2  * dir.c
3  */
4 #define DEBUG_SUBSYSTEM S_SNAP
5
6 #include <linux/module.h>
7 #include <linux/kernel.h>
8 #include <linux/string.h>
9 #include <linux/slab.h>
10 #include <linux/stat.h>
11 #include <linux/unistd.h>
12 #include <linux/jbd.h>
13 #include <linux/ext3_fs.h>
14 #include <linux/snap.h>
15
16 #include "snapfs_internal.h" 
17
18 static ino_t get_parent_ino(struct inode * inode)
19 {
20         ino_t ino = 0;
21         struct dentry * dentry;
22
23         if (list_empty(&inode->i_dentry)) {
24                 CERROR("No dentry for ino %lu\n", inode->i_ino);
25                 return 0;
26         }
27
28         dentry = dget(list_entry(inode->i_dentry.next, struct dentry, d_alias));
29
30         if(dentry->d_parent->d_inode)
31                 ino = dentry->d_parent->d_inode->i_ino;
32
33         dput(dentry);
34         return ino;
35
36 }
37
38 static void d_unadd_iput(struct dentry *dentry)
39 {
40         spin_lock(&dcache_lock);
41         list_del(&dentry->d_alias);
42         INIT_LIST_HEAD(&dentry->d_alias);
43         list_del(&dentry->d_hash);
44         INIT_LIST_HEAD(&dentry->d_hash);
45         spin_unlock(&dcache_lock);
46         
47         iput(dentry->d_inode);
48         dentry->d_inode = NULL;
49 }
50
51 /* XXX check the return values */
52 static struct dentry *currentfs_lookup(struct inode * dir,struct dentry *dentry)
53 {
54         struct snap_cache *cache;
55         struct dentry *rc;
56         struct inode_operations *iops;
57         struct inode *cache_inode;
58         int index;
59
60         ENTRY;
61
62         cache = snap_find_cache(dir->i_dev);
63         if ( !cache ) { 
64                 RETURN(ERR_PTR(-EINVAL));
65         }
66
67         if ( dentry->d_name.len == strlen(".snap") &&
68              (memcmp(dentry->d_name.name, ".snap", strlen(".snap")) == 0) ) {
69                 struct inode *snap;
70                 ino_t ino;
71
72                 /* Don't permit .snap in clonefs */
73                 if( dentry->d_sb != cache->cache_sb )
74                         RETURN(ERR_PTR(-ENOENT));
75
76                 /* Don't permit .snap under .snap */
77                 if( currentfs_is_under_dotsnap(dentry) )
78                         RETURN(ERR_PTR(-ENOENT));
79
80                 ino = 0xF0000000 | dir->i_ino;
81                 snap = iget(dir->i_sb, ino);
82                 CDEBUG(D_INODE, ".snap inode ino %ld, mode %o\n", 
83                        snap->i_ino, snap->i_mode);
84                 d_add(dentry, snap);
85                 RETURN(NULL);
86         }
87
88         iops = filter_c2cdiops(cache->cache_filter); 
89         if (!iops || !iops->lookup) {
90                 RETURN(ERR_PTR(-EINVAL));
91         }
92
93         rc = iops->lookup(dir, dentry);
94         if (rc || !dentry->d_inode || 
95             is_bad_inode(dentry->d_inode) ||
96             IS_ERR(dentry->d_inode)) {
97                 RETURN(NULL);
98         }
99
100         CDEBUG(D_INODE, "cache inode ino %lu, mode %o\n", 
101                dentry->d_inode->i_ino, dentry->d_inode->i_mode);
102         /*
103          * If we are under dotsnap, we need save extra data into
104          * dentry->d_fsdata:  For dir, we only need _this_ snapshot's index; 
105          * For others, save primary ino, with it we could found index later
106          * anyway
107          */
108         cache_inode = dentry->d_inode;
109         if ( (index = currentfs_is_under_dotsnap(dentry)) ) {
110                 struct snapshot_operations *snapops;
111                 struct inode *ind_inode;
112                 ino_t pri_ino, ind_ino;
113                
114                 pri_ino = cache_inode->i_ino;
115                 snapops = filter_c2csnapops(cache->cache_filter);
116                 if( !snapops )
117                         goto err_out;
118
119                 ind_ino = snapops->get_indirect_ino(cache_inode, index);
120                 if( ind_ino <=0 && ind_ino != -ENOATTR )
121                         goto err_out;
122                 else if( ind_ino != -ENOATTR ){
123                         ind_inode = iget(cache_inode->i_sb, ind_ino);
124                         if( !ind_inode ){
125                                 goto err_out;
126                         }
127                         list_del(&dentry->d_alias);
128                         INIT_LIST_HEAD(&dentry->d_alias);
129                         list_add(&dentry->d_alias, &ind_inode->i_dentry);
130                         dentry->d_inode = ind_inode;
131                         iput(cache_inode);
132                 }
133
134                 if( S_ISDIR(dentry->d_inode->i_mode) )
135                         dentry->d_fsdata = (void*)index;
136                 else
137                         dentry->d_fsdata = (void*)pri_ino;
138         }
139
140         RETURN(NULL);
141
142 #if 0
143         /* XXX: PJB these need to be set up again. See dcache.c */
144         printk("set up dentry ops\n");
145         CDEBUG(D_CACHE, "\n");
146         filter_setup_dentry_ops(cache->cache_filter,
147                                 dentry->d_op, &currentfs_dentry_ops);
148         dentry->d_op = filter_c2udops(cache->cache_filter);
149         CDEBUG(D_CACHE, "\n");
150 #endif
151
152 err_out:
153         d_unadd_iput(dentry);
154         RETURN(ERR_PTR(-EINVAL));
155 }
156
157 static int currentfs_create(struct inode *dir, struct dentry *dentry, int mode)
158 {
159         struct snap_cache       *cache;
160         struct inode_operations *iops;
161         void                    *handle = NULL;
162         int                     rc;
163
164         ENTRY;
165
166         if (currentfs_is_under_dotsnap(dentry)) {
167                 RETURN(-EPERM);
168         }
169
170         cache = snap_find_cache(dir->i_dev);
171         if (!cache) { 
172                 RETURN(-EINVAL);
173         }
174
175         handle = snap_trans_start(cache, dir, SNAP_OP_CREATE);
176
177         if (snap_needs_cow(dir) != -1) {
178                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
179                 snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 1);
180                 if ((snap_do_cow(dir, get_parent_ino(dir), 0))) {
181                         CERROR("Do cow error\n");
182                         RETURN(-EINVAL);
183                 }
184         }
185
186         iops = filter_c2cdiops(cache->cache_filter); 
187         if (!iops || !iops->create) {
188                 RETURN(-EINVAL);
189         }
190         snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 2);
191         rc = iops->create(dir, dentry, mode);
192
193         /* XXX now set the correct snap_{file,dir,sym}_iops */
194         if (!dentry->d_inode) {
195                 CERROR("Error in currentfs_create, dentry->d_inode is NULL\n");
196                 GOTO(exit, 0);
197         }
198         set_filter_ops(cache, dentry->d_inode);
199         CDEBUG(D_INODE, "inode %lu, i_op %p\n", dentry->d_inode->i_ino, dentry->d_inode->i_op);
200         snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 3);
201         init_filter_data(dentry->d_inode, 0); 
202 exit:
203         snap_trans_commit(cache, handle);
204         RETURN(rc);
205 }
206
207 static int currentfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
208 {
209         struct snap_cache *cache;
210         int rc;
211         struct inode_operations *iops;
212         void *handle = NULL;
213
214         ENTRY;
215
216         if (currentfs_is_under_dotsnap(dentry)) {
217                 RETURN(-EPERM);
218         }
219
220         cache = snap_find_cache(dir->i_dev);
221         if ( !cache ) { 
222                 RETURN(-EINVAL);
223         }
224
225         handle = snap_trans_start(cache, dir, SNAP_OP_MKDIR);
226
227         if ( snap_needs_cow(dir) != -1 ) {
228                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
229                 snap_debug_device_fail(dir->i_dev, SNAP_OP_MKDIR, 1);
230                 snap_do_cow(dir, get_parent_ino(dir), 0);
231         }
232
233         iops = filter_c2cdiops(cache->cache_filter); 
234         if (!iops || !iops->mkdir) {
235                 rc = -EINVAL;
236                 goto exit;
237         }
238
239         snap_debug_device_fail(dir->i_dev, SNAP_OP_MKDIR, 2);
240         rc = iops->mkdir(dir, dentry, mode);
241
242         if ( rc ) 
243                 goto exit;
244                      
245         /* XXX now set the correct snap_{file,dir,sym}_iops */
246         if ( dentry->d_inode) {
247                 dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter);
248                 CDEBUG(D_INODE, "inode %lu, i_op %p\n", dentry->d_inode->i_ino, dentry->d_inode->i_op);
249         } else {
250                 CERROR("Error in currentfs_mkdir, dentry->d_inode is NULL\n");
251         }
252
253         set_filter_ops(cache, dentry->d_inode);
254         init_filter_data(dentry->d_inode, 0); 
255         
256         CDEBUG(D_INODE, "inode %lu, i_op %p\n", dentry->d_inode->i_ino, dentry->d_inode->i_op);
257         snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 3);
258
259         
260 exit:
261         snap_trans_commit(cache, handle);
262         RETURN(rc);
263 }
264
265 static int currentfs_link (struct dentry * old_dentry, struct inode * dir, 
266                         struct dentry *dentry)
267 {
268         struct snap_cache *cache;
269         int rc;
270         struct inode_operations *iops;
271         void *handle = NULL;
272
273         ENTRY;
274
275         if (currentfs_is_under_dotsnap(dentry)) 
276                 RETURN(-EPERM);
277
278         cache = snap_find_cache(dir->i_dev);
279         if ( !cache )  
280                 RETURN(-EINVAL);
281
282         handle = snap_trans_start(cache, dir, SNAP_OP_LINK);
283
284         if ( snap_needs_cow(dir) != -1 ) {
285                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
286                 snap_debug_device_fail(dir->i_dev, SNAP_OP_LINK, 1);
287                 snap_do_cow(dir, get_parent_ino(dir), 0);
288         }
289         if ( snap_needs_cow(old_dentry->d_inode) != -1 ) {
290                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",old_dentry->d_inode->i_ino);
291                 snap_debug_device_fail(dir->i_dev, SNAP_OP_LINK, 2);
292                 snap_do_cow(old_dentry->d_inode, dir->i_ino, 0);
293         }
294
295         iops = filter_c2cdiops(cache->cache_filter); 
296
297         if (!iops || !iops->link) 
298                 GOTO(exit, rc = -EINVAL);
299         
300         snap_debug_device_fail(dir->i_dev, SNAP_OP_LINK, 2);
301         rc = iops->link(old_dentry,dir, dentry);
302         snap_debug_device_fail(dir->i_dev, SNAP_OP_LINK, 3);
303 exit:
304         snap_trans_commit(cache, handle);
305         RETURN(rc);
306 }
307
308 static int currentfs_symlink(struct inode *dir, struct dentry *dentry, 
309                         const char * symname)
310 {
311         struct snap_cache *cache;
312         int rc;
313         struct inode_operations *iops;
314         void *handle = NULL;
315
316         ENTRY;
317
318         cache = snap_find_cache(dir->i_dev);
319         if (!cache)  
320                 RETURN(-EINVAL);
321
322         handle = snap_trans_start(cache, dir, SNAP_OP_SYMLINK);
323
324         if ( snap_needs_cow(dir) != -1 ) {
325                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
326                 snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 1);
327                 snap_do_cow(dir, get_parent_ino(dir), 0);
328         }
329
330         iops = filter_c2cdiops(cache->cache_filter); 
331         if (!iops || !iops->symlink) 
332                 GOTO(exit, rc = -EINVAL);
333
334         snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 2);
335         rc = iops->symlink(dir, dentry, symname);
336         
337         set_filter_ops(cache, dentry->d_inode);
338         init_filter_data(dentry->d_inode, 0); 
339         
340         snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 3);
341 exit:
342         snap_trans_commit(cache, handle);
343         RETURN(rc);
344 }
345
346 static int currentfs_mknod(struct inode *dir, struct dentry *dentry, int mode, 
347                         int rdev)
348 {
349         struct snap_cache *cache;
350         int rc;
351         struct inode_operations *iops;
352         void *handle = NULL;
353
354         ENTRY;
355
356         if (currentfs_is_under_dotsnap(dentry)) {
357                 RETURN(-EPERM);
358         }
359
360         cache = snap_find_cache(dir->i_dev);
361         if ( !cache ) { 
362                 RETURN(-EINVAL);
363         }
364
365         handle = snap_trans_start(cache, dir, SNAP_OP_MKNOD);
366
367         if ( snap_needs_cow(dir) != -1 ) {
368                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
369                 snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 1);
370                 snap_do_cow(dir, get_parent_ino(dir), 0);
371         }
372
373         iops = filter_c2cdiops(cache->cache_filter); 
374         if (!iops || !iops->mknod) 
375                 GOTO(exit, rc = -EINVAL);
376
377         snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 2);
378         rc = iops->mknod(dir, dentry, mode, rdev);
379         
380         set_filter_ops(cache, dentry->d_inode);
381         init_filter_data(dentry->d_inode, 0); 
382         snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 3);
383         
384         /* XXX do we need to set the correct snap_{*}_iops */
385
386 exit:
387         snap_trans_commit(cache, handle);
388         RETURN(rc);
389 }
390
391 static int currentfs_rmdir(struct inode *dir, struct dentry *dentry)
392 {
393         struct snap_cache *cache;
394         int rc;
395         struct inode_operations *iops;
396         struct inode *inode = NULL;
397 //      time_t i_ctime = 0;
398         nlink_t i_nlink = 0;
399         off_t   i_size = 0;
400         ino_t ino = 0;
401         int keep_inode = 0;
402         void *handle = NULL;
403
404         ENTRY;
405
406         if (currentfs_is_under_dotsnap(dentry)) {
407                 RETURN(-EPERM);
408         }
409
410         cache = snap_find_cache(dir->i_dev);
411         if ( !cache ) { 
412                 RETURN(-EINVAL);
413         }
414
415         handle = snap_trans_start(cache, dir, SNAP_OP_RMDIR);
416
417         if ( snap_needs_cow(dir) != -1 ) {
418                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
419                 snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 1);
420                 snap_do_cow(dir, get_parent_ino(dir), 0);
421         }
422
423         iops = filter_c2cdiops(cache->cache_filter); 
424         if (!iops || !iops->rmdir) 
425                 GOTO(exit, rc = -EINVAL);
426
427         /* XXX : there are two cases that we can't remove this inode from disk. 
428                 1. the inode needs to be cowed. 
429                 2. the inode is a redirector.
430                 then we must keep this inode(dir) so that the inode 
431                 will not be deleted after rmdir, will only remove dentry 
432         */
433
434         if (snap_needs_cow(dentry->d_inode) != -1 || 
435             snap_is_redirector(dentry->d_inode)) {
436                 snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 2);
437                 snap_do_cow (dentry->d_inode, get_parent_ino(dentry->d_inode), 
438                              SNAP_CREATE_IND_DEL_PRI);
439                 keep_inode = 1;
440         }
441
442         if( keep_inode && dentry->d_inode ) {
443                 ino = dentry->d_inode->i_ino;
444         //      i_ctime = dentry->d_inode->i_ctime;
445                 i_nlink = dentry->d_inode->i_nlink;
446                 i_size = dentry->d_inode->i_size;
447         }
448
449         snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 4);
450         rc = iops->rmdir(dir, dentry);
451         snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 5);
452
453         if( keep_inode && ino) {
454                 inode = iget (dir->i_sb, ino);
455                 if( inode) {
456 //                      inode->i_ctime = i_ctime;
457                         inode->i_nlink = i_nlink;
458                         inode->i_size = i_size;
459                         mark_inode_dirty(inode);
460                         iput( inode);
461                         /*
462                          * In Ext3, rmdir() will put this inode into
463                          * orphan list, we must remove it out. It's ugly!!
464                          */
465                         if( cache->cache_type == FILTER_FS_EXT3 )
466                                 ext3_orphan_del(handle, inode);
467                         snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 6);
468                 }
469         }
470 exit:
471         snap_trans_commit(cache, handle);
472         EXIT;
473         return rc;
474 }
475
476 static int currentfs_unlink(struct inode *dir, struct dentry *dentry)
477 {
478         struct inode *inode = dentry->d_inode;
479         struct snap_cache *cache;
480         int rc;
481         struct inode_operations *iops;
482         void *handle = NULL;
483
484         ENTRY;
485
486         if (currentfs_is_under_dotsnap(dentry)) {
487                 RETURN(-EPERM);
488         }
489
490         cache = snap_find_cache(dir->i_dev);
491         if ( !cache ) { 
492                 RETURN(-EINVAL);
493         }
494
495         handle = snap_trans_start(cache, dir, SNAP_OP_UNLINK);
496
497         if ( snap_needs_cow(dir) != -1 ) {
498                 CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
499                 snap_debug_device_fail(dir->i_dev, SNAP_OP_UNLINK, 1);
500                 snap_do_cow(dir, get_parent_ino(dir), 0);
501         }
502
503         iops = filter_c2cdiops(cache->cache_filter); 
504         if (!iops || !iops->unlink) {
505                 rc = -EINVAL;
506                 goto exit;
507         }
508
509         /* XXX : if nlink for this inode is 1, there are two cases that we 
510                 can't remove this inode from disk. 
511                 1. the inode needs to be cowed. 
512                 2. the inode is a redirector.
513                 then we increament dentry->d_inode->i_nlink so that the inode 
514                 will not be deleted after unlink, will only remove dentry 
515         */
516
517         if( snap_needs_cow (inode) != -1) {
518                 /* call snap_do_cow with DEL_WITHOUT_IND option */
519                 snap_debug_device_fail(dir->i_dev, SNAP_OP_UNLINK, 2);
520                 snap_do_cow(inode, dir->i_ino, SNAP_CREATE_IND_DEL_PRI);
521                 if( inode->i_nlink == 1 )
522                         inode->i_nlink++;
523         } else if (snap_is_redirector (inode) && inode->i_nlink == 1) {
524                 /* call snap_do_cow with DEL_WITH_IND option 
525                  * just free the blocks of inode, not really delete it
526                  */
527                 snap_debug_device_fail(dir->i_dev, SNAP_OP_UNLINK, 3);
528                 snap_do_cow (inode, dir->i_ino, SNAP_CREATE_IND_DEL_PRI);
529                 inode->i_nlink++;
530         }
531
532         snap_debug_device_fail(dir->i_dev, SNAP_OP_UNLINK, 4);
533         rc = iops->unlink(dir, dentry);
534         snap_debug_device_fail(dir->i_dev, SNAP_OP_UNLINK, 5);
535
536 exit:
537         snap_trans_commit(cache, handle);
538         RETURN(rc);
539 }
540
541 static int currentfs_rename (struct inode * old_dir, struct dentry *old_dentry,
542                         struct inode * new_dir, struct dentry *new_dentry)
543 {
544         struct snap_cache *cache;
545         int rc;
546         struct inode_operations *iops;
547         void *handle = NULL;
548
549         ENTRY;
550
551         if (currentfs_is_under_dotsnap(old_dentry) ||
552             currentfs_is_under_dotsnap(new_dentry)) {
553                 RETURN(-EPERM);
554         }
555
556         cache = snap_find_cache(old_dir->i_dev);
557         if ( !cache ) { 
558                 RETURN(-EINVAL);
559         }
560
561         handle = snap_trans_start(cache, old_dir, SNAP_OP_RENAME);
562        
563         /* Always cow the old dir and old dentry->d_inode */ 
564         if ( snap_needs_cow(old_dir) != -1 ) {
565                 CDEBUG(D_INODE, "rename: needs_cow for old_dir %lu\n",old_dir->i_ino);
566                 snap_debug_device_fail(old_dir->i_dev, SNAP_OP_RENAME, 1);
567                 snap_do_cow(old_dir, get_parent_ino(old_dir), 0);
568         }
569         if( snap_needs_cow (old_dentry->d_inode) != -1) {
570                 CDEBUG(D_INODE, "rename: needs_cow for old_dentry, ino %lu\n",
571                        old_dentry->d_inode->i_ino);
572                 snap_debug_device_fail(old_dir->i_dev, SNAP_OP_RENAME, 2);
573                 snap_do_cow(old_dentry->d_inode, old_dir->i_ino,0);
574         }
575
576         /* If it's not in the same dir, whether the new_dentry is NULL or not,
577          * we should cow the new_dir. Because rename will use the ino of 
578          * old_dentry as the ino of the new_dentry in new_dir. 
579          */
580         if(( old_dir != new_dir) ) {
581                 if( snap_needs_cow(new_dir) !=-1 ){
582                         CDEBUG(D_INODE, "rename:snap_needs_cow for new_dir %lu\n",
583                                 new_dir->i_ino);
584                         snap_debug_device_fail(old_dir->i_dev,SNAP_OP_RENAME,3);
585                         snap_do_cow(new_dir, get_parent_ino(new_dir), 0);       
586                 }
587         }
588
589 #if 0
590         if( ( old_dir != new_dir) && ( new_dentry->d_inode )) {
591                 if(snap_needs_cow(new_dentry->d_inode) !=-1 ){
592                         printk("rename:needs_cow for new_entry ,ino %lu\n",
593                                 new_dentry->d_inode->i_ino);
594                         snap_debug_device_fail(old_dir->i_dev, SNAP_OP_RENAME, 4);
595                         snap_do_cow (new_dentry->d_inode, 
596                                 new_dentry->d_parent->d_inode->i_ino, 0);       
597                 }
598         }
599 #endif
600         /* The inode for the new_dentry will be freed for normal rename option.
601          * But we should keep this inode since we need to keep it available 
602          * for the clone and for snap rollback
603          */
604         if( new_dentry->d_inode && new_dentry->d_inode->i_nlink == 1 ) {
605                 if( snap_needs_cow (new_dentry->d_inode) != -1) {
606                         /* call snap_do_cow with DEL_WITHOUT_IND option */
607                         snap_debug_device_fail(old_dir->i_dev,SNAP_OP_RENAME,4);
608                         snap_do_cow(new_dentry->d_inode, new_dir->i_ino,
609                                     SNAP_CREATE_IND_DEL_PRI);
610                         new_dentry->d_inode->i_nlink++;
611                 }
612                 else if( snap_is_redirector (new_dentry->d_inode) ) {
613                         /* call snap_do_cow with DEL_WITH_IND option 
614                          * just free the blocks of inode, not really delete it
615                          */
616                         snap_debug_device_fail(old_dir->i_dev,SNAP_OP_RENAME,4);
617                         snap_do_cow (new_dentry->d_inode, new_dir->i_ino, 
618                                      SNAP_CREATE_IND_DEL_PRI);
619                         new_dentry->d_inode->i_nlink++;
620                 }       
621         }
622
623         iops = filter_c2cdiops(cache->cache_filter); 
624         if (!iops || !iops->rename) {
625                 rc = -EINVAL;
626                 goto exit;
627         }
628
629         snap_debug_device_fail(old_dir->i_dev, SNAP_OP_RENAME, 5);
630         rc = iops->rename(old_dir, old_dentry, new_dir, new_dentry);
631         snap_debug_device_fail(old_dir->i_dev, SNAP_OP_RENAME, 6);
632
633 exit:
634         snap_trans_commit(cache, handle);
635         RETURN(rc);
636 }
637
638 static int currentfs_readdir(struct file *filp, void *dirent,
639                              filldir_t filldir)
640 {
641         struct snap_cache *cache;
642         struct file_operations *fops;
643         int rc;
644         
645         ENTRY;
646         if( !filp || !filp->f_dentry || !filp->f_dentry->d_inode ) {
647                 RETURN(-EINVAL);
648         }
649
650         cache = snap_find_cache(filp->f_dentry->d_inode->i_dev);
651         if ( !cache ) { 
652                 RETURN(-EINVAL);
653         }
654         fops = filter_c2cdfops( cache->cache_filter );
655         if( !fops ) {
656                 RETURN(-EINVAL);
657         }
658
659         /*
660          * no action if we are under clonefs or .snap
661          */
662         if( cache->cache_show_dotsnap &&
663             (filp->f_dentry->d_sb == cache->cache_sb) &&
664             !currentfs_is_under_dotsnap(filp->f_dentry) ){
665                 if( filp->f_pos == 0 ){
666                         if( filldir(dirent, ".snap",
667                                     strlen(".snap")+1, filp->f_pos,
668                                     -1, 0) ){
669                                 return -EINVAL;
670                         }
671                         filp->f_pos += strlen(".snap")+1;
672                 }
673                 filp->f_pos -= strlen(".snap")+1;
674                 rc = fops->readdir(filp, dirent, filldir);
675                 filp->f_pos += strlen(".snap")+1;
676         }else
677                 rc = fops->readdir(filp, dirent, filldir);
678
679         RETURN(rc);
680 }
681
682 struct file_operations currentfs_dir_fops = {
683         readdir: currentfs_readdir
684 };
685
686 struct inode_operations currentfs_dir_iops = { 
687         create:         currentfs_create,
688         mkdir:          currentfs_mkdir,
689         link:           currentfs_link,
690         symlink:        currentfs_symlink,
691         mknod:          currentfs_mknod,
692         rmdir:          currentfs_rmdir,
693         unlink:         currentfs_unlink,
694         rename:         currentfs_rename,
695         lookup:         currentfs_lookup,
696         removexattr:    currentfs_removexattr,
697         setattr:        currentfs_setattr,
698         setxattr:       currentfs_setxattr,
699 };