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