bsd-new-releases-20040727
[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 RCSID
102     ("$Header$");
103
104 #include "afs/sysincludes.h"    /* Standard vendor system headers */
105 #include "afs/afsincludes.h"    /* Afs-based standard headers */
106 #include "afs/afs_stats.h"      /* statistics */
107
108 #include <sys/malloc.h>
109 #include <sys/namei.h>
110 #ifdef AFS_OBSD36_ENV
111 #include <sys/pool.h>
112 #endif
113
114 #include "afs/afs_cbqueue.h"
115 #include "afs/nfsclient.h"
116 #include "afs/afs_osidnlc.h"
117
118 #ifdef AFS_DISCON_ENV
119 extern int afs_FlushVS(struct vcache *tvc);
120 #endif
121
122 #define M_AFSNODE (M_TEMP-1)    /* XXX */
123
124 int afs_nbsd_lookup(void *);
125 int afs_nbsd_create(void *);
126 int afs_nbsd_mknod(void *);
127 int afs_nbsd_open(void *);
128 int afs_nbsd_close(void *);
129 int afs_nbsd_access(void *);
130 int afs_nbsd_getattr(void *);
131 int afs_nbsd_setattr(void *);
132 int afs_nbsd_read(void *);
133 int afs_nbsd_write(void *);
134 int afs_nbsd_ioctl(void *);
135 int afs_nbsd_select(void *);
136 int afs_nbsd_fsync(void *);
137 int afs_nbsd_remove(void *);
138 int afs_nbsd_link(void *);
139 int afs_nbsd_rename(void *);
140 int afs_nbsd_mkdir(void *);
141 int afs_nbsd_rmdir(void *);
142 int afs_nbsd_symlink(void *);
143 int afs_nbsd_readdir(void *);
144 int afs_nbsd_readlink(void *);
145 int afs_nbsd_inactive(void *);
146 int afs_nbsd_reclaim(void *);
147 int afs_nbsd_lock(void *);
148 int afs_nbsd_unlock(void *);
149 int afs_nbsd_bmap(void *);
150 int afs_nbsd_strategy(void *);
151 int afs_nbsd_print(void *);
152 int afs_nbsd_islocked(void *);
153 int afs_nbsd_pathconf(void *);
154 int afs_nbsd_advlock(void *);
155
156 #define afs_nbsd_opnotsupp \
157         ((int (*) __P((void *)))eopnotsupp)
158 #define afs_nbsd_reallocblks afs_nbsd_opnotsupp
159
160 /* Global vfs data structures for AFS. */
161 int (**afs_vnodeop_p) __P((void *));
162 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
163     {&vop_default_desc, vn_default_error},
164     {&vop_lookup_desc, afs_nbsd_lookup},        /* lookup */
165     {&vop_create_desc, afs_nbsd_create},        /* create */
166     {&vop_mknod_desc, afs_nbsd_mknod},          /* mknod */
167     {&vop_open_desc, afs_nbsd_open},            /* open */
168     {&vop_close_desc, afs_nbsd_close},          /* close */
169     {&vop_access_desc, afs_nbsd_access},        /* access */
170     {&vop_getattr_desc, afs_nbsd_getattr},      /* getattr */
171     {&vop_setattr_desc, afs_nbsd_setattr},      /* setattr */
172     {&vop_read_desc, afs_nbsd_read},            /* read */
173     {&vop_write_desc, afs_nbsd_write},          /* write */
174     {&vop_ioctl_desc, afs_nbsd_ioctl},          /* XXX ioctl */
175 #ifdef AFS_OBSD35_ENV
176     {&vop_poll_desc, afs_nbsd_select},          /* select */
177 #else
178     {&vop_select_desc, afs_nbsd_select},        /* select */
179 #endif
180     {&vop_fsync_desc, afs_nbsd_fsync},          /* fsync */
181     {&vop_remove_desc, afs_nbsd_remove},        /* remove */
182     {&vop_link_desc, afs_nbsd_link},            /* link */
183     {&vop_rename_desc, afs_nbsd_rename},        /* rename */
184     {&vop_mkdir_desc, afs_nbsd_mkdir},          /* mkdir */
185     {&vop_rmdir_desc, afs_nbsd_rmdir},          /* rmdir */
186     {&vop_symlink_desc, afs_nbsd_symlink},      /* symlink */
187     {&vop_readdir_desc, afs_nbsd_readdir},      /* readdir */
188     {&vop_readlink_desc, afs_nbsd_readlink},    /* readlink */
189     {&vop_abortop_desc, vop_generic_abortop},   /* abortop */
190     {&vop_inactive_desc, afs_nbsd_inactive},    /* inactive */
191     {&vop_reclaim_desc, afs_nbsd_reclaim},      /* reclaim */
192     {&vop_lock_desc, afs_nbsd_lock},            /* lock */
193     {&vop_unlock_desc, afs_nbsd_unlock},        /* unlock */
194     {&vop_bmap_desc, afs_nbsd_bmap},            /* bmap */
195     {&vop_strategy_desc, afs_nbsd_strategy},    /* strategy */
196     {&vop_print_desc, afs_nbsd_print},          /* print */
197     {&vop_islocked_desc, afs_nbsd_islocked},    /* islocked */
198     {&vop_pathconf_desc, afs_nbsd_pathconf},    /* pathconf */
199     {&vop_advlock_desc, afs_nbsd_advlock},      /* advlock */
200     {&vop_reallocblks_desc, afs_nbsd_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     MALLOC(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() FREE(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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_select(void *v)
528 {
529     return 1;
530 }
531
532 int
533 afs_nbsd_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_nbsd_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_nbsd_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_nbsd_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     MALLOC(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     MALLOC(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     FREE(fname, M_TEMP);
706     FREE(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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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_nbsd_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 (!haveGlock)
898         AFS_GLOCK();
899     if (!haveVlock)
900         ObtainWriteLock(&afs_xvcache, 901);
901 #ifndef AFS_DISCON_ENV
902     code = afs_FlushVCache(avc, &slept);        /* tosses our stuff from vnode */
903 #else
904     /* reclaim the vnode and the in-memory vcache, but keep the on-disk vcache */
905     code = afs_FlushVS(avc);
906 #endif
907     if (!haveVlock)
908         ReleaseWriteLock(&afs_xvcache);
909     if (!haveGlock)
910         AFS_GUNLOCK();
911     return code;
912 }
913
914 int
915 afs_nbsd_lock(void *v)
916 {
917     struct vop_lock_args        /* {
918                                  * struct vnode *a_vp;
919                                  * int a_flags;
920                                  * sturct proc *a_p;
921                                  * } */ *ap = v;
922     struct vnode *vp = ap->a_vp;
923     struct vcache *vc = VTOAFS(vp);
924
925     if (!vc)
926         panic("afs_nbsd_lock: null vcache");
927     return lockmgr(&vc->rwlock, ap->a_flags | LK_CANRECURSE, &vp->v_interlock,
928                    ap->a_p);
929 }
930
931 int
932 afs_nbsd_unlock(void *v)
933 {
934     struct vop_unlock_args      /* {
935                                  * struct vnode *a_vp;
936                                  * int a_flags;
937                                  * struct proc *a_p;
938                                  * } */ *ap = v;
939     struct vnode *vp = ap->a_vp;
940     struct vcache *vc = VTOAFS(vp);
941
942     if (!vc)
943         panic("afs_nbsd_unlock: null vcache");
944     return lockmgr(&vc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
945                    ap->a_p);
946 }
947
948 int
949 afs_nbsd_bmap(void *v)
950 {
951     struct vop_bmap_args        /* {
952                                  * struct vnode *a_vp;
953                                  * daddr_t  a_bn;
954                                  * struct vnode **a_vpp;
955                                  * daddr_t *a_bnp;
956                                  * int *a_runp;
957                                  * } */ *ap = v;
958     struct vcache *vcp = VTOAFS(ap->a_vp);
959
960     AFS_STATCNT(afs_bmap);
961     if (ap->a_bnp)
962         ap->a_bnp = (daddr_t *) (ap->a_bn * (8192 / DEV_BSIZE));
963     if (ap->a_vpp)
964         *ap->a_vpp = (vcp) ? AFSTOV(vcp) : NULL;
965     return 0;
966 }
967
968 int
969 afs_nbsd_strategy(void *v)
970 {
971     struct vop_strategy_args    /* {
972                                  * struct buf *a_bp;
973                                  * } */ *ap = v;
974     struct buf *abp = ap->a_bp;
975     struct uio tuio;
976     struct iovec tiovec[1];
977     struct vcache *tvc = VTOAFS(abp->b_vp);
978     struct ucred *credp = osi_curcred();
979     long len = abp->b_bcount;
980     int code;
981
982     AFS_STATCNT(afs_strategy);
983
984     tuio.afsio_iov = tiovec;
985     tuio.afsio_iovcnt = 1;
986     tuio.afsio_seg = AFS_UIOSYS;
987     tuio.afsio_resid = len;
988     tiovec[0].iov_base = abp->b_un.b_addr;
989     tiovec[0].iov_len = len;
990
991     AFS_GLOCK();
992     if ((abp->b_flags & B_READ) == B_READ) {
993         code = afs_rdwr(tvc, &tuio, UIO_READ, 0, credp);
994         if (code == 0 && tuio.afsio_resid > 0)
995             bzero(abp->b_un.b_addr + len - tuio.afsio_resid,
996                   tuio.afsio_resid);
997     } else
998         code = afs_rdwr(tvc, &tuio, UIO_WRITE, 0, credp);
999     AFS_GUNLOCK();
1000
1001     ReleaseWriteLock(&tvc->lock);
1002     AFS_RELE(AFSTOV(tvc));
1003     return code;
1004 }
1005
1006 int
1007 afs_nbsd_print(void *v)
1008 {
1009     struct vop_print_args       /* {
1010                                  * struct vnode *a_vp;
1011                                  * } */ *ap = v;
1012     struct vnode *vp = ap->a_vp;
1013     struct vcache *vc = VTOAFS(ap->a_vp);
1014
1015     printf("tag %d, fid: %d.%x.%x.%x, ", vp->v_tag, vc->fid.Cell,
1016            (int)vc->fid.Fid.Volume, (int)vc->fid.Fid.Vnode,
1017            (int)vc->fid.Fid.Unique);
1018     lockmgr_printinfo(&vc->rwlock);
1019     printf("\n");
1020     return 0;
1021 }
1022
1023 int
1024 afs_nbsd_islocked(void *v)
1025 {
1026     struct vop_islocked_args    /* {
1027                                  * struct vnode *a_vp;
1028                                  * } */ *ap = v;
1029     return lockstatus(&VTOAFS(ap->a_vp)->rwlock);
1030 }
1031
1032 /*
1033  * Return POSIX pathconf information applicable to ufs filesystems.
1034  */
1035 int
1036 afs_nbsd_pathconf(void *v)
1037 {
1038     struct vop_pathconf_args    /* {
1039                                  * struct vnode *a_vp;
1040                                  * int a_name;
1041                                  * int *a_retval;
1042                                  * } */ *ap = v;
1043     AFS_STATCNT(afs_cntl);
1044     switch (ap->a_name) {
1045     case _PC_LINK_MAX:
1046         *ap->a_retval = LINK_MAX;
1047         break;
1048     case _PC_NAME_MAX:
1049         *ap->a_retval = NAME_MAX;
1050         break;
1051     case _PC_PATH_MAX:
1052         *ap->a_retval = PATH_MAX;
1053         break;
1054     case _PC_CHOWN_RESTRICTED:
1055         *ap->a_retval = 1;
1056         break;
1057     case _PC_NO_TRUNC:
1058         *ap->a_retval = 1;
1059         break;
1060     case _PC_PIPE_BUF:
1061         return EINVAL;
1062         break;
1063     default:
1064         return EINVAL;
1065     }
1066     return 0;
1067 }
1068
1069 extern int
1070   afs_lockctl(struct vcache *avc, struct AFS_FLOCK *af, int acmd,
1071               struct AFS_UCRED *acred, pid_t clid);
1072
1073 /*
1074  * Advisory record locking support (fcntl() POSIX style)
1075  */
1076 int
1077 afs_nbsd_advlock(void *v)
1078 {
1079     struct vop_advlock_args     /* {
1080                                  * struct vnode *a_vp;
1081                                  * caddr_t  a_id;
1082                                  * int  a_op;
1083                                  * struct flock *a_fl;
1084                                  * int  a_flags;
1085                                  * } */ *ap = v;
1086     int code;
1087
1088     AFS_GLOCK();
1089     code =
1090         afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, osi_curcred(),
1091                     (int)ap->a_id);
1092     AFS_GUNLOCK();
1093     return code;
1094 }