Device layer rollup commit.
[dragonfly.git] / sys / vfs / coda / coda_vfsops.c
1 /*
2  * 
3  *             Coda: an Experimental Distributed File System
4  *                              Release 3.1
5  * 
6  *           Copyright (c) 1987-1998 Carnegie Mellon University
7  *                          All Rights Reserved
8  * 
9  * Permission  to  use, copy, modify and distribute this software and its
10  * documentation is hereby granted,  provided  that  both  the  copyright
11  * notice  and  this  permission  notice  appear  in  all  copies  of the
12  * software, derivative works or  modified  versions,  and  any  portions
13  * thereof, and that both notices appear in supporting documentation, and
14  * that credit is given to Carnegie Mellon University  in  all  documents
15  * and publicity pertaining to direct or indirect use of this code or its
16  * derivatives.
17  * 
18  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
19  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
20  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
21  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
22  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
23  * ANY DERIVATIVE WORK.
24  * 
25  * Carnegie  Mellon  encourages  users  of  this  software  to return any
26  * improvements or extensions that  they  make,  and  to  grant  Carnegie
27  * Mellon the rights to redistribute these changes without encumbrance.
28  * 
29  *      @(#) src/sys/cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
30  * $FreeBSD: src/sys/coda/coda_vfsops.c,v 1.24.2.1 2001/07/26 20:36:45 iedowse Exp $
31  * $DragonFly: src/sys/vfs/coda/Attic/coda_vfsops.c,v 1.14 2004/05/19 22:53:04 dillon Exp $
32  * 
33  */
34
35 /* 
36  * Mach Operating System
37  * Copyright (c) 1989 Carnegie-Mellon University
38  * All rights reserved.  The CMU software License Agreement specifies
39  * the terms and conditions for use and redistribution.
40  */
41
42 /*
43  * This code was written for the Coda file system at Carnegie Mellon
44  * University.  Contributers include David Steere, James Kistler, and
45  * M. Satyanarayanan.  
46  */
47
48 #include "use_vcoda.h"
49
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/proc.h>
54 #include <sys/malloc.h>
55 #include <sys/conf.h>
56 #include <sys/namei.h>
57 #include <sys/mount.h>
58 #include <sys/select.h>
59
60 #include <vm/vm_zone.h>
61
62 #include "coda.h"
63 #include "cnode.h"
64 #include "coda_vfsops.h"
65 #include "coda_venus.h"
66 #include "coda_subr.h"
67 #include "coda_opstats.h"
68
69 MALLOC_DEFINE(M_CODA, "CODA storage", "Various Coda Structures");
70
71 int codadebug = 0;
72 int coda_vfsop_print_entry = 0;
73 #define ENTRY    if(coda_vfsop_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
74
75 struct vnode *coda_ctlvp;
76 struct coda_mntinfo coda_mnttbl[NVCODA]; /* indexed by minor device number */
77
78 /* structure to keep statistics of internally generated/satisfied calls */
79
80 struct coda_op_stats coda_vfsopstats[CODA_VFSOPS_SIZE];
81
82 #define MARK_ENTRY(op) (coda_vfsopstats[op].entries++)
83 #define MARK_INT_SAT(op) (coda_vfsopstats[op].sat_intrn++)
84 #define MARK_INT_FAIL(op) (coda_vfsopstats[op].unsat_intrn++)
85 #define MRAK_INT_GEN(op) (coda_vfsopstats[op].gen_intrn++)
86
87 extern int coda_nc_initialized;     /* Set if cache has been initialized */
88 extern int vc_nb_open (dev_t, int, int, d_thread_t *);
89
90 int
91 coda_vfsopstats_init(void)
92 {
93         int i;
94         
95         for (i=0;i<CODA_VFSOPS_SIZE;i++) {
96                 coda_vfsopstats[i].opcode = i;
97                 coda_vfsopstats[i].entries = 0;
98                 coda_vfsopstats[i].sat_intrn = 0;
99                 coda_vfsopstats[i].unsat_intrn = 0;
100                 coda_vfsopstats[i].gen_intrn = 0;
101         }
102         
103         return 0;
104 }
105
106 /*
107  * cfs mount vfsop
108  * Set up mount info record and attach it to vfs struct.
109  */
110 /*ARGSUSED*/
111 int
112 coda_mount(struct mount *vfsp,  /* Allocated and initialized by mount(2) */
113            char *path,          /* path covered: ignored by the fs-layer */
114            caddr_t data,        /* Need to define a data type for this in
115                                  * netbsd? */
116            struct nameidata *ndp, /* Clobber this to lookup the device name */
117            struct thread *td)   /* The ever-famous proc pointer */
118 {
119     struct vnode *dvp;
120     struct cnode *cp;
121     udev_t udev;
122     struct coda_mntinfo *mi;
123     struct vnode *rootvp;
124     ViceFid rootfid;
125     ViceFid ctlfid;
126     int error;
127
128     ENTRY;
129
130     coda_vfsopstats_init();
131     coda_vnodeopstats_init();
132     
133     MARK_ENTRY(CODA_MOUNT_STATS);
134     if (CODA_MOUNTED(vfsp)) {
135         MARK_INT_FAIL(CODA_MOUNT_STATS);
136         return(EBUSY);
137     }
138     
139     /* Validate mount device.  Similar to getmdev(). */
140     NDINIT(ndp, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, data, td);
141     error = namei(ndp);
142     dvp = ndp->ni_vp;
143
144     if (error) {
145         MARK_INT_FAIL(CODA_MOUNT_STATS);
146         return (error);
147     }
148     if (dvp->v_type != VCHR) {
149         MARK_INT_FAIL(CODA_MOUNT_STATS);
150         vrele(dvp);
151         NDFREE(ndp, NDF_ONLY_PNBUF);
152         return(ENXIO);
153     }
154     udev = dvp->v_rdev;
155     vrele(dvp);
156     NDFREE(ndp, NDF_ONLY_PNBUF);
157
158 #if 0   /* YYY huh? what paranoia is this? */
159     /*
160      * See if the device table matches our expectations.
161      */
162     if (devsw(dev)->d_open != vc_nb_open)
163     {
164         MARK_INT_FAIL(CODA_MOUNT_STATS);
165         return(ENXIO);
166     }
167 #endif
168     
169     if (uminor(udev) >= NVCODA || uminor(udev) < 0) {
170         MARK_INT_FAIL(CODA_MOUNT_STATS);
171         return(ENXIO);
172     }
173     
174     /*
175      * Initialize the mount record and link it to the vfs struct
176      */
177     mi = &coda_mnttbl[uminor(udev)];
178     
179     if (!VC_OPEN(&mi->mi_vcomm)) {
180         MARK_INT_FAIL(CODA_MOUNT_STATS);
181         return(ENODEV);
182     }
183     
184     /* No initialization (here) of mi_vcomm! */
185     vfsp->mnt_data = (qaddr_t)mi;
186     vfs_getnewfsid (vfsp);
187
188     mi->mi_vfsp = vfsp;
189     
190     /*
191      * Make a root vnode to placate the Vnode interface, but don't
192      * actually make the CODA_ROOT call to venus until the first call
193      * to coda_root in case a server is down while venus is starting.
194      */
195     rootfid.Volume = 0;
196     rootfid.Vnode = 0;
197     rootfid.Unique = 0;
198     cp = make_coda_node(&rootfid, vfsp, VDIR);
199     rootvp = CTOV(cp);
200     rootvp->v_flag |= VROOT;
201         
202     ctlfid.Volume = CTL_VOL;
203     ctlfid.Vnode = CTL_VNO;
204     ctlfid.Unique = CTL_UNI;
205 /*  cp = make_coda_node(&ctlfid, vfsp, VCHR);
206     The above code seems to cause a loop in the cnode links.
207     I don't totally understand when it happens, it is caught
208     when closing down the system.
209  */
210     cp = make_coda_node(&ctlfid, 0, VCHR);
211
212     coda_ctlvp = CTOV(cp);
213
214     /* Add vfs and rootvp to chain of vfs hanging off mntinfo */
215     mi->mi_vfsp = vfsp;
216     mi->mi_rootvp = rootvp;
217     
218     /* set filesystem block size */
219     vfsp->mnt_stat.f_bsize = 8192;          /* XXX -JJK */
220
221     /* Set f_iosize.  XXX -- inamura@isl.ntt.co.jp. 
222        For vnode_pager_haspage() references. The value should be obtained 
223        from underlying UFS. */
224     /* Checked UFS. iosize is set as 8192 */
225     vfsp->mnt_stat.f_iosize = 8192;
226
227     /* error is currently guaranteed to be zero, but in case some
228        code changes... */
229     CODADEBUG(1,
230              myprintf(("coda_mount returned %d\n",error)););
231     if (error)
232         MARK_INT_FAIL(CODA_MOUNT_STATS);
233     else
234         MARK_INT_SAT(CODA_MOUNT_STATS);
235     
236     return(error);
237 }
238
239 int
240 coda_unmount(struct mount *vfsp, int mntflags, struct thread *td)
241 {
242     struct coda_mntinfo *mi = vftomi(vfsp);
243     int active, error = 0;
244     
245     ENTRY;
246     MARK_ENTRY(CODA_UMOUNT_STATS);
247     if (!CODA_MOUNTED(vfsp)) {
248         MARK_INT_FAIL(CODA_UMOUNT_STATS);
249         return(EINVAL);
250     }
251     
252     if (mi->mi_vfsp == vfsp) {  /* We found the victim */
253         if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp)))
254             return (EBUSY);     /* Venus is still running */
255
256 #ifdef  DEBUG
257         printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, VTOC(mi->mi_rootvp));
258 #endif
259         vrele(mi->mi_rootvp);
260
261         active = coda_kill(vfsp, NOT_DOWNCALL);
262         mi->mi_rootvp->v_flag &= ~VROOT;
263         error = vflush(mi->mi_vfsp, 0, FORCECLOSE);
264         printf("coda_unmount: active = %d, vflush active %d\n", active, error);
265         error = 0;
266         /* I'm going to take this out to allow lookups to go through. I'm
267          * not sure it's important anyway. -- DCS 2/2/94
268          */
269         /* vfsp->VFS_DATA = NULL; */
270
271         /* No more vfsp's to hold onto */
272         mi->mi_vfsp = NULL;
273         mi->mi_rootvp = NULL;
274
275         if (error)
276             MARK_INT_FAIL(CODA_UMOUNT_STATS);
277         else
278             MARK_INT_SAT(CODA_UMOUNT_STATS);
279
280         return(error);
281     }
282     return (EINVAL);
283 }
284
285 /*
286  * find root of cfs
287  */
288 int
289 coda_root(struct mount *vfsp, struct vnode **vpp)
290 {
291     struct coda_mntinfo *mi = vftomi(vfsp);
292     struct vnode **result;
293     int error;
294     struct thread *td = curthread;    /* XXX - bnoble */
295     struct ucred *cred;
296     ViceFid VFid;
297
298     KKASSERT(td->td_proc);
299     cred = td->td_proc->p_ucred;
300
301     ENTRY;
302     MARK_ENTRY(CODA_ROOT_STATS);
303     result = NULL;
304     
305     if (vfsp == mi->mi_vfsp) {
306         if ((VTOC(mi->mi_rootvp)->c_fid.Volume != 0) ||
307             (VTOC(mi->mi_rootvp)->c_fid.Vnode != 0) ||
308             (VTOC(mi->mi_rootvp)->c_fid.Unique != 0))
309             { /* Found valid root. */
310                 *vpp = mi->mi_rootvp;
311                 /* On Mach, this is vref.  On NetBSD, VOP_LOCK */
312 #if 1
313                 vref(*vpp);
314                 vn_lock(*vpp, NULL, LK_EXCLUSIVE, td);
315 #else
316                 vget(*vpp, NULL, LK_EXCLUSIVE, td);
317 #endif
318                 MARK_INT_SAT(CODA_ROOT_STATS);
319                 return(0);
320             }
321     }
322
323     error = venus_root(vftomi(vfsp), cred, td, &VFid);
324
325     if (!error) {
326         /*
327          * Save the new rootfid in the cnode, and rehash the cnode into the
328          * cnode hash with the new fid key.
329          */
330         coda_unsave(VTOC(mi->mi_rootvp));
331         VTOC(mi->mi_rootvp)->c_fid = VFid;
332         coda_save(VTOC(mi->mi_rootvp));
333
334         *vpp = mi->mi_rootvp;
335 #if     1
336         vref(*vpp);
337         vn_lock(*vpp, NULL, LK_EXCLUSIVE, td);
338 #else
339         vget(*vpp, NULL, LK_EXCLUSIVE, td);
340 #endif
341
342         MARK_INT_SAT(CODA_ROOT_STATS);
343         goto exit;
344     } else if (error == ENODEV || error == EINTR) {
345         /* Gross hack here! */
346         /*
347          * If Venus fails to respond to the CODA_ROOT call, coda_call returns
348          * ENODEV. Return the uninitialized root vnode to allow vfs
349          * operations such as unmount to continue. Without this hack,
350          * there is no way to do an unmount if Venus dies before a 
351          * successful CODA_ROOT call is done. All vnode operations 
352          * will fail.
353          */
354         *vpp = mi->mi_rootvp;
355 #if     1
356         vref(*vpp);
357         vn_lock(*vpp, NULL, LK_EXCLUSIVE, td);
358 #else
359         vget(*vpp, NULL, LK_EXCLUSIVE, td);
360 #endif
361
362         MARK_INT_FAIL(CODA_ROOT_STATS);
363         error = 0;
364         goto exit;
365     } else {
366         CODADEBUG( CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", error)); );
367         MARK_INT_FAIL(CODA_ROOT_STATS);
368                 
369         goto exit;
370     }
371
372  exit:
373     return(error);
374 }
375
376 /*
377  * Get file system statistics.
378  */
379 int
380 coda_nb_statfs(struct mount *vfsp, struct statfs *sbp, struct thread *td)
381 {
382     ENTRY;
383 /*  MARK_ENTRY(CODA_STATFS_STATS); */
384     if (!CODA_MOUNTED(vfsp)) {
385 /*      MARK_INT_FAIL(CODA_STATFS_STATS);*/
386         return(EINVAL);
387     }
388     
389     bzero(sbp, sizeof(struct statfs));
390     /* XXX - what to do about f_flags, others? --bnoble */
391     /* Below This is what AFS does
392         #define NB_SFS_SIZ 0x895440
393      */
394     /* Note: Normal fs's have a bsize of 0x400 == 1024 */
395     sbp->f_type = vfsp->mnt_vfc->vfc_typenum;
396     sbp->f_bsize = 8192; /* XXX */
397     sbp->f_iosize = 8192; /* XXX */
398 #define NB_SFS_SIZ 0x8AB75D
399     sbp->f_blocks = NB_SFS_SIZ;
400     sbp->f_bfree = NB_SFS_SIZ;
401     sbp->f_bavail = NB_SFS_SIZ;
402     sbp->f_files = NB_SFS_SIZ;
403     sbp->f_ffree = NB_SFS_SIZ;
404     bcopy((caddr_t)&(vfsp->mnt_stat.f_fsid), (caddr_t)&(sbp->f_fsid), sizeof (fsid_t));
405     snprintf(sbp->f_mntonname, sizeof(sbp->f_mntonname), "/coda");
406     snprintf(sbp->f_mntfromname, sizeof(sbp->f_mntfromname), "CODA");
407 /*  MARK_INT_SAT(CODA_STATFS_STATS); */
408     return(0);
409 }
410
411 /*
412  * Flush any pending I/O.
413  */
414 int
415 coda_sync(struct mount *vfsp, int waitfor, struct thread *td)
416 {
417     ENTRY;
418     MARK_ENTRY(CODA_SYNC_STATS);
419     MARK_INT_SAT(CODA_SYNC_STATS);
420     return(0);
421 }
422
423 /* 
424  * fhtovp is now what vget used to be in 4.3-derived systems.  For
425  * some silly reason, vget is now keyed by a 32 bit ino_t, rather than
426  * a type-specific fid.  
427  */
428 int
429 coda_fhtovp(struct mount *vfsp, struct fid *fhp, struct mbuf *nam,
430             struct vnode **vpp, int *exflagsp, struct ucred **creadanonp)
431 {
432     struct cfid *cfid = (struct cfid *)fhp;
433     struct cnode *cp = 0;
434     int error;
435     struct thread *td = curthread; /* XXX -mach */
436     struct ucred *cred;
437     ViceFid VFid;
438     int vtype;
439
440     KKASSERT(td->td_proc);
441     cred = td->td_proc->p_ucred;
442
443     ENTRY;
444     
445     MARK_ENTRY(CODA_VGET_STATS);
446     /* Check for vget of control object. */
447     if (IS_CTL_FID(&cfid->cfid_fid)) {
448         *vpp = coda_ctlvp;
449         vref(coda_ctlvp);
450         MARK_INT_SAT(CODA_VGET_STATS);
451         return(0);
452     }
453     
454     error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, cred, td, &VFid, &vtype);
455     
456     if (error) {
457         CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));)
458             *vpp = (struct vnode *)0;
459     } else {
460         CODADEBUG(CODA_VGET, 
461                  myprintf(("vget: vol %lx vno %lx uni %lx type %d result %d\n",
462                         VFid.Volume, VFid.Vnode, VFid.Unique, vtype, error)); )
463             
464         cp = make_coda_node(&VFid, vfsp, vtype);
465         *vpp = CTOV(cp);
466     }
467     return(error);
468 }
469
470 /*
471  * To allow for greater ease of use, some vnodes may be orphaned when
472  * Venus dies.  Certain operations should still be allowed to go
473  * through, but without propagating orphan-ness.  So this function will
474  * get a new vnode for the file from the current run of Venus.
475  */
476  
477 int
478 getNewVnode(struct vnode **vpp)
479 {
480     struct cfid cfid;
481     struct coda_mntinfo *mi = vftomi((*vpp)->v_mount);
482     
483     ENTRY;
484
485     cfid.cfid_len = (short)sizeof(ViceFid);
486     cfid.cfid_fid = VTOC(*vpp)->c_fid;  /* Structure assignment. */
487     /* XXX ? */
488
489     /* We're guessing that if set, the 1st element on the list is a
490      * valid vnode to use. If not, return ENODEV as venus is dead.
491      */
492     if (mi->mi_vfsp == NULL)
493         return ENODEV;
494     
495     return coda_fhtovp(mi->mi_vfsp, (struct fid*)&cfid, NULL, vpp,
496                       NULL, NULL);
497 }
498
499 #include <vfs/ufs/quota.h>
500 #include <vfs/ufs/ufsmount.h>
501 /* get the mount structure corresponding to a given device.  Assume 
502  * device corresponds to a UFS. Return NULL if no device is found.
503  */ 
504 struct mount *devtomp(dev_t dev)
505 {
506     struct mount *mp;
507    
508     TAILQ_FOREACH(mp, &mountlist, mnt_list) {
509         if (((VFSTOUFS(mp))->um_dev == dev)) {
510             /* mount corresponds to UFS and the device matches one we want */
511             return(mp); 
512         }
513     }
514     /* mount structure wasn't found */ 
515     return(NULL); 
516 }
517
518 struct vfsops coda_vfsops = {
519     coda_mount,
520     vfs_stdstart,
521     coda_unmount,
522     coda_root,
523     vfs_stdquotactl,
524     coda_nb_statfs,
525     coda_sync,
526     vfs_stdvget,
527     vfs_stdfhtovp,
528     vfs_stdcheckexp,
529     vfs_stdvptofh,
530     vfs_stdinit,
531     vfs_stduninit,
532     vfs_stdextattrctl,
533 };
534
535 VFS_SET(coda_vfsops, coda, VFCF_NETWORK);