1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
6 * This file is part of InterMezzo, http://www.inter-mezzo.org.
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.
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.
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.
25 #include <asm/bitops.h>
26 #include <asm/uaccess.h>
27 #include <asm/system.h>
29 #include <linux/errno.h>
31 #include <linux/namei.h>
32 #include <linux/ext2_fs.h>
33 #include <linux/slab.h>
34 #include <linux/vmalloc.h>
35 #include <linux/sched.h>
36 #include <linux/stat.h>
37 #include <linux/string.h>
38 #include <linux/blkdev.h>
39 #include <linux/init.h>
40 #include <linux/module.h>
42 #include "intermezzo_fs.h"
43 #include "intermezzo_psdev.h"
45 static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
47 if (presto_d2d(dentry) == NULL) {
51 return presto_d2d(dentry)->dd_fset;
54 /* find the fileset dentry for this dentry */
55 struct presto_file_set *presto_fset(struct dentry *de)
60 /* FIXME: is this ok to be NULL? */
61 CDEBUG(D_INODE,"presto_fset: warning %*s has NULL inode.\n",
62 de->d_name.len, de->d_name.name);
64 for (fsde = de;; fsde = fsde->d_parent) {
65 if ( presto_dentry2fset(fsde) ) {
67 return presto_dentry2fset(fsde);
69 if (fsde->d_parent == fsde)
76 int presto_get_lastrecno(char *path, off_t *recno)
79 struct presto_file_set *fset;
80 struct dentry *dentry;
84 error = presto_walk(path, &nd);
93 if ( !presto_ispresto(dentry->d_inode) ) {
99 if ( ! presto_dentry2fset(dentry)) {
104 fset = presto_dentry2fset(dentry);
110 *recno = fset->fset_kml.fd_recno;
117 static char * _izo_make_path(char *fsetname, char *name)
122 len = strlen("/.intermezzo/") + strlen(fsetname)
123 + 1 + strlen(name) + 1;
125 PRESTO_ALLOC(path, len);
129 sprintf(path, "/.intermezzo/%s/%s", fsetname, name);
134 char * izo_make_path(struct presto_file_set *fset, char *name)
136 return _izo_make_path(fset->fset_name, name);
139 static struct file *_izo_fset_open(char *fsetname, char *name, int flags, int mode)
146 path = _izo_make_path(fsetname, name);
149 return ERR_PTR(-ENOMEM);
152 CDEBUG(D_INODE, "opening file %s\n", path);
153 f = filp_open(path, flags, mode);
156 CDEBUG(D_INODE, "Error %d\n", error);
159 PRESTO_FREE(path, strlen(path));
166 struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode)
168 return _izo_fset_open(fset->fset_name, name, flags, mode);
174 * note: this routine "pins" a dentry for a fileset root
176 int presto_set_fsetroot(struct dentry *ioctl_dentry, char *fsetname,
179 struct presto_file_set *fset = NULL;
180 struct presto_cache *cache;
182 struct file *fset_root;
183 struct dentry *dentry;
187 fset_root = _izo_fset_open(fsetname, "ROOT", O_RDONLY, 000);
188 if (IS_ERR(fset_root)) {
189 CERROR("Can't open %s/ROOT\n", fsetname);
191 error = PTR_ERR(fset_root);
194 dentry = dget(fset_root->f_dentry);
195 filp_close(fset_root, NULL);
197 dentry->d_inode->i_op = ioctl_dentry->d_inode->i_op;
198 dentry->d_inode->i_fop = ioctl_dentry->d_inode->i_fop;
199 dentry->d_op = ioctl_dentry->d_op;
200 fset = presto_dentry2fset(dentry);
201 if (fset && (fset->fset_dentry == dentry) ) {
202 CERROR("Fsetroot already set (inode %ld)\n",
203 dentry->d_inode->i_ino);
204 /* XXX: ignore because clear_fsetroot is broken */
213 cache = presto_get_cache(dentry->d_inode);
215 CERROR("No cache found for inode %ld\n",
216 dentry->d_inode->i_ino);
222 PRESTO_ALLOC(fset, sizeof(*fset));
224 CERROR("No memory allocating fset for %s\n", fsetname);
229 CDEBUG(D_INODE, "fset at %p\n", fset);
231 CDEBUG(D_INODE, "InterMezzo: fsetroot: inode %ld, fileset name %s\n",
232 dentry->d_inode->i_ino, fsetname);
234 fset->fset_mnt = mntget(current->fs->pwdmnt);
235 fset->fset_cache = cache;
236 fset->fset_dentry = dentry;
237 fset->fset_name = strdup(fsetname);
238 fset->fset_chunkbits = CHUNK_BITS;
239 fset->fset_flags = flags;
240 fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO;
241 fset->fset_permit_lock = SPIN_LOCK_UNLOCKED;
242 PRESTO_ALLOC(fset->fset_reint_buf, 64 * 1024);
243 if (fset->fset_reint_buf == NULL) {
248 init_waitqueue_head(&fset->fset_permit_queue);
250 if (presto_d2d(dentry) == NULL) {
251 dentry->d_fsdata = izo_alloc_ddata();
253 if (presto_d2d(dentry) == NULL) {
254 CERROR("InterMezzo: %s: no memory\n", __FUNCTION__);
259 presto_d2d(dentry)->dd_fset = fset;
260 list_add(&fset->fset_list, &cache->cache_fset_list);
262 error = izo_init_kml_file(fset, &fset->fset_kml);
265 CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
269 error = izo_init_lml_file(fset, &fset->fset_lml);
273 rc = izo_log_close(&fset->fset_kml);
274 CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
278 /* init_last_rcvd_file could trigger a presto_file_write(), which
279 * requires that the lml structure be initialized. -phil */
280 error = izo_init_last_rcvd_file(fset, &fset->fset_rcvd);
284 rc = izo_log_close(&fset->fset_kml);
285 rc = izo_log_close(&fset->fset_lml);
286 CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
290 CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p,"
291 "fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n",
292 fset, dentry, fset->fset_dentry, fset->fset_name, cache,
293 presto_d2d(dentry)->dd_fset);
299 list_del(&fset->fset_list);
300 presto_d2d(dentry)->dd_fset = NULL;
303 mntput(fset->fset_mnt);
304 if (fset->fset_reint_buf != NULL)
305 PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
306 PRESTO_FREE(fset, sizeof(*fset));
313 static int izo_cleanup_fset(struct presto_file_set *fset)
316 struct presto_cache *cache;
320 CERROR("Cleaning up fset %s\n", fset->fset_name);
322 error = izo_log_close(&fset->fset_kml);
324 CERROR("InterMezzo: Closing kml for fset %s: %d\n",
325 fset->fset_name, error);
326 error = izo_log_close(&fset->fset_lml);
328 CERROR("InterMezzo: Closing lml for fset %s: %d\n",
329 fset->fset_name, error);
330 error = izo_log_close(&fset->fset_rcvd);
332 CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n",
333 fset->fset_name, error);
335 cache = fset->fset_cache;
337 list_del(&fset->fset_list);
339 presto_d2d(fset->fset_dentry)->dd_fset = NULL;
340 dput(fset->fset_dentry);
341 mntput(fset->fset_mnt);
343 PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
344 PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
345 PRESTO_FREE(fset, sizeof(*fset));
350 int izo_clear_fsetroot(struct dentry *dentry)
352 struct presto_file_set *fset;
356 fset = presto_dentry2fset(dentry);
362 izo_cleanup_fset(fset);
367 int izo_clear_all_fsetroots(struct presto_cache *cache)
369 struct presto_file_set *fset;
370 struct list_head *tmp,*tmpnext;
374 tmp = &cache->cache_fset_list;
376 while ( tmpnext != &cache->cache_fset_list) {
379 fset = list_entry(tmp, struct presto_file_set, fset_list);
381 error = izo_cleanup_fset(fset);
388 static struct vfsmount *izo_alloc_vfsmnt(void)
390 struct vfsmount *mnt;
391 PRESTO_ALLOC(mnt, sizeof(*mnt));
393 memset(mnt, 0, sizeof(struct vfsmount));
394 atomic_set(&mnt->mnt_count,1);
395 INIT_LIST_HEAD(&mnt->mnt_hash);
396 INIT_LIST_HEAD(&mnt->mnt_child);
397 INIT_LIST_HEAD(&mnt->mnt_mounts);
398 INIT_LIST_HEAD(&mnt->mnt_list);
404 static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt,
405 struct run_ctxt *save)
409 mnt->mnt_root = root;
410 mnt->mnt_sb = root->d_inode->i_sb;
411 unlock_super(mnt->mnt_sb);
420 /* XXX where can we get the groups from? */
421 new.group_info = groups_alloc(0);
423 push_ctxt(save, &new);
426 static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save)
428 lock_super(mnt->mnt_sb);
432 static int izo_simple_mkdir(struct dentry *dir, char *name, int mode)
434 struct dentry *dchild;
438 dchild = lookup_one_len(name, dir, strlen(name));
439 if (IS_ERR(dchild)) {
441 return PTR_ERR(dchild);
444 if (dchild->d_inode) {
450 err = vfs_mkdir(dir->d_inode, dchild, mode);
457 static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt)
459 struct dentry *dchild;
463 dchild = lookup_one_len(name, dir, strlen(name));
464 if (IS_ERR(dchild)) {
466 return PTR_ERR(dchild);
469 if (dchild->d_inode) {
475 err = vfs_symlink(dir->d_inode, dchild, tgt);
483 * run set_fsetroot in chroot environment
485 int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname,
489 struct presto_cache *cache;
490 struct vfsmount *mnt;
491 struct run_ctxt save;
493 if (root != root->d_inode->i_sb->s_root) {
494 CERROR ("IOC_SET_FSET must be called on mount point\n");
498 cache = presto_get_cache(root->d_inode);
499 mnt = cache->cache_vfsmount;
505 izo_setup_ctxt(root, mnt, &save);
506 rc = presto_set_fsetroot(root, fsetname, flags);
507 izo_cleanup_ctxt(mnt, &save);
511 /* XXX: this function should detect if fsetname is already in use for
514 int izo_prepare_fileset(struct dentry *root, char *fsetname)
517 struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL;
518 struct presto_cache *cache;
519 struct vfsmount *mnt;
520 struct run_ctxt save;
522 cache = presto_get_cache(root->d_inode);
523 mnt = cache->cache_vfsmount = izo_alloc_vfsmnt();
530 fsetname = "rootfset";
532 izo_setup_ctxt(root, mnt, &save);
534 err = izo_simple_mkdir(root, ".intermezzo", 0755);
535 CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err);
537 err = izo_simple_mkdir(root, "..iopen..", 0755);
538 CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err);
540 dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen.."));
541 if (IS_ERR(dotiopen)) {
545 dotiopen->d_inode->i_op = &presto_dir_iops;
549 dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo"));
550 if (IS_ERR(dotizo)) {
556 err = izo_simple_mkdir(dotizo, fsetname, 0755);
557 CDEBUG(D_CACHE, "mkdir err %d\n", err);
559 /* XXX find the dentry of the root of the fileset (root for now) */
560 fsetdir = lookup_one_len(fsetname, dotizo, strlen(fsetname));
561 if (IS_ERR(fsetdir)) {
566 err = izo_simple_symlink(fsetdir, "ROOT", "../..");
568 /* XXX read flags from flags file */
569 err = presto_set_fsetroot(root, fsetname, 0);
570 CDEBUG(D_CACHE, "set_fsetroot err %d\n", err);
573 if (dotizo && !IS_ERR(dotizo))
575 if (fsetdir && !IS_ERR(fsetdir))
577 izo_cleanup_ctxt(mnt, &save);
581 int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data)
584 struct presto_cache *cache;
585 struct vfsmount *mnt;
586 struct run_ctxt save;
588 struct dentry *dentry;
589 struct presto_dentry_data *dd;
596 root = dir->f_dentry;
598 /* actually, needs to be called on ROOT of fset, not mount point
599 if (root != root->d_inode->i_sb->s_root) {
600 CERROR ("IOC_SET_FSET must be called on mount point\n");
605 cache = presto_get_cache(root->d_inode);
606 mnt = cache->cache_vfsmount;
612 izo_setup_ctxt(root, mnt, &save);
614 PRESTO_ALLOC(buf, data->ioc_plen1);
620 if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) {
626 rc = presto_walk(buf, &nd);
628 CERROR("Unable to open: %s\n", buf);
634 CERROR("no dentry!\n");
639 dd = presto_d2d(dentry);
641 CERROR("no dentry_data!\n");
647 CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd);
649 if (dd->remote_ino != 0) {
650 CERROR("remote_ino already set? %Lx:%Lx\n",
651 (unsigned long long) dd->remote_ino,
652 (unsigned long long) dd->remote_generation);
659 CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd,
661 (unsigned long long) data->ioc_ino,
662 (unsigned long long) data->ioc_generation);
663 dd->remote_ino = data->ioc_ino;
664 dd->remote_generation = data->ioc_generation;
671 PRESTO_FREE(buf, data->ioc_plen1);
672 izo_cleanup_ctxt(mnt, &save);