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