afs: casting NULL is generally unnecessary
[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     {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);
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 = afs_read(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, 0);
466     AFS_GUNLOCK();
467     return code;
468 }
469
470 int
471 afs_obsd_write(void *v)
472 {
473     struct vop_write_args       /* {
474                                  * struct vnode *a_vp;
475                                  * struct uio *a_uio;
476                                  * int a_ioflag;
477                                  * struct ucred *a_cred;
478                                  * } */ *ap = v;
479     int code;
480
481 #ifdef UVM
482     (void)uvm_vnp_uncache(ap->a_vp);    /* toss stale pages */
483 #else
484     vnode_pager_uncache(ap->a_vp);
485 #endif
486     AFS_GLOCK();
487     code =
488         afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
489     AFS_GUNLOCK();
490     return code;
491 }
492
493 int
494 afs_obsd_ioctl(void *v)
495 {
496     struct vop_ioctl_args       /* {
497                                  * struct vnode *a_vp;
498                                  * int  a_command;
499                                  * caddr_t  a_data;
500                                  * int  a_fflag;
501                                  * struct ucred *a_cred;
502                                  * struct proc *a_p;
503                                  * } */ *ap = v;
504     int code;
505
506     /* in case we ever get in here... */
507
508     AFS_STATCNT(afs_ioctl);
509     AFS_GLOCK();
510     if (((ap->a_command >> 8) & 0xff) == 'V')
511         /* This is a VICEIOCTL call */
512         code =
513             HandleIoctl(VTOAFS(ap->a_vp), ap->a_command,
514                         (struct afs_ioctl *)ap->a_data);
515     else
516         /* No-op call; just return. */
517         code = ENOTTY;
518     AFS_GUNLOCK();
519     return code;
520 }
521
522 int
523 afs_obsd_select(void *v)
524 {
525     return 1;
526 }
527
528 int
529 afs_obsd_fsync(void *v)
530 {
531     struct vop_fsync_args       /* {
532                                  * struct vnode *a_vp;
533                                  * struct ucred *a_cred;
534                                  * int a_waitfor;
535                                  * struct proc *a_p;
536                                  * } */ *ap = v;
537     int wait = ap->a_waitfor == MNT_WAIT;
538     struct vnode *vp = ap->a_vp;
539     int code;
540
541     AFS_GLOCK();
542     vflushbuf(vp, wait);
543     code = afs_fsync(VTOAFS(vp), ap->a_cred);
544     AFS_GUNLOCK();
545     return code;
546 }
547
548 int
549 afs_obsd_remove(void *v)
550 {
551     struct vop_remove_args      /* {
552                                  * struct vnode *a_dvp;
553                                  * struct vnode *a_vp;
554                                  * struct componentname *a_cnp;
555                                  * } */ *ap = v;
556     int code;
557     struct vnode *vp = ap->a_vp;
558     struct vnode *dvp = ap->a_dvp;
559
560     GETNAME();
561     AFS_GLOCK();
562     code = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
563     AFS_GUNLOCK();
564     if (dvp == vp)
565         vrele(vp);
566     else
567         vput(vp);
568     vput(dvp);
569     DROPCNP(cnp);
570     DROPNAME();
571     return code;
572 }
573
574 int
575 afs_obsd_link(void *v)
576 {
577     struct vop_link_args        /* {
578                                  * struct vnode *a_vp;
579                                  * struct vnode *a_tdvp;
580                                  * struct componentname *a_cnp;
581                                  * } */ *ap = v;
582     int code;
583     struct vnode *dvp = ap->a_dvp;
584     struct vnode *vp = ap->a_vp;
585
586     GETNAME();
587     if (dvp->v_mount != vp->v_mount) {
588         VOP_ABORTOP(vp, cnp);
589         code = EXDEV;
590         goto out;
591     }
592     if (vp->v_type == VDIR) {
593         VOP_ABORTOP(vp, cnp);
594         code = EISDIR;
595         goto out;
596     }
597     if ((code = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc))) {
598         VOP_ABORTOP(dvp, cnp);
599         goto out;
600     }
601
602     AFS_GLOCK();
603     code = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
604     AFS_GUNLOCK();
605     DROPCNP(cnp);
606     if (dvp != vp)
607         VOP_UNLOCK(vp, 0, curproc);
608
609   out:
610     vput(dvp);
611     DROPNAME();
612     return code;
613 }
614
615 int
616 afs_obsd_rename(void *v)
617 {
618     struct vop_rename_args      /* {
619                                  * struct vnode *a_fdvp;
620                                  * struct vnode *a_fvp;
621                                  * struct componentname *a_fcnp;
622                                  * struct vnode *a_tdvp;
623                                  * struct vnode *a_tvp;
624                                  * struct componentname *a_tcnp;
625                                  * } */ *ap = v;
626     int code = 0;
627     struct componentname *fcnp = ap->a_fcnp;
628     char *fname;
629     struct componentname *tcnp = ap->a_tcnp;
630     char *tname;
631     struct vnode *tvp = ap->a_tvp;
632     struct vnode *tdvp = ap->a_tdvp;
633     struct vnode *fvp = ap->a_fvp;
634     struct vnode *fdvp = ap->a_fdvp;
635
636     /*
637      * Check for cross-device rename.
638      */
639     if ((fvp->v_mount != tdvp->v_mount)
640         || (tvp && (fvp->v_mount != tvp->v_mount))) {
641         code = EXDEV;
642       abortit:
643         VOP_ABORTOP(tdvp, tcnp);        /* XXX, why not in NFS? */
644         if (tdvp == tvp)
645             vrele(tdvp);
646         else
647             vput(tdvp);
648         if (tvp)
649             vput(tvp);
650         VOP_ABORTOP(fdvp, fcnp);        /* XXX, why not in NFS? */
651         vrele(fdvp);
652         vrele(fvp);
653         return (code);
654     }
655     /*
656      * if fvp == tvp, we're just removing one name of a pair of
657      * directory entries for the same element.  convert call into rename.
658      ( (pinched from NetBSD 1.0's ufs_rename())
659      */
660     if (fvp == tvp) {
661         if (fvp->v_type == VDIR) {
662             code = EINVAL;
663             goto abortit;
664         }
665
666         /* Release destination completely. */
667         VOP_ABORTOP(tdvp, tcnp);
668         vput(tdvp);
669         vput(tvp);
670
671         /* Delete source. */
672         vrele(fdvp);
673         vrele(fvp);
674         fcnp->cn_flags &= ~MODMASK;
675         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
676         if ((fcnp->cn_flags & SAVESTART) == 0)
677             panic("afs_rename: lost from startdir");
678         fcnp->cn_nameiop = DELETE;
679         (void)relookup(fdvp, &fvp, fcnp);
680         return (VOP_REMOVE(fdvp, fvp, fcnp));
681     }
682
683     if ((code = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curproc)))
684         goto abortit;
685
686     BSD_KMALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
687     bcopy(fcnp->cn_nameptr, fname, fcnp->cn_namelen);
688     fname[fcnp->cn_namelen] = '\0';
689     BSD_KMALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
690     bcopy(tcnp->cn_nameptr, tname, tcnp->cn_namelen);
691     tname[tcnp->cn_namelen] = '\0';
692
693
694     AFS_GLOCK();
695     /* XXX use "from" or "to" creds? NFS uses "to" creds */
696     code =
697         afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
698     AFS_GUNLOCK();
699
700     VOP_UNLOCK(fvp, 0, curproc);
701     BSD_KFREE(fname, M_TEMP);
702     BSD_KFREE(tname, M_TEMP);
703     if (code)
704         goto abortit;           /* XXX */
705     if (tdvp == tvp)
706         vrele(tdvp);
707     else
708         vput(tdvp);
709     if (tvp)
710         vput(tvp);
711     vrele(fdvp);
712     vrele(fvp);
713     return code;
714 }
715
716 int
717 afs_obsd_mkdir(void *v)
718 {
719     struct vop_mkdir_args       /* {
720                                  * struct vnode *a_dvp;
721                                  * struct vnode **a_vpp;
722                                  * struct componentname *a_cnp;
723                                  * struct vattr *a_vap;
724                                  * } */ *ap = v;
725     struct vnode *dvp = ap->a_dvp;
726     struct vattr *vap = ap->a_vap;
727     int code;
728     struct vcache *vcp;
729
730     GETNAME();
731 #ifdef DIAGNOSTIC
732     if ((cnp->cn_flags & HASBUF) == 0)
733         panic("afs_obsd_mkdir: no name");
734 #endif
735     AFS_GLOCK();
736     code = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
737     AFS_GUNLOCK();
738     if (code) {
739         VOP_ABORTOP(dvp, cnp);
740         vput(dvp);
741         DROPNAME();
742         return (code);
743     }
744     if (vcp) {
745         *ap->a_vpp = AFSTOV(vcp);
746         vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, curproc);
747     } else
748         *ap->a_vpp = 0;
749     DROPCNP(cnp);
750     DROPNAME();
751     vput(dvp);
752     return code;
753 }
754
755 int
756 afs_obsd_rmdir(void *v)
757 {
758     struct vop_rmdir_args       /* {
759                                  * struct vnode *a_dvp;
760                                  * struct vnode *a_vp;
761                                  * struct componentname *a_cnp;
762                                  * } */ *ap = v;
763     int code;
764     struct vnode *vp = ap->a_vp;
765     struct vnode *dvp = ap->a_dvp;
766
767     GETNAME();
768     if (dvp == vp) {
769         vrele(dvp);
770         vput(vp);
771         DROPCNP(cnp);
772         DROPNAME();
773         return (EINVAL);
774     }
775
776     AFS_GLOCK();
777     code = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
778     AFS_GUNLOCK();
779     DROPNAME();
780     vput(dvp);
781     vput(vp);
782     return code;
783 }
784
785 int
786 afs_obsd_symlink(void *v)
787 {
788     struct vop_symlink_args     /* {
789                                  * struct vnode *a_dvp;
790                                  * struct vnode **a_vpp;
791                                  * struct componentname *a_cnp;
792                                  * struct vattr *a_vap;
793                                  * char *a_target;
794                                  * } */ *ap = v;
795     struct vnode *dvp = ap->a_dvp;
796     int code;
797     /* NFS ignores a_vpp; so do we. */
798
799     GETNAME();
800     AFS_GLOCK();
801     code =
802         afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
803     AFS_GUNLOCK();
804     DROPCNP(cnp);
805     DROPNAME();
806     vput(dvp);
807     return code;
808 }
809
810 int
811 afs_obsd_readdir(void *v)
812 {
813     struct vop_readdir_args     /* {
814                                  * struct vnode *a_vp;
815                                  * struct uio *a_uio;
816                                  * struct ucred *a_cred;
817                                  * int *a_eofflag;
818                                  * int *a_ncookies;
819                                  * u_long **a_cookies;
820                                  * } */ *ap = v;
821     int code;
822
823     AFS_GLOCK();
824 #ifdef AFS_HAVE_COOKIES
825     printf("readdir %p cookies %p ncookies %d\n", ap->a_vp, ap->a_cookies,
826            ap->a_ncookies);
827     code =
828         afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag,
829                     ap->a_ncookies, ap->a_cookies);
830 #else
831     code =
832         afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
833 #endif
834     AFS_GUNLOCK();
835     return code;
836 }
837
838 int
839 afs_obsd_readlink(void *v)
840 {
841     struct vop_readlink_args    /* {
842                                  * struct vnode *a_vp;
843                                  * struct uio *a_uio;
844                                  * struct ucred *a_cred;
845                                  * } */ *ap = v;
846     int code;
847
848     AFS_GLOCK();
849     code = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
850     AFS_GUNLOCK();
851     return code;
852 }
853
854 extern int prtactive;
855
856 int
857 afs_obsd_inactive(void *v)
858 {
859     struct vop_inactive_args    /* {
860                                  * struct vnode *a_vp;
861                                  * } */ *ap = v;
862     struct vnode *vp = ap->a_vp;
863     struct vcache *vc = VTOAFS(vp);
864     int haveGlock = ISAFS_GLOCK();
865
866     AFS_STATCNT(afs_inactive);
867
868     if (prtactive && vp->v_usecount != 0)
869         vprint("afs_obsd_inactive(): pushing active", vp);
870
871     if (!haveGlock)
872         AFS_GLOCK();
873     afs_InactiveVCache(vc, 0);  /* decrs ref counts */
874     if (!haveGlock)
875         AFS_GUNLOCK();
876
877     lockinit(&vc->rwlock, PINOD, "vcache", 0, 0);
878     return 0;
879 }
880
881 int
882 afs_obsd_reclaim(void *v)
883 {
884     struct vop_reclaim_args     /* {
885                                  * struct vnode *a_vp;
886                                  * } */ *ap = v;
887     int code, slept;
888     struct vnode *vp = ap->a_vp;
889     struct vcache *avc = VTOAFS(vp);
890     int haveGlock = ISAFS_GLOCK();
891     int haveVlock = CheckLock(&afs_xvcache);
892
893 #if 0
894     printf("reclaim usecount %d\n", vp->v_usecount);
895     /* OK, there are no internal vrefCounts, so there shouldn't
896      * be any more refs here. */
897     vp->v_data = NULL;          /* remove from vnode */
898     avc->v = NULL;              /* also drop the ptr to vnode */
899     return 0;
900 #else
901     if (!haveGlock)
902         AFS_GLOCK();
903     if (!haveVlock)
904         ObtainWriteLock(&afs_xvcache, 901);
905     /* reclaim the vnode and the in-memory vcache, but keep the on-disk vcache */
906     code = afs_FlushVCache(avc, &slept);
907     if (!haveVlock)
908         ReleaseWriteLock(&afs_xvcache);
909     if (!haveGlock)
910         AFS_GUNLOCK();
911     return code;
912 #endif
913 }
914
915 #ifdef AFS_OBSD42_ENV
916 #define VP_INTERLOCK NULL
917 #else
918 #define VP_INTERLOCK (&vp->v_interlock)
919 #endif
920
921 int
922 afs_obsd_lock(void *v)
923 {
924     struct vop_lock_args        /* {
925                                  * struct vnode *a_vp;
926                                  * int a_flags;
927                                  * sturct proc *a_p;
928                                  * } */ *ap = v;
929     struct vnode *vp = ap->a_vp;
930     struct vcache *vc = VTOAFS(vp);
931
932     if (!vc)
933         panic("afs_obsd_lock: null vcache");
934     return afs_osi_lockmgr(&vc->rwlock, ap->a_flags | LK_CANRECURSE, VP_INTERLOCK, ap->a_p);
935 }
936
937 int
938 afs_obsd_unlock(void *v)
939 {
940     struct vop_unlock_args      /* {
941                                  * struct vnode *a_vp;
942                                  * int a_flags;
943                                  * struct proc *a_p;
944                                  * } */ *ap = v;
945     struct vnode *vp = ap->a_vp;
946     struct vcache *vc = VTOAFS(vp);
947
948     if (!vc)
949         panic("afs_obsd_unlock: null vcache");
950     return afs_osi_lockmgr(&vc->rwlock, ap->a_flags | LK_RELEASE, VP_INTERLOCK, ap->a_p);
951 }
952
953 int
954 afs_obsd_bmap(void *v)
955 {
956     struct vop_bmap_args        /* {
957                                  * struct vnode *a_vp;
958                                  * daddr_t  a_bn;
959                                  * struct vnode **a_vpp;
960                                  * daddr_t *a_bnp;
961                                  * int *a_runp;
962                                  * } */ *ap = v;
963     struct vcache *vcp = VTOAFS(ap->a_vp);
964
965     AFS_STATCNT(afs_bmap);
966     if (ap->a_bnp)
967         *ap->a_bnp = ap->a_bn * btodb(8192);
968     if (ap->a_vpp)
969         *ap->a_vpp = (vcp) ? AFSTOV(vcp) : NULL;
970     return 0;
971 }
972
973 int
974 afs_obsd_strategy(void *v)
975 {
976     struct vop_strategy_args    /* {
977                                  * struct buf *a_bp;
978                                  * } */ *ap = v;
979     struct buf *abp = ap->a_bp;
980     struct uio tuio;
981     struct iovec tiovec[1];
982     struct vcache *tvc = VTOAFS(abp->b_vp);
983     struct ucred *credp = osi_curcred();
984     long len = abp->b_bcount;
985     int code;
986
987     AFS_STATCNT(afs_strategy);
988
989     tuio.afsio_iov = tiovec;
990     tuio.afsio_iovcnt = 1;
991     tuio.afsio_seg = AFS_UIOSYS;
992     tuio.afsio_resid = len;
993     tiovec[0].iov_base = abp->b_data;
994     tiovec[0].iov_len = len;
995
996     AFS_GLOCK();
997     if ((abp->b_flags & B_READ) == B_READ) {
998         code = afs_rdwr(tvc, &tuio, UIO_READ, 0, credp);
999         if (code == 0 && tuio.afsio_resid > 0)
1000             bzero(abp->b_data + len - tuio.afsio_resid, tuio.afsio_resid);
1001     } else
1002         code = afs_rdwr(tvc, &tuio, UIO_WRITE, 0, credp);
1003     AFS_GUNLOCK();
1004
1005     ReleaseWriteLock(&tvc->lock);
1006     AFS_RELE(AFSTOV(tvc));
1007     return code;
1008 }
1009
1010 int
1011 afs_obsd_print(void *v)
1012 {
1013     struct vop_print_args       /* {
1014                                  * struct vnode *a_vp;
1015                                  * } */ *ap = v;
1016     struct vnode *vp = ap->a_vp;
1017     struct vcache *vc = VTOAFS(ap->a_vp);
1018
1019     printf("tag %d, fid: %d.%x.%x.%x, ", vp->v_tag, vc->f.fid.Cell,
1020            (int)vc->f.fid.Fid.Volume, (int)vc->f.fid.Fid.Vnode,
1021            (int)vc->f.fid.Fid.Unique);
1022     lockmgr_printinfo(&vc->rwlock);
1023     printf("\n");
1024     return 0;
1025 }
1026
1027 int
1028 afs_obsd_islocked(void *v)
1029 {
1030     struct vop_islocked_args    /* {
1031                                  * struct vnode *a_vp;
1032                                  * } */ *ap = v;
1033     return lockstatus(&VTOAFS(ap->a_vp)->rwlock);
1034 }
1035
1036 /*
1037  * Return POSIX pathconf information applicable to ufs filesystems.
1038  */
1039 int
1040 afs_obsd_pathconf(void *v)
1041 {
1042     struct vop_pathconf_args    /* {
1043                                  * struct vnode *a_vp;
1044                                  * int a_name;
1045                                  * int *a_retval;
1046                                  * } */ *ap = v;
1047     AFS_STATCNT(afs_cntl);
1048     switch (ap->a_name) {
1049     case _PC_LINK_MAX:
1050         *ap->a_retval = LINK_MAX;
1051         break;
1052     case _PC_NAME_MAX:
1053         *ap->a_retval = NAME_MAX;
1054         break;
1055     case _PC_PATH_MAX:
1056         *ap->a_retval = PATH_MAX;
1057         break;
1058     case _PC_CHOWN_RESTRICTED:
1059         *ap->a_retval = 1;
1060         break;
1061     case _PC_NO_TRUNC:
1062         *ap->a_retval = 1;
1063         break;
1064     case _PC_PIPE_BUF:
1065         return EINVAL;
1066         break;
1067     default:
1068         return EINVAL;
1069     }
1070     return 0;
1071 }
1072
1073 extern int
1074   afs_lockctl(struct vcache *avc, struct AFS_FLOCK *af, int acmd,
1075               afs_ucred_t *acred, pid_t clid);
1076
1077 /*
1078  * Advisory record locking support (fcntl() POSIX style)
1079  */
1080 int
1081 afs_obsd_advlock(void *v)
1082 {
1083     struct vop_advlock_args     /* {
1084                                  * struct vnode *a_vp;
1085                                  * caddr_t  a_id;
1086                                  * int  a_op;
1087                                  * struct flock *a_fl;
1088                                  * int  a_flags;
1089                                  * } */ *ap = v;
1090     int code;
1091
1092     AFS_GLOCK();
1093     code =
1094         afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, osi_curcred(),
1095                     (int)ap->a_id);
1096     AFS_GUNLOCK();
1097     return code;
1098 }