openbsd-20021107
[openafs.git] / src / afs / OBSD / osi_vfsops.c
1 /*
2 Copyright 1995 Massachusetts Institute of Technology.  All Rights
3 Reserved.
4
5 You are hereby granted a worldwide, irrevocable, paid-up, right and
6 license to use, execute, display, modify, copy and distribute MIT's
7 Modifications, provided that (i) you abide by the terms and conditions
8 of your Transarc AFS License Agreement, and (ii) you do not use the name
9 of MIT in any advertising or publicity without the prior written consent
10 of MIT.  MIT disclaims all liability for your use of MIT's
11 Modifications.  MIT's Modifications are provided "AS IS" WITHOUT
12 WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO,
13 ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
14 NONINFRINGEMENT.
15 */
16
17 /*
18  * OpenBSD specific assistance routines & VFS ops
19  * Original NetBSD version for Transarc afs by John Kohl <jtk@MIT.EDU>
20  * OpenBSD version by Jim Rees <rees@umich.edu>
21  *
22  * $Id$
23  */
24
25 /*
26  * Some code cribbed from ffs_vfsops and other NetBSD sources, which
27  * are marked:
28  */
29 /*
30  * Copyright (c) 1989, 1991, 1993, 1994
31  *      The Regents of the University of California.  All rights reserved.
32  *
33  * Redistribution and use in source and binary forms, with or without
34  * modification, are permitted provided that the following conditions
35  * are met:
36  * 1. Redistributions of source code must retain the above copyright
37  *    notice, this list of conditions and the following disclaimer.
38  * 2. Redistributions in binary form must reproduce the above copyright
39  *    notice, this list of conditions and the following disclaimer in the
40  *    documentation and/or other materials provided with the distribution.
41  * 3. All advertising materials mentioning features or use of this software
42  *    must display the following acknowledgement:
43  *      This product includes software developed by the University of
44  *      California, Berkeley and its contributors.
45  * 4. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  *
61  */
62
63 #include <afsconfig.h>
64 #include "afs/param.h"
65
66 RCSID("$Header$");
67
68 #include "afs/sysincludes.h"    /* Standard vendor system headers */
69 #include "afs/afsincludes.h"    /* Afs-based standard headers */
70 #include "afs/afs_stats.h" /* statistics */
71
72 #include <sys/conf.h>
73 #include <sys/exec.h>
74 #include <sys/lkm.h>
75 #include <sys/namei.h>
76 #include <sys/syscall.h>
77 #include <sys/syscallargs.h>
78
79 #define NBSD_DONTFOLLOW_LINK 0
80 #define NBSD_FOLLOW_LINK 1
81 static int lkmid = -1;
82 static int afs_badcall(struct proc *p, void *xx, register_t *yy);
83
84 char afs_NetBSD_osname[] = "OpenBSD";
85 struct osi_vfs *afs_globalVFS;
86 struct vcache *afs_globalVp;
87
88 int afs_quotactl();
89 int afs_fhtovp();
90 int afs_vptofh();
91 int afsinit();
92 int afs_start();
93 int afs_mount();
94 int afs_unmount();
95 int afs_root();
96 int afs_statfs();
97 int afs_sync();
98 int afs_vget();
99 int afs_sysctl();
100 int afs_checkexp();
101
102 struct vfsops afs_vfsops = {
103     afs_mount,
104     afs_start,
105     afs_unmount,
106     afs_root,
107     afs_quotactl,
108     afs_statfs,
109     afs_sync,
110     afs_vget,
111     afs_fhtovp,
112     afs_vptofh,
113     afsinit,
114     afs_sysctl,
115     afs_checkexp,
116 };
117
118 int
119 afs_nbsd_lookupname(char *fnamep,
120                     enum uio_seg segflg,
121                     int followlink,
122                     struct vnode **dirvpp,
123                     struct vnode **compvpp)
124 {
125     struct nameidata nd;
126     int niflag;
127     int error;
128
129     /*
130      * Lookup pathname "fnamep", returning parent directory in
131      * *dirvpp (if non-null) and leaf in *compvpp.  segflg says whether the
132      * pathname is user or system space.
133      */
134     /* XXX LOCKLEAF ? */
135     niflag =  (followlink == NBSD_FOLLOW_LINK) ? FOLLOW : NOFOLLOW;
136     if (dirvpp)
137         niflag |= WANTPARENT;           /* XXX LOCKPARENT? */
138     NDINIT(&nd, LOOKUP,
139            niflag,
140            segflg,
141            fnamep, osi_curproc());
142     if ((error = namei(&nd)))
143         return error;
144     *compvpp = nd.ni_vp;
145     if (dirvpp)
146         *dirvpp = nd.ni_dvp;
147     return error;
148 }
149
150 #if 0
151 int
152 afs_rdwr(struct vnode *vp, struct uio *uiop, enum uio_rw op,
153               int flags, struct AFS_UCRED *cred)
154 {
155     uiop->uio_rw = op;
156     if (op == UIO_READ)
157         return VOP_READ(vp, uiop, flags, cred);
158     if (op == UIO_WRITE)
159         return VOP_WRITE(vp, uiop, flags, cred);
160 #ifdef DIAGNOSTIC
161     panic("afs_rdwr mode");
162 #endif
163     return EINVAL;
164 }
165 #endif
166
167 int
168 afs_quotactl()
169 {
170     return EOPNOTSUPP;
171 }
172
173 int
174 afs_sysctl()
175 {
176     return EOPNOTSUPP;
177 }
178
179 int
180 afs_checkexp()
181 {
182         return EOPNOTSUPP;
183 }
184
185 int
186 afs_fhtovp(mp, fhp, vpp)
187 struct mount *mp;
188 struct fid *fhp;
189 struct vnode **vpp;
190 {
191
192     return (EINVAL);
193 }
194
195 int
196 afs_vptofh(vp, fhp)
197 struct vnode *vp;
198 struct fid *fhp;
199 {
200
201     return (EINVAL);
202 }
203
204 int
205 afs_start(mp, flags, p)
206 struct mount *mp;
207 int flags;
208 struct proc *p;
209 {
210     return (0);                         /* nothing to do. ? */
211 }
212
213 int
214 afs_mount(mp, path, data, ndp, p)
215 register struct mount *mp;
216 char *path;
217 caddr_t data;
218 struct nameidata *ndp;
219 struct proc *p;
220 {
221     /* ndp contains the mounted-from device.  Just ignore it.
222        we also don't care about our proc struct. */
223     int size;
224
225     if (mp->mnt_flag & MNT_UPDATE)
226         return EINVAL;
227
228     if (afs_globalVFS) {
229         /* Don't allow remounts */
230         return EBUSY;
231     }
232
233     AFS_GLOCK();
234     AFS_STATCNT(afs_mount);
235
236 #ifdef AFS_DISCON_ENV
237     /* initialize the vcache entries before we start using them */
238
239     /* XXX find a better place for this if possible  */
240     init_vcache_entries();
241 #endif
242     afs_globalVFS = mp;
243     mp->osi_vfs_bsize = 8192;
244     mp->osi_vfs_fsid.val[0] = AFS_VFSMAGIC; /* magic */
245     mp->osi_vfs_fsid.val[1] = (int) AFS_VFSFSID; 
246
247     AFS_GUNLOCK();
248
249     (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN-1, &size);
250     bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
251     bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
252     strcpy(mp->mnt_stat.f_mntfromname, "AFS");
253     /* null terminated string "AFS" will fit, just leave it be. */
254     strcpy(mp->mnt_stat.f_fstypename, MOUNT_AFS);
255     (void) afs_statfs(mp, &mp->mnt_stat);
256
257     return 0;
258 }
259
260 int
261 afs_unmount(afsp, flags, p)
262 struct mount *afsp;
263 int flags;
264 struct proc *p;
265 {
266     extern int sys_ioctl(), sys_setgroups();
267
268     AFS_STATCNT(afs_unmount);
269 #ifdef AFS_DISCON_ENV
270     give_up_cbs();
271 #endif
272     if (!afs_globalVFS) {
273         printf("afs already unmounted\n");
274         return 0;
275     }
276     if (afs_globalVp)
277         AFS_RELE(AFSTOV(afs_globalVp));
278     afs_globalVp = NULL;
279
280     vflush(afsp, NULLVP, 0); /* don't support forced */
281     afsp->mnt_data = NULL;
282 #ifdef  AFS_GLOBAL_SUNLOCK
283     mutex_enter(&afs_global_lock);
284 #endif
285     afs_globalVFS = 0;
286     afs_cold_shutdown = 1;
287     afs_shutdown();                     /* XXX */
288 #ifdef  AFS_GLOBAL_SUNLOCK
289     mutex_exit(&afs_global_lock);
290 #endif
291
292     /* give up syscall entries for ioctl & setgroups, which we've stolen */
293     sysent[SYS_ioctl].sy_call = sys_ioctl;
294     sysent[SYS_setgroups].sy_call = sys_setgroups;
295
296     /* give up the stolen syscall entry */
297     sysent[AFS_SYSCALL].sy_narg = 0;
298     sysent[AFS_SYSCALL].sy_argsize = 0;
299     sysent[AFS_SYSCALL].sy_call = afs_badcall;
300     printf("AFS unmounted--use `/sbin/modunload -i %d' to unload before restarting AFS\n", lkmid);
301     return 0;
302 }
303
304 static int
305 afs_badcall(struct proc *p, void *xx, register_t *yy)
306 {
307     return ENOSYS;
308 }
309
310 void
311 afs_nbsd_getnewvnode(struct vcache *tvc)
312 {
313     while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &tvc->v)) {
314         /* no vnodes available, force an alloc (limits be damned)! */
315         desiredvnodes++;
316     }
317     tvc->v->v_data = (void *)tvc;
318 }
319
320 int
321 afs_root(struct mount *mp,
322               struct vnode **vpp)
323 {
324     struct vrequest treq;
325     struct vcache *tvp;
326     int code;
327
328     AFS_STATCNT(afs_root);
329
330 #ifdef  AFS_GLOBAL_SUNLOCK
331     mutex_enter(&afs_global_lock);
332 #endif
333     if (!(code = afs_InitReq(&treq, osi_curcred())) &&
334         !(code = afs_CheckInit())) {
335         tvp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
336         if (tvp) {
337 printf("tvp %x %d\n", tvp, AFSTOV(tvp)->v_usecount);
338             /* There is really no reason to over-hold this bugger--it's held
339                by the root filesystem reference. */
340             if (afs_globalVp != tvp) {
341                 if (afs_globalVp)
342 printf("afs_globalVp %x %d\n", afs_globalVp, AFSTOV(afs_globalVp)->v_usecount);
343 /*                  AFS_RELE(AFSTOV(afs_globalVp));*/
344                 afs_globalVp = tvp;
345                 AFS_HOLD(AFSTOV(afs_globalVp));
346             }
347             AFSTOV(tvp)->v_flag |= VROOT;
348             afs_globalVFS = mp;
349             *vpp = AFSTOV(tvp);
350         } else
351             code = ENOENT;
352     }
353 #ifdef  AFS_GLOBAL_SUNLOCK
354     mutex_exit(&afs_global_lock);
355 #endif
356
357     if (!code)
358         vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curproc); /* return it locked */
359     return code;
360 }
361
362 int
363 afs_statfs(struct osi_vfs *afsp, struct statfs *abp)
364 {
365     AFS_STATCNT(afs_statfs);
366 #ifdef  AFS_GLOBAL_SUNLOCK
367     mutex_enter(&afs_global_lock);
368 #endif
369     abp->f_bsize = afsp->osi_vfs_bsize;
370     /* Fake a high number below to satisfy programs that use the ustat (for AIX), or statfs (for the rest) call to make sure that there's enough space in the device partition before storing something there (like ed(1)) */
371     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files = abp->f_ffree  = 9000000; /* XXX */
372     abp->f_fsid.val[0] = AFS_VFSMAGIC; /* magic */
373     abp->f_fsid.val[1] = (int) AFS_VFSFSID;
374 #ifdef  AFS_GLOBAL_SUNLOCK
375     mutex_exit(&afs_global_lock);
376 #endif
377     return 0;
378 }
379
380 int
381 afs_sync(struct osi_vfs *afsp)
382 {
383     AFS_STATCNT(afs_sync);
384 #if defined(AFS_DISCON_ENV) && !defined(AFS_OBSD_ENV)
385     /* Can't do this in OpenBSD 2.7, it faults when called from apm_suspend() */
386     store_dirty_vcaches();
387 #endif
388     return 0;
389 }
390
391 void
392 afs_nbsd_ref(struct vnode *vp)
393 {
394     if (vp->v_usecount == 0) {
395         vprint("holding unheld node", vp);
396         panic("afs_ref");
397     }
398     VREF(vp);
399 }
400
401 void
402 afs_nbsd_rele(struct vnode *vp)
403 {
404     if (vp->v_usecount <= 0) {
405         vprint("rele'ing unheld node", vp);
406         panic("afs_rele");
407     }
408     vrele(vp);
409 }
410
411 int
412 afs_vget(vp, lfl)
413 struct vnode *vp;
414 int lfl;
415 {
416     int error;
417
418     if (vp->v_usecount < 0) {
419         vprint("bad usecount", vp);
420         panic("afs_vget");
421     }
422     error = vget(vp, lfl, curproc);
423     if (!error)
424         insmntque(vp, afs_globalVFS);   /* take off free list */
425     return error;
426 }
427
428 extern struct vfsops afs_vfsops;
429 extern struct vnodeopv_desc afs_vnodeop_opv_desc;
430
431 static struct vfsconf afs_vfsconf = {
432     &afs_vfsops,
433     "afs",
434     0,
435     0,
436     0,
437     NULL,
438     NULL,
439 };
440
441 MOD_VFS("afs", 0, &afs_vfsconf);
442
443 static char afsgenmem[] = "afsgenmem";
444 static char afsfidmem[] = "afsfidmem";
445 static char afsbhdrmem[] = "afsbhdrmem";
446 static char afsbfrmem[] = "afsbfrmem";
447
448 int
449 afsinit()
450 {
451     extern int afs3_syscall(), afs_xioctl(), Afs_xsetgroups(), afs_xflock();
452
453     sysent[AFS_SYSCALL].sy_call = afs3_syscall;
454     sysent[AFS_SYSCALL].sy_narg = 6;
455     sysent[AFS_SYSCALL].sy_argsize = 6 * sizeof(long);
456     sysent[54].sy_call = afs_xioctl;
457     sysent[80].sy_call = Afs_xsetgroups;
458
459     return 0;
460 }
461
462 int
463 afs_vfs_load(struct lkm_table *lkmtp,
464              int cmd)
465 {
466     extern char *memname[];
467
468     vfs_opv_init_explicit(&afs_vnodeop_opv_desc);
469     vfs_opv_init_default(&afs_vnodeop_opv_desc);
470     if (memname[M_AFSGENERIC] == NULL)
471         memname[M_AFSGENERIC] = afsgenmem;
472     if (memname[M_AFSFID] == NULL)
473         memname[M_AFSFID] = afsfidmem;
474     if (memname[M_AFSBUFHDR] == NULL)
475         memname[M_AFSBUFHDR] = afsbhdrmem;
476     if (memname[M_AFSBUFFER] == NULL)
477         memname[M_AFSBUFFER] = afsbfrmem;
478     lkmid = lkmtp->id;
479     printf("OpenAFS ($Revision$) lkm loaded\n");
480     return 0;
481 }
482
483 int
484 afs_vfs_unload(struct lkm_table *lktmp,
485              int cmd)
486 {
487     extern char *memname[];
488     extern int sys_lkmnosys();
489
490     if (afs_globalVp)
491         return EBUSY;
492     if (sysent[SYS_ioctl].sy_call != sys_ioctl)
493         return EBUSY;
494
495     if (memname[M_AFSGENERIC] == afsgenmem)
496         memname[M_AFSGENERIC] = NULL;
497     if (memname[M_AFSFID] == afsfidmem)
498         memname[M_AFSFID] = NULL;
499     if (memname[M_AFSBUFHDR] == afsbhdrmem)
500         memname[M_AFSBUFHDR] = NULL;
501     if (memname[M_AFSBUFFER] == afsbfrmem)
502         memname[M_AFSBUFFER] = NULL;
503
504     sysent[AFS_SYSCALL].sy_call = sys_lkmnosys;
505     printf("OpenAFS unloaded\n");
506     return 0;
507 }
508
509
510
511 int
512 afsmodload(struct lkm_table *lkmtp,
513            int cmd,
514            int ver)
515 {
516     extern int sys_lkmnosys();
517
518     if (cmd == LKM_E_LOAD) {
519         if (strcmp(ostype,afs_NetBSD_osname)) {
520             printf("This is %s version %s\n", ostype, osrelease);
521             printf("This version of AFS is only for %s\n",
522                    afs_NetBSD_osname);
523 /*          return EPROGMISMATCH;*/
524         }
525         if (sysent[AFS_SYSCALL].sy_call != sys_lkmnosys) {
526             printf("AFS must be loaded with syscall %d assigned to sys_lkmnosys\nIs AFS already loaded?\n",
527                    AFS_SYSCALL);
528             return EINVAL;
529         }
530     }
531     DISPATCH(lkmtp,cmd,ver,afs_vfs_load,afs_vfs_unload,lkm_nofunc);
532 }