3ea68b35bd0cb66d0f059e8efd6bde386111fdf9
[openafs.git] / src / afs / OBSD / osi_vnodeops.c
1 /*
2 Copyright 1995 Massachusetts Institute of Technology.  All Rights
3 Reserved.
4
5 You are hereby granted a worldwide, irrevocable, paid-up, right and
6 license to use, execute, display, modify, copy and distribute MIT's
7 Modifications, provided that (i) you abide by the terms and conditions
8 of your Transarc AFS License Agreement, and (ii) you do not use the name
9 of MIT in any advertising or publicity without the prior written consent
10 of MIT.  MIT disclaims all liability for your use of MIT's
11 Modifications.  MIT's Modifications are provided "AS IS" WITHOUT
12 WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO,
13 ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
14 NONINFRINGEMENT.
15 */
16
17 /*
18  * OpenBSD specific vnodeops + other misc interface glue
19  * Original NetBSD version for Transarc afs by John Kohl <jtk@MIT.EDU>
20  * OpenBSD version by Jim Rees <rees@umich.edu>
21  *
22  * $Id$
23  */
24
25 /*
26  * A bunch of code cribbed from NetBSD ufs_vnops.c, ffs_vnops.c, and
27  * nfs_vnops.c which carry this copyright:
28  */
29 /*
30  * Copyright (c) 1982, 1986, 1989, 1993
31  *      The Regents of the University of California.  All rights reserved.
32  * (c) UNIX System Laboratories, Inc.
33  * All or some portions of this file are derived from material licensed
34  * to the University of California by American Telephone and Telegraph
35  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36  * the permission of UNIX System Laboratories, Inc.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *      This product includes software developed by the University of
49  *      California, Berkeley and its contributors.
50  * 4. Neither the name of the University nor the names of its contributors
51  *    may be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64  * SUCH DAMAGE.
65  *
66  */
67
68 #include <afsconfig.h>
69 #include "afs/param.h"
70
71 RCSID("$Header$");
72
73 #include "afs/sysincludes.h"    /* Standard vendor system headers */
74 #include "afs/afsincludes.h"    /* Afs-based standard headers */
75 #include "afs/afs_stats.h" /* statistics */
76
77 #include <sys/malloc.h>
78 #include <sys/namei.h>
79
80 #include "afs/afs_cbqueue.h"
81 #include "afs/nfsclient.h"
82 #include "afs/afs_osidnlc.h"
83
84 #ifdef DISCONN
85 extern int afs_FlushVS(struct vcache *tvc);
86 #endif
87
88 #define M_AFSNODE (M_TEMP-1)            /* XXX */
89
90 int afs_nbsd_lookup(struct vop_lookup_args *);
91 int afs_nbsd_create(struct vop_create_args *);
92 int afs_nbsd_mknod(struct vop_mknod_args *);
93 int afs_nbsd_open(struct vop_open_args *);
94 int afs_nbsd_close(struct vop_close_args *);
95 int afs_nbsd_access(struct vop_access_args *);
96 int afs_nbsd_getattr(struct vop_getattr_args *);
97 int afs_nbsd_setattr(struct vop_setattr_args *);
98 int afs_nbsd_read(struct vop_read_args *);
99 int afs_nbsd_write(struct vop_write_args *);
100 int afs_nbsd_ioctl(struct vop_ioctl_args *);
101 int afs_nbsd_select(struct vop_select_args *);
102 int afs_nbsd_fsync(struct vop_fsync_args *);
103 int afs_nbsd_remove(struct vop_remove_args *);
104 int afs_nbsd_link(struct vop_link_args *);
105 int afs_nbsd_rename(struct vop_rename_args *);
106 int afs_nbsd_mkdir(struct vop_mkdir_args *);
107 int afs_nbsd_rmdir(struct vop_rmdir_args *);
108 int afs_nbsd_symlink(struct vop_symlink_args *);
109 int afs_nbsd_readdir(struct vop_readdir_args *);
110 int afs_nbsd_readlink(struct vop_readlink_args *);
111 extern int ufs_abortop(struct vop_abortop_args *);
112 int afs_nbsd_inactive(struct vop_inactive_args *);
113 int afs_nbsd_reclaim(struct vop_reclaim_args *);
114 int afs_nbsd_lock(struct vop_lock_args *);
115 int afs_nbsd_unlock(struct vop_unlock_args *);
116 int afs_nbsd_bmap(struct vop_bmap_args *);
117 int afs_nbsd_strategy(struct vop_strategy_args *);
118 int afs_nbsd_print(struct vop_print_args *);
119 int afs_nbsd_islocked(struct vop_islocked_args *);
120 int afs_nbsd_pathconf(struct vop_pathconf_args *);
121 int afs_nbsd_advlock(struct vop_advlock_args *);
122
123 #define afs_nbsd_opnotsupp \
124         ((int (*) __P((struct  vop_reallocblks_args *)))eopnotsupp)
125 #define afs_nbsd_reallocblks afs_nbsd_opnotsupp
126
127 /* Global vfs data structures for AFS. */
128 int (**afs_vnodeop_p) __P((void *));
129 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
130         { &vop_default_desc, vn_default_error },
131         { &vop_lookup_desc, afs_nbsd_lookup },          /* lookup */
132         { &vop_create_desc, afs_nbsd_create },          /* create */
133         { &vop_mknod_desc, afs_nbsd_mknod },            /* mknod */
134         { &vop_open_desc, afs_nbsd_open },              /* open */
135         { &vop_close_desc, afs_nbsd_close },            /* close */
136         { &vop_access_desc, afs_nbsd_access },          /* access */
137         { &vop_getattr_desc, afs_nbsd_getattr },        /* getattr */
138         { &vop_setattr_desc, afs_nbsd_setattr },        /* setattr */
139         { &vop_read_desc, afs_nbsd_read },              /* read */
140         { &vop_write_desc, afs_nbsd_write },            /* write */
141         { &vop_ioctl_desc, afs_nbsd_ioctl }, /* XXX ioctl */
142         { &vop_select_desc, afs_nbsd_select },          /* select */
143         { &vop_fsync_desc, afs_nbsd_fsync },            /* fsync */
144         { &vop_remove_desc, afs_nbsd_remove },          /* remove */
145         { &vop_link_desc, afs_nbsd_link },              /* link */
146         { &vop_rename_desc, afs_nbsd_rename },          /* rename */
147         { &vop_mkdir_desc, afs_nbsd_mkdir },            /* mkdir */
148         { &vop_rmdir_desc, afs_nbsd_rmdir },            /* rmdir */
149         { &vop_symlink_desc, afs_nbsd_symlink },        /* symlink */
150         { &vop_readdir_desc, afs_nbsd_readdir },        /* readdir */
151         { &vop_readlink_desc, afs_nbsd_readlink },      /* readlink */
152         { &vop_abortop_desc, vop_generic_abortop },     /* abortop */
153         { &vop_inactive_desc, afs_nbsd_inactive },      /* inactive */
154         { &vop_reclaim_desc, afs_nbsd_reclaim },        /* reclaim */
155         { &vop_lock_desc, afs_nbsd_lock },              /* lock */
156         { &vop_unlock_desc, afs_nbsd_unlock },          /* unlock */
157         { &vop_bmap_desc, afs_nbsd_bmap },              /* bmap */
158         { &vop_strategy_desc, afs_nbsd_strategy },      /* strategy */
159         { &vop_print_desc, afs_nbsd_print },            /* print */
160         { &vop_islocked_desc, afs_nbsd_islocked },      /* islocked */
161         { &vop_pathconf_desc, afs_nbsd_pathconf },      /* pathconf */
162         { &vop_advlock_desc, afs_nbsd_advlock },        /* advlock */
163         { &vop_reallocblks_desc, afs_nbsd_reallocblks }, /* reallocblks */
164         { &vop_bwrite_desc, vop_generic_bwrite },
165         { (struct vnodeop_desc *) NULL, (int (*) __P((void *))) NULL}
166 };
167 struct vnodeopv_desc afs_vnodeop_opv_desc =
168         { &afs_vnodeop_p, afs_vnodeop_entries };
169
170 #define GETNAME()       \
171     struct componentname *cnp = ap->a_cnp; \
172     char *name; \
173     MALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
174     bcopy(cnp->cn_nameptr, name, cnp->cn_namelen); \
175     name[cnp->cn_namelen] = '\0'
176
177 #define DROPNAME() FREE(name, M_TEMP)
178
179 int afs_debug;
180
181 #define NBSD_WRITES_ALLOWED
182 #ifndef NBSD_WRITES_ALLOWED
183 int nbsd_writes_allowed = 0;
184 #endif
185
186 #undef vrele
187 #define vrele afs_nbsd_rele
188 #undef VREF
189 #define VREF afs_nbsd_ref
190
191 int
192 afs_nbsd_lookup(ap)
193 struct vop_lookup_args /* {
194                           struct vnodeop_desc * a_desc;
195                           struct vnode *a_dvp;
196                           struct vnode **a_vpp;
197                           struct componentname *a_cnp;
198                           } */ *ap;
199 {
200     int error;
201     struct vcache *vcp;
202     struct vnode *vp, *dvp;
203     int flags = ap->a_cnp->cn_flags;
204     int lockparent;                     /* 1 => lockparent flag is set */
205     int wantparent;                     /* 1 => wantparent or lockparent flag */
206
207     GETNAME();
208     lockparent = flags & LOCKPARENT;
209     wantparent = flags & (LOCKPARENT|WANTPARENT);
210
211     if (ap->a_dvp->v_type != VDIR) {
212         *ap->a_vpp = 0;
213         DROPNAME();
214         return ENOTDIR;
215     }
216     dvp = ap->a_dvp;
217     if (afs_debug & AFSDEB_VNLAYER && !(dvp->v_flag & VROOT))
218         printf("nbsd_lookup dvp %p flags %x name %s cnt %d\n", dvp, flags, name, dvp->v_usecount);
219     error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
220     if (error) {
221         if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
222             (flags & ISLASTCN) && error == ENOENT)
223             error = EJUSTRETURN;
224         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
225             cnp->cn_flags |= SAVENAME;
226         DROPNAME();
227         *ap->a_vpp = 0;
228         return (error);
229     }
230     vp = AFSTOV(vcp);                   /* always get a node if no error */
231
232     /* The parent directory comes in locked.  We unlock it on return
233        unless the caller wants it left locked.
234        we also always return the vnode locked. */
235
236     if (vp == dvp) {
237         /* they're the same; afs_lookup() already ref'ed the leaf.
238            It came in locked, so we don't need to ref OR lock it */
239         if (afs_debug & AFSDEB_VNLAYER)
240             printf("ref'ed %p as .\n", dvp);
241     } else {
242         if (!lockparent || !(flags & ISLASTCN))
243             VOP_UNLOCK(dvp, 0, curproc);                /* done with parent. */
244         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc);                  /* always return the child locked */
245         if (afs_debug & AFSDEB_VNLAYER)
246             printf("locked ret %p from lookup\n", vp);
247     }
248     *ap->a_vpp = vp;
249
250     if (((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN))
251          || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
252         cnp->cn_flags |= SAVENAME;
253
254     DROPNAME();
255     if (afs_debug & AFSDEB_VNLAYER && !(dvp->v_flag & VROOT))
256         printf("nbsd_lookup done dvp %p cnt %d\n", dvp, dvp->v_usecount);
257     return error;
258 }
259
260 int
261 afs_nbsd_create(ap)
262         struct vop_create_args /* {
263                 struct vnode *a_dvp;
264                 struct vnode **a_vpp;
265                 struct componentname *a_cnp;
266                 struct vattr *a_vap;
267         } */ *ap;
268 {
269     int error = 0;
270     struct vcache *vcp;
271     struct vnode *dvp = ap->a_dvp;
272     GETNAME();
273
274     if (afs_debug & AFSDEB_VNLAYER)
275         printf("nbsd_create dvp %p cnt %d\n", dvp, dvp->v_usecount);
276
277     /* vnode layer handles excl/nonexcl */
278
279 #ifndef NBSD_WRITES_ALLOWED
280     if (!nbsd_writes_allowed)
281         error = EROFS;
282     if (!error)
283 #endif
284     error = afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL,
285                        ap->a_vap->va_mode, &vcp,
286                        cnp->cn_cred);
287     if (error) {
288         VOP_ABORTOP(dvp, cnp);
289         vput(dvp);
290         DROPNAME();
291         return(error);
292     }
293
294     if (vcp) {
295         *ap->a_vpp = AFSTOV(vcp);
296         vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, curproc);
297     }
298     else *ap->a_vpp = 0;
299
300     if ((cnp->cn_flags & SAVESTART) == 0)
301         FREE(cnp->cn_pnbuf, M_NAMEI);
302     vput(dvp);
303     DROPNAME();
304     if (afs_debug & AFSDEB_VNLAYER)
305         printf("nbsd_create done dvp %p cnt %d\n", dvp, dvp->v_usecount);
306     return error;
307 }
308
309 int
310 afs_nbsd_mknod(ap)
311         struct vop_mknod_args /* {
312                 struct vnode *a_dvp;
313                 struct vnode **a_vpp;
314                 struct componentname *a_cnp;
315                 struct vattr *a_vap;
316         } */ *ap;
317 {
318     free(ap->a_cnp->cn_pnbuf, M_NAMEI);
319     vput(ap->a_dvp);
320     return(ENODEV);
321 }
322
323 int
324 afs_nbsd_open(ap)
325         struct vop_open_args /* {
326                 struct vnode *a_vp;
327                 int  a_mode;
328                 struct ucred *a_cred;
329                 struct proc *a_p;
330         } */ *ap;
331 {
332     int error;
333     struct vcache *vc = VTOAFS(ap->a_vp);
334     error = afs_open(&vc, ap->a_mode, ap->a_cred);
335 #ifdef DIAGNOSTIC
336     if (AFSTOV(vc) != ap->a_vp)
337         panic("AFS open changed vnode!");
338 #endif
339     return error;
340 }
341
342 int
343 afs_nbsd_close(ap)
344         struct vop_close_args /* {
345                 struct vnode *a_vp;
346                 int  a_fflag;
347                 struct ucred *a_cred;
348                 struct proc *a_p;
349         } */ *ap;
350 {
351     return afs_close(VTOAFS(ap->a_vp), ap->a_fflag, ap->a_cred, ap->a_p);
352 }
353
354 int
355 afs_nbsd_access(ap)
356         struct vop_access_args /* {
357                 struct vnode *a_vp;
358                 int  a_mode;
359                 struct ucred *a_cred;
360                 struct proc *a_p;
361         } */ *ap;
362 {
363     return afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
364 }
365 int
366 afs_nbsd_getattr(ap)
367         struct vop_getattr_args /* {
368                 struct vnode *a_vp;
369                 struct vattr *a_vap;
370                 struct ucred *a_cred;
371                 struct proc *a_p;
372         } */ *ap;
373 {
374     return afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
375 }
376 int
377 afs_nbsd_setattr(ap)
378         struct vop_setattr_args /* {
379                 struct vnode *a_vp;
380                 struct vattr *a_vap;
381                 struct ucred *a_cred;
382                 struct proc *a_p;
383         } */ *ap;
384 {
385     return afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
386 }
387 int
388 afs_nbsd_read(ap)
389         struct vop_read_args /* {
390                 struct vnode *a_vp;
391                 struct uio *a_uio;
392                 int a_ioflag;
393                 struct ucred *a_cred;
394         } */ *ap;
395 {
396     return afs_read(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, 0, 0, 0);
397 }
398 int
399 afs_nbsd_write(ap)
400         struct vop_write_args /* {
401                 struct vnode *a_vp;
402                 struct uio *a_uio;
403                 int a_ioflag;
404                 struct ucred *a_cred;
405         } */ *ap;
406 {
407 #ifdef UVM
408     (void) uvm_vnp_uncache(ap->a_vp);   /* toss stale pages */
409 #else
410     vnode_pager_uncache(ap->a_vp);
411 #endif
412     return afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
413 }
414 int
415 afs_nbsd_ioctl(ap)
416         struct vop_ioctl_args /* {
417                 struct vnode *a_vp;
418                 int  a_command;
419                 caddr_t  a_data;
420                 int  a_fflag;
421                 struct ucred *a_cred;
422                 struct proc *a_p;
423         } */ *ap;
424 {
425     struct vcache *tvc = VTOAFS(ap->a_vp);
426     int error = 0;
427
428     /* in case we ever get in here... */
429
430     AFS_STATCNT(afs_ioctl);
431     if (((ap->a_command >> 8) & 0xff) == 'V') {
432         /* This is a VICEIOCTL call */
433         error = HandleIoctl(tvc, (struct file *)0/*Not used*/,
434                             ap->a_command, ap->a_data);
435         return(error);
436     } else {
437         /* No-op call; just return. */
438         return(ENOTTY);
439     }
440 }
441
442 /* ARGSUSED */
443 int
444 afs_nbsd_select(ap)
445         struct vop_select_args /* {
446                 struct vnode *a_vp;
447                 int  a_which;
448                 int  a_fflags;
449                 struct ucred *a_cred;
450                 struct proc *a_p;
451         } */ *ap;
452 {
453         /*
454          * We should really check to see if I/O is possible.
455          */
456         return (1);
457 }
458
459 int
460 afs_nbsd_fsync(ap)
461         struct vop_fsync_args /* {
462                 struct vnode *a_vp;
463                 struct ucred *a_cred;
464                 int a_waitfor;
465                 struct proc *a_p;
466         } */ *ap;
467 {
468     int wait = ap->a_waitfor == MNT_WAIT;
469     struct vnode *vp = ap->a_vp;
470     vflushbuf(vp, wait);
471     return afs_fsync(VTOAFS(vp), ap->a_cred);
472 }
473
474 int
475 afs_nbsd_remove(ap)
476         struct vop_remove_args /* {
477                 struct vnode *a_dvp;
478                 struct vnode *a_vp;
479                 struct componentname *a_cnp;
480         } */ *ap;
481 {
482     int error = 0;
483     struct vnode *vp = ap->a_vp;
484     struct vnode *dvp = ap->a_dvp;
485
486     GETNAME();
487 #ifndef NBSD_WRITES_ALLOWED
488     if (!nbsd_writes_allowed)
489         error = EROFS;
490     if (!error)
491 #endif
492     error =  afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
493     if (dvp == vp)
494         vrele(vp);
495     else
496         vput(vp);
497     vput(dvp);
498     FREE(cnp->cn_pnbuf, M_NAMEI);
499     DROPNAME();
500     return error;
501 }
502
503 int
504 afs_nbsd_link(ap)
505         struct vop_link_args /* {
506                 struct vnode *a_vp;
507                 struct vnode *a_tdvp;
508                 struct componentname *a_cnp;
509         } */ *ap;
510 {
511     int error = 0;
512     struct vnode *dvp = ap->a_dvp;
513     struct vnode *vp = ap->a_vp;
514
515     GETNAME();
516     if (dvp->v_mount != vp->v_mount) {
517         VOP_ABORTOP(vp, cnp);
518         error = EXDEV;
519         goto out;
520     }
521     if (vp->v_type == VDIR) {
522         VOP_ABORTOP(vp, cnp);
523         error = EISDIR;
524         goto out;
525     }
526     if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc))) {
527         VOP_ABORTOP(dvp, cnp);
528         goto out;
529     }
530 #ifndef NBSD_WRITES_ALLOWED
531     if (!nbsd_writes_allowed)
532         error = EROFS;
533     if (!error)
534 #endif
535     error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
536     FREE(cnp->cn_pnbuf, M_NAMEI);
537     if (dvp != vp)
538         VOP_UNLOCK(vp, 0, curproc);
539 out:
540     vput(dvp);
541     DROPNAME();
542     return error;
543 }
544
545 int
546 afs_nbsd_rename(ap)
547         struct vop_rename_args  /* {
548                 struct vnode *a_fdvp;
549                 struct vnode *a_fvp;
550                 struct componentname *a_fcnp;
551                 struct vnode *a_tdvp;
552                 struct vnode *a_tvp;
553                 struct componentname *a_tcnp;
554         } */ *ap;
555 {
556     int error = 0;
557     struct componentname *fcnp = ap->a_fcnp;
558     char *fname;
559     struct componentname *tcnp = ap->a_tcnp;
560     char *tname;
561     struct vnode *tvp = ap->a_tvp;
562     struct vnode *tdvp = ap->a_tdvp;
563     struct vnode *fvp = ap->a_fvp;
564     struct vnode *fdvp = ap->a_fdvp;
565
566     /*
567      * Check for cross-device rename.
568      */
569     if ((fvp->v_mount != tdvp->v_mount) ||
570         (tvp && (fvp->v_mount != tvp->v_mount))) {
571         error = EXDEV;
572 abortit:
573         VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
574         if (tdvp == tvp)
575             vrele(tdvp);
576         else
577             vput(tdvp);
578         if (tvp)
579             vput(tvp);
580         VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
581         vrele(fdvp);
582         vrele(fvp);
583         return (error);
584     }
585     /*
586      * if fvp == tvp, we're just removing one name of a pair of
587      * directory entries for the same element.  convert call into rename.
588      ( (pinched from NetBSD 1.0's ufs_rename())
589      */
590     if (fvp == tvp) {
591         if (fvp->v_type == VDIR) {
592             error = EINVAL;
593             goto abortit;
594         }
595
596         /* Release destination completely. */
597         VOP_ABORTOP(tdvp, tcnp);
598         vput(tdvp);
599         vput(tvp);
600
601         /* Delete source. */
602         vrele(fdvp);
603         vrele(fvp);
604         fcnp->cn_flags &= ~MODMASK;
605         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
606         if ((fcnp->cn_flags & SAVESTART) == 0)
607             panic("afs_rename: lost from startdir");
608         fcnp->cn_nameiop = DELETE;
609         (void) relookup(fdvp, &fvp, fcnp);
610         return (VOP_REMOVE(fdvp, fvp, fcnp));
611     }
612
613     if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curproc)))
614         goto abortit;
615
616     MALLOC(fname, char *, fcnp->cn_namelen+1, M_TEMP, M_WAITOK);
617     bcopy(fcnp->cn_nameptr, fname, fcnp->cn_namelen);
618     fname[fcnp->cn_namelen] = '\0';
619     MALLOC(tname, char *, tcnp->cn_namelen+1, M_TEMP, M_WAITOK);
620     bcopy(tcnp->cn_nameptr, tname, tcnp->cn_namelen);
621     tname[tcnp->cn_namelen] = '\0';
622
623
624 #ifndef NBSD_WRITES_ALLOWED
625     if (!nbsd_writes_allowed)
626         error = EROFS;
627     if (!error)
628 #endif
629     /* XXX use "from" or "to" creds? NFS uses "to" creds */
630     error = afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
631
632     VOP_UNLOCK(fvp, 0, curproc);
633     FREE(fname, M_TEMP);
634     FREE(tname, M_TEMP);
635     if (error)
636         goto abortit;                   /* XXX */
637     if (tdvp == tvp)
638         vrele(tdvp);
639     else
640         vput(tdvp);
641     if (tvp)
642         vput(tvp);
643     vrele(fdvp);
644     vrele(fvp);
645     return error;
646 }
647
648 int
649 afs_nbsd_mkdir(ap)
650         struct vop_mkdir_args /* {
651                 struct vnode *a_dvp;
652                 struct vnode **a_vpp;
653                 struct componentname *a_cnp;
654                 struct vattr *a_vap;
655         } */ *ap;
656 {
657     struct vnode *dvp = ap->a_dvp;
658     struct vattr *vap = ap->a_vap;
659     int error = 0;
660     struct vcache *vcp;
661
662     GETNAME();
663 #ifdef DIAGNOSTIC
664     if ((cnp->cn_flags & HASBUF) == 0)
665         panic("afs_nbsd_mkdir: no name");
666 #endif
667 #ifndef NBSD_WRITES_ALLOWED
668     if (!nbsd_writes_allowed)
669         error = EROFS;
670     if (!error)
671 #endif
672     error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
673     if (error) {
674         VOP_ABORTOP(dvp, cnp);
675         vput(dvp);
676         DROPNAME();
677         return(error);
678     }
679     if (vcp) {
680         *ap->a_vpp = AFSTOV(vcp);
681         vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, curproc);
682     } else
683         *ap->a_vpp = 0;
684     DROPNAME();
685     FREE(cnp->cn_pnbuf, M_NAMEI);
686     vput(dvp);
687     return error;
688 }
689
690 int
691 afs_nbsd_rmdir(ap)
692         struct vop_rmdir_args /* {
693                 struct vnode *a_dvp;
694                 struct vnode *a_vp;
695                 struct componentname *a_cnp;
696         } */ *ap;
697 {
698     int error = 0;
699     struct vnode *vp = ap->a_vp;
700     struct vnode *dvp = ap->a_dvp;
701
702     GETNAME();
703     if (dvp == vp) {
704         vrele(dvp);
705         vput(vp);
706         FREE(cnp->cn_pnbuf, M_NAMEI);
707         DROPNAME();
708         return (EINVAL);
709     }
710
711 #ifndef NBSD_WRITES_ALLOWED
712     if (!nbsd_writes_allowed)
713         error = EROFS;
714     if (!error)
715 #endif
716     error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
717     DROPNAME();
718     vput(dvp);
719     vput(vp);
720     return error;
721 }
722
723 int
724 afs_nbsd_symlink(ap)
725         struct vop_symlink_args /* {
726                 struct vnode *a_dvp;
727                 struct vnode **a_vpp;
728                 struct componentname *a_cnp;
729                 struct vattr *a_vap;
730                 char *a_target;
731         } */ *ap;
732 {
733     struct vnode *dvp = ap->a_dvp;
734     int error = 0;
735     /* NFS ignores a_vpp; so do we. */
736
737     GETNAME();
738 #ifndef NBSD_WRITES_ALLOWED
739     if (!nbsd_writes_allowed)
740         error = EROFS;
741     if (!error)
742 #endif
743     error = afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target,
744                         cnp->cn_cred);
745     DROPNAME();
746     FREE(cnp->cn_pnbuf, M_NAMEI);
747     vput(dvp);
748     return error;
749 }
750
751 int
752 afs_nbsd_readdir(ap)
753         struct vop_readdir_args /* {
754                 struct vnode *a_vp;
755                 struct uio *a_uio;
756                 struct ucred *a_cred;
757                 int *a_eofflag;
758                 int *a_ncookies;
759                 u_long **a_cookies;
760         } */ *ap;
761 {
762 /*    printf("readdir %p cookies %p ncookies %d\n", ap->a_vp, ap->a_cookies,
763            ap->a_ncookies); */
764     return afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred,
765                        ap->a_eofflag, ap->a_ncookies, ap->a_cookies);
766 }
767
768 int
769 afs_nbsd_readlink(ap)
770         struct vop_readlink_args /* {
771                 struct vnode *a_vp;
772                 struct uio *a_uio;
773                 struct ucred *a_cred;
774         } */ *ap;
775 {
776 /*    printf("readlink %p\n", ap->a_vp);*/
777     return afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
778 }
779
780 extern int prtactive;
781
782 int
783 afs_nbsd_inactive(ap)
784         struct vop_inactive_args /* {
785                 struct vnode *a_vp;
786         } */ *ap;
787 {
788     struct vnode *vp = ap->a_vp;
789     struct vcache *vc = VTOAFS(vp);
790
791     AFS_STATCNT(afs_inactive);
792
793     if (prtactive && vp->v_usecount != 0)
794         vprint("afs_nbsd_inactive(): pushing active", vp);
795
796     vc->states &= ~CMAPPED;
797     vc->states &= ~CDirty;
798
799     lockinit(&vc->rwlock, PINOD, "vcache", 0, 0);
800     return 0;
801 }
802
803 int
804 afs_nbsd_reclaim(ap)
805         struct vop_reclaim_args /* {
806                 struct vnode *a_vp;
807         } */ *ap;
808 {
809     int error, slept;
810     struct vnode *vp = ap->a_vp;
811     struct vcache *avc = VTOAFS(vp);
812
813     cache_purge(vp);                    /* just in case... */
814 #ifdef UVM
815     uvm_vnp_uncache(vp);
816 #else
817     vnode_pager_uncache(vp);
818 #endif
819
820 #ifndef DISCONN
821     error = afs_FlushVCache(avc, &slept); /* tosses our stuff from vnode */
822 #else
823     /* reclaim the vnode and the in-memory vcache, but keep the on-disk vcache */
824     error = afs_FlushVS(avc);
825 #endif
826     if (!error && vp->v_data)
827         panic("afs_reclaim: vnode not cleaned");
828     return error;
829 }
830
831 int
832 afs_nbsd_lock(ap)
833         struct vop_lock_args /* {
834                 struct vnode *a_vp;
835                 int a_flags;
836                 sturct proc *a_p;
837         } */ *ap;
838 {
839     struct vnode *vp = ap->a_vp;
840     struct vcache *vc = VTOAFS(vp);
841
842 #ifdef DIAGNOSTIC
843     if (!vc)
844         panic("afs_nbsd_lock: null vcache");
845 #endif
846     return lockmgr(&vc->rwlock, ap->a_flags | LK_CANRECURSE, &vp->v_interlock, ap->a_p);
847 }
848
849 int
850 afs_nbsd_unlock(ap)
851         struct vop_unlock_args /* {
852                 struct vnode *a_vp;
853                 int a_flags;
854                 struct proc *a_p;
855         } */ *ap;
856 {
857     struct vnode *vp = ap->a_vp;
858     struct vcache *vc = VTOAFS(vp);
859
860 #ifdef DIAGNOSTIC
861     if (!vc)
862         panic("afs_nbsd_unlock: null vcache");
863 #endif
864     return lockmgr(&vc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p);
865 }
866
867 int
868 afs_nbsd_bmap(ap)
869         struct vop_bmap_args /* {
870                 struct vnode *a_vp;
871                 daddr_t  a_bn;
872                 struct vnode **a_vpp;
873                 daddr_t *a_bnp;
874                 int *a_runp;
875         } */ *ap;
876 {
877     struct vcache *vcp = VTOAFS(ap->a_vp);
878
879     AFS_STATCNT(afs_bmap);
880     if (ap->a_bnp)
881         ap->a_bnp = ap->a_bn * (8192 / DEV_BSIZE);
882     if (ap->a_vpp)
883         *ap->a_vpp = (vcp) ? AFSTOV(vcp) : NULL;
884     return 0;
885 }
886
887 int
888 afs_nbsd_strategy(ap)
889     struct vop_strategy_args /* {
890         struct buf *a_bp;
891     } */ *ap;
892 {
893     struct buf *abp = ap->a_bp;
894     struct uio tuio;
895     struct iovec tiovec[1];
896     struct vcache *tvc = VTOAFS(abp->b_vp);
897     struct ucred *credp = osi_curcred();
898     long len = abp->b_bcount;
899     int code;
900
901     AFS_STATCNT(afs_strategy);
902
903     tuio.afsio_iov = tiovec;
904     tuio.afsio_iovcnt = 1;
905     tuio.afsio_seg = AFS_UIOSYS;
906     tuio.afsio_resid = len;
907     tiovec[0].iov_base = abp->b_un.b_addr;
908     tiovec[0].iov_len = len;
909
910     if ((abp->b_flags & B_READ) == B_READ) {
911         code = afs_rdwr(tvc, &tuio, UIO_READ, 0, credp);
912         if (code == 0 && tuio.afsio_resid > 0)
913             bzero(abp->b_un.b_addr + len - tuio.afsio_resid, tuio.afsio_resid);
914     } else
915         code = afs_rdwr(tvc, &tuio, UIO_WRITE, 0, credp);
916
917     ReleaseWriteLock(&tvc->lock);
918     AFS_RELE(AFSTOV(tvc));
919     return code;
920 }
921
922 int
923 afs_nbsd_print(ap)
924         struct vop_print_args /* {
925                 struct vnode *a_vp;
926         } */ *ap;
927 {
928     struct vnode *vp = ap->a_vp;
929     struct vcache *vc = VTOAFS(ap->a_vp);
930
931     printf("tag %d, fid: %ld.%x.%x.%x, ", vp->v_tag, vc->fid.Cell,
932            (int) vc->fid.Fid.Volume, (int) vc->fid.Fid.Vnode, (int) vc->fid.Fid.Unique);
933     lockmgr_printinfo(&vc->rwlock);
934     printf("\n");
935     return 0;
936 }
937
938 int
939 afs_nbsd_islocked(ap)
940         struct vop_islocked_args /* {
941                 struct vnode *a_vp;
942         } */ *ap;
943 {
944     return lockstatus(&VTOAFS(ap->a_vp)->rwlock);
945 }
946
947 /*
948  * Return POSIX pathconf information applicable to ufs filesystems.
949  */
950 int
951 afs_nbsd_pathconf(ap)
952         struct vop_pathconf_args /* {
953                 struct vnode *a_vp;
954                 int a_name;
955                 int *a_retval;
956         } */ *ap;
957 {
958     AFS_STATCNT(afs_cntl);
959     switch (ap->a_name) {
960       case _PC_LINK_MAX:
961         *ap->a_retval = LINK_MAX;
962         break;
963       case _PC_NAME_MAX:
964         *ap->a_retval = NAME_MAX;
965         break;
966       case _PC_PATH_MAX:
967         *ap->a_retval = PATH_MAX;
968         break;
969       case _PC_CHOWN_RESTRICTED:
970         *ap->a_retval = 1;
971         break;
972       case _PC_NO_TRUNC:
973         *ap->a_retval = 1;
974         break;
975       case _PC_PIPE_BUF:
976         return EINVAL;
977         break;
978       default:
979         return EINVAL;
980     }
981     return 0;
982 }
983
984 /*
985  * Advisory record locking support (fcntl() POSIX style)
986  */
987 int
988 afs_nbsd_advlock(ap)
989         struct vop_advlock_args /* {
990                 struct vnode *a_vp;
991                 caddr_t  a_id;
992                 int  a_op;
993                 struct flock *a_fl;
994                 int  a_flags;
995         } */ *ap;
996 {
997     return afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, osi_curcred(),
998                        (int) ap->a_id);
999 }