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