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