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