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