make oldconfig will rebuild these...
[linux-2.4.21-pre4.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
304         filter_setup_dentry_ops(cache->cache_filter,
305                                 dentry->d_op, &presto_dentry_ops);
306         dentry->d_op = filter_c2udops(cache->cache_filter);
307
308         /* In lookup we will tolerate EROFS return codes from presto_set_dd
309          * to placate NFS. EROFS indicates that a fileset was not found but
310          * we should still be able to continue through a lookup.
311          * Anything else is a hard error and must be returned to VFS. */
312         if (!is_ilookup)
313                 rc = presto_set_dd(dentry);
314         if (rc && rc != -EROFS) {
315                 CERROR("presto_set_dd failed (dir %ld, name %*s): %d\n",
316                        dir->i_ino, dentry->d_name.len, dentry->d_name.name, rc);
317                 return ERR_PTR(rc);
318         }
319
320         EXIT;
321         return NULL;
322 }
323
324 static inline int presto_check_set_fsdata (struct dentry *de)
325 {
326         if (presto_d2d(de) == NULL) {
327 #ifdef PRESTO_NO_NFS
328                 CERROR("dentry without fsdata: %p: %*s\n", de, 
329                                 de->d_name.len, de->d_name.name);
330                 BUG();
331 #endif
332                 return presto_set_dd (de);
333         }
334
335         return 0;
336 }
337
338 int presto_setattr(struct dentry *de, struct iattr *iattr)
339 {
340         int error;
341         struct presto_cache *cache;
342         struct presto_file_set *fset;
343         struct lento_vfs_context info = { 0, 0, 0 };
344
345         ENTRY;
346
347         error = presto_prep(de, &cache, &fset);
348         if ( error ) {
349                 EXIT;
350                 return error;
351         }
352
353         if (!iattr->ia_valid)
354                 CDEBUG(D_INODE, "presto_setattr: iattr is not valid\n");
355
356         CDEBUG(D_INODE, "valid %#x, mode %#o, uid %u, gid %u, size %Lu, "
357                "atime %lu mtime %lu ctime %lu flags %d\n",
358                iattr->ia_valid, iattr->ia_mode, iattr->ia_uid, iattr->ia_gid,
359                iattr->ia_size, iattr->ia_atime, iattr->ia_mtime,
360                iattr->ia_ctime, iattr->ia_attr_flags);
361         
362         if ( presto_get_permit(de->d_inode) < 0 ) {
363                 EXIT;
364                 return -EROFS;
365         }
366
367         if (!ISLENTO(presto_c2m(cache)))
368                 info.flags = LENTO_FL_KML;
369         info.flags |= LENTO_FL_IGNORE_TIME;
370         error = presto_do_setattr(fset, de, iattr, &info);
371         presto_put_permit(de->d_inode);
372         return error;
373 }
374
375 /*
376  *  Now the meat: the fs operations that require journaling
377  *
378  *
379  *  XXX: some of these need modifications for hierarchical filesets
380  */
381
382 int presto_prep(struct dentry *dentry, struct presto_cache **cache,
383                 struct presto_file_set **fset)
384 {       
385         int rc;
386
387         /* NFS might pass us dentries which have not gone through lookup.
388          * Test and set d_fsdata for such dentries
389          */
390         rc = presto_check_set_fsdata (dentry);
391         if (rc) return rc;
392
393         *fset = presto_fset(dentry);
394         if ( *fset == NULL ) {
395                 CERROR("No file set for dentry at %p: %*s\n", dentry,
396                                 dentry->d_name.len, dentry->d_name.name);
397                 return -EROFS;
398         }
399
400         *cache = (*fset)->fset_cache;
401         if ( *cache == NULL ) {
402                 CERROR("PRESTO: BAD, BAD: cannot find cache\n");
403                 return -EBADF;
404         }
405
406         CDEBUG(D_PIOCTL, "---> cache flags %x, fset flags %x\n",
407               (*cache)->cache_flags, (*fset)->fset_flags);
408         if( presto_is_read_only(*fset) ) {
409                 CERROR("PRESTO: cannot modify read-only fileset, minor %d.\n",
410                        presto_c2m(*cache));
411                 return -EROFS;
412         }
413         return 0;
414 }
415
416 static int presto_create(struct inode * dir, struct dentry * dentry, int mode)
417 {
418         int error;
419         struct presto_cache *cache;
420         struct dentry *parent = dentry->d_parent;
421         struct lento_vfs_context info;
422         struct presto_file_set *fset;
423
424         ENTRY;
425         error = presto_check_set_fsdata(dentry);
426         if ( error ) {
427                 EXIT;
428                 return error;
429         }
430
431         error = presto_prep(dentry->d_parent, &cache, &fset);
432         if ( error ) {
433                 EXIT;
434                 return error;
435         }
436         presto_unlock(dir);
437
438         /* Does blocking and non-blocking behavious need to be 
439            checked for.  Without blocking (return 1), the permit
440            was acquired without reintegration
441         */
442         if ( presto_get_permit(dir) < 0 ) {
443                 EXIT;
444                 presto_fulllock(dir);
445                 return -EROFS;
446         }
447
448         presto_relock_sem(dir);
449         parent = dentry->d_parent; 
450         memset(&info, 0, sizeof(info));
451         if (!ISLENTO(presto_c2m(cache)))
452                 info.flags = LENTO_FL_KML;
453         info.flags |= LENTO_FL_IGNORE_TIME;
454         error = presto_do_create(fset, parent, dentry, mode, &info);
455
456         presto_relock_other(dir);
457         presto_put_permit(dir);
458         EXIT;
459         return error;
460 }
461
462 static int presto_link(struct dentry *old_dentry, struct inode *dir,
463                 struct dentry *new_dentry)
464 {
465         int error;
466         struct presto_cache *cache, *new_cache;
467         struct presto_file_set *fset, *new_fset;
468         struct dentry *parent = new_dentry->d_parent;
469         struct lento_vfs_context info;
470
471         ENTRY;
472         error = presto_prep(old_dentry, &cache, &fset);
473         if ( error ) {
474                 EXIT;
475                 return error;
476         }
477
478         error = presto_check_set_fsdata(new_dentry);
479         if ( error ) {
480                 EXIT;
481                 return error;
482         }
483
484         error = presto_prep(new_dentry->d_parent, &new_cache, &new_fset);
485         if ( error ) {
486                 EXIT;
487                 return error;
488         }
489
490         if (fset != new_fset) { 
491                 EXIT;
492                 return -EXDEV;
493         }
494
495         presto_unlock(dir);
496         if ( presto_get_permit(old_dentry->d_inode) < 0 ) {
497                 EXIT;
498                 presto_fulllock(dir);
499                 return -EROFS;
500         }
501
502         if ( presto_get_permit(dir) < 0 ) {
503                 EXIT;
504                 presto_fulllock(dir);
505                 return -EROFS;
506         }
507
508         presto_relock_sem(dir);
509         parent = new_dentry->d_parent;
510
511         memset(&info, 0, sizeof(info));
512         if (!ISLENTO(presto_c2m(cache)))
513                 info.flags = LENTO_FL_KML;
514         info.flags |= LENTO_FL_IGNORE_TIME;
515         error = presto_do_link(fset, old_dentry, parent,
516                                new_dentry, &info);
517
518 #if 0
519         /* XXX for links this is not right */
520         if (cache->cache_filter->o_trops->tr_add_ilookup ) { 
521                 struct dentry *d;
522                 d = cache->cache_filter->o_trops->tr_add_ilookup
523                         (dir->i_sb->s_root, new_dentry, 1); 
524         }
525 #endif 
526
527         presto_relock_other(dir);
528         presto_put_permit(dir);
529         presto_put_permit(old_dentry->d_inode);
530         return error;
531 }
532
533 static int presto_mkdir(struct inode * dir, struct dentry * dentry, int mode)
534 {
535         int error;
536         struct presto_file_set *fset;
537         struct presto_cache *cache;
538         struct dentry *parent = dentry->d_parent;
539         struct lento_vfs_context info;
540
541         ENTRY;
542
543         error = presto_check_set_fsdata(dentry);
544         if ( error  ) {
545                 EXIT;
546                 return error;
547         }
548
549         error = presto_prep(dentry->d_parent, &cache, &fset);
550         if ( error  ) {
551                 EXIT;
552                 return error;
553         }
554
555         presto_unlock(dir); 
556
557         if ( presto_get_permit(dir) < 0 ) {
558                 EXIT;
559                 presto_fulllock(dir);
560                 return -EROFS;
561         }
562
563         memset(&info, 0, sizeof(info));
564         if (!ISLENTO(presto_c2m(cache)))
565                 info.flags = LENTO_FL_KML;
566         info.flags |= LENTO_FL_IGNORE_TIME;
567
568         presto_relock_sem(dir); 
569         parent = dentry->d_parent;
570         error = presto_do_mkdir(fset, parent, dentry, mode, &info);
571         presto_relock_other(dir); 
572         presto_put_permit(dir);
573         return error;
574 }
575
576
577
578 static int presto_symlink(struct inode *dir, struct dentry *dentry,
579                    const char *name)
580 {
581         int error;
582         struct presto_cache *cache;
583         struct presto_file_set *fset;
584         struct dentry *parent = dentry->d_parent;
585         struct lento_vfs_context info;
586
587         ENTRY;
588         error = presto_check_set_fsdata(dentry);
589         if ( error ) {
590                 EXIT;
591                 return error;
592         }
593
594         error = presto_prep(dentry->d_parent, &cache, &fset);
595         if ( error ) {
596                 EXIT;
597                 return error;
598         }
599
600         presto_unlock(dir);
601         if ( presto_get_permit(dir) < 0 ) {
602                 EXIT;
603                 presto_fulllock(dir);
604                 return -EROFS;
605         }
606
607         presto_relock_sem(dir);
608         parent = dentry->d_parent;
609         memset(&info, 0, sizeof(info));
610         if (!ISLENTO(presto_c2m(cache)))
611                 info.flags = LENTO_FL_KML;
612         info.flags |= LENTO_FL_IGNORE_TIME;
613         error = presto_do_symlink(fset, parent, dentry, name, &info);
614         presto_relock_other(dir);
615         presto_put_permit(dir);
616         return error;
617 }
618
619 int presto_unlink(struct inode *dir, struct dentry *dentry)
620 {
621         int error;
622         struct presto_cache *cache;
623         struct presto_file_set *fset;
624         struct dentry *parent = dentry->d_parent;
625         struct lento_vfs_context info;
626
627         ENTRY;
628         error = presto_check_set_fsdata(dentry);
629         if ( error ) {
630                 EXIT;
631                 return error;
632         }
633
634         error = presto_prep(dentry->d_parent, &cache, &fset);
635         if ( error  ) {
636                 EXIT;
637                 return error;
638         }
639
640         presto_unlock(dir);
641         if ( presto_get_permit(dir) < 0 ) {
642                 EXIT;
643                 presto_fulllock(dir);
644                 return -EROFS;
645         }
646
647         presto_relock_sem(dir);
648         parent = dentry->d_parent;
649         memset(&info, 0, sizeof(info));
650         if (!ISLENTO(presto_c2m(cache)))
651                 info.flags = LENTO_FL_KML;
652         info.flags |= LENTO_FL_IGNORE_TIME;
653
654         error = presto_do_unlink(fset, parent, dentry, &info);
655
656         presto_relock_other(dir);
657         presto_put_permit(dir);
658         return error;
659 }
660
661 static int presto_rmdir(struct inode *dir, struct dentry *dentry)
662 {
663         int error;
664         struct presto_cache *cache;
665         struct presto_file_set *fset;
666         struct dentry *parent = dentry->d_parent;
667         struct lento_vfs_context info;
668
669         ENTRY;
670         CDEBUG(D_FILE, "prepping presto\n");
671         error = presto_check_set_fsdata(dentry);
672
673         if ( error ) {
674                 EXIT;
675                 return error;
676         }
677
678         error = presto_prep(dentry->d_parent, &cache, &fset);
679         if ( error ) {
680                 EXIT;
681                 return error;
682         }
683
684         CDEBUG(D_FILE, "unlocking\n");
685         /* We need to dget() before the dput in double_unlock, to ensure we
686          * still have dentry references.  double_lock doesn't do dget for us.
687          */
688         unlock_kernel();
689         if (d_unhashed(dentry))
690                 d_rehash(dentry);
691         double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
692         double_up(&dir->i_sem, &dentry->d_inode->i_sem);
693
694         CDEBUG(D_FILE, "getting permit\n");
695         if ( presto_get_permit(parent->d_inode) < 0 ) {
696                 EXIT;
697                 double_down(&dir->i_sem, &dentry->d_inode->i_sem);
698                 double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
699                 
700                 lock_kernel();
701                 return -EROFS;
702         }
703         CDEBUG(D_FILE, "locking\n");
704
705         double_down(&dir->i_sem, &dentry->d_inode->i_sem);
706         parent = dentry->d_parent;
707         memset(&info, 0, sizeof(info));
708         if (!ISLENTO(presto_c2m(cache)))
709                 info.flags = LENTO_FL_KML;
710         info.flags |= LENTO_FL_IGNORE_TIME;
711         error = presto_do_rmdir(fset, parent, dentry, &info);
712         presto_put_permit(parent->d_inode);
713         lock_kernel();
714         EXIT;
715         return error;
716 }
717
718 static int presto_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
719 {
720         int error;
721         struct presto_cache *cache;
722         struct presto_file_set *fset;
723         struct dentry *parent = dentry->d_parent;
724         struct lento_vfs_context info;
725
726         ENTRY;
727         error = presto_check_set_fsdata(dentry);
728         if ( error ) {
729                 EXIT;
730                 return error;
731         }
732
733         error = presto_prep(dentry->d_parent, &cache, &fset);
734         if ( error  ) {
735                 EXIT;
736                 return error;
737         }
738
739         presto_unlock(dir);
740         if ( presto_get_permit(dir) < 0 ) {
741                 EXIT;
742                 presto_fulllock(dir);
743                 return -EROFS;
744         }
745         
746         presto_relock_sem(dir);
747         parent = dentry->d_parent;
748         memset(&info, 0, sizeof(info));
749         if (!ISLENTO(presto_c2m(cache)))
750                 info.flags = LENTO_FL_KML;
751         info.flags |= LENTO_FL_IGNORE_TIME;
752         error = presto_do_mknod(fset, parent, dentry, mode, rdev, &info);
753         presto_relock_other(dir);
754         presto_put_permit(dir);
755         EXIT;
756         return error;
757 }
758
759 inline void presto_triple_unlock(struct inode *old_dir, struct inode *new_dir, 
760                                  struct dentry *old_dentry, 
761                                  struct dentry *new_dentry, int triple)
762 {
763         /* rename_dir case */ 
764         if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
765                 if (triple) {                   
766                         triple_up(&old_dir->i_zombie,
767                                   &new_dir->i_zombie,
768                                   &new_dentry->d_inode->i_zombie);
769                 } else { 
770                         double_up(&old_dir->i_zombie,
771                                   &new_dir->i_zombie);
772                 }
773                 up(&old_dir->i_sb->s_vfs_rename_sem);
774         } else /* this case is rename_other */
775                 double_up(&old_dir->i_zombie, &new_dir->i_zombie);
776         /* done by do_rename */
777         unlock_kernel();
778         double_up(&old_dir->i_sem, &new_dir->i_sem);
779 }
780
781 inline void presto_triple_fulllock(struct inode *old_dir, 
782                                    struct inode *new_dir, 
783                                    struct dentry *old_dentry, 
784                                    struct dentry *new_dentry, int triple)
785 {
786         /* done by do_rename */
787         double_down(&old_dir->i_sem, &new_dir->i_sem);
788         lock_kernel();
789         /* rename_dir case */ 
790         if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
791                 down(&old_dir->i_sb->s_vfs_rename_sem);
792                 if (triple) {                   
793                         triple_down(&old_dir->i_zombie,
794                                   &new_dir->i_zombie,
795                                   &new_dentry->d_inode->i_zombie);
796                 } else { 
797                         double_down(&old_dir->i_zombie,
798                                   &new_dir->i_zombie);
799                 }
800         } else /* this case is rename_other */
801                 double_down(&old_dir->i_zombie, &new_dir->i_zombie);
802 }
803
804 inline void presto_triple_relock_sem(struct inode *old_dir, 
805                                    struct inode *new_dir, 
806                                    struct dentry *old_dentry, 
807                                    struct dentry *new_dentry, int triple)
808 {
809         /* done by do_rename */
810         double_down(&old_dir->i_sem, &new_dir->i_sem);
811         lock_kernel();
812 }
813
814 inline void presto_triple_relock_other(struct inode *old_dir, 
815                                    struct inode *new_dir, 
816                                    struct dentry *old_dentry, 
817                                    struct dentry *new_dentry, int triple)
818 {
819         /* rename_dir case */ 
820         if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
821                 down(&old_dir->i_sb->s_vfs_rename_sem);
822                 if (triple) {                   
823                         triple_down(&old_dir->i_zombie,
824                                   &new_dir->i_zombie,
825                                   &new_dentry->d_inode->i_zombie);
826                 } else { 
827                         double_down(&old_dir->i_zombie,
828                                   &new_dir->i_zombie);
829                 }
830         } else /* this case is rename_other */
831                 double_down(&old_dir->i_zombie, &new_dir->i_zombie);
832 }
833
834
835 // XXX this can be optimized: renamtes across filesets only require 
836 //     multiple KML records, but can locally be executed normally. 
837 int presto_rename(struct inode *old_dir, struct dentry *old_dentry,
838                   struct inode *new_dir, struct dentry *new_dentry)
839 {
840         int error;
841         struct presto_cache *cache, *new_cache;
842         struct presto_file_set *fset, *new_fset;
843         struct lento_vfs_context info;
844         struct dentry *old_parent = old_dentry->d_parent;
845         struct dentry *new_parent = new_dentry->d_parent;
846         int triple;
847
848         ENTRY;
849         error = presto_prep(old_dentry, &cache, &fset);
850         if ( error ) {
851                 EXIT;
852                 return error;
853         }
854         error = presto_prep(new_parent, &new_cache, &new_fset);
855         if ( error ) {
856                 EXIT;
857                 return error;
858         }
859
860         if ( fset != new_fset ) {
861                 EXIT;
862                 return -EXDEV;
863         }
864
865         /* We need to do dget before the dput in double_unlock, to ensure we
866          * still have dentry references.  double_lock doesn't do dget for us.
867          */
868
869         triple = (S_ISDIR(old_dentry->d_inode->i_mode) && new_dentry->d_inode)?
870                 1:0;
871
872         presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple); 
873
874         if ( presto_get_permit(old_dir) < 0 ) {
875                 EXIT;
876                 presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
877                 return -EROFS;
878         }
879         if ( presto_get_permit(new_dir) < 0 ) {
880                 EXIT;
881                 presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
882                 return -EROFS;
883         }
884
885         presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple); 
886         memset(&info, 0, sizeof(info));
887         if (!ISLENTO(presto_c2m(cache)))
888                 info.flags = LENTO_FL_KML;
889         info.flags |= LENTO_FL_IGNORE_TIME;
890         error = do_rename(fset, old_parent, old_dentry, new_parent,
891                           new_dentry, &info);
892         presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple); 
893
894         presto_put_permit(new_dir);
895         presto_put_permit(old_dir);
896         return error;
897 }
898
899 /* basically this allows the ilookup processes access to all files for
900  * reading, while not making ilookup totally insecure.  This could all
901  * go away if we could set the CAP_DAC_READ_SEARCH capability for the client.
902  */
903 /* If posix acls are available, the underlying cache fs will export the
904  * appropriate permission function. Thus we do not worry here about ACLs
905  * or EAs. -SHP
906  */
907 int presto_permission(struct inode *inode, int mask)
908 {
909         unsigned short mode = inode->i_mode;
910         struct presto_cache *cache;
911         int rc;
912
913         ENTRY;
914         if ( presto_can_ilookup() && !(mask & S_IWOTH)) {
915                 CDEBUG(D_CACHE, "ilookup on %ld OK\n", inode->i_ino);
916                 EXIT;
917                 return 0;
918         }
919
920         cache = presto_get_cache(inode);
921
922         if ( cache ) {
923                 /* we only override the file/dir permission operations */
924                 struct inode_operations *fiops = filter_c2cfiops(cache->cache_filter);
925                 struct inode_operations *diops = filter_c2cdiops(cache->cache_filter);
926
927                 if ( S_ISREG(mode) && fiops && fiops->permission ) {
928                         EXIT;
929                         return fiops->permission(inode, mask);
930                 }
931                 if ( S_ISDIR(mode) && diops && diops->permission ) {
932                         EXIT;
933                         return diops->permission(inode, mask);
934                 }
935         }
936
937         /* The cache filesystem doesn't have its own permission function,
938          * but we don't want to duplicate the VFS code here.  In order
939          * to avoid looping from permission calling this function again,
940          * we temporarily override the permission operation while we call
941          * the VFS permission function.
942          */
943         inode->i_op->permission = NULL;
944         rc = permission(inode, mask);
945         inode->i_op->permission = &presto_permission;
946
947         EXIT;
948         return rc;
949 }
950
951
952 int presto_ioctl(struct inode *inode, struct file *file,
953                         unsigned int cmd, unsigned long arg)
954 {
955         char buf[1024];
956         struct izo_ioctl_data *data = NULL;
957         struct presto_dentry_data *dd;
958         int rc;
959
960         ENTRY;
961
962         /* Try the filesystem's ioctl first, and return if it succeeded. */
963         dd = presto_d2d(file->f_dentry); 
964         if (dd && dd->dd_fset) { 
965                 int (*cache_ioctl)(struct inode *, struct file *, unsigned int, unsigned long ) = filter_c2cdfops(dd->dd_fset->fset_cache->cache_filter)->ioctl;
966                 rc = -ENOTTY;
967                 if (cache_ioctl)
968                         rc = cache_ioctl(inode, file, cmd, arg);
969                 if (rc != -ENOTTY) {
970                         EXIT;
971                         return rc;
972                 }
973         }
974
975         if (current->euid != 0 && current->euid != izo_authorized_uid) {
976                 EXIT;
977                 return -EPERM;
978         }
979
980         memset(buf, 0, sizeof(buf));
981         
982         if (izo_ioctl_getdata(buf, buf + 1024, (void *)arg)) { 
983                 CERROR("intermezzo ioctl: data error\n");
984                 return -EINVAL;
985         }
986         data = (struct izo_ioctl_data *)buf;
987         
988         switch(cmd) {
989         case IZO_IOC_REINTKML: { 
990                 int rc;
991                 int cperr;
992                 rc = kml_reint_rec(file, data);
993
994                 EXIT;
995                 cperr = copy_to_user((char *)arg, data, sizeof(*data));
996                 if (cperr) { 
997                         CERROR("WARNING: cperr %d\n", cperr); 
998                         rc = -EFAULT;
999                 }
1000                 return rc;
1001         }
1002
1003         case IZO_IOC_GET_RCVD: {
1004                 struct izo_rcvd_rec rec;
1005                 struct presto_file_set *fset;
1006                 int rc;
1007
1008                 fset = presto_fset(file->f_dentry);
1009                 if (fset == NULL) {
1010                         EXIT;
1011                         return -ENODEV;
1012                 }
1013                 rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
1014                 if (rc < 0) {
1015                         EXIT;
1016                         return rc;
1017                 }
1018
1019                 EXIT;
1020                 return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
1021         }
1022
1023         case IZO_IOC_REPSTATUS: {
1024                 __u64 client_kmlsize;
1025                 struct izo_rcvd_rec *lr_client;
1026                 struct izo_rcvd_rec rec;
1027                 struct presto_file_set *fset;
1028                 int minor;
1029                 int rc;
1030
1031                 fset = presto_fset(file->f_dentry);
1032                 if (fset == NULL) {
1033                         EXIT;
1034                         return -ENODEV;
1035                 }
1036                 minor = presto_f2m(fset);
1037
1038                 client_kmlsize = data->ioc_kmlsize;
1039                 lr_client =  (struct izo_rcvd_rec *) data->ioc_pbuf1;
1040
1041                 rc = izo_repstatus(fset, client_kmlsize, 
1042                                        lr_client, &rec);
1043                 if (rc < 0) {
1044                         EXIT;
1045                         return rc;
1046                 }
1047
1048                 EXIT;
1049                 return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
1050         }
1051
1052         case IZO_IOC_GET_CHANNEL: {
1053                 struct presto_file_set *fset;
1054
1055                 fset = presto_fset(file->f_dentry);
1056                 if (fset == NULL) {
1057                         EXIT;
1058                         return -ENODEV;
1059                 }
1060                 
1061                 data->ioc_dev = fset->fset_cache->cache_psdev->uc_minor;
1062                 CDEBUG(D_PSDEV, "CHANNEL %d\n", data->ioc_dev); 
1063                 EXIT;
1064                 return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
1065         }
1066
1067         case IZO_IOC_SET_IOCTL_UID:
1068                 izo_authorized_uid = data->ioc_uid;
1069                 EXIT;
1070                 return 0;
1071
1072         case IZO_IOC_SET_PID:
1073                 rc = izo_psdev_setpid(data->ioc_dev);
1074                 EXIT;
1075                 return rc;
1076
1077         case IZO_IOC_SET_CHANNEL:
1078                 rc = izo_psdev_setchannel(file, data->ioc_dev);
1079                 EXIT;
1080                 return rc;
1081
1082         case IZO_IOC_GET_KML_SIZE: {
1083                 struct presto_file_set *fset;
1084                 __u64 kmlsize;
1085
1086                 fset = presto_fset(file->f_dentry);
1087                 if (fset == NULL) {
1088                         EXIT;
1089                         return -ENODEV;
1090                 }
1091
1092                 kmlsize = presto_kml_offset(fset) + fset->fset_kml_logical_off;
1093
1094                 EXIT;
1095                 return copy_to_user((char *)arg, &kmlsize, sizeof(kmlsize))?-EFAULT : 0;
1096         }
1097
1098         case IZO_IOC_PURGE_FILE_DATA: {
1099                 struct presto_file_set *fset;
1100
1101                 fset = presto_fset(file->f_dentry);
1102                 if (fset == NULL) {
1103                         EXIT;
1104                         return -ENODEV;
1105                 }
1106
1107                 rc = izo_purge_file(fset, data->ioc_inlbuf1);
1108                 EXIT;
1109                 return rc;
1110         }
1111
1112         case IZO_IOC_GET_FILEID: {
1113                 rc = izo_get_fileid(file, data);
1114                 EXIT;
1115                 if (rc)
1116                         return rc;
1117                 return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
1118         }
1119
1120         case IZO_IOC_SET_FILEID: {
1121                 rc = izo_set_fileid(file, data);
1122                 EXIT;
1123                 if (rc)
1124                         return rc;
1125                 return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT  : 0;
1126         }
1127
1128         case IZO_IOC_ADJUST_LML: { 
1129                 struct lento_vfs_context *info; 
1130                 info = (struct lento_vfs_context *)data->ioc_inlbuf1;
1131                 rc = presto_adjust_lml(file, info); 
1132                 EXIT;
1133                 return rc;
1134         }
1135
1136         case IZO_IOC_CONNECT: {
1137                 struct presto_file_set *fset;
1138                 int minor;
1139
1140                 fset = presto_fset(file->f_dentry);
1141                 if (fset == NULL) {
1142                         EXIT;
1143                         return -ENODEV;
1144                 }
1145                 minor = presto_f2m(fset);
1146
1147                 rc = izo_upc_connect(minor, data->ioc_ino,
1148                                      data->ioc_generation, data->ioc_uuid,
1149                                      data->ioc_flags);
1150                 EXIT;
1151                 return rc;
1152         }
1153
1154         case IZO_IOC_GO_FETCH_KML: {
1155                 struct presto_file_set *fset;
1156                 int minor;
1157
1158                 fset = presto_fset(file->f_dentry);
1159                 if (fset == NULL) {
1160                         EXIT;
1161                         return -ENODEV;
1162                 }
1163                 minor = presto_f2m(fset);
1164
1165                 rc = izo_upc_go_fetch_kml(minor, fset->fset_name,
1166                                           data->ioc_uuid, data->ioc_kmlsize);
1167                 EXIT;
1168                 return rc;
1169         }
1170
1171         case IZO_IOC_REVOKE_PERMIT:
1172                 if (data->ioc_flags)
1173                         rc = izo_revoke_permit(file->f_dentry, data->ioc_uuid);
1174                 else
1175                         rc = izo_revoke_permit(file->f_dentry, NULL);
1176                 EXIT;
1177                 return rc;
1178
1179         case IZO_IOC_CLEAR_FSET:
1180                 rc = izo_clear_fsetroot(file->f_dentry);
1181                 EXIT;
1182                 return rc;
1183
1184         case IZO_IOC_CLEAR_ALL_FSETS: { 
1185                 struct presto_file_set *fset;
1186
1187                 fset = presto_fset(file->f_dentry);
1188                 if (fset == NULL) {
1189                         EXIT;
1190                         return -ENODEV;
1191                 }
1192
1193                 rc = izo_clear_all_fsetroots(fset->fset_cache);
1194                 EXIT;
1195                 return rc;
1196         }
1197
1198         case IZO_IOC_SET_FSET:
1199                 /*
1200                  * Mark this dentry as being a fileset root.
1201                  */
1202                 rc = presto_set_fsetroot_from_ioc(file->f_dentry, 
1203                                                   data->ioc_inlbuf1,
1204                                                   data->ioc_flags);
1205                 EXIT;
1206                 return rc;
1207
1208
1209         case IZO_IOC_MARK: {
1210                 int res = 0;  /* resulting flags - returned to user */
1211                 int error;
1212
1213                 CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %d\n",
1214                        file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
1215                        data->ioc_or_flag, data->ioc_mark_what);
1216
1217                 switch (data->ioc_mark_what) {
1218                 case MARK_DENTRY:               
1219                         error = izo_mark_dentry(file->f_dentry,
1220                                                    data->ioc_and_flag,
1221                                                    data->ioc_or_flag, &res);
1222                         break;
1223                 case MARK_FSET:
1224                         error = izo_mark_fset(file->f_dentry,
1225                                                  data->ioc_and_flag,
1226                                                  data->ioc_or_flag, &res);
1227                         break;
1228                 case MARK_CACHE:
1229                         error = izo_mark_cache(file->f_dentry,
1230                                                   data->ioc_and_flag,
1231                                                   data->ioc_or_flag, &res);
1232                         break;
1233                 case MARK_GETFL: {
1234                         int fflags, cflags;
1235                         data->ioc_and_flag = 0xffffffff;
1236                         data->ioc_or_flag = 0; 
1237                         error = izo_mark_dentry(file->f_dentry,
1238                                                    data->ioc_and_flag,
1239                                                    data->ioc_or_flag, &res);
1240                         if (error) 
1241                                 break;
1242                         error = izo_mark_fset(file->f_dentry,
1243                                                  data->ioc_and_flag,
1244                                                  data->ioc_or_flag, &fflags);
1245                         if (error) 
1246                                 break;
1247                         error = izo_mark_cache(file->f_dentry,
1248                                                   data->ioc_and_flag,
1249                                                   data->ioc_or_flag,
1250                                                   &cflags);
1251
1252                         if (error) 
1253                                 break;
1254                         data->ioc_and_flag = fflags;
1255                         data->ioc_or_flag = cflags;
1256                         break;
1257                 }
1258                 default:
1259                         error = -EINVAL;
1260                 }
1261
1262                 if (error) { 
1263                         EXIT;
1264                         return error;
1265                 }
1266                 data->ioc_mark_what = res;
1267                 CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %x\n",
1268                        file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
1269                        data->ioc_or_flag, data->ioc_mark_what);
1270
1271                 EXIT;
1272                 return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
1273         }
1274 #if 0
1275         case IZO_IOC_CLIENT_MAKE_BRANCH: {
1276                 struct presto_file_set *fset;
1277                 int minor;
1278
1279                 fset = presto_fset(file->f_dentry);
1280                 if (fset == NULL) {
1281                         EXIT;
1282                         return -ENODEV;
1283                 }
1284                 minor = presto_f2m(fset);
1285
1286                 rc = izo_upc_client_make_branch(minor, fset->fset_name,
1287                                                 data->ioc_inlbuf1,
1288                                                 data->ioc_inlbuf2);
1289                 EXIT;
1290                 return rc;
1291         }
1292 #endif
1293         case IZO_IOC_SERVER_MAKE_BRANCH: {
1294                 struct presto_file_set *fset;
1295                 int minor;
1296
1297                 fset = presto_fset(file->f_dentry);
1298                 if (fset == NULL) {
1299                         EXIT;
1300                         return -ENODEV;
1301                 }
1302                 minor = presto_f2m(fset);
1303
1304                 izo_upc_server_make_branch(minor, data->ioc_inlbuf1);
1305                 EXIT;
1306                 return 0;
1307         }
1308         case IZO_IOC_SET_KMLSIZE: {
1309                 struct presto_file_set *fset;
1310                 int minor;
1311                 struct izo_rcvd_rec rec;
1312
1313                 fset = presto_fset(file->f_dentry);
1314                 if (fset == NULL) {
1315                         EXIT;
1316                         return -ENODEV;
1317                 }
1318                 minor = presto_f2m(fset);
1319
1320                 rc = izo_upc_set_kmlsize(minor, fset->fset_name, data->ioc_uuid,
1321                                          data->ioc_kmlsize);
1322
1323                 if (rc != 0) {
1324                         EXIT;
1325                         return rc;
1326                 }
1327
1328                 rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
1329                 if (rc == -EINVAL) {
1330                         /* We don't know anything about this uuid yet; no
1331                          * worries. */
1332                         memset(&rec, 0, sizeof(rec));
1333                 } else if (rc <= 0) {
1334                         CERROR("InterMezzo: error reading last_rcvd: %d\n", rc);
1335                         EXIT;
1336                         return rc;
1337                 }
1338                 rec.lr_remote_offset = data->ioc_kmlsize;
1339                 rc = izo_rcvd_write(fset, &rec);
1340                 if (rc <= 0) {
1341                         CERROR("InterMezzo: error writing last_rcvd: %d\n", rc);
1342                         EXIT;
1343                         return rc;
1344                 }
1345                 EXIT;
1346                 return rc;
1347         }
1348         case IZO_IOC_BRANCH_UNDO: {
1349                 struct presto_file_set *fset;
1350                 int minor;
1351
1352                 fset = presto_fset(file->f_dentry);
1353                 if (fset == NULL) {
1354                         EXIT;
1355                         return -ENODEV;
1356                 }
1357                 minor = presto_f2m(fset);
1358
1359                 rc = izo_upc_branch_undo(minor, fset->fset_name,
1360                                          data->ioc_inlbuf1);
1361                 EXIT;
1362                 return rc;
1363         }
1364         case IZO_IOC_BRANCH_REDO: {
1365                 struct presto_file_set *fset;
1366                 int minor;
1367
1368                 fset = presto_fset(file->f_dentry);
1369                 if (fset == NULL) {
1370                         EXIT;
1371                         return -ENODEV;
1372                 }
1373                 minor = presto_f2m(fset);
1374
1375                 rc = izo_upc_branch_redo(minor, fset->fset_name,
1376                                          data->ioc_inlbuf1);
1377                 EXIT;
1378                 return rc;
1379         }
1380
1381         case TCGETS:
1382                 EXIT;
1383                 return -EINVAL;
1384
1385         default:
1386                 EXIT;
1387                 return -EINVAL;
1388                 
1389         }
1390         EXIT;
1391         return 0;
1392 }
1393
1394 struct file_operations presto_dir_fops = {
1395         .ioctl =  presto_ioctl
1396 };
1397
1398 struct inode_operations presto_dir_iops = {
1399         .create       = presto_create,
1400         .lookup       = presto_lookup,
1401         .link         = presto_link,
1402         .unlink       = presto_unlink,
1403         .symlink      = presto_symlink,
1404         .mkdir        = presto_mkdir,
1405         .rmdir        = presto_rmdir,
1406         .mknod        = presto_mknod,
1407         .rename       = presto_rename,
1408         .permission   = presto_permission,
1409         .setattr      = presto_setattr,
1410 #ifdef CONFIG_FS_EXT_ATTR
1411         .set_ext_attr = presto_set_ext_attr,
1412 #endif
1413 };
1414
1415