Merge from vendor branch OPENSSH:
[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.21 2005/04/19 17:54:44 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/nlookup.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",__func__))
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 thread *td)   /* The ever-famous proc pointer */
117 {
118     struct vnode *dvp;
119     struct cnode *cp;
120     udev_t udev;
121     struct coda_mntinfo *mi;
122     struct vnode *rootvp;
123     ViceFid rootfid;
124     ViceFid ctlfid;
125     int error;
126     struct nlookupdata nd;
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     dvp = NULL;
141     error = nlookup_init(&nd, data, UIO_USERSPACE, NLC_FOLLOW);
142     if (error == 0)
143         error = nlookup(&nd);
144     if (error == 0)
145         error = cache_vref(nd.nl_ncp, nd.nl_cred, &dvp);
146     nlookup_done(&nd);
147     if (error) {
148         MARK_INT_FAIL(CODA_MOUNT_STATS);
149         return (error);
150     }
151     if (dvp->v_type != VCHR) {
152         MARK_INT_FAIL(CODA_MOUNT_STATS);
153         vrele(dvp);
154         return(ENXIO);
155     }
156     udev = dvp->v_udev;
157     vrele(dvp);
158
159 #if 0   /* YYY huh? what paranoia is this? */
160     /*
161      * See if the device table matches our expectations.
162      */
163     if (devsw(dev)->d_open != vc_nb_open)
164     {
165         MARK_INT_FAIL(CODA_MOUNT_STATS);
166         return(ENXIO);
167     }
168 #endif
169     
170     if (uminor(udev) >= NVCODA || uminor(udev) < 0) {
171         MARK_INT_FAIL(CODA_MOUNT_STATS);
172         return(ENXIO);
173     }
174     
175     /*
176      * Initialize the mount record and link it to the vfs struct
177      */
178     mi = &coda_mnttbl[uminor(udev)];
179     
180     if (!VC_OPEN(&mi->mi_vcomm)) {
181         MARK_INT_FAIL(CODA_MOUNT_STATS);
182         return(ENODEV);
183     }
184     
185     /* No initialization (here) of mi_vcomm! */
186     vfsp->mnt_data = (qaddr_t)mi;
187     vfs_getnewfsid (vfsp);
188
189     mi->mi_vfsp = vfsp;
190     
191     /*
192      * Make a root vnode to placate the Vnode interface, but don't
193      * actually make the CODA_ROOT call to venus until the first call
194      * to coda_root in case a server is down while venus is starting.
195      */
196     rootfid.Volume = 0;
197     rootfid.Vnode = 0;
198     rootfid.Unique = 0;
199     cp = make_coda_node(&rootfid, vfsp, VDIR);
200     rootvp = CTOV(cp);
201     rootvp->v_flag |= VROOT;
202         
203     ctlfid.Volume = CTL_VOL;
204     ctlfid.Vnode = CTL_VNO;
205     ctlfid.Unique = CTL_UNI;
206 /*  cp = make_coda_node(&ctlfid, vfsp, VCHR);
207     The above code seems to cause a loop in the cnode links.
208     I don't totally understand when it happens, it is caught
209     when closing down the system.
210  */
211     cp = make_coda_node(&ctlfid, 0, VCHR);
212
213     coda_ctlvp = CTOV(cp);
214
215     /* Add vfs and rootvp to chain of vfs hanging off mntinfo */
216     mi->mi_vfsp = vfsp;
217     mi->mi_rootvp = rootvp;
218     
219     /* set filesystem block size */
220     vfsp->mnt_stat.f_bsize = 8192;          /* XXX -JJK */
221
222     /* Set f_iosize.  XXX -- inamura@isl.ntt.co.jp. 
223        For vnode_pager_haspage() references. The value should be obtained 
224        from underlying UFS. */
225     /* Checked UFS. iosize is set as 8192 */
226     vfsp->mnt_stat.f_iosize = 8192;
227
228     /* error is currently guaranteed to be zero, but in case some
229        code changes... */
230     CODADEBUG(1,
231              myprintf(("coda_mount returned %d\n",error)););
232     if (error)
233         MARK_INT_FAIL(CODA_MOUNT_STATS);
234     else
235         MARK_INT_SAT(CODA_MOUNT_STATS);
236     
237     return(error);
238 }
239
240 int
241 coda_unmount(struct mount *vfsp, int mntflags, struct thread *td)
242 {
243     struct coda_mntinfo *mi = vftomi(vfsp);
244     int active, error = 0;
245     
246     ENTRY;
247     MARK_ENTRY(CODA_UMOUNT_STATS);
248     if (!CODA_MOUNTED(vfsp)) {
249         MARK_INT_FAIL(CODA_UMOUNT_STATS);
250         return(EINVAL);
251     }
252     
253     if (mi->mi_vfsp == vfsp) {  /* We found the victim */
254         if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp)))
255             return (EBUSY);     /* Venus is still running */
256
257 #ifdef  DEBUG
258         printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, VTOC(mi->mi_rootvp));
259 #endif
260         vrele(mi->mi_rootvp);
261
262         active = coda_kill(vfsp, NOT_DOWNCALL);
263         mi->mi_rootvp->v_flag &= ~VROOT;
264         error = vflush(mi->mi_vfsp, 0, FORCECLOSE);
265         printf("coda_unmount: active = %d, vflush active %d\n", active, error);
266         error = 0;
267         /* I'm going to take this out to allow lookups to go through. I'm
268          * not sure it's important anyway. -- DCS 2/2/94
269          */
270         /* vfsp->VFS_DATA = NULL; */
271
272         /* No more vfsp's to hold onto */
273         mi->mi_vfsp = NULL;
274         mi->mi_rootvp = NULL;
275
276         if (error)
277             MARK_INT_FAIL(CODA_UMOUNT_STATS);
278         else
279             MARK_INT_SAT(CODA_UMOUNT_STATS);
280
281         return(error);
282     }
283     return (EINVAL);
284 }
285
286 /*
287  * find root of cfs
288  */
289 int
290 coda_root(struct mount *vfsp, struct vnode **vpp)
291 {
292     struct coda_mntinfo *mi = vftomi(vfsp);
293     struct vnode **result;
294     int error;
295     struct thread *td = curthread;    /* XXX - bnoble */
296     struct ucred *cred;
297     ViceFid VFid;
298
299     KKASSERT(td->td_proc);
300     cred = td->td_proc->p_ucred;
301
302     ENTRY;
303     MARK_ENTRY(CODA_ROOT_STATS);
304     result = NULL;
305     
306     if (vfsp == mi->mi_vfsp) {
307         if ((VTOC(mi->mi_rootvp)->c_fid.Volume != 0) ||
308             (VTOC(mi->mi_rootvp)->c_fid.Vnode != 0) ||
309             (VTOC(mi->mi_rootvp)->c_fid.Unique != 0))
310             { /* Found valid root. */
311                 *vpp = mi->mi_rootvp;
312                 /* On Mach, this is vref.  On NetBSD, VOP_LOCK */
313                 vget(*vpp, LK_EXCLUSIVE, td);
314                 MARK_INT_SAT(CODA_ROOT_STATS);
315                 return(0);
316             }
317     }
318
319     error = venus_root(vftomi(vfsp), cred, td, &VFid);
320
321     if (!error) {
322         /*
323          * Save the new rootfid in the cnode, and rehash the cnode into the
324          * cnode hash with the new fid key.
325          */
326         coda_unsave(VTOC(mi->mi_rootvp));
327         VTOC(mi->mi_rootvp)->c_fid = VFid;
328         coda_save(VTOC(mi->mi_rootvp));
329
330         *vpp = mi->mi_rootvp;
331         vget(*vpp, LK_EXCLUSIVE, td);
332
333         MARK_INT_SAT(CODA_ROOT_STATS);
334         goto exit;
335     } else if (error == ENODEV || error == EINTR) {
336         /* Gross hack here! */
337         /*
338          * If Venus fails to respond to the CODA_ROOT call, coda_call returns
339          * ENODEV. Return the uninitialized root vnode to allow vfs
340          * operations such as unmount to continue. Without this hack,
341          * there is no way to do an unmount if Venus dies before a 
342          * successful CODA_ROOT call is done. All vnode operations 
343          * will fail.
344          */
345         *vpp = mi->mi_rootvp;
346         vget(*vpp, LK_EXCLUSIVE, td);
347
348         MARK_INT_FAIL(CODA_ROOT_STATS);
349         error = 0;
350         goto exit;
351     } else {
352         CODADEBUG( CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", error)); );
353         MARK_INT_FAIL(CODA_ROOT_STATS);
354                 
355         goto exit;
356     }
357
358  exit:
359     return(error);
360 }
361
362 /*
363  * Get file system statistics.
364  */
365 int
366 coda_nb_statfs(struct mount *vfsp, struct statfs *sbp, struct thread *td)
367 {
368     ENTRY;
369 /*  MARK_ENTRY(CODA_STATFS_STATS); */
370     if (!CODA_MOUNTED(vfsp)) {
371 /*      MARK_INT_FAIL(CODA_STATFS_STATS);*/
372         return(EINVAL);
373     }
374     
375     bzero(sbp, sizeof(struct statfs));
376     /* XXX - what to do about f_flags, others? --bnoble */
377     /* Below This is what AFS does
378         #define NB_SFS_SIZ 0x895440
379      */
380     /* Note: Normal fs's have a bsize of 0x400 == 1024 */
381     sbp->f_type = vfsp->mnt_vfc->vfc_typenum;
382     sbp->f_bsize = 8192; /* XXX */
383     sbp->f_iosize = 8192; /* XXX */
384 #define NB_SFS_SIZ 0x8AB75D
385     sbp->f_blocks = NB_SFS_SIZ;
386     sbp->f_bfree = NB_SFS_SIZ;
387     sbp->f_bavail = NB_SFS_SIZ;
388     sbp->f_files = NB_SFS_SIZ;
389     sbp->f_ffree = NB_SFS_SIZ;
390     bcopy((caddr_t)&(vfsp->mnt_stat.f_fsid), (caddr_t)&(sbp->f_fsid), sizeof (fsid_t));
391     snprintf(sbp->f_mntfromname, sizeof(sbp->f_mntfromname), "CODA");
392 /*  MARK_INT_SAT(CODA_STATFS_STATS); */
393     return(0);
394 }
395
396 /*
397  * Flush any pending I/O.
398  */
399 int
400 coda_sync(struct mount *vfsp, int waitfor, struct thread *td)
401 {
402     ENTRY;
403     MARK_ENTRY(CODA_SYNC_STATS);
404     MARK_INT_SAT(CODA_SYNC_STATS);
405     return(0);
406 }
407
408 /* 
409  * fhtovp is now what vget used to be in 4.3-derived systems.  For
410  * some silly reason, vget is now keyed by a 32 bit ino_t, rather than
411  * a type-specific fid.  
412  */
413 int
414 coda_fhtovp(struct mount *vfsp, struct fid *fhp, struct mbuf *nam,
415             struct vnode **vpp, int *exflagsp, struct ucred **creadanonp)
416 {
417     struct cfid *cfid = (struct cfid *)fhp;
418     struct cnode *cp = 0;
419     int error;
420     struct thread *td = curthread; /* XXX -mach */
421     struct ucred *cred;
422     ViceFid VFid;
423     int vtype;
424
425     KKASSERT(td->td_proc);
426     cred = td->td_proc->p_ucred;
427
428     ENTRY;
429     
430     MARK_ENTRY(CODA_VGET_STATS);
431     /* Check for vget of control object. */
432     if (IS_CTL_FID(&cfid->cfid_fid)) {
433         *vpp = coda_ctlvp;
434         vref(coda_ctlvp);
435         MARK_INT_SAT(CODA_VGET_STATS);
436         return(0);
437     }
438     
439     error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, cred, td, &VFid, &vtype);
440     
441     if (error) {
442         CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));)
443             *vpp = (struct vnode *)0;
444     } else {
445         CODADEBUG(CODA_VGET, 
446                  myprintf(("vget: vol %lx vno %lx uni %lx type %d result %d\n",
447                         VFid.Volume, VFid.Vnode, VFid.Unique, vtype, error)); )
448             
449         cp = make_coda_node(&VFid, vfsp, vtype);
450         *vpp = CTOV(cp);
451     }
452     return(error);
453 }
454
455 /*
456  * To allow for greater ease of use, some vnodes may be orphaned when
457  * Venus dies.  Certain operations should still be allowed to go
458  * through, but without propagating orphan-ness.  So this function will
459  * get a new vnode for the file from the current run of Venus.
460  */
461  
462 int
463 getNewVnode(struct vnode **vpp)
464 {
465     struct cfid cfid;
466     struct coda_mntinfo *mi = vftomi((*vpp)->v_mount);
467     
468     ENTRY;
469
470     cfid.cfid_len = (short)sizeof(ViceFid);
471     cfid.cfid_fid = VTOC(*vpp)->c_fid;  /* Structure assignment. */
472     /* XXX ? */
473
474     /* We're guessing that if set, the 1st element on the list is a
475      * valid vnode to use. If not, return ENODEV as venus is dead.
476      */
477     if (mi->mi_vfsp == NULL)
478         return ENODEV;
479     
480     return coda_fhtovp(mi->mi_vfsp, (struct fid*)&cfid, NULL, vpp,
481                       NULL, NULL);
482 }
483
484 #include <vfs/ufs/quota.h>
485 #include <vfs/ufs/ufsmount.h>
486
487 /*
488  * get the mount structure corresponding to a given device.  Assume 
489  * device corresponds to a UFS. Return NULL if no device is found.
490  */ 
491 struct devtomp_info {
492         struct mount *ret_mp;
493         dev_t dev;
494 };
495
496 static int devtomp_callback(struct mount *mp, void *data);
497
498 struct mount *
499 devtomp(dev_t dev)
500 {
501     struct devtomp_info info;
502
503     info.ret_mp = NULL;
504     info.dev = dev;
505
506     mountlist_scan(devtomp_callback, &info, MNTSCAN_FORWARD|MNTSCAN_NOBUSY);
507     return(info.ret_mp);
508 }
509
510 static int
511 devtomp_callback(struct mount *mp, void *data)
512 {
513         struct devtomp_info *info = data;
514
515         if ((VFSTOUFS(mp))->um_dev == info->dev) {
516                 info->ret_mp = mp;
517                 return(-1);
518         }
519         return(0);
520 }
521
522 struct vfsops coda_vfsops = {
523     coda_mount,
524     vfs_stdstart,
525     coda_unmount,
526     coda_root,
527     vfs_stdquotactl,
528     coda_nb_statfs,
529     coda_sync,
530     vfs_stdvget,
531     vfs_stdfhtovp,
532     vfs_stdcheckexp,
533     vfs_stdvptofh,
534     vfs_stdinit,
535     vfs_stduninit,
536     vfs_stdextattrctl,
537 };
538
539 VFS_SET(coda_vfsops, coda, VFCF_NETWORK);