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
Cache object: ff8f7b6aff6e7a3c3f3bebe6f7ba27d8
|