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