make oldconfig will rebuild these...
[linux-2.4.21-pre4.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 #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
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 */
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
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
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
137 char * izo_make_path(struct presto_file_set *fset, char *name)
138 {
139         return _izo_make_path(fset->fset_name, name);
140 }
141
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));
163
164         EXIT;
165         return f;
166
167 }
168
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  */
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         presto_d2d(dentry)->dd_fset = fset;
263         list_add(&fset->fset_list, &cache->cache_fset_list);
264
265         error = izo_init_kml_file(fset, &fset->fset_kml);
266         if ( error ) {
267                 EXIT;
268                 CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
269                 goto out_list_del;
270         }
271
272         error = izo_init_lml_file(fset, &fset->fset_lml);
273         if ( error ) {
274                 int rc;
275                 EXIT;
276                 rc = izo_log_close(&fset->fset_kml);
277                 CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
278                 goto out_list_del;
279         }
280
281         /* init_last_rcvd_file could trigger a presto_file_write(), which
282          * requires that the lml structure be initialized. -phil */
283         error = izo_init_last_rcvd_file(fset, &fset->fset_rcvd);
284         if ( error ) {
285                 int rc;
286                 EXIT;
287                 rc = izo_log_close(&fset->fset_kml);
288                 rc = izo_log_close(&fset->fset_lml);
289                 CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
290                 goto out_list_del;
291         }
292
293         CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p,"
294                "fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n",
295                fset, dentry, fset->fset_dentry, fset->fset_name, cache,
296                presto_d2d(dentry)->dd_fset);
297
298         EXIT;
299         return 0;
300
301  out_list_del:
302         list_del(&fset->fset_list);
303         presto_d2d(dentry)->dd_fset = NULL;
304  out_free:
305         if (fset) {
306                 mntput(fset->fset_mnt); 
307                 if (fset->fset_reint_buf != NULL)
308                         PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
309                 PRESTO_FREE(fset, sizeof(*fset));
310         }
311         dput(dentry); 
312  out:
313         return error;
314 }
315
316 static int izo_cleanup_fset(struct presto_file_set *fset)
317 {
318         int error;
319         struct presto_cache *cache;
320
321         ENTRY;
322
323         CERROR("Cleaning up fset %s\n", fset->fset_name);
324
325         error = izo_log_close(&fset->fset_kml);
326         if (error)
327                 CERROR("InterMezzo: Closing kml for fset %s: %d\n",
328                        fset->fset_name, error);
329         error = izo_log_close(&fset->fset_lml);
330         if (error)
331                 CERROR("InterMezzo: Closing lml for fset %s: %d\n",
332                        fset->fset_name, error);
333         error = izo_log_close(&fset->fset_rcvd);
334         if (error)
335                 CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n",
336                        fset->fset_name, error);
337
338         cache = fset->fset_cache;
339
340         list_del(&fset->fset_list);
341
342         presto_d2d(fset->fset_dentry)->dd_fset = NULL;
343         dput(fset->fset_dentry);
344         mntput(fset->fset_mnt);
345
346         PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
347         PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
348         PRESTO_FREE(fset, sizeof(*fset));
349         EXIT;
350         return error;
351 }
352
353 int izo_clear_fsetroot(struct dentry *dentry)
354 {
355         struct presto_file_set *fset;
356
357         ENTRY;
358
359         fset = presto_dentry2fset(dentry);
360         if (!fset) {
361                 EXIT;
362                 return -EINVAL;
363         }
364
365         izo_cleanup_fset(fset);
366         EXIT;
367         return 0;
368 }
369
370 int izo_clear_all_fsetroots(struct presto_cache *cache)
371 {
372         struct presto_file_set *fset;
373         struct list_head *tmp,*tmpnext;
374         int error;
375  
376         error = 0;
377         tmp = &cache->cache_fset_list;
378         tmpnext = tmp->next;
379         while ( tmpnext != &cache->cache_fset_list) {
380                 tmp = tmpnext;
381                 tmpnext = tmp->next;
382                 fset = list_entry(tmp, struct presto_file_set, fset_list);
383
384                 error = izo_cleanup_fset(fset);
385                 if (error)
386                         break;
387         }
388         return error;
389 }
390
391 static struct vfsmount *izo_alloc_vfsmnt(void)
392 {
393         struct vfsmount *mnt;
394         PRESTO_ALLOC(mnt, sizeof(*mnt));
395         if (mnt) {
396                 memset(mnt, 0, sizeof(struct vfsmount));
397                 atomic_set(&mnt->mnt_count,1);
398                 INIT_LIST_HEAD(&mnt->mnt_hash);
399                 INIT_LIST_HEAD(&mnt->mnt_child);
400                 INIT_LIST_HEAD(&mnt->mnt_mounts);
401                 INIT_LIST_HEAD(&mnt->mnt_list);
402         }
403         return mnt;
404 }
405
406
407 static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt,
408                            struct run_ctxt *save) 
409 {
410         struct run_ctxt new;
411
412         mnt->mnt_root = root;
413         mnt->mnt_sb = root->d_inode->i_sb;
414         unlock_super(mnt->mnt_sb);
415
416         new.rootmnt = mnt;
417         new.root = root;
418         new.pwdmnt = mnt;
419         new.pwd = root;
420         new.fsuid = 0;
421         new.fsgid = 0;
422         new.fs = get_fs(); 
423         /* XXX where can we get the groups from? */
424         new.ngroups = 0;
425
426         push_ctxt(save, &new); 
427 }
428
429 static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save) 
430 {
431         lock_super(mnt->mnt_sb);
432         pop_ctxt(save); 
433 }
434
435 static int izo_simple_mkdir(struct dentry *dir, char *name, int mode)
436 {
437         struct dentry *dchild; 
438         int err;
439         ENTRY;
440         
441         dchild = lookup_one_len(name, dir, strlen(name));
442         if (IS_ERR(dchild)) { 
443                 EXIT;
444                 return PTR_ERR(dchild); 
445         }
446
447         if (dchild->d_inode) { 
448                 dput(dchild);
449                 EXIT;
450                 return -EEXIST;
451         }
452
453         err = vfs_mkdir(dir->d_inode, dchild, mode);
454         dput(dchild);
455         
456         EXIT;
457         return err;
458 }
459
460 static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt)
461 {
462         struct dentry *dchild; 
463         int err;
464         ENTRY;
465         
466         dchild = lookup_one_len(name, dir, strlen(name));
467         if (IS_ERR(dchild)) { 
468                 EXIT;
469                 return PTR_ERR(dchild); 
470         }
471
472         if (dchild->d_inode) { 
473                 dput(dchild);
474                 EXIT;
475                 return -EEXIST;
476         }
477
478         err = vfs_symlink(dir->d_inode, dchild, tgt);
479         dput(dchild);
480         
481         EXIT;
482         return err;
483 }
484
485 /*
486  * run set_fsetroot in chroot environment
487  */
488 int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname,
489                                  unsigned int flags)
490 {
491         int rc;
492         struct presto_cache *cache;
493         struct vfsmount *mnt;
494         struct run_ctxt save;
495
496         if (root != root->d_inode->i_sb->s_root) {
497                 CERROR ("IOC_SET_FSET must be called on mount point\n");
498                 return -ENODEV;
499         }
500
501         cache = presto_get_cache(root->d_inode);
502         mnt = cache->cache_vfsmount;
503         if (!mnt) { 
504                 EXIT;
505                 return -ENOMEM;
506         }
507         
508         izo_setup_ctxt(root, mnt, &save); 
509         rc = presto_set_fsetroot(root, fsetname, flags);
510         izo_cleanup_ctxt(mnt, &save);
511         return rc;
512 }
513
514 /* XXX: this function should detect if fsetname is already in use for
515    the cache under root
516 */ 
517 int izo_prepare_fileset(struct dentry *root, char *fsetname) 
518 {
519         int err;
520         struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL; 
521         struct presto_cache *cache;
522         struct vfsmount *mnt;
523         struct run_ctxt save;
524
525         cache = presto_get_cache(root->d_inode);
526         mnt = cache->cache_vfsmount = izo_alloc_vfsmnt();
527         if (!mnt) { 
528                 EXIT;
529                 return -ENOMEM;
530         }
531         
532         if (!fsetname) 
533                 fsetname = "rootfset"; 
534
535         izo_setup_ctxt(root, mnt, &save); 
536
537         err = izo_simple_mkdir(root, ".intermezzo", 0755);
538         CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err); 
539
540         err = izo_simple_mkdir(root, "..iopen..", 0755);
541         CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err); 
542
543         dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen.."));
544         if (IS_ERR(dotiopen)) { 
545                 EXIT;
546                 goto out;
547         }
548         dotiopen->d_inode->i_op = &presto_dir_iops;
549         dput(dotiopen);
550
551
552         dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo"));
553         if (IS_ERR(dotizo)) { 
554                 EXIT;
555                 goto out;
556         }
557
558
559         err = izo_simple_mkdir(dotizo, fsetname, 0755);
560         CDEBUG(D_CACHE, "mkdir err %d\n", err); 
561
562         /* XXX find the dentry of the root of the fileset (root for now) */ 
563         fsetdir = lookup_one_len(fsetname, dotizo, strlen(fsetname));
564         if (IS_ERR(fsetdir)) { 
565                 EXIT;
566                 goto out;
567         }
568
569         err = izo_simple_symlink(fsetdir, "ROOT", "../.."); 
570
571         /* XXX read flags from flags file */ 
572         err =  presto_set_fsetroot(root, fsetname, 0); 
573         CDEBUG(D_CACHE, "set_fsetroot err %d\n", err); 
574
575  out:
576         if (dotizo && !IS_ERR(dotizo)) 
577                 dput(dotizo); 
578         if (fsetdir && !IS_ERR(fsetdir)) 
579                 dput(fsetdir); 
580         izo_cleanup_ctxt(mnt, &save);
581         return err; 
582 }
583
584 int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data)
585 {
586         int rc = 0;
587         struct presto_cache *cache;
588         struct vfsmount *mnt;
589         struct run_ctxt save;
590         struct nameidata nd;
591         struct dentry *dentry;
592         struct presto_dentry_data *dd;
593         struct dentry *root;
594         char *buf = NULL; 
595
596         ENTRY;
597
598
599         root = dir->f_dentry;
600
601         /* actually, needs to be called on ROOT of fset, not mount point  
602         if (root != root->d_inode->i_sb->s_root) {
603                 CERROR ("IOC_SET_FSET must be called on mount point\n");
604                 return -ENODEV;
605         }
606         */
607
608         cache = presto_get_cache(root->d_inode);
609         mnt = cache->cache_vfsmount;
610         if (!mnt) { 
611                 EXIT;
612                 return -ENOMEM;
613         }
614         
615         izo_setup_ctxt(root, mnt, &save); 
616         
617         PRESTO_ALLOC(buf, data->ioc_plen1);
618         if (!buf) { 
619                 rc = -ENOMEM;
620                 EXIT;
621                 goto out;
622         }
623         if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 
624                 rc =  -EFAULT;
625                 EXIT;
626                 goto out;
627         }
628
629         rc = presto_walk(buf, &nd);
630         if (rc) {
631                 CERROR("Unable to open: %s\n", buf);
632                 EXIT;
633                 goto out;
634         }
635         dentry = nd.dentry;
636         if (!dentry) {
637                 CERROR("no dentry!\n");
638                 rc =  -EINVAL;
639                 EXIT;
640                 goto out_close;
641         }
642         dd = presto_d2d(dentry);
643         if (!dd) {
644                 CERROR("no dentry_data!\n");
645                 rc = -EINVAL;
646                 EXIT;
647                 goto out_close;
648         }
649
650         CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd);
651
652         if (dd->remote_ino != 0) {
653                 CERROR("remote_ino already set? %Lx:%Lx\n", dd->remote_ino,
654                        dd->remote_generation);
655                 rc = 0;
656                 EXIT;
657                 goto out_close;
658         }
659
660
661         CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd, 
662                buf, data->ioc_ino,
663                data->ioc_generation);
664         dd->remote_ino = data->ioc_ino;
665         dd->remote_generation = data->ioc_generation;
666
667         EXIT;
668  out_close:
669         path_release(&nd);
670  out:
671         if (buf)
672                 PRESTO_FREE(buf, data->ioc_plen1);
673         izo_cleanup_ctxt(mnt, &save);
674         return rc;
675 }