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