| 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_obsd_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 | 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 | /* initialize the vcache entries before we start using them */ |
| 241 | |
| 242 | /* XXX find a better place for this if possible */ |
| 243 | afs_globalVFS = mp; |
| 244 | mp->osi_vfs_bsize = 8192; |
| 245 | mp->osi_vfs_fsid.val[0] = AFS_VFSMAGIC; /* magic */ |
| 246 | mp->osi_vfs_fsid.val[1] = (int)AFS_VFSFSID; |
| 247 | |
| 248 | #if defined(AFS_OBSD53_ENV) |
| 249 | bzero(mp->mnt_stat.f_mntonname, MNAMELEN); |
| 250 | strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN); |
| 251 | #else |
| 252 | (void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); |
| 253 | bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); |
| 254 | #endif |
| 255 | bzero(mp->mnt_stat.f_mntfromname, MNAMELEN); |
| 256 | strcpy(mp->mnt_stat.f_mntfromname, "AFS"); |
| 257 | /* null terminated string "AFS" will fit, just leave it be. */ |
| 258 | strcpy(mp->mnt_stat.f_fstypename, MOUNT_AFS); |
| 259 | AFS_GUNLOCK(); |
| 260 | (void)afs_statfs(mp, &mp->mnt_stat); |
| 261 | |
| 262 | return 0; |
| 263 | } |
| 264 | |
| 265 | int |
| 266 | afs_unmount(afsp, flags, p) |
| 267 | struct mount *afsp; |
| 268 | int flags; |
| 269 | struct proc *p; |
| 270 | { |
| 271 | extern int sys_ioctl(), sys_setgroups(); |
| 272 | |
| 273 | struct vnode *vp; |
| 274 | |
| 275 | for (vp = LIST_FIRST(&afsp->mnt_vnodelist); vp != NULL; |
| 276 | vp = LIST_NEXT(vp, v_mntvnodes)) { |
| 277 | if (vp->v_usecount) return EBUSY; |
| 278 | } |
| 279 | |
| 280 | AFS_STATCNT(afs_unmount); |
| 281 | if (afs_globalVFS == NULL) { |
| 282 | printf("afs already unmounted\n"); |
| 283 | return 0; |
| 284 | } |
| 285 | if (afs_globalVp) |
| 286 | vrele(AFSTOV(afs_globalVp)); |
| 287 | afs_globalVp = NULL; |
| 288 | |
| 289 | vflush(afsp, NULLVP, 0); /* don't support forced */ |
| 290 | afsp->mnt_data = NULL; |
| 291 | AFS_GLOCK(); |
| 292 | afs_globalVFS = 0; |
| 293 | afs_cold_shutdown = 1; |
| 294 | afs_shutdown(); /* XXX */ |
| 295 | AFS_GUNLOCK(); |
| 296 | |
| 297 | /* give up syscall entries for ioctl & setgroups, which we've stolen */ |
| 298 | sysent[SYS_ioctl].sy_call = sys_ioctl; |
| 299 | sysent[SYS_setgroups].sy_call = sys_setgroups; |
| 300 | |
| 301 | /* give up the stolen syscall entry */ |
| 302 | sysent[AFS_SYSCALL].sy_narg = 0; |
| 303 | sysent[AFS_SYSCALL].sy_argsize = 0; |
| 304 | sysent[AFS_SYSCALL].sy_call = afs_badcall; |
| 305 | printf |
| 306 | ("AFS unmounted--use `/sbin/modunload -i %d' to unload before restarting AFS\n", |
| 307 | lkmid); |
| 308 | return 0; |
| 309 | } |
| 310 | |
| 311 | static int |
| 312 | afs_badcall(struct proc *p, void *xx, register_t * yy) |
| 313 | { |
| 314 | return ENOSYS; |
| 315 | } |
| 316 | |
| 317 | #if defined(AFS_OBSD49_ENV) |
| 318 | extern struct vops afs_vops; |
| 319 | #endif |
| 320 | |
| 321 | void |
| 322 | afs_obsd_getnewvnode(struct vcache *tvc) |
| 323 | { |
| 324 | #if defined(AFS_OBSD49_ENV) |
| 325 | while (getnewvnode(VT_AFS, afs_globalVFS, &afs_vops, &tvc->v)) { |
| 326 | #else |
| 327 | while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &tvc->v)) { |
| 328 | #endif |
| 329 | /* no vnodes available, force an alloc (limits be damned)! */ |
| 330 | desiredvnodes++; |
| 331 | } |
| 332 | tvc->v->v_data = (void *)tvc; |
| 333 | } |
| 334 | |
| 335 | int |
| 336 | afs_root(struct mount *mp, struct vnode **vpp) |
| 337 | { |
| 338 | struct vrequest treq; |
| 339 | struct vcache *tvp; |
| 340 | int code; |
| 341 | |
| 342 | AFS_STATCNT(afs_root); |
| 343 | |
| 344 | AFS_GLOCK(); |
| 345 | if (!(code = afs_InitReq(&treq, osi_curcred())) |
| 346 | && !(code = afs_CheckInit())) { |
| 347 | tvp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL); |
| 348 | if (tvp) { |
| 349 | /* There is really no reason to over-hold this bugger--it's held |
| 350 | * by the root filesystem reference. */ |
| 351 | if (afs_globalVp != tvp) { |
| 352 | #ifdef AFS_DONT_OVERHOLD_GLOBALVP |
| 353 | if (afs_globalVp) |
| 354 | AFS_RELE(AFSTOV(afs_globalVp)); |
| 355 | #endif |
| 356 | afs_globalVp = tvp; |
| 357 | vref(AFSTOV(afs_globalVp)); |
| 358 | } |
| 359 | AFSTOV(tvp)->v_flag |= VROOT; |
| 360 | afs_globalVFS = mp; |
| 361 | *vpp = AFSTOV(tvp); |
| 362 | } else |
| 363 | code = EIO; |
| 364 | } |
| 365 | AFS_GUNLOCK(); |
| 366 | |
| 367 | if (!code) |
| 368 | vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curproc); /* return it locked */ |
| 369 | return code; |
| 370 | } |
| 371 | |
| 372 | int |
| 373 | afs_statfs(struct osi_vfs *afsp, struct statfs *abp) |
| 374 | { |
| 375 | AFS_STATCNT(afs_statfs); |
| 376 | abp->f_bsize = afsp->osi_vfs_bsize; |
| 377 | |
| 378 | abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files = |
| 379 | abp->f_ffree = AFS_VFS_FAKEFREE; |
| 380 | abp->f_fsid.val[0] = AFS_VFSMAGIC; /* magic */ |
| 381 | abp->f_fsid.val[1] = (int)AFS_VFSFSID; |
| 382 | return 0; |
| 383 | } |
| 384 | |
| 385 | int |
| 386 | afs_sync(struct osi_vfs *afsp) |
| 387 | { |
| 388 | AFS_STATCNT(afs_sync); |
| 389 | return 0; |
| 390 | } |
| 391 | |
| 392 | int |
| 393 | afs_vget(vp, lfl) |
| 394 | struct vnode *vp; |
| 395 | int lfl; |
| 396 | { |
| 397 | int error; |
| 398 | |
| 399 | if (vp->v_usecount < 0) { |
| 400 | vprint("bad usecount", vp); |
| 401 | panic("afs_vget"); |
| 402 | } |
| 403 | error = vget(vp, lfl, curproc); |
| 404 | if (!error && vp->v_usecount == 1) { |
| 405 | /* vget() took it off the freelist; put it on our mount queue */ |
| 406 | insmntque(vp, afs_globalVFS); |
| 407 | } |
| 408 | return error; |
| 409 | } |
| 410 | |
| 411 | extern struct vfsops afs_vfsops; |
| 412 | extern struct vnodeopv_desc afs_vnodeop_opv_desc; |
| 413 | |
| 414 | static struct vfsconf afs_vfsconf = { |
| 415 | &afs_vfsops, |
| 416 | "afs", |
| 417 | 0, |
| 418 | 0, |
| 419 | 0, |
| 420 | NULL, |
| 421 | NULL, |
| 422 | }; |
| 423 | |
| 424 | MOD_VFS("afs", 0, &afs_vfsconf); |
| 425 | |
| 426 | static char afsgenmem[] = "afsgenmem"; |
| 427 | static char afsfidmem[] = "afsfidmem"; |
| 428 | static char afsbhdrmem[] = "afsbhdrmem"; |
| 429 | static char afsbfrmem[] = "afsbfrmem"; |
| 430 | |
| 431 | int |
| 432 | afsinit() |
| 433 | { |
| 434 | old_sysent = sysent[AFS_SYSCALL]; |
| 435 | |
| 436 | sysent[AFS_SYSCALL].sy_call = afs3_syscall; |
| 437 | sysent[AFS_SYSCALL].sy_narg = 6; |
| 438 | sysent[AFS_SYSCALL].sy_argsize = 6 * sizeof(long); |
| 439 | sysent[SYS_ioctl].sy_call = afs_xioctl; |
| 440 | sysent[SYS_setgroups].sy_call = Afs_xsetgroups; |
| 441 | osi_Init(); |
| 442 | |
| 443 | return 0; |
| 444 | } |
| 445 | |
| 446 | int |
| 447 | afs_vfs_load(struct lkm_table *lkmtp, int cmd) |
| 448 | { |
| 449 | extern char *memname[]; |
| 450 | |
| 451 | #if ! defined(AFS_OBSD49_ENV) |
| 452 | vfs_opv_init_explicit(&afs_vnodeop_opv_desc); |
| 453 | vfs_opv_init_default(&afs_vnodeop_opv_desc); |
| 454 | #endif |
| 455 | if (memname[M_AFSGENERIC] == NULL) |
| 456 | memname[M_AFSGENERIC] = afsgenmem; |
| 457 | if (memname[M_AFSFID] == NULL) |
| 458 | memname[M_AFSFID] = afsfidmem; |
| 459 | if (memname[M_AFSBUFHDR] == NULL) |
| 460 | memname[M_AFSBUFHDR] = afsbhdrmem; |
| 461 | if (memname[M_AFSBUFFER] == NULL) |
| 462 | memname[M_AFSBUFFER] = afsbfrmem; |
| 463 | lkmid = lkmtp->id; |
| 464 | printf("OpenAFS ($Revision$) lkm loaded\n"); |
| 465 | return 0; |
| 466 | } |
| 467 | |
| 468 | int |
| 469 | afs_vfs_unload(struct lkm_table *lktmp, int cmd) |
| 470 | { |
| 471 | extern char *memname[]; |
| 472 | |
| 473 | if (afs_globalVp) |
| 474 | return EBUSY; |
| 475 | if (sysent[SYS_ioctl].sy_call != sys_ioctl) |
| 476 | return EBUSY; |
| 477 | |
| 478 | if (memname[M_AFSGENERIC] == afsgenmem) |
| 479 | memname[M_AFSGENERIC] = NULL; |
| 480 | if (memname[M_AFSFID] == afsfidmem) |
| 481 | memname[M_AFSFID] = NULL; |
| 482 | if (memname[M_AFSBUFHDR] == afsbhdrmem) |
| 483 | memname[M_AFSBUFHDR] = NULL; |
| 484 | if (memname[M_AFSBUFFER] == afsbfrmem) |
| 485 | memname[M_AFSBUFFER] = NULL; |
| 486 | |
| 487 | sysent[AFS_SYSCALL] = old_sysent; |
| 488 | printf("OpenAFS unloaded\n"); |
| 489 | return 0; |
| 490 | } |
| 491 | |
| 492 | int |
| 493 | libafs_lkmentry(struct lkm_table *lkmtp, int cmd, int ver) |
| 494 | { |
| 495 | if (cmd == LKM_E_LOAD) { |
| 496 | if (sysent[AFS_SYSCALL].sy_call == afs3_syscall |
| 497 | || sysent[AFS_SYSCALL].sy_call == afs_badcall) { |
| 498 | printf("AFS already loaded\n"); |
| 499 | return EINVAL; |
| 500 | } |
| 501 | } |
| 502 | DISPATCH(lkmtp, cmd, ver, afs_vfs_load, afs_vfs_unload, lkm_nofunc); |
| 503 | } |