a52629b732ed3650bb89c4e10dcbed4e8da80c03
[openafs.git] / src / afs / NBSD / 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  * Reported to NetBSD 4.0 by Matt Benjamin (matt@linuxbox.com)
6  *
7  * $Id: osi_vfsops.c,v 1.20 2005/03/08 21:58:04 shadow Exp $
8  */
9
10 /*
11 copyright 2002
12 the regents of the university of michigan
13 all rights reserved
14
15 permission is granted to use, copy, create derivative works
16 and redistribute this software and such derivative works
17 for any purpose, so long as the name of the university of
18 michigan is not used in any advertising or publicity
19 pertaining to the use or distribution of this software
20 without specific, written prior authorization.  if the
21 above copyright notice or any other identification of the
22 university of michigan is included in any copy of any
23 portion of this software, then the disclaimer below must
24 also be included.
25
26 this software is provided as is, without representation
27 from the university of michigan as to its fitness for any
28 purpose, and without warranty by the university of
29 michigan of any kind, either express or implied, including
30 without limitation the implied warranties of
31 merchantability and fitness for a particular purpose. the
32 regents of the university of michigan shall not be liable
33 for any damages, including special, indirect, incidental, or
34 consequential damages, with respect to any claim arising
35 out of or in connection with the use of the software, even
36 if it has been or is hereafter advised of the possibility of
37 such damages.
38 */
39
40 /*
41 Copyright 1995 Massachusetts Institute of Technology.  All Rights
42 Reserved.
43
44 You are hereby granted a worldwide, irrevocable, paid-up, right and
45 license to use, execute, display, modify, copy and distribute MIT's
46 Modifications, provided that (i) you abide by the terms and conditions
47 of the OpenAFS License Agreement, and (ii) you do not use the name
48 of MIT in any advertising or publicity without the prior written consent
49 of MIT.  MIT disclaims all liability for your use of MIT's
50 Modifications.  MIT's Modifications are provided "AS IS" WITHOUT
51 WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO,
52 ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
53 NONINFRINGEMENT.
54 */
55
56 /*
57  * Some code cribbed from ffs_vfsops and other NetBSD sources, which
58  * are marked:
59  */
60 /*
61  * Copyright (c) 1989, 1991, 1993, 1994
62  *      The Regents of the University of California.  All rights reserved.
63  *
64  * Redistribution and use in source and binary forms, with or without
65  * modification, are permitted provided that the following conditions
66  * are met:
67  * 1. Redistributions of source code must retain the above copyright
68  *    notice, this list of conditions and the following disclaimer.
69  * 2. Redistributions in binary form must reproduce the above copyright
70  *    notice, this list of conditions and the following disclaimer in the
71  *    documentation and/or other materials provided with the distribution.
72  * 3. All advertising materials mentioning features or use of this software
73  *    must display the following acknowledgement:
74  *      This product includes software developed by the University of
75  *      California, Berkeley and its contributors.
76  * 4. Neither the name of the University nor the names of its contributors
77  *    may be used to endorse or promote products derived from this software
78  *    without specific prior written permission.
79  *
80  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
81  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
82  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
83  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
84  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
85  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
86  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
87  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
88  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
89  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
90  * SUCH DAMAGE.
91  *
92  */
93
94 #include <afsconfig.h>
95 #include "afs/param.h"
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/ioctl.h>
102 #ifndef AFS_NBSD60_ENV
103 #include <sys/lkm.h>
104 #endif
105 #include <sys/namei.h>
106 #include <miscfs/genfs/genfs.h>
107
108 VFS_PROTOS(afs);
109
110 #ifndef AFS_NBSD60_ENV
111 extern int sys_lkmnosys(struct lwp *, const void *, register_t *);
112 extern int afs3_syscall(struct lwp *, const void *, register_t *);
113 extern int afs_xioctl(struct lwp *, const void *, register_t *);
114 extern int Afs_xsetgroups(struct lwp *, const void *, register_t *);
115 static int afs_badcall(struct lwp *, const void *, register_t *);
116
117 static int lkmid = -1;
118
119 struct sysent afs_sysent = { 6,
120                              sizeof(struct afs_sysargs),
121                              0,
122                              afs3_syscall};
123
124 static struct sysent old_sysent;
125 static struct sysent old_setgroups;
126 #endif
127
128 struct osi_vfs *afs_globalVFS;
129 struct vcache *afs_globalVp;
130 fsid_t afs_dynamic_fsid;
131
132 int afs_mount(struct mount *, const char *, void *, size_t *);
133 int afs_start(struct mount *, int);
134 int afs_unmount(struct mount *, int);
135 int afs_root(struct mount *, struct vnode **);
136 int afs_statvfs(struct mount *, struct statvfs *);
137 int afs_sync(struct mount *, int, kauth_cred_t);
138 void afs_init(void);
139 void afs_reinit(void);
140 void afs_done(void);
141
142 extern struct vnodeopv_desc afs_vnodeop_opv_desc;
143 static const struct vnodeopv_desc *afs_vnodeopv_descs[] = {
144         &afs_vnodeop_opv_desc,
145         NULL,
146 };
147
148 struct vfsops afs_vfsops = {
149     AFS_MOUNT_AFS,
150 #ifdef AFS_NBSD50_ENV
151         0,                                              /* vfs_min_mount_data */
152 #endif
153     afs_mount,
154     afs_start,
155     afs_unmount,
156     afs_root,
157     (void *) eopnotsupp,        /* vfs_quotactl */
158     afs_statvfs,
159     afs_sync,
160     (void *) eopnotsupp,        /* vfs_vget */
161     (void *) eopnotsupp,        /* vfs_fhtovp */
162     (void *) eopnotsupp,        /* vfs_vptofh */
163     afs_init,
164     afs_reinit,
165     afs_done,
166     (void *) eopnotsupp,        /* vfs_mountroot */
167     (void *) eopnotsupp,        /* vfs_snapshot */
168     vfs_stdextattrctl,
169 #ifdef AFS_NBSD50_ENV
170     (void *) eopnotsupp,        /* vfs_suspendctl */
171     genfs_renamelock_enter,     /* vfs_renamelock_enter */
172     genfs_renamelock_exit,      /* vfs_renamelock_exit */
173     (void *) eopnotsupp,        /* vfs_fsync */
174 #endif
175     afs_vnodeopv_descs,
176     0,                          /* vfs_refcount */
177     { NULL, NULL },
178 };
179
180 int
181 afs_nbsd_lookupname(const char *fnamep, enum uio_seg segflg, int followlink,
182                     struct vnode **compvpp)
183 {
184     struct nameidata nd;
185     int niflag;
186     int error;
187
188     if ((afs_debug & AFSDEB_VNLAYER) != 0) {
189         afs_warn("afs_nbsd_lookupname enter (%s)\n", fnamep);
190     }
191
192     /*
193      * Lookup pathname "fnamep", returning leaf in *compvpp.  segflg says
194      * whether the pathname is user or system space.
195      */
196     /* XXX LOCKLEAF ? */
197     niflag = followlink ? FOLLOW : NOFOLLOW;
198         /*
199         *       NBSD50 seems to have stopped caring about the curproc of things.
200         *       mattjsm
201         */
202 #if defined(AFS_NBSD60_ENV)
203     struct pathbuf *ipb = NULL;
204     ipb = pathbuf_create(fnamep);
205     NDINIT(&nd, LOOKUP, niflag, ipb);
206 #elif defined(AFS_NBSD50_ENV)
207     NDINIT(&nd, LOOKUP, niflag, segflg, fnamep);
208 #else
209     NDINIT(&nd, LOOKUP, niflag, segflg, fnamep, osi_curproc());
210 #endif
211     if ((error = namei(&nd))) {
212         goto out;
213     }
214     *compvpp = nd.ni_vp;
215 out:
216 #if defined(AFS_NBSD60_ENV)
217     pathbuf_destroy(ipb);
218 #endif
219     return error;
220 }
221
222 int
223 afs_start(struct mount *mp, int flags)
224 {
225     return (0); /* nothing to do? */
226 }
227
228 void afs_done(void)
229 {
230     return; /* nothing to do? */
231 }
232
233 int
234 afs_mount(struct mount *mp, const char *path, void *data,
235           size_t *dlen)
236 {
237     /* ndp contains the mounted-from device.  Just ignore it.
238      * we also don't care about our proc struct. */
239     size_t size;
240
241     AFS_STATCNT(afs_mount);
242
243     if ((afs_debug & AFSDEB_VNLAYER) != 0) {
244         afs_warn("afs_mount enter\n");
245     }
246
247     if (mp->mnt_flag & MNT_UPDATE)
248         return EINVAL;
249
250     if (afs_globalVFS != NULL) {
251         /* Don't allow remounts */
252         return EBUSY;
253     }
254
255     AFS_GLOCK();
256 #ifdef AFS_DISCON_ENV
257     /* initialize the vcache entries before we start using them */
258
259     /* XXX find a better place for this if possible  */
260     init_vcache_entries();
261 #endif
262     afs_globalVFS = mp;
263     mp->mnt_stat.f_bsize = 8192;
264     mp->mnt_stat.f_frsize = 8192;
265     mp->mnt_stat.f_iosize = 8192;
266     mp->mnt_fs_bshift = DEV_BSHIFT;
267     mp->mnt_dev_bshift = DEV_BSHIFT;
268     vfs_getnewfsid(mp);
269     afs_dynamic_fsid = mp->mnt_stat.f_fsidx;
270     (void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1,
271                     &size);
272     memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size);
273     memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
274     strcpy(mp->mnt_stat.f_mntfromname, "AFS");
275     /* null terminated string "AFS" will fit, just leave it be. */
276     strcpy(mp->mnt_stat.f_fstypename, AFS_MOUNT_AFS);
277     AFS_GUNLOCK();
278     (void)afs_statvfs(mp, &mp->mnt_stat);
279
280     if ((afs_debug & AFSDEB_VNLAYER) != 0) {
281         afs_warn("afs_mount exit\n");
282     }
283
284     return 0;
285 }
286
287 int
288 afs_unmount(struct mount *mp, int mntflags)
289 {
290     AFS_STATCNT(afs_unmount);
291 #ifdef AFS_DISCON_ENV
292     give_up_cbs();
293 #endif
294     if (afs_globalVFS == NULL) {
295         printf("afs already unmounted\n");
296         return 0;
297     }
298     if (afs_globalVp)
299         vrele(AFSTOV(afs_globalVp));
300     afs_globalVp = NULL;
301
302     vflush(mp, NULLVP, 0);      /* don't support forced */
303     AFS_GLOCK();
304     afs_globalVFS = NULL;
305     afs_cold_shutdown = 1;
306     afs_shutdown();             /* XXX */
307     AFS_GUNLOCK();
308
309     mp->mnt_data = NULL;
310
311     printf("AFS unmounted.\n");
312     return 0;
313 }
314
315 #ifndef AFS_NBSD60_ENV
316 static int
317 afs_badcall(struct lwp *l, const void *xx, register_t *yy)
318 {
319     return ENOSYS;
320 }
321 #endif
322
323 int
324 afs_root(struct mount *mp, struct vnode **vpp)
325 {
326     struct vrequest treq;
327     struct vcache *tvp;
328     struct vcache *gvp;
329     int code;
330
331     AFS_STATCNT(afs_root);
332
333     if ((afs_debug & AFSDEB_VNLAYER) != 0) {
334         int glocked = ISAFS_GLOCK();
335         afs_warn("afs_root enter, glocked==%d\n", glocked);
336     }
337
338     AFS_GLOCK();
339
340     if ((afs_debug & AFSDEB_VNLAYER) != 0) {
341         afs_warn("afs_root: glocked\n");
342     }
343
344     tvp = NULL;
345 tryagain:
346     if (afs_globalVp && (afs_globalVp->f.states & CStatd)) {
347         tvp = afs_globalVp;
348         code = 0;
349     } else {
350         if (afs_globalVp) {
351             gvp = afs_globalVp;
352             afs_globalVp = NULL;
353             afs_PutVCache(gvp);
354         }
355
356         if (!(code = afs_InitReq(&treq, osi_curcred()))
357             && !(code = afs_CheckInit())) {
358             tvp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
359
360             if (tvp) {
361                 if (afs_globalVp) {
362
363                     afs_PutVCache(tvp);
364                     tvp = NULL;
365                     goto tryagain;
366                 }
367                 afs_globalVp = tvp;
368             } else
369                 code = EIO;
370         }
371     }
372     if (tvp) {
373         struct vnode *vp = AFSTOV(tvp);
374         AFS_GUNLOCK();
375         vref(vp);
376         if (code != 0) {
377                 vrele(vp);
378                 return code;
379         }
380         if (!VOP_ISLOCKED(*vpp))
381             code = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
382         AFS_GLOCK();
383         if (!afs_globalVp || !(afs_globalVp->f.states & CStatd) ||
384             tvp != afs_globalVp) {
385             vput(vp);
386             afs_PutVCache(tvp);
387             tvp = NULL;
388             goto tryagain;
389         }
390         if (code != 0)
391             goto tryagain;
392         vp->v_vflag |= VV_ROOT;
393         if (afs_globalVFS != mp)
394             afs_globalVFS = mp;
395         *vpp = vp;
396     }
397     AFS_GUNLOCK();
398
399     if ((afs_debug & AFSDEB_VNLAYER) != 0) {
400         afs_warn("afs_root exit\n");
401     }
402
403     return code;
404 }
405
406 int
407 afs_statvfs(struct mount *mp, struct statvfs *abp)
408 {
409     AFS_STATCNT(afs_statfs);
410
411     if ((afs_debug & AFSDEB_VNLAYER) != 0) {
412         afs_warn("afs_statvfs enter\n");
413     }
414
415     /* thank you, NetBSD */
416     copy_statvfs_info(abp, mp);
417
418     /* not actually sure which we really must set, but
419      * pretty sure of the right values (and in 40, none touched by
420      * the above convenience function) */
421     abp->f_bsize = mp->osi_vfs_bsize;
422     abp->f_frsize = mp->osi_vfs_bsize;
423     abp->f_iosize = mp->osi_vfs_bsize;
424
425     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
426         abp->f_ffree = AFS_VFS_FAKEFREE;
427
428     return (0);
429 }
430
431 int
432 afs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
433 {
434     AFS_STATCNT(afs_sync);
435 #if defined(AFS_DISCON_ENV)
436     /* Can't do this in OpenBSD 2.7, it faults when called from apm_suspend() */
437     store_dirty_vcaches();
438 #endif
439     return 0;
440 }
441
442 void
443 afs_init(void)
444 {
445     osi_Init();
446     return;
447 }
448
449 void
450 afs_reinit(void)
451 {
452     return;
453 }
454
455 #ifndef AFS_NBSD60_ENV
456 /* LKM */
457
458 /*
459  * declare the filesystem
460  */
461 MOD_VFS("afs", -1, &afs_vfsops);
462
463 static int
464 afs_vfs_load(struct lkm_table *lkmtp, int cmd)
465 {
466     lkmid = lkmtp->id;
467     if (sysent[AFS_SYSCALL].sy_call != sys_lkmnosys) {
468         printf("LKM afs_vfs_load(): AFS3 syscall %d already used\n",
469             AFS_SYSCALL);
470         /* return EEXIST; */
471     }
472
473     old_sysent = sysent[AFS_SYSCALL];
474     sysent[AFS_SYSCALL] = afs_sysent;
475     old_setgroups = sysent[SYS_setgroups];
476     sysent[SYS_setgroups].sy_call = Afs_xsetgroups;
477 #if NOTYET
478     old_ioctl = sysent[SYS_ioctl];
479     sysent[SYS_ioctl].sy_call = afs_xioctl;
480 #endif
481
482     aprint_verbose("OpenAFS loaded\n");
483
484     return (0);
485 }
486
487 static int
488 afs_vfs_unload(struct lkm_table *lktmp, int cmd)
489 {
490     if (afs_globalVp)
491         return EBUSY;
492
493     if (sysent[AFS_SYSCALL].sy_call != afs_sysent.sy_call) {
494         printf("LKM afs_vfs_load(): AFS3 syscall %d already used\n",
495                AFS_SYSCALL);
496         return EEXIST;
497     }
498
499     sysent[AFS_SYSCALL] = old_sysent;
500     sysent[SYS_setgroups] = old_setgroups;
501 #if NOTYET
502     sysent[SYS_ioctl] = old_ioctl;
503 #endif
504     printf("OpenAFS unloaded\n");
505
506     return (0);
507 }
508
509 int libafs_lkmentry(struct lkm_table *, int, int);
510
511 int
512 libafs_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
513 {
514     if (cmd == LKM_E_LOAD) {
515         if (sysent[AFS_SYSCALL].sy_call == afs3_syscall
516             || sysent[AFS_SYSCALL].sy_call == afs_badcall) {
517             printf("AFS already loaded\n");
518             return EINVAL;
519         }
520     }
521
522     DISPATCH(lkmtp, cmd, ver, afs_vfs_load, afs_vfs_unload, lkm_nofunc);
523 }
524 #endif