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