b45ba6cfb54efbd93ab1b0407bcc359a5e9b7c1a
[openafs.git] / src / afs / OBSD / osi_vnodeops.c
1 /*
2  * OpenBSD specific vnodeops + other misc interface glue
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 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  * A bunch of code cribbed from NetBSD ufs_vnops.c, ffs_vnops.c, and
57  * nfs_vnops.c which carry this copyright:
58  */
59 /*
60  * Copyright (c) 1982, 1986, 1989, 1993
61  *      The Regents of the University of California.  All rights reserved.
62  * (c) UNIX System Laboratories, Inc.
63  * All or some portions of this file are derived from material licensed
64  * to the University of California by American Telephone and Telegraph
65  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
66  * the permission of UNIX System Laboratories, Inc.
67  *
68  * Redistribution and use in source and binary forms, with or without
69  * modification, are permitted provided that the following conditions
70  * are met:
71  * 1. Redistributions of source code must retain the above copyright
72  *    notice, this list of conditions and the following disclaimer.
73  * 2. Redistributions in binary form must reproduce the above copyright
74  *    notice, this list of conditions and the following disclaimer in the
75  *    documentation and/or other materials provided with the distribution.
76  * 3. All advertising materials mentioning features or use of this software
77  *    must display the following acknowledgement:
78  *      This product includes software developed by the University of
79  *      California, Berkeley and its contributors.
80  * 4. Neither the name of the University nor the names of its contributors
81  *    may be used to endorse or promote products derived from this software
82  *    without specific prior written permission.
83  *
84  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
85  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
88  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94  * SUCH DAMAGE.
95  *
96  */
97
98 #include <afsconfig.h>
99 #include "afs/param.h"
100
101
102 #include "afs/sysincludes.h"    /* Standard vendor system headers */
103 #include "afs/afsincludes.h"    /* Afs-based standard headers */
104 #include "afs/afs_stats.h"      /* statistics */
105
106 #include <sys/malloc.h>
107 #include <sys/namei.h>
108 #ifdef AFS_OBSD36_ENV
109 #include <sys/pool.h>
110 #endif
111
112 #include "afs/afs_cbqueue.h"
113 #include "afs/nfsclient.h"
114 #include "afs/afs_osidnlc.h"
115
116 #define M_AFSNODE (M_TEMP-1)    /* XXX */
117
118 int afs_obsd_lookup(void *);
119 int afs_obsd_create(void *);
120 int afs_obsd_mknod(void *);
121 int afs_obsd_open(void *);
122 int afs_obsd_close(void *);
123 int afs_obsd_access(void *);
124 int afs_obsd_getattr(void *);
125 int afs_obsd_setattr(void *);
126 int afs_obsd_read(void *);
127 int afs_obsd_write(void *);
128 int afs_obsd_ioctl(void *);
129 int afs_obsd_select(void *);
130 int afs_obsd_fsync(void *);
131 int afs_obsd_remove(void *);
132 int afs_obsd_link(void *);
133 int afs_obsd_rename(void *);
134 int afs_obsd_mkdir(void *);
135 int afs_obsd_rmdir(void *);
136 int afs_obsd_symlink(void *);
137 int afs_obsd_readdir(void *);
138 int afs_obsd_readlink(void *);
139 int afs_obsd_inactive(void *);
140 int afs_obsd_reclaim(void *);
141 int afs_obsd_lock(void *);
142 int afs_obsd_unlock(void *);
143 int afs_obsd_bmap(void *);
144 int afs_obsd_strategy(void *);
145 int afs_obsd_print(void *);
146 int afs_obsd_islocked(void *);
147 int afs_obsd_pathconf(void *);
148 int afs_obsd_advlock(void *);
149
150 #define afs_obsd_opnotsupp \
151         ((int (*) __P((void *)))eopnotsupp)
152 #define afs_obsd_reallocblks afs_obsd_opnotsupp
153
154 /* Global vfs data structures for AFS. */
155 int (**afs_vnodeop_p) __P((void *));
156 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
157 #ifdef AFS_OBSD44_ENV /* feel free to zero in on this */
158   {&vop_default_desc, eopnotsupp},
159 #else
160     {&vop_default_desc, vn_default_error},
161 #endif
162     {&vop_lookup_desc, afs_obsd_lookup},        /* lookup */
163     {&vop_create_desc, afs_obsd_create},        /* create */
164     {&vop_mknod_desc, afs_obsd_mknod},          /* mknod */
165     {&vop_open_desc, afs_obsd_open},            /* open */
166     {&vop_close_desc, afs_obsd_close},          /* close */
167     {&vop_access_desc, afs_obsd_access},        /* access */
168     {&vop_getattr_desc, afs_obsd_getattr},      /* getattr */
169     {&vop_setattr_desc, afs_obsd_setattr},      /* setattr */
170     {&vop_read_desc, afs_obsd_read},            /* read */
171     {&vop_write_desc, afs_obsd_write},          /* write */
172     {&vop_ioctl_desc, afs_obsd_ioctl},          /* XXX ioctl */
173 #ifdef AFS_OBSD35_ENV
174     {&vop_poll_desc, afs_obsd_select},          /* select */
175 #else
176     {&vop_select_desc, afs_obsd_select},        /* select */
177 #endif
178     {&vop_fsync_desc, afs_obsd_fsync},          /* fsync */
179     {&vop_remove_desc, afs_obsd_remove},        /* remove */
180     {&vop_link_desc, afs_obsd_link},            /* link */
181     {&vop_rename_desc, afs_obsd_rename},        /* rename */
182     {&vop_mkdir_desc, afs_obsd_mkdir},          /* mkdir */
183     {&vop_rmdir_desc, afs_obsd_rmdir},          /* rmdir */
184     {&vop_symlink_desc, afs_obsd_symlink},      /* symlink */
185     {&vop_readdir_desc, afs_obsd_readdir},      /* readdir */
186     {&vop_readlink_desc, afs_obsd_readlink},    /* readlink */
187     {&vop_abortop_desc, vop_generic_abortop},   /* abortop */
188     {&vop_inactive_desc, afs_obsd_inactive},    /* inactive */
189     {&vop_reclaim_desc, afs_obsd_reclaim},      /* reclaim */
190     {&vop_lock_desc, afs_obsd_lock},            /* lock */
191     {&vop_unlock_desc, afs_obsd_unlock},        /* unlock */
192     {&vop_bmap_desc, afs_obsd_bmap},            /* bmap */
193     {&vop_strategy_desc, afs_obsd_strategy},    /* strategy */
194     {&vop_print_desc, afs_obsd_print},          /* print */
195     {&vop_islocked_desc, afs_obsd_islocked},    /* islocked */
196     {&vop_pathconf_desc, afs_obsd_pathconf},    /* pathconf */
197     {&vop_advlock_desc, afs_obsd_advlock},      /* advlock */
198     {&vop_reallocblks_desc, afs_obsd_reallocblks},      /* reallocblks */
199     {&vop_bwrite_desc, vop_generic_bwrite},
200     {(struct vnodeop_desc *)NULL, (int (*)__P((void *)))NULL}
201 };
202 struct vnodeopv_desc afs_vnodeop_opv_desc =
203     { &afs_vnodeop_p, afs_vnodeop_entries };
204
205 #define GETNAME()       \
206     struct componentname *cnp = ap->a_cnp; \
207     char *name; \
208     BSD_KMALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
209     bcopy(cnp->cn_nameptr, name, cnp->cn_namelen); \
210     name[cnp->cn_namelen] = '\0'
211
212 #define DROPNAME() BSD_KFREE(name, M_TEMP)
213
214 #ifdef AFS_OBSD36_ENV
215 #define DROPCNP(cnp) pool_put(&namei_pool, (cnp)->cn_pnbuf)
216 #else
217 #define DROPCNP(cnp) FREE((cnp)->cn_pnbuf, M_NAMEI)
218 #endif
219
220 int afs_debug;
221
222 int
223 afs_obsd_lookup(void *v)
224 {
225     struct vop_lookup_args      /* {
226                                  * struct vnodeop_desc * a_desc;
227                                  * struct vnode *a_dvp;
228                                  * struct vnode **a_vpp;
229                                  * struct componentname *a_cnp;
230                                  * } */ *ap = v;
231     int code;
232     struct vcache *vcp;
233     struct vnode *vp, *dvp;
234     int flags = ap->a_cnp->cn_flags;
235     int lockparent;             /* 1 => lockparent flag is set */
236     int wantparent;             /* 1 => wantparent or lockparent flag */
237
238     GETNAME();
239     lockparent = flags & LOCKPARENT;
240     wantparent = flags & (LOCKPARENT | WANTPARENT);
241 #ifdef PDIRUNLOCK
242     cnp->cn_flags &= ~PDIRUNLOCK;
243 #endif
244
245     if (ap->a_dvp->v_type != VDIR) {
246         *ap->a_vpp = NULL;
247         DROPNAME();
248         return ENOTDIR;
249     }
250     dvp = ap->a_dvp;
251     if (afs_debug & AFSDEB_VNLAYER && !(dvp->v_flag & VROOT))
252         printf("nbsd_lookup dvp %p flags %x name %s cnt %d\n", dvp, flags,
253                name, dvp->v_usecount);
254     AFS_GLOCK();
255     code = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
256     AFS_GUNLOCK();
257     if (code) {
258         if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
259             && (flags & ISLASTCN) && code == ENOENT)
260             code = EJUSTRETURN;
261         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
262             cnp->cn_flags |= SAVENAME;
263         DROPNAME();
264         *ap->a_vpp = NULL;
265         return (code);
266     }
267     vp = AFSTOV(vcp);           /* always get a node if no error */
268
269     /*
270      * The parent directory comes in locked.  We unlock it on return
271      * unless the caller wants it left locked.
272      * we also always return the vnode locked.
273      */
274
275     if (vp == dvp) {
276         /* they're the same; afs_lookup() already ref'ed the leaf.
277          * It came in locked, so we don't need to ref OR lock it */
278         if (afs_debug & AFSDEB_VNLAYER)
279             printf("ref'ed %p as .\n", dvp);
280     } else {
281         if (!lockparent || !(flags & ISLASTCN)) {
282             VOP_UNLOCK(dvp, 0, curproc);        /* done with parent. */
283 #ifdef PDIRUNLOCK
284             cnp->cn_flags |= PDIRUNLOCK;
285 #endif
286         }
287         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc);  /* always return the child locked */
288         if (afs_debug & AFSDEB_VNLAYER)
289             printf("locked ret %p from lookup\n", vp);
290     }
291     *ap->a_vpp = vp;
292
293     if (((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN))
294          || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
295         cnp->cn_flags |= SAVENAME;
296
297     DROPNAME();
298     if (afs_debug & AFSDEB_VNLAYER && !(dvp->v_flag & VROOT))
299         printf("nbsd_lookup done dvp %p cnt %d\n", dvp, dvp->v_usecount);
300     return code;
301 }
302
303 int
304 afs_obsd_create(void *v)
305 {
306     struct vop_create_args      /* {
307                                  * struct vnode *a_dvp;
308                                  * struct vnode **a_vpp;
309                                  * struct componentname *a_cnp;
310                                  * struct vattr *a_vap;
311                                  * } */ *ap = v;
312     int code = 0;
313     struct vcache *vcp;
314     struct vnode *dvp = ap->a_dvp;
315     GETNAME();
316
317     if (afs_debug & AFSDEB_VNLAYER)
318         printf("nbsd_create dvp %p cnt %d\n", dvp, dvp->v_usecount);
319
320     /* vnode layer handles excl/nonexcl */
321
322     AFS_GLOCK();
323     code =
324         afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
325                    &vcp, cnp->cn_cred);
326     AFS_GUNLOCK();
327     if (code) {
328         VOP_ABORTOP(dvp, cnp);
329         vput(dvp);
330         DROPNAME();
331         return (code);
332     }
333
334     if (vcp) {
335         *ap->a_vpp = AFSTOV(vcp);
336         vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, curproc);
337     } else
338         *ap->a_vpp = 0;
339
340     if ((cnp->cn_flags & SAVESTART) == 0)
341         DROPCNP(cnp);
342     vput(dvp);
343     DROPNAME();
344     if (afs_debug & AFSDEB_VNLAYER)
345         printf("nbsd_create done dvp %p cnt %d\n", dvp, dvp->v_usecount);
346     return code;
347 }
348
349 int
350 afs_obsd_mknod(void *v)
351 {
352     struct vop_mknod_args       /* {
353                                  * struct vnode *a_dvp;
354                                  * struct vnode **a_vpp;
355                                  * struct componentname *a_cnp;
356                                  * struct vattr *a_vap;
357                                  * } */ *ap = v;
358     DROPCNP(ap->a_cnp);
359     vput(ap->a_dvp);
360     return (ENODEV);
361 }
362
363 int
364 afs_obsd_open(void *v)
365 {
366     struct vop_open_args        /* {
367                                  * struct vnode *a_vp;
368                                  * int  a_mode;
369                                  * struct ucred *a_cred;
370                                  * struct proc *a_p;
371                                  * } */ *ap = v;
372     int code;
373     struct vcache *vc = VTOAFS(ap->a_vp);
374
375     AFS_GLOCK();
376     code = afs_open(&vc, ap->a_mode, ap->a_cred);
377 #ifdef DIAGNOSTIC
378     if (AFSTOV(vc) != ap->a_vp)
379         panic("AFS open changed vnode!");
380 #endif
381     AFS_GUNLOCK();
382     return code;
383 }
384
385 int
386 afs_obsd_close(void *v)
387 {
388     struct vop_close_args       /* {
389                                  * struct vnode *a_vp;
390                                  * int  a_fflag;
391                                  * struct ucred *a_cred;
392                                  * struct proc *a_p;
393                                  * } */ *ap = v;
394     int code;
395
396     AFS_GLOCK();
397     code = afs_close(VTOAFS(ap->a_vp), ap->a_fflag, ap->a_cred, ap->a_p);
398     AFS_GUNLOCK();
399     return code;
400 }
401
402 int
403 afs_obsd_access(void *v)
404 {
405     struct vop_access_args      /* {
406                                  * struct vnode *a_vp;
407                                  * int  a_mode;
408                                  * struct ucred *a_cred;
409                                  * struct proc *a_p;
410                                  * } */ *ap = v;
411     int code;
412
413     AFS_GLOCK();
414     code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
415     AFS_GUNLOCK();
416     return code;
417 }
418
419 int
420 afs_obsd_getattr(void *v)
421 {
422     struct vop_getattr_args     /* {
423                                  * struct vnode *a_vp;
424                                  * struct vattr *a_vap;
425                                  * struct ucred *a_cred;
426                                  * struct proc *a_p;
427                                  * } */ *ap = v;
428     int code;
429
430     AFS_GLOCK();
431     code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
432     AFS_GUNLOCK();
433     return code;
434 }
435
436 int
437 afs_obsd_setattr(void *v)
438 {
439     struct vop_setattr_args     /* {
440                                  * struct vnode *a_vp;
441                                  * struct vattr *a_vap;
442                                  * struct ucred *a_cred;
443                                  * struct proc *a_p;
444                                  * } */ *ap = v;
445     int code;
446
447     AFS_GLOCK();
448     code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
449     AFS_GUNLOCK();
450     return code;
451 }
452
453 int
454 afs_obsd_read(void *v)
455 {
456     struct vop_read_args        /* {
457                                  * struct vnode *a_vp;
458                                  * struct uio *a_uio;
459                                  * int a_ioflag;
460                                  * struct ucred *a_cred;
461                                  * } */ *ap = v;
462     int code;
463
464     AFS_GLOCK();
465     code =
466         afs_read(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, (daddr_t) 0, NULL,
467                  0);
468     AFS_GUNLOCK();
469     return code;
470 }
471
472 int
473 afs_obsd_write(void *v)
474 {
475     struct vop_write_args       /* {
476                                  * struct vnode *a_vp;
477                                  * struct uio *a_uio;
478                                  * int a_ioflag;
479                                  * struct ucred *a_cred;
480                                  * } */ *ap = v;
481     int code;
482
483 #ifdef UVM
484     (void)uvm_vnp_uncache(ap->a_vp);    /* toss stale pages */
485 #else
486     vnode_pager_uncache(ap->a_vp);
487 #endif
488     AFS_GLOCK();
489     code =
490         afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
491     AFS_GUNLOCK();
492     return code;
493 }
494
495 int
496 afs_obsd_ioctl(void *v)
497 {
498     struct vop_ioctl_args       /* {
499                                  * struct vnode *a_vp;
500                                  * int  a_command;
501                                  * caddr_t  a_data;
502                                  * int  a_fflag;
503                                  * struct ucred *a_cred;
504                                  * struct proc *a_p;
505                                  * } */ *ap = v;
506     int code;
507
508     /* in case we ever get in here... */
509
510     AFS_STATCNT(afs_ioctl);
511     AFS_GLOCK();
512     if (((ap->a_command >> 8) & 0xff) == 'V')
513         /* This is a VICEIOCTL call */
514         code =
515             HandleIoctl(VTOAFS(ap->a_vp), ap->a_command,
516                         (struct afs_ioctl *)ap->a_data);
517     else
518         /* No-op call; just return. */
519         code = ENOTTY;
520     AFS_GUNLOCK();
521     return code;
522 }
523
524 int
525 afs_obsd_select(void *v)
526 {
527     return 1;
528 }
529
530 int
531 afs_obsd_fsync(void *v)
532 {
533     struct vop_fsync_args       /* {
534                                  * struct vnode *a_vp;
535                                  * struct ucred *a_cred;
536                                  * int a_waitfor;
537                                  * struct proc *a_p;
538                                  * } */ *ap = v;
539     int wait = ap->a_waitfor == MNT_WAIT;
540     struct vnode *vp = ap->a_vp;
541     int code;
542
543     AFS_GLOCK();
544     vflushbuf(vp, wait);
545     code = afs_fsync(VTOAFS(vp), ap->a_cred);
546     AFS_GUNLOCK();
547     return code;
548 }
549
550 int
551 afs_obsd_remove(void *v)
552 {
553     struct vop_remove_args      /* {
554                                  * struct vnode *a_dvp;
555                                  * struct vnode *a_vp;
556                                  * struct componentname *a_cnp;
557                                  * } */ *ap = v;
558     int code;
559     struct vnode *vp = ap->a_vp;
560     struct vnode *dvp = ap->a_dvp;
561
562     GETNAME();
563     AFS_GLOCK();
564     code = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
565     AFS_GUNLOCK();
566     if (dvp == vp)
567         vrele(vp);
568     else
569         vput(vp);
570     vput(dvp);
571     DROPCNP(cnp);
572     DROPNAME();
573     return code;
574 }
575
576 int
577 afs_obsd_link(void *v)
578 {
579     struct vop_link_args        /* {
580                                  * struct vnode *a_vp;
581                                  * struct vnode *a_tdvp;
582                                  * struct componentname *a_cnp;
583                                  * } */ *ap = v;
584     int code;
585     struct vnode *dvp = ap->a_dvp;
586     struct vnode *vp = ap->a_vp;
587
588     GETNAME();
589     if (dvp->v_mount != vp->v_mount) {
590         VOP_ABORTOP(vp, cnp);
591         code = EXDEV;
592         goto out;
593     }
594     if (vp->v_type == VDIR) {
595         VOP_ABORTOP(vp, cnp);
596         code = EISDIR;
597         goto out;
598     }
599     if ((code = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc))) {
600         VOP_ABORTOP(dvp, cnp);
601         goto out;
602     }
603
604     AFS_GLOCK();
605     code = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
606     AFS_GUNLOCK();
607     DROPCNP(cnp);
608     if (dvp != vp)
609         VOP_UNLOCK(vp, 0, curproc);
610
611   out:
612     vput(dvp);
613     DROPNAME();
614     return code;
615 }
616
617 int
618 afs_obsd_rename(void *v)
619 {
620     struct vop_rename_args      /* {
621                                  * struct vnode *a_fdvp;
622                                  * struct vnode *a_fvp;
623                                  * struct componentname *a_fcnp;
624                                  * struct vnode *a_tdvp;
625                                  * struct vnode *a_tvp;
626                                  * struct componentname *a_tcnp;
627                                  * } */ *ap = v;
628     int code = 0;
629     struct componentname *fcnp = ap->a_fcnp;
630     char *fname;
631     struct componentname *tcnp = ap->a_tcnp;
632     char *tname;
633     struct vnode *tvp = ap->a_tvp;
634     struct vnode *tdvp = ap->a_tdvp;
635     struct vnode *fvp = ap->a_fvp;
636     struct vnode *fdvp = ap->a_fdvp;
637
638     /*
639      * Check for cross-device rename.
640      */
641     if ((fvp->v_mount != tdvp->v_mount)
642         || (tvp && (fvp->v_mount != tvp->v_mount))) {
643         code = EXDEV;
644       abortit:
645         VOP_ABORTOP(tdvp, tcnp);        /* XXX, why not in NFS? */
646         if (tdvp == tvp)
647             vrele(tdvp);
648         else
649             vput(tdvp);
650         if (tvp)
651             vput(tvp);
652         VOP_ABORTOP(fdvp, fcnp);        /* XXX, why not in NFS? */
653         vrele(fdvp);
654         vrele(fvp);
655         return (code);
656     }
657     /*
658      * if fvp == tvp, we're just removing one name of a pair of
659      * directory entries for the same element.  convert call into rename.
660      ( (pinched from NetBSD 1.0's ufs_rename())
661      */
662     if (fvp == tvp) {
663         if (fvp->v_type == VDIR) {
664             code = EINVAL;
665             goto abortit;
666         }
667
668         /* Release destination completely. */
669         VOP_ABORTOP(tdvp, tcnp);
670         vput(tdvp);
671         vput(tvp);
672
673         /* Delete source. */
674         vrele(fdvp);
675         vrele(fvp);
676         fcnp->cn_flags &= ~MODMASK;
677         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
678         if ((fcnp->cn_flags & SAVESTART) == 0)
679             panic("afs_rename: lost from startdir");
680         fcnp->cn_nameiop = DELETE;
681         (void)relookup(fdvp, &fvp, fcnp);
682         return (VOP_REMOVE(fdvp, fvp, fcnp));
683     }
684
685     if ((code = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curproc)))
686         goto abortit;
687
688     BSD_KMALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
689     bcopy(fcnp->cn_nameptr, fname, fcnp->cn_namelen);
690     fname[fcnp->cn_namelen] = '\0';
691     BSD_KMALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
692     bcopy(tcnp->cn_nameptr, tname, tcnp->cn_namelen);
693     tname[tcnp->cn_namelen] = '\0';
694
695
696     AFS_GLOCK();
697     /* XXX use "from" or "to" creds? NFS uses "to" creds */
698     code =
699         afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
700     AFS_GUNLOCK();
701
702     VOP_UNLOCK(fvp, 0, curproc);
703     BSD_KFREE(fname, M_TEMP);
704     BSD_KFREE(tname, M_TEMP);
705     if (code)
706         goto abortit;           /* XXX */
707     if (tdvp == tvp)
708         vrele(tdvp);
709     else
710         vput(tdvp);
711     if (tvp)
712         vput(tvp);
713     vrele(fdvp);
714     vrele(fvp);
715     return code;
716 }
717
718 int
719 afs_obsd_mkdir(void *v)
720 {
721     struct vop_mkdir_args       /* {
722                                  * struct vnode *a_dvp;
723                                  * struct vnode **a_vpp;
724                                  * struct componentname *a_cnp;
725                                  * struct vattr *a_vap;
726                                  * } */ *ap = v;
727     struct vnode *dvp = ap->a_dvp;
728     struct vattr *vap = ap->a_vap;
729     int code;
730     struct vcache *vcp;
731
732     GETNAME();
733 #ifdef DIAGNOSTIC
734     if ((cnp->cn_flags & HASBUF) == 0)
735         panic("afs_obsd_mkdir: no name");
736 #endif
737     AFS_GLOCK();
738     code = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
739     AFS_GUNLOCK();
740     if (code) {
741         VOP_ABORTOP(dvp, cnp);
742         vput(dvp);
743         DROPNAME();
744         return (code);
745     }
746     if (vcp) {
747         *ap->a_vpp = AFSTOV(vcp);
748         vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, curproc);
749     } else
750         *ap->a_vpp = 0;
751     DROPCNP(cnp);
752     DROPNAME();
753     vput(dvp);
754     return code;
755 }
756
757 int
758 afs_obsd_rmdir(void *v)
759 {
760     struct vop_rmdir_args       /* {
761                                  * struct vnode *a_dvp;
762                                  * struct vnode *a_vp;
763                                  * struct componentname *a_cnp;
764                                  * } */ *ap = v;
765     int code;
766     struct vnode *vp = ap->a_vp;
767     struct vnode *dvp = ap->a_dvp;
768
769     GETNAME();
770     if (dvp == vp) {
771         vrele(dvp);
772         vput(vp);
773         DROPCNP(cnp);
774         DROPNAME();
775         return (EINVAL);
776     }
777
778     AFS_GLOCK();
779     code = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
780     AFS_GUNLOCK();
781     DROPNAME();
782     vput(dvp);
783     vput(vp);
784     return code;
785 }
786
787 int
788 afs_obsd_symlink(void *v)
789 {
790     struct vop_symlink_args     /* {
791                                  * struct vnode *a_dvp;
792                                  * struct vnode **a_vpp;
793                                  * struct componentname *a_cnp;
794                                  * struct vattr *a_vap;
795                                  * char *a_target;
796                                  * } */ *ap = v;
797     struct vnode *dvp = ap->a_dvp;
798     int code;
799     /* NFS ignores a_vpp; so do we. */
800
801     GETNAME();
802     AFS_GLOCK();
803     code =
804         afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
805     AFS_GUNLOCK();
806     DROPCNP(cnp);
807     DROPNAME();
808     vput(dvp);
809     return code;
810 }
811
812 int
813 afs_obsd_readdir(void *v)
814 {
815     struct vop_readdir_args     /* {
816                                  * struct vnode *a_vp;
817                                  * struct uio *a_uio;
818                                  * struct ucred *a_cred;
819                                  * int *a_eofflag;
820                                  * int *a_ncookies;
821                                  * u_long **a_cookies;
822                                  * } */ *ap = v;
823     int code;
824
825     AFS_GLOCK();
826 #ifdef AFS_HAVE_COOKIES
827     printf("readdir %p cookies %p ncookies %d\n", ap->a_vp, ap->a_cookies,
828            ap->a_ncookies);
829     code =
830         afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag,
831                     ap->a_ncookies, ap->a_cookies);
832 #else
833     code =
834         afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
835 #endif
836     AFS_GUNLOCK();
837     return code;
838 }
839
840 int
841 afs_obsd_readlink(void *v)
842 {
843     struct vop_readlink_args    /* {
844                                  * struct vnode *a_vp;
845                                  * struct uio *a_uio;
846                                  * struct ucred *a_cred;
847                                  * } */ *ap = v;
848     int code;
849
850     AFS_GLOCK();
851     code = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
852     AFS_GUNLOCK();
853     return code;
854 }
855
856 extern int prtactive;
857
858 int
859 afs_obsd_inactive(void *v)
860 {
861     struct vop_inactive_args    /* {
862                                  * struct vnode *a_vp;
863                                  * } */ *ap = v;
864     struct vnode *vp = ap->a_vp;
865     struct vcache *vc = VTOAFS(vp);
866     int haveGlock = ISAFS_GLOCK();
867
868     AFS_STATCNT(afs_inactive);
869
870     if (prtactive && vp->v_usecount != 0)
871         vprint("afs_obsd_inactive(): pushing active", vp);
872
873     if (!haveGlock)
874         AFS_GLOCK();
875     afs_InactiveVCache(vc, 0);  /* decrs ref counts */
876     if (!haveGlock)
877         AFS_GUNLOCK();
878
879     lockinit(&vc->rwlock, PINOD, "vcache", 0, 0);
880     return 0;
881 }
882
883 int
884 afs_obsd_reclaim(void *v)
885 {
886     struct vop_reclaim_args     /* {
887                                  * struct vnode *a_vp;
888                                  * } */ *ap = v;
889     int code, slept;
890     struct vnode *vp = ap->a_vp;
891     struct vcache *avc = VTOAFS(vp);
892     int haveGlock = ISAFS_GLOCK();
893     int haveVlock = CheckLock(&afs_xvcache);
894
895 #if 0
896     printf("reclaim usecount %d\n", vp->v_usecount);
897     /* OK, there are no internal vrefCounts, so there shouldn't
898      * be any more refs here. */
899     vp->v_data = NULL;          /* remove from vnode */
900     avc->v = NULL;              /* also drop the ptr to vnode */
901     return 0;
902 #else
903     if (!haveGlock)
904         AFS_GLOCK();
905     if (!haveVlock)
906         ObtainWriteLock(&afs_xvcache, 901);
907     /* reclaim the vnode and the in-memory vcache, but keep the on-disk vcache */
908     code = afs_FlushVCache(avc, &slept);
909     if (!haveVlock)
910         ReleaseWriteLock(&afs_xvcache);
911     if (!haveGlock)
912         AFS_GUNLOCK();
913     return code;
914 #endif
915 }
916
917 #ifdef AFS_OBSD42_ENV
918 #define VP_INTERLOCK NULL
919 #else
920 #define VP_INTERLOCK (&vp->v_interlock)
921 #endif
922
923 int
924 afs_obsd_lock(void *v)
925 {
926     struct vop_lock_args        /* {
927                                  * struct vnode *a_vp;
928                                  * int a_flags;
929                                  * sturct proc *a_p;
930                                  * } */ *ap = v;
931     struct vnode *vp = ap->a_vp;
932     struct vcache *vc = VTOAFS(vp);
933
934     if (!vc)
935         panic("afs_obsd_lock: null vcache");
936     return afs_osi_lockmgr(&vc->rwlock, ap->a_flags | LK_CANRECURSE, VP_INTERLOCK, ap->a_p);
937 }
938
939 int
940 afs_obsd_unlock(void *v)
941 {
942     struct vop_unlock_args      /* {
943                                  * struct vnode *a_vp;
944                                  * int a_flags;
945                                  * struct proc *a_p;
946                                  * } */ *ap = v;
947     struct vnode *vp = ap->a_vp;
948     struct vcache *vc = VTOAFS(vp);
949
950     if (!vc)
951         panic("afs_obsd_unlock: null vcache");
952     return afs_osi_lockmgr(&vc->rwlock, ap->a_flags | LK_RELEASE, VP_INTERLOCK, ap->a_p);
953 }
954
955 int
956 afs_obsd_bmap(void *v)
957 {
958     struct vop_bmap_args        /* {
959                                  * struct vnode *a_vp;
960                                  * daddr_t  a_bn;
961                                  * struct vnode **a_vpp;
962                                  * daddr_t *a_bnp;
963                                  * int *a_runp;
964                                  * } */ *ap = v;
965     struct vcache *vcp = VTOAFS(ap->a_vp);
966
967     AFS_STATCNT(afs_bmap);
968     if (ap->a_bnp)
969         *ap->a_bnp = ap->a_bn * btodb(8192);
970     if (ap->a_vpp)
971         *ap->a_vpp = (vcp) ? AFSTOV(vcp) : NULL;
972     return 0;
973 }
974
975 int
976 afs_obsd_strategy(void *v)
977 {
978     struct vop_strategy_args    /* {
979                                  * struct buf *a_bp;
980                                  * } */ *ap = v;
981     struct buf *abp = ap->a_bp;
982     struct uio tuio;
983     struct iovec tiovec[1];
984     struct vcache *tvc = VTOAFS(abp->b_vp);
985     struct ucred *credp = osi_curcred();
986     long len = abp->b_bcount;
987     int code;
988
989     AFS_STATCNT(afs_strategy);
990
991     tuio.afsio_iov = tiovec;
992     tuio.afsio_iovcnt = 1;
993     tuio.afsio_seg = AFS_UIOSYS;
994     tuio.afsio_resid = len;
995     tiovec[0].iov_base = abp->b_data;
996     tiovec[0].iov_len = len;
997
998     AFS_GLOCK();
999     if ((abp->b_flags & B_READ) == B_READ) {
1000         code = afs_rdwr(tvc, &tuio, UIO_READ, 0, credp);
1001         if (code == 0 && tuio.afsio_resid > 0)
1002             bzero(abp->b_data + len - tuio.afsio_resid, tuio.afsio_resid);
1003     } else
1004         code = afs_rdwr(tvc, &tuio, UIO_WRITE, 0, credp);
1005     AFS_GUNLOCK();
1006
1007     ReleaseWriteLock(&tvc->lock);
1008     AFS_RELE(AFSTOV(tvc));
1009     return code;
1010 }
1011
1012 int
1013 afs_obsd_print(void *v)
1014 {
1015     struct vop_print_args       /* {
1016                                  * struct vnode *a_vp;
1017                                  * } */ *ap = v;
1018     struct vnode *vp = ap->a_vp;
1019     struct vcache *vc = VTOAFS(ap->a_vp);
1020
1021     printf("tag %d, fid: %d.%x.%x.%x, ", vp->v_tag, vc->f.fid.Cell,
1022            (int)vc->f.fid.Fid.Volume, (int)vc->f.fid.Fid.Vnode,
1023            (int)vc->f.fid.Fid.Unique);
1024     lockmgr_printinfo(&vc->rwlock);
1025     printf("\n");
1026     return 0;
1027 }
1028
1029 int
1030 afs_obsd_islocked(void *v)
1031 {
1032     struct vop_islocked_args    /* {
1033                                  * struct vnode *a_vp;
1034                                  * } */ *ap = v;
1035     return lockstatus(&VTOAFS(ap->a_vp)->rwlock);
1036 }
1037
1038 /*
1039  * Return POSIX pathconf information applicable to ufs filesystems.
1040  */
1041 int
1042 afs_obsd_pathconf(void *v)
1043 {
1044     struct vop_pathconf_args    /* {
1045                                  * struct vnode *a_vp;
1046                                  * int a_name;
1047                                  * int *a_retval;
1048                                  * } */ *ap = v;
1049     AFS_STATCNT(afs_cntl);
1050     switch (ap->a_name) {
1051     case _PC_LINK_MAX:
1052         *ap->a_retval = LINK_MAX;
1053         break;
1054     case _PC_NAME_MAX:
1055         *ap->a_retval = NAME_MAX;
1056         break;
1057     case _PC_PATH_MAX:
1058         *ap->a_retval = PATH_MAX;
1059         break;
1060     case _PC_CHOWN_RESTRICTED:
1061         *ap->a_retval = 1;
1062         break;
1063     case _PC_NO_TRUNC:
1064         *ap->a_retval = 1;
1065         break;
1066     case _PC_PIPE_BUF:
1067         return EINVAL;
1068         break;
1069     default:
1070         return EINVAL;
1071     }
1072     return 0;
1073 }
1074
1075 extern int
1076   afs_lockctl(struct vcache *avc, struct AFS_FLOCK *af, int acmd,
1077               afs_ucred_t *acred, pid_t clid);
1078
1079 /*
1080  * Advisory record locking support (fcntl() POSIX style)
1081  */
1082 int
1083 afs_obsd_advlock(void *v)
1084 {
1085     struct vop_advlock_args     /* {
1086                                  * struct vnode *a_vp;
1087                                  * caddr_t  a_id;
1088                                  * int  a_op;
1089                                  * struct flock *a_fl;
1090                                  * int  a_flags;
1091                                  * } */ *ap = v;
1092     int code;
1093
1094     AFS_GLOCK();
1095     code =
1096         afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, osi_curcred(),
1097                     (int)ap->a_id);
1098     AFS_GUNLOCK();
1099     return code;
1100 }