1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
3 *
4 * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
5 *
6 * This file is part of InterMezzo, http://www.inter-mezzo.org.
7 *
8 * InterMezzo is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
11 *
12 * InterMezzo is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with InterMezzo; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * Managing filesets
22 *
23 */
24
25 #define __NO_VERSION__
26 #include <stdarg.h>
27
28 #include <asm/bitops.h>
29 #include <asm/uaccess.h>
30 #include <asm/system.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 #include <linux/module.h>
44
45 #include <linux/intermezzo_fs.h>
46 #include <linux/intermezzo_psdev.h>
47
presto_dentry2fset(struct dentry * dentry)48 static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
49 {
50 if (presto_d2d(dentry) == NULL) {
51 EXIT;
52 return NULL;
53 }
54 return presto_d2d(dentry)->dd_fset;
55 }
56
57 /* find the fileset dentry for this dentry */
presto_fset(struct dentry * de)58 struct presto_file_set *presto_fset(struct dentry *de)
59 {
60 struct dentry *fsde;
61 ENTRY;
62 if ( !de->d_inode ) {
63 /* FIXME: is this ok to be NULL? */
64 CDEBUG(D_INODE,"presto_fset: warning %*s has NULL inode.\n",
65 de->d_name.len, de->d_name.name);
66 }
67 for (fsde = de;; fsde = fsde->d_parent) {
68 if ( presto_dentry2fset(fsde) ) {
69 EXIT;
70 return presto_dentry2fset(fsde);
71 }
72 if (fsde->d_parent == fsde)
73 break;
74 }
75 EXIT;
76 return NULL;
77 }
78
presto_get_lastrecno(char * path,off_t * recno)79 int presto_get_lastrecno(char *path, off_t *recno)
80 {
81 struct nameidata nd;
82 struct presto_file_set *fset;
83 struct dentry *dentry;
84 int error;
85 ENTRY;
86
87 error = presto_walk(path, &nd);
88 if (error) {
89 EXIT;
90 return error;
91 }
92
93 dentry = nd.dentry;
94
95 error = -ENXIO;
96 if ( !presto_ispresto(dentry->d_inode) ) {
97 EXIT;
98 goto kml_out;
99 }
100
101 error = -EINVAL;
102 if ( ! presto_dentry2fset(dentry)) {
103 EXIT;
104 goto kml_out;
105 }
106
107 fset = presto_dentry2fset(dentry);
108 if (!fset) {
109 EXIT;
110 goto kml_out;
111 }
112 error = 0;
113 *recno = fset->fset_kml.fd_recno;
114
115 kml_out:
116 path_release(&nd);
117 return error;
118 }
119
_izo_make_path(char * fsetname,char * name)120 static char * _izo_make_path(char *fsetname, char *name)
121 {
122 char *path = NULL;
123 int len;
124
125 len = strlen("/.intermezzo/") + strlen(fsetname)
126 + 1 + strlen(name) + 1;
127
128 PRESTO_ALLOC(path, len);
129 if (path == NULL)
130 return NULL;
131
132 sprintf(path, "/.intermezzo/%s/%s", fsetname, name);
133
134 return path;
135 }
136
izo_make_path(struct presto_file_set * fset,char * name)137 char * izo_make_path(struct presto_file_set *fset, char *name)
138 {
139 return _izo_make_path(fset->fset_name, name);
140 }
141
_izo_fset_open(char * fsetname,char * name,int flags,int mode)142 static struct file *_izo_fset_open(char *fsetname, char *name, int flags, int mode)
143 {
144 char *path;
145 struct file *f;
146 int error;
147 ENTRY;
148
149 path = _izo_make_path(fsetname, name);
150 if (path == NULL) {
151 EXIT;
152 return ERR_PTR(-ENOMEM);
153 }
154
155 CDEBUG(D_INODE, "opening file %s\n", path);
156 f = filp_open(path, flags, mode);
157 error = PTR_ERR(f);
158 if (IS_ERR(f)) {
159 CDEBUG(D_INODE, "Error %d\n", error);
160 }
161
162 PRESTO_FREE(path, strlen(path)+1);
163
164 EXIT;
165 return f;
166
167 }
168
izo_fset_open(struct presto_file_set * fset,char * name,int flags,int mode)169 struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode)
170 {
171 return _izo_fset_open(fset->fset_name, name, flags, mode);
172 }
173
174
175
176 /*
177 * note: this routine "pins" a dentry for a fileset root
178 */
presto_set_fsetroot(struct dentry * ioctl_dentry,char * fsetname,unsigned int flags)179 int presto_set_fsetroot(struct dentry *ioctl_dentry, char *fsetname,
180 unsigned int flags)
181 {
182 struct presto_file_set *fset = NULL;
183 struct presto_cache *cache;
184 int error;
185 struct file *fset_root;
186 struct dentry *dentry;
187
188 ENTRY;
189
190 fset_root = _izo_fset_open(fsetname, "ROOT", O_RDONLY, 000);
191 if (IS_ERR(fset_root)) {
192 CERROR("Can't open %s/ROOT\n", fsetname);
193 EXIT;
194 error = PTR_ERR(fset_root);
195 goto out;
196 }
197 dentry = dget(fset_root->f_dentry);
198 filp_close(fset_root, NULL);
199
200 dentry->d_inode->i_op = ioctl_dentry->d_inode->i_op;
201 dentry->d_inode->i_fop = ioctl_dentry->d_inode->i_fop;
202 dentry->d_op = ioctl_dentry->d_op;
203 fset = presto_dentry2fset(dentry);
204 if (fset && (fset->fset_dentry == dentry) ) {
205 CERROR("Fsetroot already set (inode %ld)\n",
206 dentry->d_inode->i_ino);
207 /* XXX: ignore because clear_fsetroot is broken */
208 #if 0
209 dput(dentry);
210 EXIT;
211 error = -EEXIST;
212 goto out;
213 #endif
214 }
215
216 cache = presto_get_cache(dentry->d_inode);
217 if (!cache) {
218 CERROR("No cache found for inode %ld\n",
219 dentry->d_inode->i_ino);
220 EXIT;
221 error = -ENODEV;
222 goto out_free;
223 }
224
225 PRESTO_ALLOC(fset, sizeof(*fset));
226 if ( !fset ) {
227 CERROR("No memory allocating fset for %s\n", fsetname);
228 EXIT;
229 error = -ENOMEM;
230 goto out_free;
231 }
232 CDEBUG(D_INODE, "fset at %p\n", fset);
233
234 CDEBUG(D_INODE, "InterMezzo: fsetroot: inode %ld, fileset name %s\n",
235 dentry->d_inode->i_ino, fsetname);
236
237 fset->fset_mnt = mntget(current->fs->pwdmnt);
238 fset->fset_cache = cache;
239 fset->fset_dentry = dentry;
240 fset->fset_name = strdup(fsetname);
241 fset->fset_chunkbits = CHUNK_BITS;
242 fset->fset_flags = flags;
243 fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO;
244 fset->fset_permit_lock = SPIN_LOCK_UNLOCKED;
245 PRESTO_ALLOC(fset->fset_reint_buf, 64 * 1024);
246 if (fset->fset_reint_buf == NULL) {
247 EXIT;
248 error = -ENOMEM;
249 goto out_free;
250 }
251 init_waitqueue_head(&fset->fset_permit_queue);
252
253 if (presto_d2d(dentry) == NULL) {
254 dentry->d_fsdata = izo_alloc_ddata();
255 }
256 if (presto_d2d(dentry) == NULL) {
257 CERROR("InterMezzo: %s: no memory\n", __FUNCTION__);
258 EXIT;
259 error = -ENOMEM;
260 goto out_free;
261 }
262
263 presto_d2d(dentry)->dd_fset = fset;
264 list_add(&fset->fset_list, &cache->cache_fset_list);
265
266 error = izo_init_kml_file(fset, &fset->fset_kml);
267 if ( error ) {
268 EXIT;
269 CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
270 goto out_list_del;
271 }
272
273 error = izo_init_lml_file(fset, &fset->fset_lml);
274 if ( error ) {
275 int rc;
276 EXIT;
277 rc = izo_log_close(&fset->fset_kml);
278 CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
279 goto out_list_del;
280 }
281
282 /* init_last_rcvd_file could trigger a presto_file_write(), which
283 * requires that the lml structure be initialized. -phil */
284 error = izo_init_last_rcvd_file(fset, &fset->fset_rcvd);
285 if ( error ) {
286 int rc;
287 EXIT;
288 rc = izo_log_close(&fset->fset_kml);
289 rc = izo_log_close(&fset->fset_lml);
290 CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
291 goto out_list_del;
292 }
293
294 CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p,"
295 "fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n",
296 fset, dentry, fset->fset_dentry, fset->fset_name, cache,
297 presto_d2d(dentry)->dd_fset);
298
299 EXIT;
300 return 0;
301
302 out_list_del:
303 list_del(&fset->fset_list);
304 presto_d2d(dentry)->dd_fset = NULL;
305 out_free:
306 if (fset) {
307 mntput(fset->fset_mnt);
308 if (fset->fset_reint_buf != NULL)
309 PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
310 PRESTO_FREE(fset, sizeof(*fset));
311 }
312 dput(dentry);
313 out:
314 return error;
315 }
316
izo_cleanup_fset(struct presto_file_set * fset)317 static int izo_cleanup_fset(struct presto_file_set *fset)
318 {
319 int error;
320 struct presto_cache *cache;
321
322 ENTRY;
323
324 CERROR("Cleaning up fset %s\n", fset->fset_name);
325
326 error = izo_log_close(&fset->fset_kml);
327 if (error)
328 CERROR("InterMezzo: Closing kml for fset %s: %d\n",
329 fset->fset_name, error);
330 error = izo_log_close(&fset->fset_lml);
331 if (error)
332 CERROR("InterMezzo: Closing lml for fset %s: %d\n",
333 fset->fset_name, error);
334 error = izo_log_close(&fset->fset_rcvd);
335 if (error)
336 CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n",
337 fset->fset_name, error);
338
339 cache = fset->fset_cache;
340
341 list_del(&fset->fset_list);
342
343 presto_d2d(fset->fset_dentry)->dd_fset = NULL;
344 dput(fset->fset_dentry);
345 mntput(fset->fset_mnt);
346
347 izo_rep_cache_clean(fset);
348 PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
349 PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
350 PRESTO_FREE(fset, sizeof(*fset));
351 EXIT;
352 return error;
353 }
354
izo_clear_fsetroot(struct dentry * dentry)355 int izo_clear_fsetroot(struct dentry *dentry)
356 {
357 struct presto_file_set *fset;
358
359 ENTRY;
360
361 fset = presto_dentry2fset(dentry);
362 if (!fset) {
363 EXIT;
364 return -EINVAL;
365 }
366
367 izo_cleanup_fset(fset);
368 EXIT;
369 return 0;
370 }
371
izo_clear_all_fsetroots(struct presto_cache * cache)372 int izo_clear_all_fsetroots(struct presto_cache *cache)
373 {
374 struct presto_file_set *fset;
375 struct list_head *tmp,*tmpnext;
376 int error;
377
378 error = 0;
379 tmp = &cache->cache_fset_list;
380 tmpnext = tmp->next;
381 while ( tmpnext != &cache->cache_fset_list) {
382 tmp = tmpnext;
383 tmpnext = tmp->next;
384 fset = list_entry(tmp, struct presto_file_set, fset_list);
385
386 error = izo_cleanup_fset(fset);
387 if (error)
388 break;
389 }
390 return error;
391 }
392
izo_alloc_vfsmnt(void)393 static struct vfsmount *izo_alloc_vfsmnt(void)
394 {
395 struct vfsmount *mnt;
396 PRESTO_ALLOC(mnt, sizeof(*mnt));
397 if (mnt) {
398 memset(mnt, 0, sizeof(struct vfsmount));
399 atomic_set(&mnt->mnt_count,1);
400 INIT_LIST_HEAD(&mnt->mnt_hash);
401 INIT_LIST_HEAD(&mnt->mnt_child);
402 INIT_LIST_HEAD(&mnt->mnt_mounts);
403 INIT_LIST_HEAD(&mnt->mnt_list);
404 }
405 return mnt;
406 }
407
408
izo_setup_ctxt(struct dentry * root,struct vfsmount * mnt,struct run_ctxt * save)409 static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt,
410 struct run_ctxt *save)
411 {
412 struct run_ctxt new;
413
414 mnt->mnt_root = root;
415 mnt->mnt_sb = root->d_inode->i_sb;
416 unlock_super(mnt->mnt_sb);
417
418 new.rootmnt = mnt;
419 new.root = root;
420 new.pwdmnt = mnt;
421 new.pwd = root;
422 new.fsuid = 0;
423 new.fsgid = 0;
424 new.fs = get_fs();
425 /* XXX where can we get the groups from? */
426 new.ngroups = 0;
427
428 push_ctxt(save, &new);
429 }
430
izo_cleanup_ctxt(struct vfsmount * mnt,struct run_ctxt * save)431 static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save)
432 {
433 lock_super(mnt->mnt_sb);
434 pop_ctxt(save);
435 }
436
izo_simple_mkdir(struct dentry * dir,char * name,int mode)437 static int izo_simple_mkdir(struct dentry *dir, char *name, int mode)
438 {
439 struct dentry *dchild;
440 int err;
441 ENTRY;
442
443 dchild = lookup_one_len(name, dir, strlen(name));
444 if (IS_ERR(dchild)) {
445 EXIT;
446 return PTR_ERR(dchild);
447 }
448
449 if (dchild->d_inode) {
450 dput(dchild);
451 EXIT;
452 return -EEXIST;
453 }
454
455 err = vfs_mkdir(dir->d_inode, dchild, mode);
456 dput(dchild);
457
458 EXIT;
459 return err;
460 }
461
izo_simple_symlink(struct dentry * dir,char * name,char * tgt)462 static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt)
463 {
464 struct dentry *dchild;
465 int err;
466 ENTRY;
467
468 dchild = lookup_one_len(name, dir, strlen(name));
469 if (IS_ERR(dchild)) {
470 EXIT;
471 return PTR_ERR(dchild);
472 }
473
474 if (dchild->d_inode) {
475 dput(dchild);
476 EXIT;
477 return -EEXIST;
478 }
479
480 err = vfs_symlink(dir->d_inode, dchild, tgt);
481 dput(dchild);
482
483 EXIT;
484 return err;
485 }
486
487 /*
488 * run set_fsetroot in chroot environment
489 */
presto_set_fsetroot_from_ioc(struct dentry * root,char * fsetname,unsigned int flags)490 int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname,
491 unsigned int flags)
492 {
493 int rc;
494 struct presto_cache *cache;
495 struct vfsmount *mnt;
496 struct run_ctxt save;
497
498 if (root != root->d_inode->i_sb->s_root) {
499 CERROR ("IOC_SET_FSET must be called on mount point\n");
500 return -ENODEV;
501 }
502
503 cache = presto_get_cache(root->d_inode);
504 mnt = cache->cache_vfsmount;
505 if (!mnt) {
506 EXIT;
507 return -ENOMEM;
508 }
509
510 izo_setup_ctxt(root, mnt, &save);
511 rc = presto_set_fsetroot(root, fsetname, flags);
512 izo_cleanup_ctxt(mnt, &save);
513 return rc;
514 }
515
516 /* XXX: this function should detect if fsetname is already in use for
517 the cache under root
518 */
izo_prepare_fileset(struct dentry * root,char * fsetname)519 int izo_prepare_fileset(struct dentry *root, char *fsetname)
520 {
521 int err;
522 struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL;
523 struct presto_cache *cache;
524 struct vfsmount *mnt;
525 struct run_ctxt save;
526
527 cache = presto_get_cache(root->d_inode);
528 mnt = cache->cache_vfsmount = izo_alloc_vfsmnt();
529 if (!mnt) {
530 EXIT;
531 return -ENOMEM;
532 }
533
534 if (!fsetname)
535 fsetname = "rootfset";
536
537 izo_setup_ctxt(root, mnt, &save);
538
539 err = izo_simple_mkdir(root, ".intermezzo", 0755);
540 CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err);
541
542 err = izo_simple_mkdir(root, "..iopen..", 0755);
543 CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err);
544
545 dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen.."));
546 if (IS_ERR(dotiopen)) {
547 EXIT;
548 goto out;
549 }
550 dotiopen->d_inode->i_op = &presto_dir_iops;
551 dput(dotiopen);
552
553
554 dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo"));
555 if (IS_ERR(dotizo)) {
556 EXIT;
557 goto out;
558 }
559
560
561 err = izo_simple_mkdir(dotizo, fsetname, 0755);
562 CDEBUG(D_CACHE, "mkdir err %d\n", err);
563
564 /* XXX find the dentry of the root of the fileset (root for now) */
565 fsetdir = lookup_one_len(fsetname, dotizo, strlen(fsetname));
566 if (IS_ERR(fsetdir)) {
567 EXIT;
568 goto out;
569 }
570
571 err = izo_simple_symlink(fsetdir, "ROOT", "../..");
572
573 /* XXX read flags from flags file */
574 err = presto_set_fsetroot(root, fsetname, 0);
575 CDEBUG(D_CACHE, "set_fsetroot err %d\n", err);
576
577 out:
578 if (dotizo && !IS_ERR(dotizo))
579 dput(dotizo);
580 if (fsetdir && !IS_ERR(fsetdir))
581 dput(fsetdir);
582 izo_cleanup_ctxt(mnt, &save);
583 return err;
584 }
585
izo_set_fileid(struct file * dir,struct izo_ioctl_data * data)586 int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data)
587 {
588 int rc = 0;
589 struct presto_cache *cache;
590 struct vfsmount *mnt;
591 struct run_ctxt save;
592 struct nameidata nd;
593 struct dentry *dentry;
594 struct presto_dentry_data *dd;
595 struct dentry *root;
596 char *buf = NULL;
597
598 ENTRY;
599
600
601 root = dir->f_dentry;
602
603 /* actually, needs to be called on ROOT of fset, not mount point
604 if (root != root->d_inode->i_sb->s_root) {
605 CERROR ("IOC_SET_FSET must be called on mount point\n");
606 return -ENODEV;
607 }
608 */
609
610 cache = presto_get_cache(root->d_inode);
611 mnt = cache->cache_vfsmount;
612 if (!mnt) {
613 EXIT;
614 return -ENOMEM;
615 }
616
617 izo_setup_ctxt(root, mnt, &save);
618
619 PRESTO_ALLOC(buf, data->ioc_plen1);
620 if (!buf) {
621 rc = -ENOMEM;
622 EXIT;
623 goto out;
624 }
625 if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) {
626 rc = -EFAULT;
627 EXIT;
628 goto out;
629 }
630
631 rc = presto_walk(buf, &nd);
632 if (rc) {
633 CERROR("Unable to open: %s\n", buf);
634 EXIT;
635 goto out;
636 }
637 dentry = nd.dentry;
638 if (!dentry) {
639 CERROR("no dentry!\n");
640 rc = -EINVAL;
641 EXIT;
642 goto out_close;
643 }
644 dd = presto_d2d(dentry);
645 if (!dd) {
646 CERROR("no dentry_data!\n");
647 rc = -EINVAL;
648 EXIT;
649 goto out_close;
650 }
651
652 CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd);
653
654 if (dd->remote_ino != 0) {
655 CERROR("remote_ino already set? %Lx:%Lx\n", dd->remote_ino,
656 dd->remote_generation);
657 rc = 0;
658 EXIT;
659 goto out_close;
660 }
661
662
663 CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd,
664 buf, data->ioc_ino,
665 data->ioc_generation);
666 dd->remote_ino = data->ioc_ino;
667 dd->remote_generation = data->ioc_generation;
668
669 EXIT;
670 out_close:
671 path_release(&nd);
672 out:
673 if (buf)
674 PRESTO_FREE(buf, data->ioc_plen1);
675 izo_cleanup_ctxt(mnt, &save);
676 return rc;
677 }
678