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