f94e7a2e338441cb5154aa074f738f47566ca12a
[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 #define NBSD_DONTFOLLOW_LINK 0
110 #define NBSD_FOLLOW_LINK 1
111 static int lkmid = -1;
112 static int afs_badcall(struct proc *p, void *xx, register_t *yy);
113
114 char afs_NetBSD_osname[] = "OpenBSD";
115 struct osi_vfs *afs_globalVFS;
116 struct vcache *afs_globalVp;
117
118 int afs_quotactl();
119 int afs_fhtovp();
120 int afs_vptofh();
121 int afsinit();
122 int afs_start();
123 int afs_mount();
124 int afs_unmount();
125 int afs_root();
126 int afs_statfs();
127 int afs_sync();
128 int afs_vget();
129 int afs_sysctl();
130 int afs_checkexp();
131
132 struct vfsops afs_vfsops = {
133     afs_mount,
134     afs_start,
135     afs_unmount,
136     afs_root,
137     afs_quotactl,
138     afs_statfs,
139     afs_sync,
140     afs_vget,
141     afs_fhtovp,
142     afs_vptofh,
143     afsinit,
144     afs_sysctl,
145     afs_checkexp,
146 };
147
148 int
149 afs_nbsd_lookupname(char *fnamep,
150                     enum uio_seg segflg,
151                     int followlink,
152                     struct vnode **dirvpp,
153                     struct vnode **compvpp)
154 {
155     struct nameidata nd;
156     int niflag;
157     int error;
158
159     /*
160      * Lookup pathname "fnamep", returning parent directory in
161      * *dirvpp (if non-null) and leaf in *compvpp.  segflg says whether the
162      * pathname is user or system space.
163      */
164     /* XXX LOCKLEAF ? */
165     niflag =  (followlink == NBSD_FOLLOW_LINK) ? FOLLOW : NOFOLLOW;
166     if (dirvpp)
167         niflag |= WANTPARENT;           /* XXX LOCKPARENT? */
168     NDINIT(&nd, LOOKUP,
169            niflag,
170            segflg,
171            fnamep, osi_curproc());
172     if ((error = namei(&nd)))
173         return error;
174     *compvpp = nd.ni_vp;
175     if (dirvpp)
176         *dirvpp = nd.ni_dvp;
177     return error;
178 }
179
180 #if 0
181 int
182 afs_rdwr(struct vnode *vp, struct uio *uiop, enum uio_rw op,
183               int flags, struct AFS_UCRED *cred)
184 {
185     uiop->uio_rw = op;
186     if (op == UIO_READ)
187         return VOP_READ(vp, uiop, flags, cred);
188     if (op == UIO_WRITE)
189         return VOP_WRITE(vp, uiop, flags, cred);
190 #ifdef DIAGNOSTIC
191     panic("afs_rdwr mode");
192 #endif
193     return EINVAL;
194 }
195 #endif
196
197 int
198 afs_quotactl()
199 {
200     return EOPNOTSUPP;
201 }
202
203 int
204 afs_sysctl()
205 {
206     return EOPNOTSUPP;
207 }
208
209 int
210 afs_checkexp()
211 {
212         return EOPNOTSUPP;
213 }
214
215 int
216 afs_fhtovp(mp, fhp, vpp)
217 struct mount *mp;
218 struct fid *fhp;
219 struct vnode **vpp;
220 {
221
222     return (EINVAL);
223 }
224
225 int
226 afs_vptofh(vp, fhp)
227 struct vnode *vp;
228 struct fid *fhp;
229 {
230
231     return (EINVAL);
232 }
233
234 int
235 afs_start(mp, flags, p)
236 struct mount *mp;
237 int flags;
238 struct proc *p;
239 {
240     return (0);                         /* nothing to do. ? */
241 }
242
243 int
244 afs_mount(mp, path, data, ndp, p)
245 register struct mount *mp;
246 char *path;
247 caddr_t data;
248 struct nameidata *ndp;
249 struct proc *p;
250 {
251     /* ndp contains the mounted-from device.  Just ignore it.
252        we also don't care about our proc struct. */
253     int size;
254
255     if (mp->mnt_flag & MNT_UPDATE)
256         return EINVAL;
257
258     if (afs_globalVFS) {
259         /* Don't allow remounts */
260         return EBUSY;
261     }
262
263     AFS_GLOCK();
264     AFS_STATCNT(afs_mount);
265
266 #ifdef AFS_DISCON_ENV
267     /* initialize the vcache entries before we start using them */
268
269     /* XXX find a better place for this if possible  */
270     init_vcache_entries();
271 #endif
272     afs_globalVFS = mp;
273     mp->osi_vfs_bsize = 8192;
274     mp->osi_vfs_fsid.val[0] = AFS_VFSMAGIC; /* magic */
275     mp->osi_vfs_fsid.val[1] = (int) AFS_VFSFSID; 
276
277     AFS_GUNLOCK();
278
279     (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN-1, &size);
280     bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
281     bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
282     strcpy(mp->mnt_stat.f_mntfromname, "AFS");
283     /* null terminated string "AFS" will fit, just leave it be. */
284     strcpy(mp->mnt_stat.f_fstypename, MOUNT_AFS);
285     (void) afs_statfs(mp, &mp->mnt_stat);
286
287     return 0;
288 }
289
290 int
291 afs_unmount(afsp, flags, p)
292 struct mount *afsp;
293 int flags;
294 struct proc *p;
295 {
296     extern int sys_ioctl(), sys_setgroups();
297
298     AFS_STATCNT(afs_unmount);
299 #ifdef AFS_DISCON_ENV
300     give_up_cbs();
301 #endif
302     if (!afs_globalVFS) {
303         printf("afs already unmounted\n");
304         return 0;
305     }
306     if (afs_globalVp)
307         AFS_RELE(AFSTOV(afs_globalVp));
308     afs_globalVp = NULL;
309
310     vflush(afsp, NULLVP, 0); /* don't support forced */
311     afsp->mnt_data = NULL;
312 #ifdef  AFS_GLOBAL_SUNLOCK
313     mutex_enter(&afs_global_lock);
314 #endif
315     afs_globalVFS = 0;
316     afs_cold_shutdown = 1;
317     afs_shutdown();                     /* XXX */
318 #ifdef  AFS_GLOBAL_SUNLOCK
319     mutex_exit(&afs_global_lock);
320 #endif
321
322     /* give up syscall entries for ioctl & setgroups, which we've stolen */
323     sysent[SYS_ioctl].sy_call = sys_ioctl;
324     sysent[SYS_setgroups].sy_call = sys_setgroups;
325
326     /* give up the stolen syscall entry */
327     sysent[AFS_SYSCALL].sy_narg = 0;
328     sysent[AFS_SYSCALL].sy_argsize = 0;
329     sysent[AFS_SYSCALL].sy_call = afs_badcall;
330     printf("AFS unmounted--use `/sbin/modunload -i %d' to unload before restarting AFS\n", lkmid);
331     return 0;
332 }
333
334 static int
335 afs_badcall(struct proc *p, void *xx, register_t *yy)
336 {
337     return ENOSYS;
338 }
339
340 void
341 afs_nbsd_getnewvnode(struct vcache *tvc)
342 {
343     while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &tvc->v)) {
344         /* no vnodes available, force an alloc (limits be damned)! */
345         desiredvnodes++;
346     }
347     tvc->v->v_data = (void *)tvc;
348 }
349
350 int
351 afs_root(struct mount *mp,
352               struct vnode **vpp)
353 {
354     struct vrequest treq;
355     struct vcache *tvp;
356     int code;
357
358     AFS_STATCNT(afs_root);
359
360 #ifdef  AFS_GLOBAL_SUNLOCK
361     mutex_enter(&afs_global_lock);
362 #endif
363     if (!(code = afs_InitReq(&treq, osi_curcred())) &&
364         !(code = afs_CheckInit())) {
365         tvp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
366         if (tvp) {
367             /* There is really no reason to over-hold this bugger--it's held
368                by the root filesystem reference. */
369             if (afs_globalVp != tvp) {
370 #ifdef AFS_DONT_OVERHOLD_GLOBALVP
371                 if (afs_globalVp)
372                     AFS_RELE(AFSTOV(afs_globalVp));
373 #endif
374                 afs_globalVp = tvp;
375                 AFS_HOLD(AFSTOV(afs_globalVp));
376             }
377             AFSTOV(tvp)->v_flag |= VROOT;
378             afs_globalVFS = mp;
379             *vpp = AFSTOV(tvp);
380         } else
381             code = ENOENT;
382     }
383 #ifdef  AFS_GLOBAL_SUNLOCK
384     mutex_exit(&afs_global_lock);
385 #endif
386
387     if (!code)
388         vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curproc); /* return it locked */
389     return code;
390 }
391
392 int
393 afs_statfs(struct osi_vfs *afsp, struct statfs *abp)
394 {
395     AFS_STATCNT(afs_statfs);
396 #ifdef  AFS_GLOBAL_SUNLOCK
397     mutex_enter(&afs_global_lock);
398 #endif
399     abp->f_bsize = afsp->osi_vfs_bsize;
400     /* 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)) */
401     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files = abp->f_ffree  = 9000000; /* XXX */
402     abp->f_fsid.val[0] = AFS_VFSMAGIC; /* magic */
403     abp->f_fsid.val[1] = (int) AFS_VFSFSID;
404 #ifdef  AFS_GLOBAL_SUNLOCK
405     mutex_exit(&afs_global_lock);
406 #endif
407     return 0;
408 }
409
410 int
411 afs_sync(struct osi_vfs *afsp)
412 {
413     AFS_STATCNT(afs_sync);
414 #if defined(AFS_DISCON_ENV) && !defined(AFS_OBSD_ENV)
415     /* Can't do this in OpenBSD 2.7, it faults when called from apm_suspend() */
416     store_dirty_vcaches();
417 #endif
418     return 0;
419 }
420
421 void
422 afs_nbsd_ref(struct vnode *vp)
423 {
424     if (vp->v_usecount == 0) {
425         vprint("holding unheld node", vp);
426         panic("afs_ref");
427     }
428     VREF(vp);
429 }
430
431 void
432 afs_nbsd_rele(struct vnode *vp)
433 {
434     if (vp->v_usecount <= 0) {
435         vprint("rele'ing unheld node", vp);
436         panic("afs_rele");
437     }
438     vrele(vp);
439 }
440
441 int
442 afs_vget(vp, lfl)
443 struct vnode *vp;
444 int lfl;
445 {
446     int error;
447
448     if (vp->v_usecount < 0) {
449         vprint("bad usecount", vp);
450         panic("afs_vget");
451     }
452     error = vget(vp, lfl, curproc);
453     if (!error)
454         insmntque(vp, afs_globalVFS);   /* take off free list */
455     return error;
456 }
457
458 extern struct vfsops afs_vfsops;
459 extern struct vnodeopv_desc afs_vnodeop_opv_desc;
460
461 static struct vfsconf afs_vfsconf = {
462     &afs_vfsops,
463     "afs",
464     0,
465     0,
466     0,
467     NULL,
468     NULL,
469 };
470
471 MOD_VFS("afs", 0, &afs_vfsconf);
472
473 static char afsgenmem[] = "afsgenmem";
474 static char afsfidmem[] = "afsfidmem";
475 static char afsbhdrmem[] = "afsbhdrmem";
476 static char afsbfrmem[] = "afsbfrmem";
477
478 int
479 afsinit()
480 {
481     extern int afs3_syscall(), afs_xioctl(), Afs_xsetgroups(), afs_xflock();
482
483     sysent[AFS_SYSCALL].sy_call = afs3_syscall;
484     sysent[AFS_SYSCALL].sy_narg = 6;
485     sysent[AFS_SYSCALL].sy_argsize = 6 * sizeof(long);
486     sysent[54].sy_call = afs_xioctl;
487     sysent[80].sy_call = Afs_xsetgroups;
488
489     return 0;
490 }
491
492 int
493 afs_vfs_load(struct lkm_table *lkmtp,
494              int cmd)
495 {
496     extern char *memname[];
497
498     vfs_opv_init_explicit(&afs_vnodeop_opv_desc);
499     vfs_opv_init_default(&afs_vnodeop_opv_desc);
500     if (memname[M_AFSGENERIC] == NULL)
501         memname[M_AFSGENERIC] = afsgenmem;
502     if (memname[M_AFSFID] == NULL)
503         memname[M_AFSFID] = afsfidmem;
504     if (memname[M_AFSBUFHDR] == NULL)
505         memname[M_AFSBUFHDR] = afsbhdrmem;
506     if (memname[M_AFSBUFFER] == NULL)
507         memname[M_AFSBUFFER] = afsbfrmem;
508     lkmid = lkmtp->id;
509     printf("OpenAFS ($Revision$) lkm loaded\n");
510     return 0;
511 }
512
513 int
514 afs_vfs_unload(struct lkm_table *lktmp,
515              int cmd)
516 {
517     extern char *memname[];
518     extern int sys_lkmnosys();
519
520     if (afs_globalVp)
521         return EBUSY;
522     if (sysent[SYS_ioctl].sy_call != sys_ioctl)
523         return EBUSY;
524
525     if (memname[M_AFSGENERIC] == afsgenmem)
526         memname[M_AFSGENERIC] = NULL;
527     if (memname[M_AFSFID] == afsfidmem)
528         memname[M_AFSFID] = NULL;
529     if (memname[M_AFSBUFHDR] == afsbhdrmem)
530         memname[M_AFSBUFHDR] = NULL;
531     if (memname[M_AFSBUFFER] == afsbfrmem)
532         memname[M_AFSBUFFER] = NULL;
533
534     sysent[AFS_SYSCALL].sy_call = sys_lkmnosys;
535     printf("OpenAFS unloaded\n");
536     return 0;
537 }
538
539
540
541 int
542 afsmodload(struct lkm_table *lkmtp,
543            int cmd,
544            int ver)
545 {
546     extern int sys_lkmnosys();
547
548     if (cmd == LKM_E_LOAD) {
549         if (strcmp(ostype,afs_NetBSD_osname)) {
550             printf("This is %s version %s\n", ostype, osrelease);
551             printf("This version of AFS is only for %s\n",
552                    afs_NetBSD_osname);
553 /*          return EPROGMISMATCH;*/
554         }
555         if (sysent[AFS_SYSCALL].sy_call != sys_lkmnosys) {
556             printf("AFS must be loaded with syscall %d assigned to sys_lkmnosys\nIs AFS already loaded?\n",
557                    AFS_SYSCALL);
558             return EINVAL;
559         }
560     }
561     DISPATCH(lkmtp,cmd,ver,afs_vfs_load,afs_vfs_unload,lkm_nofunc);
562 }