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