import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / fs / intermezzo / dir.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2000 Stelias Computing, Inc.
5  *  Copyright (C) 2000 Red Hat, Inc.
6  *  Copyright (C) 2000 Tacitus Systems
7  *  Copyright (C) 2000 Peter J. Braam
8  *
9  *   This file is part of InterMezzo, http://www.inter-mezzo.org.
10  *
11  *   InterMezzo is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   InterMezzo is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with InterMezzo; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include <stdarg.h>
26
27 #include <asm/bitops.h>
28 #include <asm/uaccess.h>
29 #include <asm/system.h>
30 #include <linux/smp_lock.h>
31
32 #include <linux/errno.h>
33 #include <linux/fs.h>
34 #include <linux/ext2_fs.h>
35 #include <linux/slab.h>
36 #include <linux/vmalloc.h>
37 #include <linux/sched.h>
38 #include <linux/stat.h>
39 #include <linux/string.h>
40 #include <linux/locks.h>
41 #include <linux/blkdev.h>
42 #include <linux/init.h>
43 #define __NO_VERSION__
44 #include <linux/module.h>
45
46 #include <linux/intermezzo_fs.h>
47 #include <linux/intermezzo_psdev.h>
48
49 static inline void presto_relock_sem(struct inode *dir) 
50 {
51         /* the lock from sys_mkdir / lookup_create */
52         down(&dir->i_sem);
53         /* the rest is done by the do_{create,mkdir, ...} */
54 }
55
56 static inline void presto_relock_other(struct inode *dir) 
57 {
58         /* vfs_mkdir locks */
59         down(&dir->i_zombie);
60         lock_kernel(); 
61 }
62
63 static inline void presto_fulllock(struct inode *dir) 
64 {
65         /* the lock from sys_mkdir / lookup_create */
66         down(&dir->i_sem);
67         /* vfs_mkdir locks */
68         down(&dir->i_zombie);
69         lock_kernel(); 
70 }
71
72 static inline void presto_unlock(struct inode *dir) 
73 {
74         /* vfs_mkdir locks */
75         unlock_kernel(); 
76         up(&dir->i_zombie);
77         /* the lock from sys_mkdir / lookup_create */
78         up(&dir->i_sem);
79 }
80
81
82 /*
83  * these are initialized in super.c
84  */
85 extern int presto_permission(struct inode *inode, int mask);
86 static int izo_authorized_uid = 0;
87
88 int izo_dentry_is_ilookup(struct dentry *dentry, ino_t *id,
89                           unsigned int *generation)
90 {
91         char tmpname[64];
92         char *next;
93
94         ENTRY;
95         /* prefix is 7 characters: '...ino:' */
96         if ( dentry->d_name.len < 7 || dentry->d_name.len > 64 ||
97              memcmp(dentry->d_name.name, PRESTO_ILOOKUP_MAGIC, 7) != 0 ) {
98                 EXIT;
99                 return 0;
100         }
101
102         memcpy(tmpname, dentry->d_name.name + 7, dentry->d_name.len - 7);
103         *(tmpname + dentry->d_name.len - 7) = '\0';
104
105         /* name is of the form ...ino:<inode number>:<generation> */
106         *id = simple_strtoul(tmpname, &next, 16);
107         if ( *next == PRESTO_ILOOKUP_SEP ) {
108                 *generation = simple_strtoul(next + 1, 0, 16);
109                 CDEBUG(D_INODE, "ino string: %s, Id = %lx (%lu), "
110                        "generation %x (%d)\n",
111                        tmpname, *id, *id, *generation, *generation);
112                 EXIT;
113                 return 1;
114         } else {
115                 EXIT;
116                 return 0;
117         }
118 }
119
120 struct dentry *presto_tmpfs_ilookup(struct inode *dir, 
121                                     struct dentry *dentry,
122                                     ino_t ino, 
123                                     unsigned int generation)
124 {
125         return dentry; 
126 }
127
128
129 inline int presto_can_ilookup(void)
130 {
131         return (current->euid == izo_authorized_uid ||
132                 capable(CAP_DAC_READ_SEARCH));
133 }
134
135 struct dentry *presto_iget_ilookup(struct inode *dir, 
136                                           struct dentry *dentry,
137                                           ino_t ino, 
138                                           unsigned int generation)
139 {
140         struct inode *inode;
141         int error;
142
143         ENTRY;
144
145         if ( !presto_can_ilookup() ) {
146                 CERROR("ilookup denied: euid %u, authorized_uid %u\n",
147                        current->euid, izo_authorized_uid);
148                 return ERR_PTR(-EPERM);
149         }
150         error = -ENOENT;
151         inode = iget(dir->i_sb, ino);
152         if (!inode) { 
153                 CERROR("fatal: NULL inode ino %lu\n", ino); 
154                 goto cleanup_iput;
155         }
156         if (is_bad_inode(inode) || inode->i_nlink == 0) {
157                 CERROR("fatal: bad inode ino %lu, links %d\n", ino, inode->i_nlink); 
158                 goto cleanup_iput;
159         }
160         if (inode->i_generation != generation) {
161                 CERROR("fatal: bad generation %u (want %u)\n",
162                        inode->i_generation, generation);
163                 goto cleanup_iput;
164         }
165
166         d_instantiate(dentry, inode);
167         dentry->d_flags |= DCACHE_NFSD_DISCONNECTED; /* NFS hack */
168
169         EXIT;
170         return NULL;
171
172 cleanup_iput:
173         if (inode)
174                 iput(inode);
175         return ERR_PTR(error);
176 }
177
178 struct dentry *presto_add_ilookup_dentry(struct dentry *parent,
179                                          struct dentry *real)
180 {
181         struct inode *inode = real->d_inode;
182         struct dentry *de;
183         char buf[32];
184         char *ptr = buf;
185         struct dentry *inodir;
186         struct presto_dentry_data *dd;
187
188         inodir = lookup_one_len("..iopen..", parent,  strlen("..iopen..")); 
189         if (!inodir || IS_ERR(inodir) || !inodir->d_inode ) { 
190                 CERROR("%s: bad ..iopen.. lookup\n", __FUNCTION__); 
191                 return NULL; 
192         }
193         inodir->d_inode->i_op = &presto_dir_iops;
194
195         snprintf(ptr, 32, "...ino:%lx:%x", inode->i_ino, inode->i_generation);
196
197         de = lookup_one_len(ptr, inodir,  strlen(ptr)); 
198         if (!de || IS_ERR(de)) {
199                 CERROR("%s: bad ...ino lookup %ld\n", 
200                        __FUNCTION__, PTR_ERR(de)); 
201                 dput(inodir);
202                 return NULL; 
203         }
204
205         dd = presto_d2d(real);
206         if (!dd) 
207                 BUG();
208
209         /* already exists */
210         if (de->d_inode)
211                 BUG();
212 #if 0 
213                 if (de->d_inode != inode ) { 
214                         CERROR("XX de->d_inode %ld, inode %ld\n", 
215                                de->d_inode->i_ino, inode->i_ino); 
216                         BUG();
217                 }
218                 if (dd->dd_inodentry) { 
219                         CERROR("inodentry exists %ld \n", inode->i_ino);
220                         BUG();
221                 }
222                 dput(inodir);
223                 return de;
224         }
225 #endif 
226
227         if (presto_d2d(de)) 
228                 BUG();
229
230         atomic_inc(&inode->i_count);
231         de->d_op = &presto_dentry_ops;
232         d_add(de, inode);
233         if (!de->d_op)
234                 CERROR("DD: no ops dentry %p, dd %p\n", de, dd);
235         dd->dd_inodentry = de;
236         dd->dd_count++;
237         de->d_fsdata = dd;
238
239         dput(inodir);
240         return de;
241 }
242
243 struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry)
244 {
245         int rc = 0;
246         struct dentry *de;
247         struct presto_cache *cache;
248         int minor;
249         ino_t ino;
250         unsigned int generation;
251         struct inode_operations *iops;
252         int is_ilookup = 0;
253
254         ENTRY;
255         cache = presto_get_cache(dir);
256         if (cache == NULL) {
257                 CERROR("InterMezzo BUG: no cache in presto_lookup "
258                        "(dir ino: %ld)!\n", dir->i_ino);
259                 EXIT;
260                 return NULL;
261         }
262         minor = presto_c2m(cache);
263
264         iops = filter_c2cdiops(cache->cache_filter);
265         if (!iops || !iops->lookup) {
266                 CERROR("InterMezzo BUG: filesystem has no lookup\n");
267                 EXIT;
268                 return NULL;
269         }
270
271
272         CDEBUG(D_CACHE, "dentry %p, dir ino: %ld, name: %*s, islento: %d\n",
273                dentry, dir->i_ino, dentry->d_name.len, dentry->d_name.name,
274                ISLENTO(minor));
275
276         if (dentry->d_fsdata)
277                 CERROR("DD -- BAD dentry %p has data\n", dentry);
278                        
279         dentry->d_fsdata = NULL;
280 #if 0
281         if (ext2_check_for_iopen(dir, dentry))
282                 de = NULL;
283         else {
284 #endif
285                 if ( izo_dentry_is_ilookup(dentry, &ino, &generation) ) { 
286                         de = cache->cache_filter->o_trops->tr_ilookup
287                                 (dir, dentry, ino, generation);
288                         is_ilookup = 1;
289                 } else
290                         de = iops->lookup(dir, dentry);
291 #if 0
292         }
293 #endif
294
295         if ( IS_ERR(de) ) {
296                 CERROR("dentry lookup error %ld\n", PTR_ERR(de));
297                 return de;
298         }
299
300         /* some file systems have no read_inode: set methods here */
301         if (dentry->d_inode)
302                 presto_set_ops(dentry->d_inode, cache->cache_filter);
303                 /* dentry->d_op is now hooked in dcache.c:presto_set_dd */
304
305         /* In lookup we will tolerate EROFS return codes from presto_set_dd
306          * to placate NFS. EROFS indicates that a fileset was not found but
307          * we should still be able to continue through a lookup.
308          * Anything else is a hard error and must be returned to VFS. */
309         if (!is_ilookup)
310                 rc = presto_set_dd(dentry);
311         if (rc && rc != -EROFS) {
312                 CERROR("presto_set_dd failed (dir %ld, name %*s): %d\n",
313                        dir->i_ino, dentry->d_name.len, dentry->d_name.name, rc);
314                 return ERR_PTR(rc);
315         }
316
317         EXIT;
318         return NULL;
319 }
320
321 static inline int presto_check_set_fsdata (struct dentry *de)
322 {
323         if (presto_d2d(de) == NULL) {
324 #ifdef PRESTO_NO_NFS
325                 CERROR("dentry without fsdata: %p: %*s\n", de, 
326                                 de->d_name.len, de->d_name.name);
327                 BUG();
328 #endif
329                 return presto_set_dd (de);
330         }
331
332         return 0;
333 }
334
335 int presto_setattr(struct dentry *de, struct iattr *iattr)
336 {
337         int error;
338         struct presto_cache *cache;
339         struct presto_file_set *fset;
340         struct lento_vfs_context info = { 0, 0, 0 };
341
342         ENTRY;
343
344         error = presto_prep(de, &cache, &fset);
345         if ( error ) {
346                 EXIT;
347                 return error;
348         }
349
350         if (!iattr->ia_valid)
351                 CDEBUG(D_INODE, "presto_setattr: iattr is not valid\n");
352
353         CDEBUG(D_INODE, "valid %#x, mode %#o, uid %u, gid %u, size %Lu, "
354                "atime %lu mtime %lu ctime %lu flags %d\n",
355                iattr->ia_valid, iattr->ia_mode, iattr->ia_uid, iattr->ia_gid,
356                iattr->ia_size, iattr->ia_atime, iattr->ia_mtime,
357                iattr->ia_ctime, iattr->ia_attr_flags);
358         
359         if ( presto_get_permit(de->d_inode) < 0 ) {
360                 EXIT;
361                 return -EROFS;
362         }
363
364         if (!ISLENTO(presto_c2m(cache)))
365                 info.flags = LENTO_FL_KML;
366         info.flags |= LENTO_FL_IGNORE_TIME;
367         error = presto_do_setattr(fset, de, iattr, &info);
368         presto_put_permit(de->d_inode);
369         return error;
370 }
371
372 /*
373  *  Now the meat: the fs operations that require journaling
374  *
375  *
376  *  XXX: some of these need modifications for hierarchical filesets
377  */
378
379 int presto_prep(struct dentry *dentry, struct presto_cache **cache,
380                 struct presto_file_set **fset)
381 {       
382         int rc;
383
384         /* NFS might pass us dentries which have not gone through lookup.
385          * Test and set d_fsdata for such dentries
386          */
387         rc = presto_check_set_fsdata (dentry);
388         if (rc) return rc;
389
390         *fset = presto_fset(dentry);
391         if ( *fset == NULL ) {
392                 CERROR("No file set for dentry at %p: %*s\n", dentry,
393                                 dentry->d_name.len, dentry->d_name.name);
394                 return -EROFS;
395         }
396
397         *cache = (*fset)->fset_cache;
398         if ( *cache == NULL ) {
399                 CERROR("PRESTO: BAD, BAD: cannot find cache\n");
400                 return -EBADF;
401         }
402
403         CDEBUG(D_PIOCTL, "---> cache flags %x, fset flags %x\n",
404               (*cache)->cache_flags, (*fset)->fset_flags);
405         if( presto_is_read_only(*fset) ) {
406                 CERROR("PRESTO: cannot modify read-only fileset, minor %d.\n",
407                        presto_c2m(*cache));
408                 return -EROFS;
409         }
410         return 0;
411 }
412
413 static int presto_create(struct inode * dir, struct dentry * dentry, int mode)
414 {
415         int error;
416         struct presto_cache *cache;
417         struct dentry *parent = dentry->d_parent;
418         struct lento_vfs_context info;
419         struct presto_file_set *fset;
420
421         ENTRY;
422         error = presto_check_set_fsdata(dentry);
423         if ( error ) {
424                 EXIT;
425                 return error;
426         }
427
428         error = presto_prep(dentry->d_parent, &cache, &fset);
429         if ( error ) {
430                 EXIT;
431                 return error;
432         }
433         presto_unlock(dir);
434
435         /* Does blocking and non-blocking behavious need to be 
436            checked for.  Without blocking (return 1), the permit
437            was acquired without reintegration
438         */
439         if ( presto_get_permit(dir) < 0 ) {
440                 EXIT;
441                 presto_fulllock(dir);
442                 return -EROFS;
443         }
444
445         presto_relock_sem(dir);
446         parent = dentry->d_parent; 
447         memset(&info, 0, sizeof(info));
448         if (!ISLENTO(presto_c2m(cache)))
449                 info.flags = LENTO_FL_KML;
450         info.flags |= LENTO_FL_IGNORE_TIME;
451         error = presto_do_create(fset, parent, dentry, mode, &info);
452
453         presto_relock_other(dir);
454         presto_put_permit(dir);
455         EXIT;
456         return error;
457 }
458
459 static int presto_link(struct dentry *old_dentry, struct inode *dir,
460                 struct dentry *new_dentry)
461 {
462         int error;
463         struct presto_cache *cache, *new_cache;
464         struct presto_file_set *fset, *new_fset;
465         struct dentry *parent = new_dentry->d_parent;
466         struct lento_vfs_context info;
467
468         ENTRY;
469         error = presto_prep(old_dentry, &cache, &fset);
470         if ( error ) {
471                 EXIT;
472                 return error;
473         }
474
475         error = presto_check_set_fsdata(new_dentry);
476         if ( error ) {
477                 EXIT;
478                 return error;
479         }
480
481         error = presto_prep(new_dentry->d_parent, &new_cache, &new_fset);
482         if ( error ) {
483                 EXIT;
484                 return error;
485         }
486
487         if (fset != new_fset) { 
488                 EXIT;
489                 return -EXDEV;
490         }
491
492         presto_unlock(dir);
493         if ( presto_get_permit(old_dentry->d_inode) < 0 ) {
494                 EXIT;
495                 presto_fulllock(dir);
496                 return -EROFS;
497         }
498
499         if ( presto_get_permit(dir) < 0 ) {
500                 EXIT;
501                 presto_fulllock(dir);
502                 return -EROFS;
503         }
504
505         presto_relock_sem(dir);
506         parent = new_dentry->d_parent;
507
508         memset(&info, 0, sizeof(info));
509         if (!ISLENTO(presto_c2m(cache)))
510                 info.flags = LENTO_FL_KML;
511         info.flags |= LENTO_FL_IGNORE_TIME;
512         error = presto_do_link(fset, old_dentry, parent,
513                                new_dentry, &info);
514
515 #if 0
516         /* XXX for links this is not right */
517         if (cache->cache_filter->o_trops->tr_add_ilookup ) { 
518                 struct dentry *d;
519                 d = cache->cache_filter->o_trops->tr_add_ilookup
520                         (dir->i_sb->s_root, new_dentry, 1); 
521         }
522 #endif 
523
524         presto_relock_other(dir);
525         presto_put_permit(dir);
526         presto_put_permit(old_dentry->d_inode);
527         return error;
528 }
529
530 static int presto_mkdir(struct inode * dir, struct dentry * dentry, int mode)
531 {
532         int error;
533         struct presto_file_set *fset;
534         struct presto_cache *cache;
535         struct dentry *parent = dentry->d_parent;
536         struct lento_vfs_context info;
537
538         ENTRY;
539
540         error = presto_check_set_fsdata(dentry);
541         if ( error  ) {
542                 EXIT;
543                 return error;
544         }
545
546         error = presto_prep(dentry->d_parent, &cache, &fset);
547         if ( error  ) {
548                 EXIT;
549                 return error;
550         }
551
552         presto_unlock(dir); 
553
554         if ( presto_get_permit(dir) < 0 ) {
555                 EXIT;
556                 presto_fulllock(dir);
557                 return -EROFS;
558         }
559
560         memset(&info, 0, sizeof(info));
561         if (!ISLENTO(presto_c2m(cache)))
562                 info.flags = LENTO_FL_KML;
563         info.flags |= LENTO_FL_IGNORE_TIME;
564
565         presto_relock_sem(dir); 
566         parent = dentry->d_parent;
567         error = presto_do_mkdir(fset, parent, dentry, mode, &info);
568         presto_relock_other(dir); 
569         presto_put_permit(dir);
570         return error;
571 }
572
573
574
575 static int presto_symlink(struct inode *dir, struct dentry *dentry,
576                    const char *name)
577 {
578         int error;
579         struct presto_cache *cache;
580         struct presto_file_set *fset;
581         struct dentry *parent = dentry->d_parent;
582         struct lento_vfs_context info;
583
584         ENTRY;
585         error = presto_check_set_fsdata(dentry);
586         if ( error ) {
587                 EXIT;
588                 return error;
589         }
590
591         error = presto_prep(dentry->d_parent, &cache, &fset);
592         if ( error ) {
593                 EXIT;
594                 return error;
595         }
596
597         presto_unlock(dir);
598         if ( presto_get_permit(dir) < 0 ) {
599                 EXIT;
600                 presto_fulllock(dir);
601                 return -EROFS;
602         }
603
604         presto_relock_sem(dir);
605         parent = dentry->d_parent;
606         memset(&info, 0, sizeof(info));
607         if (!ISLENTO(presto_c2m(cache)))
608                 info.flags = LENTO_FL_KML;
609         info.flags |= LENTO_FL_IGNORE_TIME;
610         error = presto_do_symlink(fset, parent, dentry, name, &info);
611         presto_relock_other(dir);
612         presto_put_permit(dir);
613         return error;
614 }
615
616 int presto_unlink(struct inode *dir, struct dentry *dentry)
617 {
618         int error;
619         struct presto_cache *cache;
620         struct presto_file_set *fset;
621         struct dentry *parent = dentry->d_parent;
622         struct lento_vfs_context info;
623
624         ENTRY;
625         error = presto_check_set_fsdata(dentry);
626         if ( error ) {
627                 EXIT;
628                 return error;
629         }
630
631         error = presto_prep(dentry->d_parent, &cache, &fset);
632         if ( error  ) {
633                 EXIT;
634                 return error;
635         }
636
637         presto_unlock(dir);
638         if ( presto_get_permit(dir) < 0 ) {
639                 EXIT;
640                 presto_fulllock(dir);
641                 return -EROFS;
642         }
643
644         presto_relock_sem(dir);
645         parent = dentry->d_parent;
646         memset(&info, 0, sizeof(info));
647         if (!ISLENTO(presto_c2m(cache)))
648                 info.flags = LENTO_FL_KML;
649         info.flags |= LENTO_FL_IGNORE_TIME;
650
651         error = presto_do_unlink(fset, parent, dentry, &info);
652
653         presto_relock_other(dir);
654         presto_put_permit(dir);
655         return error;
656 }
657
658 static int presto_rmdir(struct inode *dir, struct dentry *dentry)
659 {
660         int error;
661         struct presto_cache *cache;
662         struct presto_file_set *fset;
663         struct dentry *parent = dentry->d_parent;
664         struct lento_vfs_context info;
665
666         ENTRY;
667         CDEBUG(D_FILE, "prepping presto\n");
668         error = presto_check_set_fsdata(dentry);
669
670         if ( error ) {
671                 EXIT;
672                 return error;
673         }
674
675         error = presto_prep(dentry->d_parent, &cache, &fset);
676         if ( error ) {
677                 EXIT;
678                 return error;
679         }
680
681         CDEBUG(D_FILE, "unlocking\n");
682         /* We need to dget() before the dput in double_unlock, to ensure we
683          * still have dentry references.  double_lock doesn't do dget for us.
684          */
685         unlock_kernel();
686         if (d_unhashed(dentry))
687                 d_rehash(dentry);
688         double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
689         double_up(&dir->i_sem, &dentry->d_inode->i_sem);
690
691         CDEBUG(D_FILE, "getting permit\n");
692         if ( presto_get_permit(parent->d_inode) < 0 ) {
693                 EXIT;
694                 double_down(&dir->i_sem, &dentry->d_inode->i_sem);
695                 double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
696                 
697                 lock_kernel();
698                 return -EROFS;
699         }
700         CDEBUG(D_FILE, "locking\n");
701
702         double_down(&dir->i_sem, &dentry->d_inode->i_sem);
703         parent = dentry->d_parent;
704         memset(&info, 0, sizeof(info));
705         if (!ISLENTO(presto_c2m(cache)))
706                 info.flags = LENTO_FL_KML;
707         info.flags |= LENTO_FL_IGNORE_TIME;
708         error = presto_do_rmdir(fset, parent, dentry, &info);
709         presto_put_permit(parent->d_inode);
710         lock_kernel();
711         EXIT;
712         return error;
713 }
714
715 static int presto_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
716 {
717         int error;
718         struct presto_cache *cache;
719         struct presto_file_set *fset;
720         struct dentry *parent = dentry->d_parent;
721         struct lento_vfs_context info;
722
723         ENTRY;
724         error = presto_check_set_fsdata(dentry);
725         if ( error ) {
726                 EXIT;
727                 return error;
728         }
729
730         error = presto_prep(dentry->d_parent, &cache, &fset);
731         if ( error  ) {
732                 EXIT;
733                 return error;
734         }
735
736         presto_unlock(dir);
737         if ( presto_get_permit(dir) < 0 ) {
738                 EXIT;
739                 presto_fulllock(dir);
740                 return -EROFS;
741         }
742         
743         presto_relock_sem(dir);
744         parent = dentry->d_parent;
745         memset(&info, 0, sizeof(info));
746         if (!ISLENTO(presto_c2m(cache)))
747                 info.flags = LENTO_FL_KML;
748         info.flags |= LENTO_FL_IGNORE_TIME;
749         error = presto_do_mknod(fset, parent, dentry, mode, rdev, &info);
750         presto_relock_other(dir);
751         presto_put_permit(dir);
752         EXIT;
753         return error;
754 }
755
756 inline void presto_triple_unlock(struct inode *old_dir, struct inode *new_dir, 
757                                  struct dentry *old_dentry, 
758                                  struct dentry *new_dentry, int triple)
759 {
760         /* rename_dir case */ 
761         if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
762                 if (triple) {                   
763                         triple_up(&old_dir->i_zombie,
764                                   &new_dir->i_zombie,
765                                   &new_dentry->d_inode->i_zombie);
766                 } else { 
767                         double_up(&old_dir->i_zombie,
768                                   &new_dir->i_zombie);
769                 }
770                 up(&old_dir->i_sb->s_vfs_rename_sem);
771         } else /* this case is rename_other */
772                 double_up(&old_dir->i_zombie, &new_dir->i_zombie);
773         /* done by do_rename */
774         unlock_kernel();
775         double_up(&old_dir->i_sem, &new_dir->i_sem);
776 }
777
778 inline void presto_triple_fulllock(struct inode *old_dir, 
779                                    struct inode *new_dir, 
780                                    struct dentry *old_dentry, 
781                                    struct dentry *new_dentry, int triple)
782 {
783         /* done by do_rename */
784         double_down(&old_dir->i_sem, &new_dir->i_sem);
785         lock_kernel();
786         /* rename_dir case */ 
787         if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
788                 down(&old_dir->i_sb->s_vfs_rename_sem);
789                 if (triple) {                   
790                         triple_down(&old_dir->i_zombie,
791                                   &new_dir->i_zombie,
792                                   &new_dentry->d_inode->i_zombie);
793                 } else { 
794                         double_down(&old_dir->i_zombie,
795                                   &new_dir->i_zombie);
796                 }
797         } else /* this case is rename_other */
798                 double_down(&old_dir->i_zombie, &new_dir->i_zombie);
799 }
800
801 inline void presto_triple_relock_sem(struct inode *old_dir, 
802                                    struct inode *new_dir, 
803                                    struct dentry *old_dentry, 
804                                    struct dentry *new_dentry, int triple)
805 {
806         /* done by do_rename */
807         double_down(&old_dir->i_sem, &new_dir->i_sem);
808         lock_kernel();
809 }
810
811 inline void presto_triple_relock_other(struct inode *old_dir, 
812                                    struct inode *new_dir, 
813                                    struct dentry *old_dentry, 
814                                    struct dentry *new_dentry, int triple)
815 {
816         /* rename_dir case */ 
817         if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
818                 down(&old_dir->i_sb->s_vfs_rename_sem);
819                 if (triple) {                   
820                         triple_down(&old_dir->i_zombie,
821                                   &new_dir->i_zombie,
822                                   &new_dentry->d_inode->i_zombie);
823                 } else { 
824                         double_down(&old_dir->i_zombie,
825                                   &new_dir->i_zombie);
826                 }
827         } else /* this case is rename_other */
828                 double_down(&old_dir->i_zombie, &new_dir->i_zombie);
829 }
830
831
832 // XXX this can be optimized: renamtes across filesets only require 
833 //     multiple KML records, but can locally be executed normally. 
834 int presto_rename(struct inode *old_dir, struct dentry *old_dentry,
835                   struct inode *new_dir, struct dentry *new_dentry)
836 {
837         int error;
838         struct presto_cache *cache, *new_cache;
839         struct presto_file_set *fset, *new_fset;
840         struct lento_vfs_context info;
841         struct dentry *old_parent = old_dentry->d_parent;
842         struct dentry *new_parent = new_dentry->d_parent;
843         int triple;
844
845         ENTRY;
846         error = presto_prep(old_dentry, &cache, &fset);
847         if ( error ) {
848                 EXIT;
849                 return error;
850         }
851         error = presto_prep(new_parent, &new_cache, &new_fset);
852         if ( error ) {
853                 EXIT;
854                 return error;
855         }
856
857         if ( fset != new_fset ) {
858                 EXIT;
859                 return -EXDEV;
860         }
861
862         /* We need to do dget before the dput in double_unlock, to ensure we
863          * still have dentry references.  double_lock doesn't do dget for us.
864          */
865
866         triple = (S_ISDIR(old_dentry->d_inode->i_mode) && new_dentry->d_inode)?
867                 1:0;
868
869         presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple); 
870
871         if ( presto_get_permit(old_dir) < 0 ) {
872                 EXIT;
873                 presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
874                 return -EROFS;
875         }
876         if ( presto_get_permit(new_dir) < 0 ) {
877                 EXIT;
878                 presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
879                 return -EROFS;
880         }
881
882         presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple); 
883         memset(&info, 0, sizeof(info));
884         if (!ISLENTO(presto_c2m(cache)))
885                 info.flags = LENTO_FL_KML;
886         info.flags |= LENTO_FL_IGNORE_TIME;
887         error = do_rename(fset, old_parent, old_dentry, new_parent,
888                           new_dentry, &info);
889         presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple); 
890
891         presto_put_permit(new_dir);
892         presto_put_permit(old_dir);
893         return error;
894 }
895
896 /* basically this allows the ilookup processes access to all files for
897  * reading, while not making ilookup totally insecure.  This could all
898  * go away if we could set the CAP_DAC_READ_SEARCH capability for the client.
899  */
900 /* If posix acls are available, the underlying cache fs will export the
901  * appropriate permission function. Thus we do not worry here about ACLs
902  * or EAs. -SHP
903  */
904 int presto_permission(struct inode *inode, int mask)
905 {
906         unsigned short mode = inode->i_mode;
907         struct presto_cache *cache;
908         int rc;
909
910         ENTRY;
911         if ( presto_can_ilookup() && !(mask & S_IWOTH)) {
912                 CDEBUG(D_CACHE, "ilookup on %ld OK\n", inode->i_ino);
913                 EXIT;
914                 return 0;
915         }
916
917         cache = presto_get_cache(inode);
918
919         if ( cache ) {
920                 /* we only override the file/dir permission operations */
921                 struct inode_operations *fiops = filter_c2cfiops(cache->cache_filter);
922                 struct inode_operations *diops = filter_c2cdiops(cache->cache_filter);
923
924                 if ( S_ISREG(mode) && fiops && fiops->permission ) {
925                         EXIT;
926                         return fiops->permission(inode, mask);
927                 }
928                 if ( S_ISDIR(mode) && diops && diops->permission ) {
929                         EXIT;
930                         return diops->permission(inode, mask);
931                 }
932         }
933
934         /* The cache filesystem doesn't have its own permission function,
935          * but we don't want to duplicate the VFS code here.  In order
936          * to avoid looping from permission calling this function again,
937          * we temporarily override the permission operation while we call
938          * the VFS permission function.
939          */
940         inode->i_op->permission = NULL;
941         rc = permission(inode, mask);
942         inode->i_op->permission = &presto_permission;
943
944         EXIT;
945         return rc;
946 }
947
948
949 int presto_ioctl(struct inode *inode, struct file *file,
950                         unsigned int cmd, unsigned long arg)
951 {
952         char buf[1024];
953         struct izo_ioctl_data *data = NULL;
954         struct presto_dentry_data *dd;
955         int rc;
956
957         ENTRY;
958
959         /* Try the filesystem's ioctl first, and return if it succeeded. */
960         dd = presto_d2d(file->f_dentry); 
961         if (dd && dd->dd_fset) { 
962                 int (*cache_ioctl)(struct inode *, struct file *, unsigned int, unsigned long ) = filter_c2cdfops(dd->dd_fset->fset_cache->cache_filter)->ioctl;
963                 rc = -ENOTTY;
964                 if (cache_ioctl)
965                         rc = cache_ioctl(inode, file, cmd, arg);
966                 if (rc != -ENOTTY) {
967                         EXIT;
968                         return rc;
969                 }
970         }
971
972         if (current->euid != 0 && current->euid != izo_authorized_uid) {
973                 EXIT;
974                 return -EPERM;
975         }
976
977         memset(buf, 0, sizeof(buf));
978         
979         if (izo_ioctl_getdata(buf, buf + 1024, (void *)arg)) { 
980                 CERROR("intermezzo ioctl: data error\n");
981                 return -EINVAL;
982         }
983         data = (struct izo_ioctl_data *)buf;
984         
985         switch(cmd) {
986         case IZO_IOC_REINTKML: { 
987                 int rc;
988                 int cperr;
989                 rc = kml_reint_rec(file, data);
990
991                 EXIT;
992                 cperr = copy_to_user((char *)arg, data, sizeof(*data));
993                 if (cperr) { 
994                         CERROR("WARNING: cperr %d\n", cperr); 
995                         rc = -EFAULT;
996                 }
997                 return rc;
998         }
999
1000         case IZO_IOC_GET_RCVD: {
1001                 struct izo_rcvd_rec rec;
1002                 struct presto_file_set *fset;
1003                 int rc;
1004
1005                 fset = presto_fset(file->f_dentry);
1006                 if (fset == NULL) {
1007                         EXIT;
1008                         return -ENODEV;
1009                 }
1010                 rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
1011                 if (rc < 0) {
1012                         EXIT;
1013                         return rc;
1014                 }
1015
1016                 EXIT;
1017                 return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
1018         }
1019
1020         case IZO_IOC_REPSTATUS: {
1021                 __u64 client_kmlsize;
1022                 struct izo_rcvd_rec *lr_client;
1023                 struct izo_rcvd_rec rec;
1024                 struct presto_file_set *fset;
1025                 int minor;
1026                 int rc;
1027
1028                 fset = presto_fset(file->f_dentry);
1029                 if (fset == NULL) {
1030                         EXIT;
1031                         return -ENODEV;
1032                 }
1033                 minor = presto_f2m(fset);
1034
1035                 client_kmlsize = data->ioc_kmlsize;
1036                 lr_client =  (struct izo_rcvd_rec *) data->ioc_pbuf1;
1037
1038                 rc = izo_repstatus(fset, client_kmlsize, 
1039                                        lr_client, &rec);
1040                 if (rc < 0) {
1041                         EXIT;
1042                         return rc;
1043                 }
1044
1045                 EXIT;
1046                 return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
1047         }
1048
1049         case IZO_IOC_GET_CHANNEL: {
1050                 struct presto_file_set *fset;
1051
1052                 fset = presto_fset(file->f_dentry);
1053                 if (fset == NULL) {
1054                         EXIT;
1055                         return -ENODEV;
1056                 }
1057                 
1058                 data->ioc_dev = fset->fset_cache->cache_psdev->uc_minor;
1059                 CDEBUG(D_PSDEV, "CHANNEL %d\n", data->ioc_dev); 
1060                 EXIT;
1061                 return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
1062         }
1063
1064         case IZO_IOC_SET_IOCTL_UID:
1065                 izo_authorized_uid = data->ioc_uid;
1066                 EXIT;
1067                 return 0;
1068
1069         case IZO_IOC_SET_PID:
1070                 rc = izo_psdev_setpid(data->ioc_dev);
1071                 EXIT;
1072                 return rc;
1073
1074         case IZO_IOC_SET_CHANNEL:
1075                 rc = izo_psdev_setchannel(file, data->ioc_dev);
1076                 EXIT;
1077                 return rc;
1078
1079         case IZO_IOC_GET_KML_SIZE: {
1080                 struct presto_file_set *fset;
1081                 __u64 kmlsize;
1082
1083                 fset = presto_fset(file->f_dentry);
1084                 if (fset == NULL) {
1085                         EXIT;
1086                         return -ENODEV;
1087                 }
1088
1089                 kmlsize = presto_kml_offset(fset) + fset->fset_kml_logical_off;
1090
1091                 EXIT;
1092                 return copy_to_user((char *)arg, &kmlsize, sizeof(kmlsize))?-EFAULT : 0;
1093         }
1094
1095         case IZO_IOC_PURGE_FILE_DATA: {
1096                 struct presto_file_set *fset;
1097
1098                 fset = presto_fset(file->f_dentry);
1099                 if (fset == NULL) {
1100                         EXIT;
1101                         return -ENODEV;
1102                 }
1103
1104                 rc = izo_purge_file(fset, data->ioc_inlbuf1);
1105                 EXIT;
1106                 return rc;
1107         }
1108
1109         case IZO_IOC_GET_FILEID: {
1110                 rc = izo_get_fileid(file, data);
1111                 EXIT;
1112                 if (rc)
1113                         return rc;
1114                 return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
1115         }
1116
1117         case IZO_IOC_SET_FILEID: {
1118                 rc = izo_set_fileid(file, data);
1119                 EXIT;
1120                 if (rc)
1121                         return rc;
1122                 return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT  : 0;
1123         }
1124
1125         case IZO_IOC_ADJUST_LML: { 
1126                 struct lento_vfs_context *info; 
1127                 info = (struct lento_vfs_context *)data->ioc_inlbuf1;
1128                 rc = presto_adjust_lml(file, info); 
1129                 EXIT;
1130                 return rc;
1131         }
1132
1133         case IZO_IOC_CONNECT: {
1134                 struct presto_file_set *fset;
1135                 int minor;
1136
1137                 fset = presto_fset(file->f_dentry);
1138                 if (fset == NULL) {
1139                         EXIT;
1140                         return -ENODEV;
1141                 }
1142                 minor = presto_f2m(fset);
1143
1144                 rc = izo_upc_connect(minor, data->ioc_ino,
1145                                      data->ioc_generation, data->ioc_uuid,
1146                                      data->ioc_flags);
1147                 EXIT;
1148                 return rc;
1149         }
1150
1151         case IZO_IOC_GO_FETCH_KML: {
1152                 struct presto_file_set *fset;
1153                 int minor;
1154
1155                 fset = presto_fset(file->f_dentry);
1156                 if (fset == NULL) {
1157                         EXIT;
1158                         return -ENODEV;
1159                 }
1160                 minor = presto_f2m(fset);
1161
1162                 rc = izo_upc_go_fetch_kml(minor, fset->fset_name,
1163                                           data->ioc_uuid, data->ioc_kmlsize);
1164                 EXIT;
1165                 return rc;
1166         }
1167
1168         case IZO_IOC_REVOKE_PERMIT:
1169                 if (data->ioc_flags)
1170                         rc = izo_revoke_permit(file->f_dentry, data->ioc_uuid);
1171                 else
1172                         rc = izo_revoke_permit(file->f_dentry, NULL);
1173                 EXIT;
1174                 return rc;
1175
1176         case IZO_IOC_CLEAR_FSET:
1177                 rc = izo_clear_fsetroot(file->f_dentry);
1178                 EXIT;
1179                 return rc;
1180
1181         case IZO_IOC_CLEAR_ALL_FSETS: { 
1182                 struct presto_file_set *fset;
1183
1184                 fset = presto_fset(file->f_dentry);
1185                 if (fset == NULL) {
1186                         EXIT;
1187                         return -ENODEV;
1188                 }
1189
1190                 rc = izo_clear_all_fsetroots(fset->fset_cache);
1191                 EXIT;
1192                 return rc;
1193         }
1194
1195         case IZO_IOC_SET_FSET:
1196                 /*
1197                  * Mark this dentry as being a fileset root.
1198                  */
1199                 rc = presto_set_fsetroot_from_ioc(file->f_dentry, 
1200                                                   data->ioc_inlbuf1,
1201                                                   data->ioc_flags);
1202                 EXIT;
1203                 return rc;
1204
1205
1206         case IZO_IOC_MARK: {
1207                 int res = 0;  /* resulting flags - returned to user */
1208                 int error;
1209
1210                 CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %d\n",
1211                        file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
1212                        data->ioc_or_flag, data->ioc_mark_what);
1213
1214                 switch (data->ioc_mark_what) {
1215                 case MARK_DENTRY:               
1216                         error = izo_mark_dentry(file->f_dentry,
1217                                                    data->ioc_and_flag,
1218                                                    data->ioc_or_flag, &res);
1219                         break;
1220                 case MARK_FSET:
1221                         error = izo_mark_fset(file->f_dentry,
1222                                                  data->ioc_and_flag,
1223                                                  data->ioc_or_flag, &res);
1224                         break;
1225                 case MARK_CACHE:
1226                         error = izo_mark_cache(file->f_dentry,
1227                                                   data->ioc_and_flag,
1228                                                   data->ioc_or_flag, &res);
1229                         break;
1230                 case MARK_GETFL: {
1231                         int fflags, cflags;
1232                         data->ioc_and_flag = 0xffffffff;
1233                         data->ioc_or_flag = 0; 
1234                         error = izo_mark_dentry(file->f_dentry,
1235                                                    data->ioc_and_flag,
1236                                                    data->ioc_or_flag, &res);
1237                         if (error) 
1238                                 break;
1239                         error = izo_mark_fset(file->f_dentry,
1240                                                  data->ioc_and_flag,
1241                                                  data->ioc_or_flag, &fflags);
1242                         if (error) 
1243                                 break;
1244                         error = izo_mark_cache(file->f_dentry,
1245                                                   data->ioc_and_flag,
1246                                                   data->ioc_or_flag,
1247                                                   &cflags);
1248
1249                         if (error) 
1250                                 break;
1251                         data->ioc_and_flag = fflags;
1252                         data->ioc_or_flag = cflags;
1253                         break;
1254                 }
1255                 default:
1256                         error = -EINVAL;
1257                 }
1258
1259                 if (error) { 
1260                         EXIT;
1261                         return error;
1262                 }
1263                 data->ioc_mark_what = res;
1264                 CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %x\n",
1265                        file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
1266                        data->ioc_or_flag, data->ioc_mark_what);
1267
1268                 EXIT;
1269                 return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
1270         }
1271 #if 0
1272         case IZO_IOC_CLIENT_MAKE_BRANCH: {
1273                 struct presto_file_set *fset;
1274                 int minor;
1275
1276                 fset = presto_fset(file->f_dentry);
1277                 if (fset == NULL) {
1278                         EXIT;
1279                         return -ENODEV;
1280                 }
1281                 minor = presto_f2m(fset);
1282
1283                 rc = izo_upc_client_make_branch(minor, fset->fset_name,
1284                                                 data->ioc_inlbuf1,
1285                                                 data->ioc_inlbuf2);
1286                 EXIT;
1287                 return rc;
1288         }
1289 #endif
1290         case IZO_IOC_SERVER_MAKE_BRANCH: {
1291                 struct presto_file_set *fset;
1292                 int minor;
1293
1294                 fset = presto_fset(file->f_dentry);
1295                 if (fset == NULL) {
1296                         EXIT;
1297                         return -ENODEV;
1298                 }
1299                 minor = presto_f2m(fset);
1300
1301                 izo_upc_server_make_branch(minor, data->ioc_inlbuf1);
1302                 EXIT;
1303                 return 0;
1304         }
1305         case IZO_IOC_SET_KMLSIZE: {
1306                 struct presto_file_set *fset;
1307                 int minor;
1308                 struct izo_rcvd_rec rec;
1309
1310                 fset = presto_fset(file->f_dentry);
1311                 if (fset == NULL) {
1312                         EXIT;
1313                         return -ENODEV;
1314                 }
1315                 minor = presto_f2m(fset);
1316
1317                 rc = izo_upc_set_kmlsize(minor, fset->fset_name, data->ioc_uuid,
1318                                          data->ioc_kmlsize);
1319
1320                 if (rc != 0) {
1321                         EXIT;
1322                         return rc;
1323                 }
1324
1325                 rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
1326                 if (rc == -EINVAL) {
1327                         /* We don't know anything about this uuid yet; no
1328                          * worries. */
1329                         memset(&rec, 0, sizeof(rec));
1330                 } else if (rc <= 0) {
1331                         CERROR("InterMezzo: error reading last_rcvd: %d\n", rc);
1332                         EXIT;
1333                         return rc;
1334                 }
1335                 rec.lr_remote_offset = data->ioc_kmlsize;
1336                 rc = izo_rcvd_write(fset, &rec);
1337                 if (rc <= 0) {
1338                         CERROR("InterMezzo: error writing last_rcvd: %d\n", rc);
1339                         EXIT;
1340                         return rc;
1341                 }
1342                 EXIT;
1343                 return rc;
1344         }
1345         case IZO_IOC_BRANCH_UNDO: {
1346                 struct presto_file_set *fset;
1347                 int minor;
1348
1349                 fset = presto_fset(file->f_dentry);
1350                 if (fset == NULL) {
1351                         EXIT;
1352                         return -ENODEV;
1353                 }
1354                 minor = presto_f2m(fset);
1355
1356                 rc = izo_upc_branch_undo(minor, fset->fset_name,
1357                                          data->ioc_inlbuf1);
1358                 EXIT;
1359                 return rc;
1360         }
1361         case IZO_IOC_BRANCH_REDO: {
1362                 struct presto_file_set *fset;
1363                 int minor;
1364
1365                 fset = presto_fset(file->f_dentry);
1366                 if (fset == NULL) {
1367                         EXIT;
1368                         return -ENODEV;
1369                 }
1370                 minor = presto_f2m(fset);
1371
1372                 rc = izo_upc_branch_redo(minor, fset->fset_name,
1373                                          data->ioc_inlbuf1);
1374                 EXIT;
1375                 return rc;
1376         }
1377
1378         case TCGETS:
1379                 EXIT;
1380                 return -EINVAL;
1381
1382         default:
1383                 EXIT;
1384                 return -EINVAL;
1385                 
1386         }
1387         EXIT;
1388         return 0;
1389 }
1390
1391 struct file_operations presto_dir_fops = {
1392         .ioctl =  presto_ioctl
1393 };
1394
1395 struct inode_operations presto_dir_iops = {
1396         .create       = presto_create,
1397         .lookup       = presto_lookup,
1398         .link         = presto_link,
1399         .unlink       = presto_unlink,
1400         .symlink      = presto_symlink,
1401         .mkdir        = presto_mkdir,
1402         .rmdir        = presto_rmdir,
1403         .mknod        = presto_mknod,
1404         .rename       = presto_rename,
1405         .permission   = presto_permission,
1406         .setattr      = presto_setattr,
1407 #ifdef CONFIG_FS_EXT_ATTR
1408         .set_ext_attr = presto_set_ext_attr,
1409 #endif
1410 };
1411
1412