This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / fs / intermezzo / fileset.c
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 #include <asm/bitops.h>
26 #include <asm/uaccess.h>
27 #include <asm/system.h>
28
29 #include <linux/errno.h>
30 #include <linux/fs.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>
41
42 #include "intermezzo_fs.h"
43 #include "intermezzo_psdev.h"
44
45 static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
46 {
47         if (presto_d2d(dentry) == NULL) {
48                 EXIT;
49                 return NULL;
50         }
51         return presto_d2d(dentry)->dd_fset;
52 }
53
54 /* find the fileset dentry for this dentry */
55 struct presto_file_set *presto_fset(struct dentry *de)
56 {
57         struct dentry *fsde;
58         ENTRY;
59         if ( !de->d_inode ) {
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);
63         }
64         for (fsde = de;; fsde = fsde->d_parent) {
65                 if ( presto_dentry2fset(fsde) ) {
66                         EXIT;
67                         return presto_dentry2fset(fsde);
68                 }
69                 if (fsde->d_parent == fsde)
70                         break;
71         }
72         EXIT;
73         return NULL;
74 }
75
76 int presto_get_lastrecno(char *path, off_t *recno)
77 {
78         struct nameidata nd; 
79         struct presto_file_set *fset;
80         struct dentry *dentry;
81         int error;
82         ENTRY;
83
84         error = presto_walk(path, &nd);
85         if (error) {
86                 EXIT;
87                 return error;
88         }
89
90         dentry = nd.dentry;
91
92         error = -ENXIO;
93         if ( !presto_ispresto(dentry->d_inode) ) {
94                 EXIT;
95                 goto kml_out;
96         }
97
98         error = -EINVAL;
99         if ( ! presto_dentry2fset(dentry)) {
100                 EXIT;
101                 goto kml_out;
102         }
103
104         fset = presto_dentry2fset(dentry);
105         if (!fset) {
106                 EXIT;
107                 goto kml_out;
108         }
109         error = 0;
110         *recno = fset->fset_kml.fd_recno;
111
112  kml_out:
113         path_release(&nd);
114         return error;
115 }
116
117 static char * _izo_make_path(char *fsetname, char *name)
118 {
119         char *path = NULL;
120         int len;
121
122         len = strlen("/.intermezzo/") + strlen(fsetname) 
123                 + 1 + strlen(name) + 1;
124
125         PRESTO_ALLOC(path, len);
126         if (path == NULL)
127                 return NULL;
128
129         sprintf(path, "/.intermezzo/%s/%s", fsetname, name);
130
131         return path;
132 }
133
134 char * izo_make_path(struct presto_file_set *fset, char *name)
135 {
136         return _izo_make_path(fset->fset_name, name);
137 }
138
139 static struct file *_izo_fset_open(char *fsetname, char *name, int flags, int mode) 
140 {
141         char *path;
142         struct file *f;
143         int error;
144         ENTRY;
145
146         path = _izo_make_path(fsetname, name);
147         if (path == NULL) {
148                 EXIT;
149                 return ERR_PTR(-ENOMEM);
150         }
151
152         CDEBUG(D_INODE, "opening file %s\n", path);
153         f = filp_open(path, flags, mode);
154         error = PTR_ERR(f);
155         if (IS_ERR(f)) {
156                 CDEBUG(D_INODE, "Error %d\n", error);
157         }
158
159         PRESTO_FREE(path, strlen(path));
160
161         EXIT;
162         return f;
163
164 }
165
166 struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode) 
167 {
168         return _izo_fset_open(fset->fset_name, name, flags, mode);
169 }
170
171
172
173 /*
174  *  note: this routine "pins" a dentry for a fileset root
175  */
176 int presto_set_fsetroot(struct dentry *ioctl_dentry, char *fsetname,
177                         unsigned int flags)
178 {
179         struct presto_file_set *fset = NULL;
180         struct presto_cache *cache;
181         int error;
182         struct file  *fset_root;
183         struct dentry *dentry;
184
185         ENTRY;
186
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);
190                 EXIT;
191                 error = PTR_ERR(fset_root);
192                 goto out;
193         }
194         dentry = dget(fset_root->f_dentry);
195         filp_close(fset_root, NULL);
196
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  */
205 #if 0
206                 dput(dentry);
207                 EXIT;
208                 error = -EEXIST;
209                 goto out;
210 #endif
211         }
212
213         cache = presto_get_cache(dentry->d_inode);
214         if (!cache) { 
215                 CERROR("No cache found for inode %ld\n",
216                        dentry->d_inode->i_ino);
217                 EXIT;
218                 error = -ENODEV;
219                 goto out_free;
220         }
221
222         PRESTO_ALLOC(fset, sizeof(*fset));
223         if ( !fset ) {
224                 CERROR("No memory allocating fset for %s\n", fsetname);
225                 EXIT;
226                 error = -ENOMEM;
227                 goto out_free;
228         }
229         CDEBUG(D_INODE, "fset at %p\n", fset);
230
231         CDEBUG(D_INODE, "InterMezzo: fsetroot: inode %ld, fileset name %s\n",
232                dentry->d_inode->i_ino, fsetname);
233
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) {
244                 EXIT;
245                 error = -ENOMEM;
246                 goto out_free;
247         }
248         init_waitqueue_head(&fset->fset_permit_queue);
249
250         if (presto_d2d(dentry) == NULL) { 
251                 dentry->d_fsdata = izo_alloc_ddata();
252         }
253         if (presto_d2d(dentry) == NULL) {
254                 CERROR("InterMezzo: %s: no memory\n", __FUNCTION__);
255                 EXIT;
256                 error = -ENOMEM;
257                 goto out_free;
258         }
259         presto_d2d(dentry)->dd_fset = fset;
260         list_add(&fset->fset_list, &cache->cache_fset_list);
261
262         error = izo_init_kml_file(fset, &fset->fset_kml);
263         if ( error ) {
264                 EXIT;
265                 CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
266                 goto out_list_del;
267         }
268
269         error = izo_init_lml_file(fset, &fset->fset_lml);
270         if ( error ) {
271                 int rc;
272                 EXIT;
273                 rc = izo_log_close(&fset->fset_kml);
274                 CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
275                 goto out_list_del;
276         }
277
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);
281         if ( error ) {
282                 int rc;
283                 EXIT;
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);
287                 goto out_list_del;
288         }
289
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);
294
295         EXIT;
296         return 0;
297
298  out_list_del:
299         list_del(&fset->fset_list);
300         presto_d2d(dentry)->dd_fset = NULL;
301  out_free:
302         if (fset) {
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));
307         }
308         dput(dentry); 
309  out:
310         return error;
311 }
312
313 static int izo_cleanup_fset(struct presto_file_set *fset)
314 {
315         int error;
316         struct presto_cache *cache;
317
318         ENTRY;
319
320         CERROR("Cleaning up fset %s\n", fset->fset_name);
321
322         error = izo_log_close(&fset->fset_kml);
323         if (error)
324                 CERROR("InterMezzo: Closing kml for fset %s: %d\n",
325                        fset->fset_name, error);
326         error = izo_log_close(&fset->fset_lml);
327         if (error)
328                 CERROR("InterMezzo: Closing lml for fset %s: %d\n",
329                        fset->fset_name, error);
330         error = izo_log_close(&fset->fset_rcvd);
331         if (error)
332                 CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n",
333                        fset->fset_name, error);
334
335         cache = fset->fset_cache;
336
337         list_del(&fset->fset_list);
338
339         presto_d2d(fset->fset_dentry)->dd_fset = NULL;
340         dput(fset->fset_dentry);
341         mntput(fset->fset_mnt);
342
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));
346         EXIT;
347         return error;
348 }
349
350 int izo_clear_fsetroot(struct dentry *dentry)
351 {
352         struct presto_file_set *fset;
353
354         ENTRY;
355
356         fset = presto_dentry2fset(dentry);
357         if (!fset) {
358                 EXIT;
359                 return -EINVAL;
360         }
361
362         izo_cleanup_fset(fset);
363         EXIT;
364         return 0;
365 }
366
367 int izo_clear_all_fsetroots(struct presto_cache *cache)
368 {
369         struct presto_file_set *fset;
370         struct list_head *tmp,*tmpnext;
371         int error;
372  
373         error = 0;
374         tmp = &cache->cache_fset_list;
375         tmpnext = tmp->next;
376         while ( tmpnext != &cache->cache_fset_list) {
377                 tmp = tmpnext;
378                 tmpnext = tmp->next;
379                 fset = list_entry(tmp, struct presto_file_set, fset_list);
380
381                 error = izo_cleanup_fset(fset);
382                 if (error)
383                         break;
384         }
385         return error;
386 }
387
388 static struct vfsmount *izo_alloc_vfsmnt(void)
389 {
390         struct vfsmount *mnt;
391         PRESTO_ALLOC(mnt, sizeof(*mnt));
392         if (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);
399         }
400         return mnt;
401 }
402
403
404 static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt,
405                            struct run_ctxt *save) 
406 {
407         struct run_ctxt new;
408
409         mnt->mnt_root = root;
410         mnt->mnt_sb = root->d_inode->i_sb;
411         unlock_super(mnt->mnt_sb);
412
413         new.rootmnt = mnt;
414         new.root = root;
415         new.pwdmnt = mnt;
416         new.pwd = root;
417         new.fsuid = 0;
418         new.fsgid = 0;
419         new.fs = get_fs(); 
420         /* XXX where can we get the groups from? */
421         new.group_info = groups_alloc(0);
422
423         push_ctxt(save, &new); 
424 }
425
426 static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save) 
427 {
428         lock_super(mnt->mnt_sb);
429         pop_ctxt(save); 
430 }
431
432 static int izo_simple_mkdir(struct dentry *dir, char *name, int mode)
433 {
434         struct dentry *dchild; 
435         int err;
436         ENTRY;
437         
438         dchild = lookup_one_len(name, dir, strlen(name));
439         if (IS_ERR(dchild)) { 
440                 EXIT;
441                 return PTR_ERR(dchild); 
442         }
443
444         if (dchild->d_inode) { 
445                 dput(dchild);
446                 EXIT;
447                 return -EEXIST;
448         }
449
450         err = vfs_mkdir(dir->d_inode, dchild, mode);
451         dput(dchild);
452         
453         EXIT;
454         return err;
455 }
456
457 static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt)
458 {
459         struct dentry *dchild; 
460         int err;
461         ENTRY;
462         
463         dchild = lookup_one_len(name, dir, strlen(name));
464         if (IS_ERR(dchild)) { 
465                 EXIT;
466                 return PTR_ERR(dchild); 
467         }
468
469         if (dchild->d_inode) { 
470                 dput(dchild);
471                 EXIT;
472                 return -EEXIST;
473         }
474
475         err = vfs_symlink(dir->d_inode, dchild, tgt);
476         dput(dchild);
477         
478         EXIT;
479         return err;
480 }
481
482 /*
483  * run set_fsetroot in chroot environment
484  */
485 int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname,
486                                  unsigned int flags)
487 {
488         int rc;
489         struct presto_cache *cache;
490         struct vfsmount *mnt;
491         struct run_ctxt save;
492
493         if (root != root->d_inode->i_sb->s_root) {
494                 CERROR ("IOC_SET_FSET must be called on mount point\n");
495                 return -ENODEV;
496         }
497
498         cache = presto_get_cache(root->d_inode);
499         mnt = cache->cache_vfsmount;
500         if (!mnt) { 
501                 EXIT;
502                 return -ENOMEM;
503         }
504         
505         izo_setup_ctxt(root, mnt, &save); 
506         rc = presto_set_fsetroot(root, fsetname, flags);
507         izo_cleanup_ctxt(mnt, &save);
508         return rc;
509 }
510
511 /* XXX: this function should detect if fsetname is already in use for
512    the cache under root
513 */ 
514 int izo_prepare_fileset(struct dentry *root, char *fsetname) 
515 {
516         int err;
517         struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL; 
518         struct presto_cache *cache;
519         struct vfsmount *mnt;
520         struct run_ctxt save;
521
522         cache = presto_get_cache(root->d_inode);
523         mnt = cache->cache_vfsmount = izo_alloc_vfsmnt();
524         if (!mnt) { 
525                 EXIT;
526                 return -ENOMEM;
527         }
528         
529         if (!fsetname) 
530                 fsetname = "rootfset"; 
531
532         izo_setup_ctxt(root, mnt, &save); 
533
534         err = izo_simple_mkdir(root, ".intermezzo", 0755);
535         CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err); 
536
537         err = izo_simple_mkdir(root, "..iopen..", 0755);
538         CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err); 
539
540         dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen.."));
541         if (IS_ERR(dotiopen)) { 
542                 EXIT;
543                 goto out;
544         }
545         dotiopen->d_inode->i_op = &presto_dir_iops;
546         dput(dotiopen);
547
548
549         dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo"));
550         if (IS_ERR(dotizo)) { 
551                 EXIT;
552                 goto out;
553         }
554
555
556         err = izo_simple_mkdir(dotizo, fsetname, 0755);
557         CDEBUG(D_CACHE, "mkdir err %d\n", err); 
558
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)) { 
562                 EXIT;
563                 goto out;
564         }
565
566         err = izo_simple_symlink(fsetdir, "ROOT", "../.."); 
567
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); 
571
572  out:
573         if (dotizo && !IS_ERR(dotizo)) 
574                 dput(dotizo); 
575         if (fsetdir && !IS_ERR(fsetdir)) 
576                 dput(fsetdir); 
577         izo_cleanup_ctxt(mnt, &save);
578         return err; 
579 }
580
581 int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data)
582 {
583         int rc = 0;
584         struct presto_cache *cache;
585         struct vfsmount *mnt;
586         struct run_ctxt save;
587         struct nameidata nd;
588         struct dentry *dentry;
589         struct presto_dentry_data *dd;
590         struct dentry *root;
591         char *buf = NULL; 
592
593         ENTRY;
594
595
596         root = dir->f_dentry;
597
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");
601                 return -ENODEV;
602         }
603         */
604
605         cache = presto_get_cache(root->d_inode);
606         mnt = cache->cache_vfsmount;
607         if (!mnt) { 
608                 EXIT;
609                 return -ENOMEM;
610         }
611         
612         izo_setup_ctxt(root, mnt, &save); 
613         
614         PRESTO_ALLOC(buf, data->ioc_plen1);
615         if (!buf) { 
616                 rc = -ENOMEM;
617                 EXIT;
618                 goto out;
619         }
620         if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 
621                 rc =  -EFAULT;
622                 EXIT;
623                 goto out;
624         }
625
626         rc = presto_walk(buf, &nd);
627         if (rc) {
628                 CERROR("Unable to open: %s\n", buf);
629                 EXIT;
630                 goto out;
631         }
632         dentry = nd.dentry;
633         if (!dentry) {
634                 CERROR("no dentry!\n");
635                 rc =  -EINVAL;
636                 EXIT;
637                 goto out_close;
638         }
639         dd = presto_d2d(dentry);
640         if (!dd) {
641                 CERROR("no dentry_data!\n");
642                 rc = -EINVAL;
643                 EXIT;
644                 goto out_close;
645         }
646
647         CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd);
648
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);
653                 rc = 0;
654                 EXIT;
655                 goto out_close;
656         }
657
658
659         CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd, 
660                buf,
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;
665
666         EXIT;
667  out_close:
668         path_release(&nd);
669  out:
670         if (buf)
671                 PRESTO_FREE(buf, data->ioc_plen1);
672         izo_cleanup_ctxt(mnt, &save);
673         return rc;
674 }