OpenBSD: allow for more graceful shutdown
[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 the OpenAFS 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
97 #include "afs/sysincludes.h"    /* Standard vendor system headers */
98 #include "afs/afsincludes.h"    /* Afs-based standard headers */
99 #include "afs/afs_stats.h"      /* statistics */
100
101 #include <sys/conf.h>
102 #include <sys/exec.h>
103 #include <sys/lkm.h>
104 #include <sys/namei.h>
105 #include <sys/syscall.h>
106 #include <sys/syscallargs.h>
107
108 /* from /usr/src/sys/kern/vfs_subr.c */
109 extern void insmntque(struct vnode *, struct mount *);
110
111 extern int sys_lkmnosys(), afs_xioctl(), Afs_xsetgroups();
112
113 static int lkmid = -1;
114 static int afs_badcall(struct proc *p, void *xx, register_t * yy);
115 static struct sysent old_sysent;
116
117 struct osi_vfs *afs_globalVFS;
118 struct vcache *afs_globalVp;
119
120 int afs_quotactl();
121 int afs_fhtovp();
122 int afs_vptofh();
123 int afsinit();
124 int afs_start();
125 int afs_mount();
126 int afs_unmount();
127 int afs_root();
128 int afs_statfs();
129 int afs_sync();
130 int afs_vget();
131 int afs_sysctl();
132 int afs_checkexp();
133
134 struct vfsops afs_vfsops = {
135     afs_mount,
136     afs_start,
137     afs_unmount,
138     afs_root,
139     afs_quotactl,
140     afs_statfs,
141     afs_sync,
142     afs_vget,
143     afs_fhtovp,
144     afs_vptofh,
145     afsinit,
146     afs_sysctl,
147     afs_checkexp,
148 };
149
150 int
151 afs_nbsd_lookupname(char *fnamep, enum uio_seg segflg, int followlink,
152                     struct vnode **compvpp)
153 {
154     struct nameidata nd;
155     int niflag;
156     int error;
157
158     /*
159      * Lookup pathname "fnamep", returning leaf in *compvpp.  segflg says
160      * whether the pathname is user or system space.
161      */
162     /* XXX LOCKLEAF ? */
163     niflag = followlink ? FOLLOW : NOFOLLOW;
164     NDINIT(&nd, LOOKUP, niflag, segflg, fnamep, osi_curproc());
165     if ((error = namei(&nd)))
166         return error;
167     *compvpp = nd.ni_vp;
168     return error;
169 }
170
171 int
172 afs_quotactl()
173 {
174     return EOPNOTSUPP;
175 }
176
177 int
178 afs_sysctl()
179 {
180     return EOPNOTSUPP;
181 }
182
183 int
184 afs_checkexp()
185 {
186     return EOPNOTSUPP;
187 }
188
189 int
190 afs_fhtovp(mp, fhp, vpp)
191      struct mount *mp;
192      struct fid *fhp;
193      struct vnode **vpp;
194 {
195
196     return (EINVAL);
197 }
198
199 int
200 afs_vptofh(vp, fhp)
201      struct vnode *vp;
202      struct fid *fhp;
203 {
204
205     return (EINVAL);
206 }
207
208 int
209 afs_start(mp, flags, p)
210      struct mount *mp;
211      int flags;
212      struct proc *p;
213 {
214     return (0);                 /* nothing to do. ? */
215 }
216
217 int
218 afs_mount(mp, path, data, ndp, p)
219      register struct mount *mp;
220      char *path;
221      caddr_t data;
222      struct nameidata *ndp;
223      struct proc *p;
224 {
225     /* ndp contains the mounted-from device.  Just ignore it.
226      * we also don't care about our proc struct. */
227     int size;
228
229     if (mp->mnt_flag & MNT_UPDATE)
230         return EINVAL;
231
232     if (afs_globalVFS) {
233         /* Don't allow remounts */
234         return EBUSY;
235     }
236
237     AFS_STATCNT(afs_mount);
238     AFS_GLOCK();
239
240 #ifdef AFS_DISCON_ENV
241     /* initialize the vcache entries before we start using them */
242
243     /* XXX find a better place for this if possible  */
244     init_vcache_entries();
245 #endif
246     afs_globalVFS = mp;
247     mp->osi_vfs_bsize = 8192;
248     mp->osi_vfs_fsid.val[0] = AFS_VFSMAGIC;     /* magic */
249     mp->osi_vfs_fsid.val[1] = (int)AFS_VFSFSID;
250
251     (void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
252     bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
253     bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
254     strcpy(mp->mnt_stat.f_mntfromname, "AFS");
255     /* null terminated string "AFS" will fit, just leave it be. */
256     strcpy(mp->mnt_stat.f_fstypename, MOUNT_AFS);
257     AFS_GUNLOCK();
258     (void)afs_statfs(mp, &mp->mnt_stat);
259
260     return 0;
261 }
262
263 int
264 afs_unmount(afsp, flags, p)
265      struct mount *afsp;
266      int flags;
267      struct proc *p;
268 {
269     extern int sys_ioctl(), sys_setgroups();
270
271     struct vnode *vp;
272
273     for (vp = LIST_FIRST(&afsp->mnt_vnodelist); vp != NULL;
274         vp = LIST_NEXT(vp, v_mntvnodes)) {
275         if (vp->v_usecount) return EBUSY;
276     }
277
278     AFS_STATCNT(afs_unmount);
279 #ifdef AFS_DISCON_ENV
280     give_up_cbs();
281 #endif
282     if (afs_globalVFS == NULL) {
283         printf("afs already unmounted\n");
284         return 0;
285     }
286     if (afs_globalVp)
287         vrele(AFSTOV(afs_globalVp));
288     afs_globalVp = NULL;
289
290     vflush(afsp, NULLVP, 0);    /* don't support forced */
291     afsp->mnt_data = NULL;
292     AFS_GLOCK();
293     afs_globalVFS = 0;
294     afs_cold_shutdown = 1;
295     afs_shutdown();             /* XXX */
296     AFS_GUNLOCK();
297
298     /* give up syscall entries for ioctl & setgroups, which we've stolen */
299     sysent[SYS_ioctl].sy_call = sys_ioctl;
300     sysent[SYS_setgroups].sy_call = sys_setgroups;
301
302     /* give up the stolen syscall entry */
303     sysent[AFS_SYSCALL].sy_narg = 0;
304     sysent[AFS_SYSCALL].sy_argsize = 0;
305     sysent[AFS_SYSCALL].sy_call = afs_badcall;
306     printf
307         ("AFS unmounted--use `/sbin/modunload -i %d' to unload before restarting AFS\n",
308          lkmid);
309     return 0;
310 }
311
312 static int
313 afs_badcall(struct proc *p, void *xx, register_t * yy)
314 {
315     return ENOSYS;
316 }
317
318 void
319 afs_nbsd_getnewvnode(struct vcache *tvc)
320 {
321     while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &tvc->v)) {
322         /* no vnodes available, force an alloc (limits be damned)! */
323         desiredvnodes++;
324     }
325     tvc->v->v_data = (void *)tvc;
326 }
327
328 int
329 afs_root(struct mount *mp, struct vnode **vpp)
330 {
331     struct vrequest treq;
332     struct vcache *tvp;
333     int code;
334
335     AFS_STATCNT(afs_root);
336
337     AFS_GLOCK();
338     if (!(code = afs_InitReq(&treq, osi_curcred()))
339         && !(code = afs_CheckInit())) {
340         tvp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
341         if (tvp) {
342             /* There is really no reason to over-hold this bugger--it's held
343              * by the root filesystem reference. */
344             if (afs_globalVp != tvp) {
345 #ifdef AFS_DONT_OVERHOLD_GLOBALVP
346                 if (afs_globalVp)
347                     AFS_RELE(AFSTOV(afs_globalVp));
348 #endif
349                 afs_globalVp = tvp;
350                 VREF(AFSTOV(afs_globalVp));
351             }
352             AFSTOV(tvp)->v_flag |= VROOT;
353             afs_globalVFS = mp;
354             *vpp = AFSTOV(tvp);
355         } else
356             code = ENOENT;
357     }
358     AFS_GUNLOCK();
359
360     if (!code)
361         vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curproc);        /* return it locked */
362     return code;
363 }
364
365 int
366 afs_statfs(struct osi_vfs *afsp, struct statfs *abp)
367 {
368     AFS_STATCNT(afs_statfs);
369     abp->f_bsize = afsp->osi_vfs_bsize;
370
371     /*
372      * Fake a high number below to satisfy programs that use the ustat (for
373      * * AIX), or statfs (for the rest) call to make sure that there's
374      * enough * space in the device partition before storing something there
375      * (like * ed(1))
376      */
377     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
378         abp->f_ffree = 9000000;
379     abp->f_fsid.val[0] = AFS_VFSMAGIC;  /* magic */
380     abp->f_fsid.val[1] = (int)AFS_VFSFSID;
381     return 0;
382 }
383
384 int
385 afs_sync(struct osi_vfs *afsp)
386 {
387     AFS_STATCNT(afs_sync);
388 #if defined(AFS_DISCON_ENV) && !defined(AFS_OBSD_ENV)
389     /* Can't do this in OpenBSD 2.7, it faults when called from apm_suspend() */
390     store_dirty_vcaches();
391 #endif
392     return 0;
393 }
394
395 int
396 afs_vget(vp, lfl)
397      struct vnode *vp;
398      int lfl;
399 {
400     int error;
401
402     if (vp->v_usecount < 0) {
403         vprint("bad usecount", vp);
404         panic("afs_vget");
405     }
406     error = vget(vp, lfl, curproc);
407     if (!error && vp->v_usecount == 1) {
408         /* vget() took it off the freelist; put it on our mount queue */
409         insmntque(vp, afs_globalVFS);
410     }
411     return error;
412 }
413
414 extern struct vfsops afs_vfsops;
415 extern struct vnodeopv_desc afs_vnodeop_opv_desc;
416
417 static struct vfsconf afs_vfsconf = {
418     &afs_vfsops,
419     "afs",
420     0,
421     0,
422     0,
423     NULL,
424     NULL,
425 };
426
427 MOD_VFS("afs", 0, &afs_vfsconf);
428
429 static char afsgenmem[] = "afsgenmem";
430 static char afsfidmem[] = "afsfidmem";
431 static char afsbhdrmem[] = "afsbhdrmem";
432 static char afsbfrmem[] = "afsbfrmem";
433
434 int
435 afsinit()
436 {
437     old_sysent = sysent[AFS_SYSCALL];
438
439     sysent[AFS_SYSCALL].sy_call = afs3_syscall;
440     sysent[AFS_SYSCALL].sy_narg = 6;
441     sysent[AFS_SYSCALL].sy_argsize = 6 * sizeof(long);
442     sysent[SYS_ioctl].sy_call = afs_xioctl;
443     sysent[SYS_setgroups].sy_call = Afs_xsetgroups;
444     osi_Init();
445
446     return 0;
447 }
448
449 int
450 afs_vfs_load(struct lkm_table *lkmtp, int cmd)
451 {
452     extern char *memname[];
453
454     vfs_opv_init_explicit(&afs_vnodeop_opv_desc);
455     vfs_opv_init_default(&afs_vnodeop_opv_desc);
456     if (memname[M_AFSGENERIC] == NULL)
457         memname[M_AFSGENERIC] = afsgenmem;
458     if (memname[M_AFSFID] == NULL)
459         memname[M_AFSFID] = afsfidmem;
460     if (memname[M_AFSBUFHDR] == NULL)
461         memname[M_AFSBUFHDR] = afsbhdrmem;
462     if (memname[M_AFSBUFFER] == NULL)
463         memname[M_AFSBUFFER] = afsbfrmem;
464     lkmid = lkmtp->id;
465     printf("OpenAFS ($Revision$) lkm loaded\n");
466     return 0;
467 }
468
469 int
470 afs_vfs_unload(struct lkm_table *lktmp, int cmd)
471 {
472     extern char *memname[];
473
474     if (afs_globalVp)
475         return EBUSY;
476     if (sysent[SYS_ioctl].sy_call != sys_ioctl)
477         return EBUSY;
478
479     if (memname[M_AFSGENERIC] == afsgenmem)
480         memname[M_AFSGENERIC] = NULL;
481     if (memname[M_AFSFID] == afsfidmem)
482         memname[M_AFSFID] = NULL;
483     if (memname[M_AFSBUFHDR] == afsbhdrmem)
484         memname[M_AFSBUFHDR] = NULL;
485     if (memname[M_AFSBUFFER] == afsbfrmem)
486         memname[M_AFSBUFFER] = NULL;
487
488     sysent[AFS_SYSCALL] = old_sysent;
489     printf("OpenAFS unloaded\n");
490     return 0;
491 }
492
493 int
494 libafs_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
495 {
496     if (cmd == LKM_E_LOAD) {
497         if (sysent[AFS_SYSCALL].sy_call == afs3_syscall
498             || sysent[AFS_SYSCALL].sy_call == afs_badcall) {
499             printf("AFS already loaded\n");
500             return EINVAL;
501         }
502     }
503     DISPATCH(lkmtp, cmd, ver, afs_vfs_load, afs_vfs_unload, lkm_nofunc);
504 }