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