vnode-ref-verification-20060217
[openafs.git] / src / afs / DARWIN / osi_vnodeops.c
1 /*
2  * Portions Copyright (c) 2003 Apple Computer, Inc.  All rights reserved.
3  */
4 #include <afsconfig.h>
5 #include <afs/param.h>
6
7 RCSID
8     ("$Header$");
9
10 #include <afs/sysincludes.h>    /* Standard vendor system headers */
11 #include <afsincludes.h>        /* Afs-based standard headers */
12 #include <afs/afs_stats.h>      /* statistics */
13 #include <sys/malloc.h>
14 #include <sys/namei.h>
15 #include <sys/ubc.h>
16 #if defined(AFS_DARWIN70_ENV)
17 #include <vfs/vfs_support.h>
18 #endif /* defined(AFS_DARWIN70_ENV) */
19 #ifdef AFS_DARWIN80_ENV
20 #include <sys/vnode_if.h>
21 #include <sys/kauth.h>
22 #endif
23
24 #ifdef AFS_DARWIN80_ENV
25 #define VOPPREF(x) &vnop_ ## x
26 #define VOPPROT(x) vnop_ ## x
27 #define OSI_UPL_ABORT_RANGE(pl, offset, size, flags) \
28   ubc_upl_abort_range((pl), (offset), (size), (flags))
29 #define OSI_UPL_COMMIT_RANGE(pl, offset, size, flags) \
30   ubc_upl_commit_range((pl), (offset), (size), (flags))
31 #define OSI_UPL_MAP(upl, offset) ubc_upl_map((upl), (offset))
32 #define OSI_UPL_UNMAP(upl) ubc_upl_unmap((upl))
33 #define VOP_ABORTOP(x, y)
34 #else
35 #define VOPPREF(x) &vop_ ## x
36 #define VOPPROT(x) vop_ ## x
37 #define OSI_UPL_ABORT_RANGE(pl, offset, size, flags) \
38   kernel_upl_abort_range((pl), (offset), (size), (flags))
39 #define OSI_UPL_COMMIT_RANGE(pl, offset, size, flags) \
40   kernel_upl_commit_range((pl), (offset), (size), (flags), \
41                           UPL_GET_INTERNAL_PAGE_LIST((pl)),\
42                                     MAX_UPL_TRANSFER)
43 #define OSI_UPL_MAP(upl, offset) kernel_upl_map(kernel_map, (upl), (offset))
44 #define OSI_UPL_UNMAP(upl) kernel_upl_unmap(kernel_map, (upl))
45 #endif
46
47 extern char afs_zeros[AFS_ZEROS];
48
49 int afs_vop_lookup(struct VOPPROT(lookup_args) *);
50 int afs_vop_create(struct VOPPROT(create_args) *);
51 int afs_vop_mknod(struct VOPPROT(mknod_args) *);
52 int afs_vop_open(struct VOPPROT(open_args) *);
53 int afs_vop_close(struct VOPPROT(close_args) *);
54 int afs_vop_access(struct VOPPROT(access_args) *);
55 int afs_vop_getattr(struct VOPPROT(getattr_args) *);
56 int afs_vop_setattr(struct VOPPROT(setattr_args) *);
57 int afs_vop_read(struct VOPPROT(read_args) *);
58 int afs_vop_write(struct VOPPROT(write_args) *);
59 int afs_vop_pagein(struct VOPPROT(pagein_args) *);
60 int afs_vop_pageout(struct VOPPROT(pageout_args) *);
61 int afs_vop_ioctl(struct VOPPROT(ioctl_args) *);
62 int afs_vop_select(struct VOPPROT(select_args) *);
63 int afs_vop_mmap(struct VOPPROT(mmap_args) *);
64 int afs_vop_fsync(struct VOPPROT(fsync_args) *);
65 int afs_vop_remove(struct VOPPROT(remove_args) *);
66 int afs_vop_link(struct VOPPROT(link_args) *);
67 int afs_vop_rename(struct VOPPROT(rename_args) *);
68 int afs_vop_mkdir(struct VOPPROT(mkdir_args) *);
69 int afs_vop_rmdir(struct VOPPROT(rmdir_args) *);
70 int afs_vop_symlink(struct VOPPROT(symlink_args) *);
71 int afs_vop_readdir(struct VOPPROT(readdir_args) *);
72 int afs_vop_readlink(struct VOPPROT(readlink_args) *);
73 #if !defined(AFS_DARWIN70_ENV)
74 extern int ufs_abortop(struct vop_abortop_args *);
75 #endif /* !defined(AFS_DARWIN70_ENV) */
76 int afs_vop_inactive(struct VOPPROT(inactive_args) *);
77 int afs_vop_reclaim(struct VOPPROT(reclaim_args) *);
78 int afs_vop_strategy(struct VOPPROT(strategy_args) *);
79 int afs_vop_pathconf(struct VOPPROT(pathconf_args) *);
80 int afs_vop_advlock(struct VOPPROT(advlock_args) *);
81 int afs_vop_blktooff __P((struct VOPPROT(blktooff_args) *));
82 int afs_vop_offtoblk __P((struct VOPPROT(offtoblk_args) *));
83 #ifndef AFS_DARWIN80_ENV
84 int afs_vop_truncate(struct VOPPROT(truncate_args) *);
85 int afs_vop_update(struct VOPPROT(update_args) *);
86 int afs_vop_lock(struct VOPPROT(lock_args) *);
87 int afs_vop_unlock(struct VOPPROT(unlock_args) *);
88 int afs_vop_bmap(struct VOPPROT(bmap_args) *);
89 int afs_vop_seek(struct VOPPROT(seek_args) *);
90 int afs_vop_cmap __P((struct VOPPROT(cmap_args) *));
91 int afs_vop_print(struct VOPPROT(print_args) *);
92 int afs_vop_islocked(struct VOPPROT(islocked_args) *);
93 #endif
94
95 #define afs_vop_opnotsupp \
96         ((int (*) __P((struct  vop_reallocblks_args *)))eopnotsupp)
97 #define afs_vop_valloc afs_vop_opnotsupp
98 #define afs_vop_vfree afs_vop_opnotsupp
99 #define afs_vop_blkatoff afs_vop_opnotsupp
100 #define afs_vop_reallocblks afs_vop_opnotsupp
101
102 /* Global vfs data structures for AFS. */
103 int (**afs_vnodeop_p) ();
104
105 #define VOPFUNC int (*)(void *)
106
107 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
108     {VOPPREF(default_desc), (VOPFUNC)vn_default_error},
109     {VOPPREF(lookup_desc), (VOPFUNC)afs_vop_lookup},    /* lookup */
110     {VOPPREF(create_desc), (VOPFUNC)afs_vop_create},    /* create */
111     {VOPPREF(mknod_desc), (VOPFUNC)afs_vop_mknod},      /* mknod */
112     {VOPPREF(open_desc), (VOPFUNC)afs_vop_open},        /* open */
113     {VOPPREF(close_desc), (VOPFUNC)afs_vop_close},      /* close */
114     {VOPPREF(access_desc), (VOPFUNC)afs_vop_access},    /* access */
115     {VOPPREF(getattr_desc), (VOPFUNC)afs_vop_getattr},  /* getattr */
116     {VOPPREF(setattr_desc), (VOPFUNC)afs_vop_setattr},  /* setattr */
117     {VOPPREF(read_desc), (VOPFUNC)afs_vop_read},        /* read */
118     {VOPPREF(write_desc), (VOPFUNC)afs_vop_write},      /* write */
119     {VOPPREF(pagein_desc), (VOPFUNC)afs_vop_pagein},    /* read */
120     {VOPPREF(pageout_desc), (VOPFUNC)afs_vop_pageout},  /* write */
121     {VOPPREF(ioctl_desc), (VOPFUNC)afs_vop_ioctl},      /* XXX ioctl */
122     {VOPPREF(select_desc), (VOPFUNC)afs_vop_select},    /* select */
123     {VOPPREF(mmap_desc), (VOPFUNC)afs_vop_mmap},        /* mmap */
124     {VOPPREF(fsync_desc), (VOPFUNC)afs_vop_fsync},      /* fsync */
125 #ifndef AFS_DARWIN80_ENV
126     {VOPPREF(seek_desc), (VOPFUNC)afs_vop_seek},        /* seek */
127 #endif
128     {VOPPREF(remove_desc), (VOPFUNC)afs_vop_remove},    /* remove */
129     {VOPPREF(link_desc), (VOPFUNC)afs_vop_link},        /* link */
130     {VOPPREF(rename_desc), (VOPFUNC)afs_vop_rename},    /* rename */
131     {VOPPREF(mkdir_desc), (VOPFUNC)afs_vop_mkdir},      /* mkdir */
132     {VOPPREF(rmdir_desc), (VOPFUNC)afs_vop_rmdir},      /* rmdir */
133     {VOPPREF(symlink_desc), (VOPFUNC)afs_vop_symlink},  /* symlink */
134     {VOPPREF(readdir_desc), (VOPFUNC)afs_vop_readdir},  /* readdir */
135     {VOPPREF(readlink_desc), (VOPFUNC)afs_vop_readlink},        /* readlink */
136 #ifndef AFS_DARWIN80_ENV
137 #if defined(AFS_DARWIN70_ENV)
138     {VOPPREF(abortop_desc), (VOPFUNC)nop_abortop },             /* abortop */
139 #else /* ! defined(AFS_DARWIN70_ENV) */
140     /* Yes, we use the ufs_abortop call.  It just releases the namei
141      * buffer stuff */
142     {VOPPREF(abortop_desc), (VOPFUNC)ufs_abortop},      /* abortop */
143 #endif /* defined(AFS_DARWIN70_ENV) */
144 #endif
145     {VOPPREF(inactive_desc), (VOPFUNC)afs_vop_inactive},        /* inactive */
146     {VOPPREF(reclaim_desc), (VOPFUNC)afs_vop_reclaim},  /* reclaim */
147 #ifndef AFS_DARWIN80_ENV
148     {VOPPREF(lock_desc), (VOPFUNC)afs_vop_lock},        /* lock */
149     {VOPPREF(unlock_desc), (VOPFUNC)afs_vop_unlock},    /* unlock */
150     {VOPPREF(bmap_desc), (VOPFUNC)afs_vop_bmap},        /* bmap */
151 #endif
152 #ifdef AFS_DARWIN80_ENV
153     {VOPPREF(strategy_desc), (VOPFUNC)err_strategy},    /* strategy */
154 #else
155     {VOPPREF(strategy_desc), (VOPFUNC)afs_vop_strategy},        /* strategy */
156 #endif
157 #ifndef AFS_DARWIN80_ENV
158     {VOPPREF(print_desc), (VOPFUNC)afs_vop_print},      /* print */
159     {VOPPREF(islocked_desc), (VOPFUNC)afs_vop_islocked},        /* islocked */
160 #endif
161     {VOPPREF(pathconf_desc), (VOPFUNC)afs_vop_pathconf},        /* pathconf */
162     {VOPPREF(advlock_desc), (VOPFUNC)afs_vop_advlock},  /* advlock */
163 #ifndef AFS_DARWIN80_ENV
164     {VOPPREF(blkatoff_desc), (VOPFUNC)afs_vop_blkatoff},        /* blkatoff */
165     {VOPPREF(valloc_desc), (VOPFUNC)afs_vop_valloc},    /* valloc */
166     {VOPPREF(reallocblks_desc), (VOPFUNC)afs_vop_reallocblks},  /* reallocblks */
167     {VOPPREF(vfree_desc), (VOPFUNC)afs_vop_vfree},      /* vfree */
168     {VOPPREF(update_desc), (VOPFUNC)afs_vop_update},    /* update */
169     {VOPPREF(cmap_desc), (VOPFUNC)afs_vop_cmap},        /* cmap */
170     {VOPPREF(truncate_desc), (VOPFUNC)afs_vop_truncate},        /* truncate */
171 #endif
172     {VOPPREF(blktooff_desc), (VOPFUNC)afs_vop_blktooff},        /* blktooff */
173     {VOPPREF(offtoblk_desc), (VOPFUNC)afs_vop_offtoblk},        /* offtoblk */
174     {VOPPREF(bwrite_desc), (VOPFUNC)vn_bwrite},
175     {(struct vnodeop_desc *)NULL, (void (*)())NULL}
176 };
177 struct vnodeopv_desc afs_vnodeop_opv_desc =
178     { &afs_vnodeop_p, afs_vnodeop_entries };
179
180 #ifdef AFS_DARWIN80_ENV
181 /* vfs structures for incompletely initialized vnodes */
182 int (**afs_dead_vnodeop_p) ();
183
184 struct vnodeopv_entry_desc afs_dead_vnodeop_entries[] = {
185     {VOPPREF(default_desc), (VOPFUNC)vn_default_error},
186     {VOPPREF(lookup_desc), (VOPFUNC)vn_default_error},  /* lookup */
187     {VOPPREF(create_desc), (VOPFUNC)err_create},        /* create */
188     {VOPPREF(mknod_desc), (VOPFUNC)err_mknod},  /* mknod */
189     {VOPPREF(open_desc), (VOPFUNC)err_open},    /* open */
190     {VOPPREF(close_desc), (VOPFUNC)err_close},  /* close */
191     {VOPPREF(access_desc), (VOPFUNC)err_access},        /* access */
192     {VOPPREF(getattr_desc), (VOPFUNC)err_getattr},      /* getattr */
193     {VOPPREF(setattr_desc), (VOPFUNC)err_setattr},      /* setattr */
194     {VOPPREF(read_desc), (VOPFUNC)err_read},    /* read */
195     {VOPPREF(write_desc), (VOPFUNC)err_write},  /* write */
196     {VOPPREF(pagein_desc), (VOPFUNC)err_pagein},        /* read */
197     {VOPPREF(pageout_desc), (VOPFUNC)err_pageout},      /* write */
198     {VOPPREF(ioctl_desc), (VOPFUNC)err_ioctl},  /* XXX ioctl */
199     {VOPPREF(select_desc), (VOPFUNC)nop_select},        /* select */
200     {VOPPREF(mmap_desc), (VOPFUNC)err_mmap},    /* mmap */
201     {VOPPREF(fsync_desc), (VOPFUNC)err_fsync},  /* fsync */
202     {VOPPREF(remove_desc), (VOPFUNC)err_remove},        /* remove */
203     {VOPPREF(link_desc), (VOPFUNC)err_link},    /* link */
204     {VOPPREF(rename_desc), (VOPFUNC)err_rename},        /* rename */
205     {VOPPREF(mkdir_desc), (VOPFUNC)err_mkdir},  /* mkdir */
206     {VOPPREF(rmdir_desc), (VOPFUNC)err_rmdir},  /* rmdir */
207     {VOPPREF(symlink_desc), (VOPFUNC)err_symlink},      /* symlink */
208     {VOPPREF(readdir_desc), (VOPFUNC)err_readdir},      /* readdir */
209     {VOPPREF(readlink_desc), (VOPFUNC)err_readlink},    /* readlink */
210     {VOPPREF(inactive_desc), (VOPFUNC)afs_vop_inactive},        /* inactive */
211     {VOPPREF(reclaim_desc), (VOPFUNC)afs_vop_reclaim},  /* reclaim */
212     {VOPPREF(strategy_desc), (VOPFUNC)err_strategy},    /* strategy */
213     {VOPPREF(pathconf_desc), (VOPFUNC)err_pathconf},    /* pathconf */
214     {VOPPREF(advlock_desc), (VOPFUNC)err_advlock},      /* advlock */
215     {VOPPREF(blktooff_desc), (VOPFUNC)err_blktooff},    /* blktooff */
216     {VOPPREF(offtoblk_desc), (VOPFUNC)err_offtoblk},    /* offtoblk */
217     {VOPPREF(bwrite_desc), (VOPFUNC)err_bwrite},
218     {(struct vnodeop_desc *)NULL, (void (*)())NULL}
219 };
220 struct vnodeopv_desc afs_dead_vnodeop_opv_desc =
221     { &afs_dead_vnodeop_p, afs_dead_vnodeop_entries };
222 #endif
223
224 #define GETNAME()       \
225     struct componentname *cnp = ap->a_cnp; \
226     char *name; \
227     MALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
228     memcpy(name, cnp->cn_nameptr, cnp->cn_namelen); \
229     name[cnp->cn_namelen] = '\0'
230
231 #define DROPNAME() FREE(name, M_TEMP)
232
233 void 
234 darwin_vn_hold(struct vnode *vp)
235 {
236     int haveGlock=ISAFS_GLOCK(); 
237     struct vcache *tvc = VTOAFS(vp);
238
239 #ifndef AFS_DARWIN80_ENV
240     tvc->states |= CUBCinit;
241 #endif
242 #ifdef AFS_DARWIN80_ENV
243     osi_Assert((tvc->states & CVInit) == 0);
244     if (tvc->states & CDeadVnode)
245        osi_Assert(!vnode_isinuse(vp, 1));
246 #endif
247     if (haveGlock) AFS_GUNLOCK(); 
248
249 #ifdef AFS_DARWIN80_ENV
250         if (vnode_get(vp)) {
251            /* being terminated. kernel won't give us a ref. Now what? our
252               callers don't expect us to fail */
253 #if 1
254            panic("vn_hold on terminating vnode");
255 #else           
256            if (haveGlock) AFS_GLOCK(); 
257            return;
258 #endif
259         }
260         if (vnode_ref(vp)) {
261 #if 1
262             panic("vn_hold on terminating vnode");
263 #else           
264             vnode_put(vp);
265             if (haveGlock) AFS_GLOCK(); 
266             return;
267 #endif
268         }
269         vnode_put(vp);
270 #else
271     /* vget needed for 0 ref'd vnode in GetVCache to not panic in vref.
272        vref needed for multiref'd vnode in vnop_remove not to deadlock
273        ourselves during vop_inactive, except we also need to not reinst
274        the ubc... so we just call VREF there now anyway. */
275
276     if (VREFCOUNT_GT(tvc, 0))
277         VREF(((struct vnode *)(vp))); 
278      else 
279         afs_vget(afs_globalVFS, 0, (vp));
280 #endif
281
282 #ifndef AFS_DARWIN80_ENV
283     if (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp)) {
284         ubc_info_init(vp); 
285     }
286 #endif
287
288     if (haveGlock) AFS_GLOCK(); 
289 #ifndef AFS_DARWIN80_ENV
290     tvc->states &= ~CUBCinit;
291 #endif
292 }
293 int
294 afs_vop_lookup(ap)
295      struct VOPPROT(lookup_args)/* {
296                                  * struct vnodeop_desc * a_desc;
297                                  * struct vnode *a_dvp;
298                                  * struct vnode **a_vpp;
299                                  * struct componentname *a_cnp;
300                                  * } */ *ap;
301 {
302     int error;
303     struct vcache *vcp;
304     struct vnode *vp, *dvp;
305     register int flags = ap->a_cnp->cn_flags;
306     int lockparent;             /* 1 => lockparent flag is set */
307     int wantparent;             /* 1 => wantparent or lockparent flag */
308     struct proc *p;
309 #ifdef AFS_DARWIN80_ENV
310     vcp = VTOAFS(ap->a_dvp);
311     if (vcp->mvstat != 1) {
312         error = cache_lookup(ap->a_dvp, ap->a_vpp, ap->a_cnp);
313         if (error == -1) 
314             return 0;
315         if (error == ENOENT) 
316             return error;
317     }
318 #endif
319
320     GETNAME();
321     p = vop_cn_proc;
322
323     lockparent = flags & LOCKPARENT;
324     wantparent = flags & (LOCKPARENT | WANTPARENT);
325
326     if (!vnode_isdir(ap->a_dvp)) {
327         *ap->a_vpp = 0;
328         DROPNAME();
329         return ENOTDIR;
330     }
331     dvp = ap->a_dvp;
332 #ifndef AFS_DARWIN80_ENV
333     if (flags & ISDOTDOT)
334         VOP_UNLOCK(dvp, 0, p);
335 #endif
336     AFS_GLOCK();
337     error = afs_lookup(VTOAFS(dvp), name, &vcp, vop_cn_cred);
338     AFS_GUNLOCK();
339     if (error) {
340 #ifndef AFS_DARWIN80_ENV
341         if (flags & ISDOTDOT)
342             VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
343 #endif
344         if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
345             && (flags & ISLASTCN) && error == ENOENT)
346             error = EJUSTRETURN;
347 #ifndef AFS_DARWIN80_ENV
348         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
349             cnp->cn_flags |= SAVENAME;
350 #endif
351         DROPNAME();
352         *ap->a_vpp = 0;
353         return (error);
354     }
355 #ifdef AFS_DARWIN80_ENV
356     if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0))) {
357         *ap->a_vpp = 0;
358         return error;
359     }
360 #endif
361     vp = AFSTOV(vcp);           /* always get a node if no error */
362 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
363     vp->v_vfsp = dvp->v_vfsp;
364
365     if (UBCINFOMISSING(vp) ||
366         UBCINFORECLAIMED(vp)) {
367             ubc_info_init(vp);
368     }
369 #endif
370
371 #ifndef AFS_DARWIN80_ENV
372     /* The parent directory comes in locked.  We unlock it on return
373      * unless the caller wants it left locked.
374      * we also always return the vnode locked. */
375
376     if (flags & ISDOTDOT) {
377         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
378         /* always return the child locked */
379         if (lockparent && (flags & ISLASTCN)
380             && (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
381             vput(vp);
382             DROPNAME();
383             return (error);
384         }
385     } else if (vp == dvp) {
386         /* they're the same; afs_lookup() already ref'ed the leaf.
387          * It came in locked, so we don't need to ref OR lock it */
388     } else {
389         if (!lockparent || !(flags & ISLASTCN))
390             VOP_UNLOCK(dvp, 0, p);      /* done with parent. */
391         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
392         /* always return the child locked */
393     }
394 #endif
395     *ap->a_vpp = vp;
396
397 #ifndef AFS_DARWIN80_ENV
398     if ((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)
399          || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
400         cnp->cn_flags |= SAVENAME;
401 #endif
402
403     DROPNAME();
404     return error;
405 }
406
407 int
408 afs_vop_create(ap)
409      struct VOPPROT(create_args)        /* {
410                                  * struct vnode *a_dvp;
411                                  * struct vnode **a_vpp;
412                                  * struct componentname *a_cnp;
413                                  * struct vattr *a_vap;
414                                  * } */ *ap;
415 {
416     int error = 0;
417     struct vcache *vcp;
418     register struct vnode *dvp = ap->a_dvp;
419     struct proc *p;
420     GETNAME();
421     p = vop_cn_proc;
422
423     /* vnode layer handles excl/nonexcl */
424     AFS_GLOCK();
425     error =
426         afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
427                    &vcp, vop_cn_cred);
428     AFS_GUNLOCK();
429     if (error) {
430 #ifndef AFS_DARWIN80_ENV
431         VOP_ABORTOP(dvp, cnp);
432         vput(dvp);
433 #endif
434         DROPNAME();
435         return (error);
436     }
437
438     if (vcp) {
439 #ifdef AFS_DARWIN80_ENV
440         if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0))) {
441              *ap->a_vpp=0;
442              return error;
443         }
444 #endif
445         *ap->a_vpp = AFSTOV(vcp);
446 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
447         (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
448         vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
449         if (UBCINFOMISSING(*ap->a_vpp) || UBCINFORECLAIMED(*ap->a_vpp)) {
450             vcp->states |= CUBCinit;
451             ubc_info_init(*ap->a_vpp);
452             vcp->states &= ~CUBCinit;
453         }
454 #endif
455     } else
456         *ap->a_vpp = 0;
457
458 #ifndef AFS_DARWIN80_ENV
459     if ((cnp->cn_flags & SAVESTART) == 0)
460         FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
461     vput(dvp);
462 #endif
463     DROPNAME();
464     return error;
465 }
466
467 int
468 afs_vop_mknod(ap)
469      struct VOPPROT(mknod_args) /* {
470                                  * struct vnode *a_dvp;
471                                  * struct vnode **a_vpp;
472                                  * struct componentname *a_cnp;
473                                  * struct vattr *a_vap;
474                                  * } */ *ap;
475 {
476 #ifndef AFS_DARWIN80_ENV
477     FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
478     vput(ap->a_dvp);
479 #endif
480     return (ENODEV);
481 }
482
483 int
484 afs_vop_open(ap)
485      struct VOPPROT(open_args)  /* {
486                                  * struct vnode *a_vp;
487                                  * int  a_mode;
488                                  * struct ucred *a_cred;
489                                  * struct proc *a_p;
490                                  * } */ *ap;
491 {
492     int error;
493     struct vnode *vp = ap->a_vp;
494     struct vcache *vc = VTOAFS(vp);
495 #if defined(AFS_DARWIN14_ENV) && !defined(AFS_DARWIN80_ENV)
496     int didhold = 0;
497     /*----------------------------------------------------------------
498      * osi_VM_TryReclaim() removes the ubcinfo of a vnode, but that vnode
499      * can later be passed to vn_open(), which will skip the call to
500      * ubc_hold(), and when the ubcinfo is later added, the ui_refcount
501      * will be off.  So we compensate by calling ubc_hold() ourselves
502      * when ui_refcount is less than 2.  If an error occurs in afs_open()
503      * we must call ubc_rele(), which is what vn_open() would do if it
504      * was able to call ubc_hold() in the first place.
505      *----------------------------------------------------------------*/
506     if (vp->v_type == VREG && !(vp->v_flag & VSYSTEM)
507       && vp->v_ubcinfo->ui_refcount < 2)
508         didhold = ubc_hold(vp);
509 #endif /* AFS_DARWIN14_ENV */
510     AFS_GLOCK();
511     error = afs_open(&vc, ap->a_mode, vop_cred);
512 #ifdef DIAGNOSTIC
513     if (AFSTOV(vc) != vp)
514         panic("AFS open changed vnode!");
515 #endif
516     osi_FlushPages(vc, vop_cred);
517     AFS_GUNLOCK();
518 #if defined(AFS_DARWIN14_ENV) && !defined(AFS_DARWIN80_ENV)
519     if (error && didhold)
520         ubc_rele(vp);
521 #endif /* AFS_DARWIN14_ENV */
522     return error;
523 }
524
525 int
526 afs_vop_close(ap)
527      struct VOPPROT(close_args) /* {
528                                  * struct vnode *a_vp;
529                                  * int  a_fflag;
530                                  * struct ucred *a_cred;
531                                  * struct proc *a_p;
532                                  * } */ *ap;
533 {
534     int code;
535     struct vnode *vp = ap->a_vp;
536     struct vcache *avc = VTOAFS(vp);
537     AFS_GLOCK();
538     if (vop_cred)
539         code = afs_close(avc, ap->a_fflag, vop_cred, vop_proc);
540     else
541         code = afs_close(avc, ap->a_fflag, &afs_osi_cred, vop_proc);
542     osi_FlushPages(avc, vop_cred);      /* hold bozon lock, but not basic vnode lock */
543     AFS_GUNLOCK();
544
545     return code;
546 }
547
548 #ifdef AFS_DARWIN80_ENV
549 extern int afs_fakestat_enable;
550
551 int
552 afs_vop_access(ap)
553      struct VOPPROT(access_args)        /* {
554                                  * struct vnode *a_vp;
555                                  * int  a_action;
556                                  * vfs_context_t a_context;
557                                  * } */ *ap;
558 {
559     int code;
560     struct vrequest treq;
561     struct afs_fakestat_state fakestate;
562     struct vcache * tvc = VTOAFS(ap->a_vp);
563     int bits=0;
564     AFS_GLOCK();
565     afs_InitFakeStat(&fakestate);
566     if ((code = afs_InitReq(&treq, vop_cred)))
567         goto out2;
568
569     code = afs_TryEvalFakeStat(&tvc, &fakestate, &treq);
570     if (code) {
571         code = afs_CheckCode(code, &treq, 55);
572         goto out;
573     }
574
575     code = afs_VerifyVCache(tvc, &treq);
576     if (code) {
577         code = afs_CheckCode(code, &treq, 56);
578         goto out;
579     }
580     if (afs_fakestat_enable && tvc->mvstat && !(tvc->states & CStatd)) {
581         code = 0;
582         goto out;
583     }
584     if (vnode_isdir(ap->a_vp)) {
585        if (ap->a_action & KAUTH_VNODE_LIST_DIRECTORY)
586           bits |= PRSFS_LOOKUP;
587        if (ap->a_action & KAUTH_VNODE_ADD_FILE)
588           bits |= PRSFS_INSERT;
589        if (ap->a_action & KAUTH_VNODE_SEARCH)
590           bits |= PRSFS_LOOKUP;
591        if (ap->a_action & KAUTH_VNODE_DELETE)
592           bits |= PRSFS_DELETE;
593        if (ap->a_action & KAUTH_VNODE_ADD_SUBDIRECTORY)
594           bits |= PRSFS_INSERT;
595        if (ap->a_action & KAUTH_VNODE_DELETE_CHILD)
596           bits |= PRSFS_DELETE;
597 #if 0 /* I'd argue this should be enforced on the parent. But that's ugly */
598        if (ap->a_action & KAUTH_VNODE_READ_ATTRIBUTES)
599           bits |= PRSFS_LOOKUP;
600        if (ap->a_action & KAUTH_VNODE_READ_SECURITY) /* mode bits/gid, not afs acl */
601           bits |= PRSFS_LOOKUP;
602 #endif
603     } else {
604        if (ap->a_action & KAUTH_VNODE_READ_DATA)
605           bits |= PRSFS_READ;
606        if (ap->a_action & KAUTH_VNODE_WRITE_DATA)
607           bits |= PRSFS_WRITE;
608        if (ap->a_action & KAUTH_VNODE_EXECUTE)
609           bits |= PRSFS_READ; /* and mode bits.... */
610        if (ap->a_action & KAUTH_VNODE_READ_ATTRIBUTES)
611           bits |= PRSFS_LOOKUP;
612        if (ap->a_action & KAUTH_VNODE_READ_SECURITY) /* mode bits/gid, not afs acl */
613           bits |= PRSFS_LOOKUP;
614     }
615     if (ap->a_action & KAUTH_VNODE_WRITE_ATTRIBUTES)
616        bits |= PRSFS_WRITE;
617 #if 0 /* no extended attributes */
618     if (ap->a_action & KAUTH_VNODE_READ_EXTATTRIBUTES)
619        bits |= PRSFS_READ;
620     if (ap->a_action & KAUTH_VNODE_WRITE_EXTATTRIBUTES)
621        bits |= PRSFS_WRITE;
622 #endif
623     if (ap->a_action & KAUTH_VNODE_WRITE_SECURITY)
624        bits |= PRSFS_WRITE;
625     /* we can't check for KAUTH_VNODE_TAKE_OWNERSHIP, so we always permit it */
626     
627     code = afs_AccessOK(tvc, bits, &treq, CHECK_MODE_BITS);
628
629     if (code == 1 && vnode_vtype(ap->a_vp) == VREG &&
630         ap->a_action & KAUTH_VNODE_EXECUTE &&
631         (tvc->m.Mode & 0100) != 0100) {
632         code = 0;
633      }
634     if (code) {
635         code= 0;               /* if access is ok */
636     } else {
637         code = afs_CheckCode(EACCES, &treq, 57);        /* failure code */
638     }
639 out:
640      afs_PutFakeStat(&fakestate);
641 out2:
642     AFS_GUNLOCK();
643     return code;
644 }
645 #else
646 int
647 afs_vop_access(ap)
648      struct VOPPROT(access_args)        /* {
649                                  * struct vnode *a_vp;
650                                  * int  a_mode;
651                                  * struct ucred *a_cred;
652                                  * struct proc *a_p;
653                                  * } */ *ap;
654 {
655     int code;
656     AFS_GLOCK();
657     code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, vop_cred);
658     AFS_GUNLOCK();
659     return code;
660 }
661 #endif
662
663 int
664 afs_vop_getattr(ap)
665      struct VOPPROT(getattr_args)       /* {
666                                  * struct vnode *a_vp;
667                                  * struct vattr *a_vap;
668                                  * struct ucred *a_cred;
669                                  * struct proc *a_p;
670                                  * } */ *ap;
671 {
672     int code;
673
674     AFS_GLOCK();
675     code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, vop_cred);
676     AFS_GUNLOCK();
677 #ifdef AFS_DARWIN80_ENV
678     VATTR_SET_SUPPORTED(ap->a_vap, va_type);
679     VATTR_SET_SUPPORTED(ap->a_vap, va_mode);
680     VATTR_SET_SUPPORTED(ap->a_vap, va_uid);
681     VATTR_SET_SUPPORTED(ap->a_vap, va_gid);
682     VATTR_SET_SUPPORTED(ap->a_vap, va_fileid);
683     VATTR_SET_SUPPORTED(ap->a_vap, va_nlink);
684     VATTR_SET_SUPPORTED(ap->a_vap, va_data_size);
685     VATTR_SET_SUPPORTED(ap->a_vap, va_access_time);
686     VATTR_SET_SUPPORTED(ap->a_vap, va_modify_time);
687     VATTR_SET_SUPPORTED(ap->a_vap, va_change_time);
688     VATTR_SET_SUPPORTED(ap->a_vap, va_gen);
689     VATTR_SET_SUPPORTED(ap->a_vap, va_flags);
690     VATTR_SET_SUPPORTED(ap->a_vap, va_iosize);
691     VATTR_SET_SUPPORTED(ap->a_vap, va_total_alloc);
692 #endif
693     return code;
694 }
695
696 int
697 afs_vop_setattr(ap)
698      struct VOPPROT(setattr_args)       /* {
699                                  * struct vnode *a_vp;
700                                  * struct vattr *a_vap;
701                                  * struct ucred *a_cred;
702                                  * struct proc *a_p;
703                                  * } */ *ap;
704 {
705     int code;
706     AFS_GLOCK();
707     code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, vop_cred);
708     AFS_GUNLOCK();
709     return code;
710 }
711
712 int
713 afs_vop_read(ap)
714      struct VOPPROT(read_args)  /* {
715                                  * struct vnode *a_vp;
716                                  * struct uio *a_uio;
717                                  * int a_ioflag;
718                                  * struct ucred *a_cred;
719                                  * } */ *ap;
720 {
721     int code;
722     struct vnode *vp = ap->a_vp;
723     struct vcache *avc = VTOAFS(vp);
724 #ifdef AFS_DARWIN80_ENV
725     ubc_sync_range(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio), AFS_UIO_OFFSET(ap->a_uio) + AFS_UIO_RESID(ap->a_uio), UBC_PUSHDIRTY);
726 #else
727     if (UBCINFOEXISTS(ap->a_vp)) {
728         ubc_clean(ap->a_vp, 0);
729     }
730 #endif
731     AFS_GLOCK();
732     osi_FlushPages(avc, vop_cred);      /* hold bozon lock, but not basic vnode lock */
733     code = afs_read(avc, ap->a_uio, vop_cred, 0, 0, 0);
734     AFS_GUNLOCK();
735     return code;
736 }
737
738 int
739 afs_vop_pagein(ap)
740      struct VOPPROT(pagein_args)        /* {
741                                  * struct vnode *a_vp;
742                                  * upl_t a_pl;
743                                  * vm_offset_t a_pl_offset;
744                                  * off_t a_f_offset;
745                                  * size_t a_size;
746                                  * struct ucred *a_cred;
747                                  * int a_flags;
748                                  * } */ *ap;
749 {
750     register struct vnode *vp = ap->a_vp;
751     upl_t pl = ap->a_pl;
752     size_t size = ap->a_size;
753     off_t f_offset = ap->a_f_offset;
754     vm_offset_t pl_offset = ap->a_pl_offset;
755     int flags = ap->a_flags;
756     struct ucred *cred;
757     vm_offset_t ioaddr;
758 #ifdef AFS_DARWIN80_ENV
759     struct uio *uio;
760 #else
761     struct uio auio;
762     struct iovec aiov;
763     struct uio *uio = &auio;
764 #endif
765     int nocommit = flags & UPL_NOCOMMIT;
766
767     int code;
768     struct vcache *tvc = VTOAFS(vp);
769 #ifndef AFS_DARWIN80_ENV
770     if (UBCINVALID(vp)) {
771 #if DIAGNOSTIC
772         panic("afs_vop_pagein: invalid vp");
773 #endif /* DIAGNOSTIC */
774         return (EPERM);
775     }
776
777     UBCINFOCHECK("afs_vop_pagein", vp);
778 #endif
779     if (pl == (upl_t) NULL) {
780         panic("afs_vop_pagein: no upl");
781     }
782
783     cred = ubc_getcred(vp);
784     if (cred == NOCRED)
785         cred = vop_cred;
786
787     if (size == 0) {
788         if (!nocommit)
789             OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
790                                    UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
791         return (0);
792     }
793     if (f_offset < 0) {
794         if (!nocommit)
795             OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
796                                    UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
797         return (EINVAL);
798     }
799     if (f_offset & PAGE_MASK)
800         panic("afs_vop_pagein: offset not page aligned");
801
802     OSI_UPL_MAP(pl, &ioaddr);
803     ioaddr += pl_offset;
804 #ifdef AFS_DARWIN80_ENV
805     uio = uio_create(1, f_offset, UIO_SYSSPACE32, UIO_READ);
806     uio_addiov(uio, CAST_USER_ADDR_T(ioaddr), size);
807 #else
808     auio.uio_iov = &aiov;
809     auio.uio_iovcnt = 1;
810     auio.uio_offset = f_offset;
811     auio.uio_segflg = UIO_SYSSPACE;
812     auio.uio_rw = UIO_READ;
813     auio.uio_procp = NULL;
814     auio.uio_resid = aiov.iov_len = size;
815     aiov.iov_base = (caddr_t) ioaddr;
816 #endif
817     AFS_GLOCK();
818     osi_FlushPages(tvc, vop_cred);      /* hold bozon lock, but not basic vnode lock */
819     code = afs_read(tvc, uio, cred, 0, 0, 0);
820     if (code == 0) {
821         ObtainWriteLock(&tvc->lock, 2);
822         tvc->states |= CMAPPED;
823         ReleaseWriteLock(&tvc->lock);
824     }
825     AFS_GUNLOCK();
826
827     /* Zero out rest of last page if there wasn't enough data in the file */
828     if (code == 0 && AFS_UIO_RESID(uio) > 0) {
829 #ifdef AFS_DARWIN80_ENV
830         memset(((caddr_t)ioaddr) + (size - AFS_UIO_RESID(uio)), 0,
831                AFS_UIO_RESID(uio));
832 #else
833         memset(aiov.iov_base, 0, auio.uio_resid);
834 #endif
835     }
836
837     OSI_UPL_UNMAP(pl);
838     if (!nocommit) {
839         if (code)
840             OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
841                                    UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
842         else
843             OSI_UPL_COMMIT_RANGE(pl, pl_offset, size,
844                                     UPL_COMMIT_CLEAR_DIRTY |
845                                     UPL_COMMIT_FREE_ON_EMPTY);
846     }
847 #ifdef AFS_DARWIN80_ENV
848     uio_free(uio);
849 #endif
850     return code;
851 }
852
853 int
854 afs_vop_write(ap)
855      struct VOPPROT(write_args) /* {
856                                  * struct vnode *a_vp;
857                                  * struct uio *a_uio;
858                                  * int a_ioflag;
859                                  * struct ucred *a_cred;
860                                  * } */ *ap;
861 {
862     int code;
863     struct vcache *avc = VTOAFS(ap->a_vp);
864     void *object;
865 #ifdef AFS_DARWIN80_ENV
866     ubc_sync_range(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio), AFS_UIO_OFFSET(ap->a_uio) + AFS_UIO_RESID(ap->a_uio), UBC_INVALIDATE);
867 #else
868     if (UBCINFOEXISTS(ap->a_vp)) {
869         ubc_clean(ap->a_vp, 1);
870     }
871     if (UBCINFOEXISTS(ap->a_vp))
872         osi_VM_NukePages(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio),
873                          AFS_UIO_RESID(ap->a_uio));
874 #endif
875     AFS_GLOCK();
876     osi_FlushPages(avc, vop_cred);      /* hold bozon lock, but not basic vnode lock */
877     code =
878         afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, vop_cred, 0);
879     AFS_GUNLOCK();
880     return code;
881 }
882
883 int
884 afs_vop_pageout(ap)
885      struct VOPPROT(pageout_args)       /* {
886                                  * struct vnode *a_vp;
887                                  * upl_t   a_pl,
888                                  * vm_offset_t   a_pl_offset,
889                                  * off_t         a_f_offset,
890                                  * size_t        a_size,
891                                  * struct ucred *a_cred,
892                                  * int           a_flags
893                                  * } */ *ap;
894 {
895     register struct vnode *vp = ap->a_vp;
896     upl_t pl = ap->a_pl;
897     size_t size = ap->a_size;
898     off_t f_offset = ap->a_f_offset;
899     vm_offset_t pl_offset = ap->a_pl_offset;
900     int flags = ap->a_flags;
901     struct ucred *cred;
902     vm_offset_t ioaddr;
903 #ifdef AFS_DARWIN80_ENV
904     struct uio *uio;
905 #else
906     struct uio auio;
907     struct iovec aiov;
908     struct uio *uio = &auio;
909 #endif
910     int nocommit = flags & UPL_NOCOMMIT;
911     int iosize;
912
913     int code;
914     struct vcache *tvc = VTOAFS(vp);
915 #ifndef AFS_DARWIN80_ENV
916     if (UBCINVALID(vp)) {
917 #if DIAGNOSTIC
918         panic("afs_vop_pageout: invalid vp");
919 #endif /* DIAGNOSTIC */
920         return (EPERM);
921     }
922
923     UBCINFOCHECK("afs_vop_pageout", vp);
924 #endif
925     if (pl == (upl_t) NULL) {
926         panic("afs_vop_pageout: no upl");
927     }
928 #if !defined(AFS_DARWIN80_ENV) /* XXX nfs now uses it's own bufs (struct nfsbuf)
929                                   maybe the generic
930                                   layer doesn't have them anymore? In any case,
931                                   we can't just copy code from nfs... */
932     {
933         int lbn, s;
934         struct buf *bp;
935         int biosize = DEV_BSIZE;
936
937         lbn = f_offset / DEV_BSIZE;
938
939         for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
940
941             s = splbio();
942             if (bp = incore(vp, lbn)) {
943                 if (ISSET(bp->b_flags, B_BUSY))
944                     panic("nfs_pageout: found BUSY buffer incore\n");
945
946                 bremfree(bp);
947                 SET(bp->b_flags, (B_BUSY | B_INVAL));
948                 brelse(bp);
949             }
950             splx(s);
951         }
952     }
953 #endif
954     cred = ubc_getcred(vp);
955     if (cred == NOCRED)
956         cred = vop_cred;
957
958     if (size == 0) {
959         if (!nocommit)
960             OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
961                                    UPL_ABORT_FREE_ON_EMPTY);
962         return (0);
963     }
964     if (flags & (IO_APPEND | IO_SYNC))
965         panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
966     if (f_offset < 0) {
967         if (!nocommit)
968             OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
969                                    UPL_ABORT_FREE_ON_EMPTY);
970         return (EINVAL);
971     }
972     if (f_offset >= tvc->m.Length) {
973         if (!nocommit)
974             OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
975                                    UPL_ABORT_FREE_ON_EMPTY);
976         return (EINVAL);
977     }
978
979     if (f_offset & PAGE_MASK)
980         panic("afs_vop_pageout: offset not page aligned");
981
982     /* size will always be a multiple of PAGE_SIZE */
983     /* pageout isn't supposed to extend files */
984     if (f_offset + size > tvc->m.Length) 
985         iosize = tvc->m.Length - f_offset;
986     else
987         iosize = size;
988
989     if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit)  {
990             int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
991             OSI_UPL_ABORT_RANGE(pl, pl_offset + iosize_rnd,
992                                    size - iosize_rnd,
993                                    UPL_ABORT_FREE_ON_EMPTY);
994     }
995     OSI_UPL_MAP(pl, &ioaddr);
996     ioaddr += pl_offset;
997 #ifdef AFS_DARWIN80_ENV
998     uio = uio_create(1, f_offset, UIO_SYSSPACE32, UIO_READ);
999     uio_addiov(uio, CAST_USER_ADDR_T(ioaddr), size);
1000 #else
1001     auio.uio_iov = &aiov;
1002     auio.uio_iovcnt = 1;
1003     auio.uio_offset = f_offset;
1004     auio.uio_segflg = UIO_SYSSPACE;
1005     auio.uio_rw = UIO_WRITE;
1006     auio.uio_procp = NULL;
1007     auio.uio_resid = aiov.iov_len = iosize;
1008     aiov.iov_base = (caddr_t) ioaddr;
1009 #endif
1010 #if 1                           /* USV [ */
1011     {
1012         /* 
1013          * check for partial page and clear the
1014          * contents past end of the file before
1015          * releasing it in the VM page cache
1016          */
1017         if ((f_offset < tvc->m.Length) && (f_offset + size) > tvc->m.Length) {
1018             size_t io = tvc->m.Length - f_offset;
1019
1020             memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
1021         }
1022     }
1023 #endif /* ] USV */
1024
1025     AFS_GLOCK();
1026     osi_FlushPages(tvc, vop_cred);      /* hold bozon lock, but not basic vnode lock */
1027     ObtainWriteLock(&tvc->lock, 1);
1028     afs_FakeOpen(tvc);
1029     ReleaseWriteLock(&tvc->lock);
1030
1031     code = afs_write(tvc, uio, flags, cred, 0);
1032
1033     ObtainWriteLock(&tvc->lock, 1);
1034     afs_FakeClose(tvc, cred);
1035     ReleaseWriteLock(&tvc->lock);
1036     AFS_GUNLOCK();
1037     OSI_UPL_UNMAP(pl);
1038     if (!nocommit) {
1039         if (code)
1040             OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1041                                    UPL_ABORT_FREE_ON_EMPTY);
1042         else
1043             OSI_UPL_COMMIT_RANGE(pl, pl_offset, size,
1044                                     UPL_COMMIT_CLEAR_DIRTY |
1045                                     UPL_COMMIT_FREE_ON_EMPTY);
1046     }
1047
1048 #ifdef AFS_DARWIN80_ENV
1049     uio_free(uio);
1050 #endif
1051     return code;
1052 }
1053
1054 int
1055 afs_vop_ioctl(ap)
1056      struct VOPPROT(ioctl_args) /* {
1057                                  * struct vnode *a_vp;
1058                                  * int  a_command;
1059                                  * caddr_t  a_data;
1060                                  * int  a_fflag;
1061                                  * struct ucred *a_cred;
1062                                  * struct proc *a_p;
1063                                  * } */ *ap;
1064 {
1065     struct vcache *tvc = VTOAFS(ap->a_vp);
1066     struct afs_ioctl data;
1067     int error = 0;
1068
1069     /* in case we ever get in here... */
1070
1071     AFS_STATCNT(afs_ioctl);
1072     if (((ap->a_command >> 8) & 0xff) == 'V') {
1073         /* This is a VICEIOCTL call */
1074         AFS_GLOCK();
1075         error = HandleIoctl(tvc, (struct file *)0 /*Not used */ ,
1076                             ap->a_command, ap->a_data);
1077         AFS_GUNLOCK();
1078         return (error);
1079     } else {
1080         /* No-op call; just return. */
1081         return (ENOTTY);
1082     }
1083 }
1084
1085 /* ARGSUSED */
1086 int
1087 afs_vop_select(ap)
1088      struct VOPPROT(select_args)        /* {
1089                                  * struct vnode *a_vp;
1090                                  * int  a_which;
1091                                  * int  a_fflags;
1092                                  * struct ucred *a_cred;
1093                                  * struct proc *a_p;
1094                                  * } */ *ap;
1095 {
1096     /*
1097      * We should really check to see if I/O is possible.
1098      */
1099     return (1);
1100 }
1101
1102 /*
1103  * Mmap a file
1104  *
1105  * NB Currently unsupported.
1106  */
1107 /* ARGSUSED */
1108 int
1109 afs_vop_mmap(ap)
1110      struct VOPPROT(mmap_args)  /* {
1111                                  * struct vnode *a_vp;
1112                                  * int  a_fflags;
1113                                  * struct ucred *a_cred;
1114                                  * struct proc *a_p;
1115                                  * } */ *ap;
1116 {
1117     return (EINVAL);
1118 }
1119
1120 int
1121 afs_vop_fsync(ap)
1122      struct VOPPROT(fsync_args) /* {
1123                                  * struct vnode *a_vp;
1124                                  * struct ucred *a_cred;
1125                                  * int a_waitfor;
1126                                  * struct proc *a_p;
1127                                  * } */ *ap;
1128 {
1129     int wait = ap->a_waitfor == MNT_WAIT;
1130     int error;
1131     register struct vnode *vp = ap->a_vp;
1132     int haveGlock = ISAFS_GLOCK();
1133
1134     /* afs_vop_lookup glocks, can call us through vinvalbuf from GetVCache */
1135     if (!haveGlock) AFS_GLOCK();
1136     if (vop_cred)
1137         error = afs_fsync(VTOAFS(vp), vop_cred);
1138     else
1139         error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
1140     if (!haveGlock) AFS_GUNLOCK();
1141     return error;
1142 }
1143
1144 #ifndef AFS_DARWIN80_ENV
1145 int
1146 afs_vop_seek(ap)
1147      struct VOPPROT(seek_args)  /* {
1148                                  * struct vnode *a_vp;
1149                                  * off_t  a_oldoff;
1150                                  * off_t  a_newoff;
1151                                  * struct ucred *a_cred;
1152                                  * } */ *ap;
1153 {
1154     if (ap->a_newoff > ULONG_MAX)       /* AFS doesn't support 64-bit offsets */
1155         return EINVAL;
1156     return (0);
1157 }
1158 #endif
1159
1160 int
1161 afs_vop_remove(ap)
1162      struct VOPPROT(remove_args)        /* {
1163                                  * struct vnode *a_dvp;
1164                                  * struct vnode *a_vp;
1165                                  * struct componentname *a_cnp;
1166                                  * } */ *ap;
1167 {
1168     int error = 0;
1169     register struct vnode *vp = ap->a_vp;
1170     register struct vnode *dvp = ap->a_dvp;
1171
1172 #ifdef AFS_DARWIN80_ENV
1173     if (ap->a_flags & VNODE_REMOVE_NODELETEBUSY) {
1174             /* Caller requested Carbon delete semantics */
1175             if (vnode_isinuse(vp, 0)) {
1176                     return EBUSY;
1177             }
1178     }
1179 #endif
1180
1181     GETNAME();
1182     AFS_GLOCK();
1183     error = afs_remove(VTOAFS(dvp), name, vop_cn_cred);
1184     AFS_GUNLOCK();
1185     cache_purge(vp);
1186     if (!error) {
1187 #ifdef AFS_DARWIN80_ENV
1188         ubc_setsize(vp, (off_t)0);
1189         vnode_recycle(vp);
1190 #else
1191         /* necessary so we don't deadlock ourselves in vclean */
1192         VOP_UNLOCK(vp, 0, cnp->cn_proc);
1193
1194         /* If crashes continue in ubc_hold, comment this out */
1195         (void)ubc_uncache(vp);
1196 #endif
1197     }
1198
1199 #ifndef AFS_DARWIN80_ENV
1200     vput(dvp);
1201     if (dvp == vp)
1202         vrele(vp);
1203     else
1204         vput(vp);
1205 #endif
1206
1207 #ifndef AFS_DARWIN80_ENV
1208     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1209 #endif
1210     DROPNAME();
1211     return error;
1212 }
1213
1214 int
1215 afs_vop_link(ap)
1216      struct VOPPROT(link_args)  /* {
1217                                  * struct vnode *a_vp;
1218                                  * struct vnode *a_tdvp;
1219                                  * struct componentname *a_cnp;
1220                                  * } */ *ap;
1221 {
1222     int error = 0;
1223     register struct vnode *dvp = ap->a_tdvp;
1224     register struct vnode *vp = ap->a_vp;
1225     struct proc *p;
1226
1227     GETNAME();
1228     p = vop_cn_proc;
1229     if (vnode_isdir(vp)) {
1230         VOP_ABORTOP(vp, cnp);
1231         error = EISDIR;
1232         goto out;
1233     }
1234 #ifndef AFS_DARWIN80_ENV
1235     if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
1236         VOP_ABORTOP(dvp, cnp);
1237         goto out;
1238     }
1239 #endif
1240     AFS_GLOCK();
1241     error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, vop_cn_cred);
1242     AFS_GUNLOCK();
1243 #ifndef AFS_DARWIN80_ENV
1244     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1245 #endif
1246 #ifndef AFS_DARWIN80_ENV
1247     if (dvp != vp)
1248         VOP_UNLOCK(vp, 0, p);
1249 #endif
1250   out:
1251 #ifndef AFS_DARWIN80_ENV
1252     vput(dvp);
1253 #endif
1254     DROPNAME();
1255     return error;
1256 }
1257
1258 int
1259 afs_vop_rename(ap)
1260      struct VOPPROT(rename_args)        /* {
1261                                  * struct vnode *a_fdvp;
1262                                  * struct vnode *a_fvp;
1263                                  * struct componentname *a_fcnp;
1264                                  * struct vnode *a_tdvp;
1265                                  * struct vnode *a_tvp;
1266                                  * struct componentname *a_tcnp;
1267                                  * } */ *ap;
1268 {
1269     int error = 0;
1270     struct componentname *fcnp = ap->a_fcnp;
1271     char *fname;
1272     struct componentname *tcnp = ap->a_tcnp;
1273     char *tname;
1274     struct vnode *tvp = ap->a_tvp;
1275     register struct vnode *tdvp = ap->a_tdvp;
1276     struct vnode *fvp = ap->a_fvp;
1277     register struct vnode *fdvp = ap->a_fdvp;
1278     struct proc *p; 
1279
1280     p = cn_proc(fcnp);
1281
1282 #ifdef AFS_DARWIN80_ENV
1283 /* generic code tests for v_mount equality, so we don't have to, but we don't
1284    get the multiple-mount "benefits" of the old behavior
1285 */
1286 #else
1287     /* Check for cross-device rename.
1288      * For AFS, this means anything not in AFS-space
1289      */
1290     if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
1291         (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
1292         error = EXDEV;
1293         goto abortit;
1294     }
1295 #endif
1296
1297 #ifdef AFS_DARWIN80_ENV
1298    /* the generic code doesn't do this, so we really should, but all the
1299       vrele's are wrong... */
1300 #else
1301     /*
1302      * if fvp == tvp, we're just removing one name of a pair of
1303      * directory entries for the same element.  convert call into rename.
1304      ( (pinched from NetBSD 1.0's ufs_rename())
1305      */
1306     if (fvp == tvp) {
1307         if (vnode_isdir(fvp)) {
1308             error = EINVAL;
1309           abortit:
1310             VOP_ABORTOP(tdvp, tcnp);    /* XXX, why not in NFS? */
1311             if (tdvp == tvp)
1312                 vrele(tdvp);
1313             else
1314                 vput(tdvp);
1315             if (tvp)
1316                 vput(tvp);
1317             VOP_ABORTOP(fdvp, fcnp);    /* XXX, why not in NFS? */
1318             vrele(fdvp);
1319             vrele(fvp);
1320             return (error);
1321         }
1322
1323         /* Release destination completely. */
1324         VOP_ABORTOP(tdvp, tcnp);
1325         vput(tdvp);
1326         vput(tvp);
1327         /* Delete source. */
1328 #if defined(AFS_DARWIN80_ENV) 
1329
1330         MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1331         memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1332         fname[fcnp->cn_namelen] = '\0';
1333         AFS_GLOCK();
1334         error = afs_remove(VTOAFS(fdvp), fname, vop_cn_cred);
1335         AFS_GUNLOCK();
1336         FREE(fname, M_TEMP);
1337         cache_purge(fvp);
1338 #else
1339         vrele(fdvp);
1340         vrele(fvp);
1341         fcnp->cn_flags &= ~MODMASK;
1342         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1343         if ((fcnp->cn_flags & SAVESTART) == 0)
1344             panic("afs_rename: lost from startdir");
1345         fcnp->cn_nameiop = DELETE;
1346
1347         VREF(fdvp); 
1348         error=relookup(fdvp, &fvp, fcnp);
1349         if (error == 0)
1350             vrele(fdvp);
1351         if (fvp == NULL) {
1352             return (ENOENT);
1353         }
1354         error=VOP_REMOVE(fdvp, fvp, fcnp);
1355 #endif
1356         
1357         if (fdvp == fvp)
1358             vrele(fdvp);
1359         else
1360             vput(fdvp);
1361         vput(fvp);
1362         return (error);
1363     }
1364 #endif
1365 #if !defined(AFS_DARWIN80_ENV) 
1366     if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
1367         goto abortit;
1368 #endif
1369
1370     MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1371     memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1372     fname[fcnp->cn_namelen] = '\0';
1373     MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1374     memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
1375     tname[tcnp->cn_namelen] = '\0';
1376
1377
1378     AFS_GLOCK();
1379     /* XXX use "from" or "to" creds? NFS uses "to" creds */
1380     error =
1381         afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, cn_cred(tcnp));
1382     AFS_GUNLOCK();
1383
1384 #if !defined(AFS_DARWIN80_ENV) 
1385     VOP_UNLOCK(fvp, 0, p);
1386 #endif
1387     FREE(fname, M_TEMP);
1388     FREE(tname, M_TEMP);
1389 #ifdef AFS_DARWIN80_ENV
1390     cache_purge(fdvp);
1391     cache_purge(fvp);
1392     cache_purge(tdvp);
1393     if (tvp) {
1394        cache_purge(tvp);
1395        if (!error) {
1396           vnode_recycle(tvp);
1397        }
1398     }
1399     if (!error)
1400        cache_enter(tdvp, fvp, tcnp);
1401 #else
1402     if (error)
1403         goto abortit;           /* XXX */
1404     if (tdvp == tvp)
1405         vrele(tdvp);
1406     else
1407         vput(tdvp);
1408     if (tvp)
1409         vput(tvp);
1410     vrele(fdvp);
1411     vrele(fvp);
1412 #endif
1413     return error;
1414 }
1415
1416 int
1417 afs_vop_mkdir(ap)
1418      struct VOPPROT(mkdir_args) /* {
1419                                  * struct vnode *a_dvp;
1420                                  * struct vnode **a_vpp;
1421                                  * struct componentname *a_cnp;
1422                                  * struct vattr *a_vap;
1423                                  * } */ *ap;
1424 {
1425     register struct vnode *dvp = ap->a_dvp;
1426     register struct vattr *vap = ap->a_vap;
1427     int error = 0;
1428     struct vcache *vcp;
1429     struct proc *p;
1430
1431     GETNAME();
1432     p = vop_cn_proc;
1433 #if defined(DIAGNOSTIC) && !defined(AFS_DARWIN80_ENV)
1434     if ((cnp->cn_flags & HASBUF) == 0)
1435         panic("afs_vop_mkdir: no name");
1436 #endif
1437     AFS_GLOCK();
1438     error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, vop_cn_cred);
1439     AFS_GUNLOCK();
1440     if (error) {
1441 #ifndef AFS_DARWIN80_ENV
1442         VOP_ABORTOP(dvp, cnp);
1443         vput(dvp);
1444 #endif
1445         DROPNAME();
1446         return (error);
1447     }
1448     if (vcp) {
1449 #ifdef AFS_DARWIN80_ENV
1450         afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0);
1451 #endif
1452         *ap->a_vpp = AFSTOV(vcp);
1453 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
1454         (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1455         vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1456 #endif
1457     } else
1458         *ap->a_vpp = 0;
1459     DROPNAME();
1460 #ifndef AFS_DARWIN80_ENV
1461     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1462     vput(dvp);
1463 #endif
1464     return error;
1465 }
1466
1467 int
1468 afs_vop_rmdir(ap)
1469      struct VOPPROT(rmdir_args) /* {
1470                                  * struct vnode *a_dvp;
1471                                  * struct vnode *a_vp;
1472                                  * struct componentname *a_cnp;
1473                                  * } */ *ap;
1474 {
1475     int error = 0;
1476     register struct vnode *vp = ap->a_vp;
1477     register struct vnode *dvp = ap->a_dvp;
1478
1479     GETNAME();
1480     if (dvp == vp) {
1481 #ifndef AFS_DARWIN80_ENV
1482         vrele(dvp);
1483         vput(vp);
1484         FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1485 #endif
1486         DROPNAME();
1487         return (EINVAL);
1488     }
1489
1490     AFS_GLOCK();
1491     error = afs_rmdir(VTOAFS(dvp), name, vop_cn_cred);
1492     AFS_GUNLOCK();
1493     DROPNAME();
1494     cache_purge(dvp);
1495     cache_purge(vp);
1496 #ifndef AFS_DARWIN80_ENV
1497     vput(dvp);
1498     vput(vp);
1499 #endif
1500     return error;
1501 }
1502
1503 int
1504 afs_vop_symlink(ap)
1505      struct VOPPROT(symlink_args)       /* {
1506                                  * struct vnode *a_dvp;
1507                                  * struct vnode **a_vpp;
1508                                  * struct componentname *a_cnp;
1509                                  * struct vattr *a_vap;
1510                                  * char *a_target;
1511                                  * } */ *ap;
1512 {
1513     register struct vnode *dvp = ap->a_dvp;
1514     int error = 0;
1515     /* NFS ignores a_vpp; so do we. */
1516
1517     GETNAME();
1518     AFS_GLOCK();
1519     error =
1520         afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, vop_cn_cred);
1521     AFS_GUNLOCK();
1522     DROPNAME();
1523 #ifndef AFS_DARWIN80_ENV
1524     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1525     vput(dvp);
1526 #endif
1527     return error;
1528 }
1529
1530 int
1531 afs_vop_readdir(ap)
1532      struct VOPPROT(readdir_args)       /* {
1533                                  * struct vnode *a_vp;
1534                                  * struct uio *a_uio;
1535                                  * struct ucred *a_cred;
1536                                  * int *a_eofflag;
1537                                  * u_long *a_cookies;
1538                                  * int ncookies;
1539                                  * } */ *ap;
1540 {
1541     int error;
1542     off_t off;
1543 /*    printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1544            ap->a_ncookies); */
1545 #ifdef AFS_DARWIN80_ENV
1546     /* too much work for now */
1547     /* should only break nfs exports */
1548     if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
1549          return (EINVAL);
1550 #endif
1551     off = AFS_UIO_OFFSET(ap->a_uio);
1552     AFS_GLOCK();
1553     error =
1554         afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, vop_cred, ap->a_eofflag);
1555     AFS_GUNLOCK();
1556 #ifndef AFS_DARWIN80_ENV
1557     if (!error && ap->a_ncookies != NULL) {
1558         struct uio *uio = ap->a_uio;
1559         const struct dirent *dp, *dp_start, *dp_end;
1560         int ncookies;
1561         u_long *cookies, *cookiep;
1562
1563         if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1564             panic("afs_readdir: burned cookies");
1565         dp = (const struct dirent *)
1566             ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1567
1568         dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1569         for (dp_start = dp, ncookies = 0; dp < dp_end;
1570              dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1571             ncookies++;
1572
1573         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1574                M_WAITOK);
1575         for (dp = dp_start, cookiep = cookies; dp < dp_end;
1576              dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1577             off += dp->d_reclen;
1578             *cookiep++ = off;
1579         }
1580         *ap->a_cookies = cookies;
1581         *ap->a_ncookies = ncookies;
1582     }
1583 #endif
1584
1585     return error;
1586 }
1587
1588 int
1589 afs_vop_readlink(ap)
1590      struct VOPPROT(readlink_args)      /* {
1591                                  * struct vnode *a_vp;
1592                                  * struct uio *a_uio;
1593                                  * struct ucred *a_cred;
1594                                  * } */ *ap;
1595 {
1596     int error;
1597 /*    printf("readlink %x\n", ap->a_vp);*/
1598     AFS_GLOCK();
1599     error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, vop_cred);
1600     AFS_GUNLOCK();
1601     return error;
1602 }
1603
1604 extern int prtactive;
1605
1606 int
1607 afs_vop_inactive(ap)
1608      struct VOPPROT(inactive_args)      /* {
1609                                  * struct vnode *a_vp;
1610                                  * struct proc *a_p;
1611                                  * } */ *ap;
1612 {
1613     register struct vnode *vp = ap->a_vp;
1614     struct vcache *tvc = VTOAFS(vp);
1615 #ifndef AFS_DARWIN80_ENV
1616     if (prtactive && vp->v_usecount != 0)
1617         vprint("afs_vop_inactive(): pushing active", vp);
1618 #endif
1619     if (tvc) {
1620        AFS_GLOCK();
1621        afs_InactiveVCache(tvc, 0);      /* decrs ref counts */
1622        AFS_GUNLOCK();
1623     }
1624 #ifndef AFS_DARWIN80_ENV
1625     VOP_UNLOCK(vp, 0, ap->a_p);
1626 #endif
1627     return 0;
1628 }
1629
1630 int
1631 afs_vop_reclaim(ap)
1632      struct VOPPROT(reclaim_args)       /* {
1633                                  * struct vnode *a_vp;
1634                                  * } */ *ap;
1635 {
1636     int error = 0;
1637     int sl, writelocked;
1638     register struct vnode *vp = ap->a_vp;
1639     struct vcache *tvc = VTOAFS(vp);
1640
1641     osi_Assert(!ISAFS_GLOCK());
1642     cache_purge(vp);            /* just in case... */
1643     if (tvc) {
1644        AFS_GLOCK();
1645        writelocked = (0 == NBObtainWriteLock(&afs_xvcache, 335));
1646        if (!writelocked) {
1647            ObtainWriteLock(&afs_xvreclaim, 176);
1648 #ifdef AFS_DARWIN80_ENV
1649            vnode_clearfsnode(AFSTOV(tvc));
1650            vnode_removefsref(AFSTOV(tvc));
1651 #else
1652            tvc->v->v_data = NULL;  /* remove from vnode */
1653 #endif
1654            AFSTOV(tvc) = NULL;             /* also drop the ptr to vnode */
1655            tvc->states |= CVInit; /* also CDeadVnode? */
1656            tvc->nextfree = ReclaimedVCList;
1657            ReclaimedVCList = tvc;
1658            ReleaseWriteLock(&afs_xvreclaim);
1659        } else {
1660            error = afs_FlushVCache(tvc, &sl);   /* toss our stuff from vnode */
1661            if (tvc->states & (CVInit
1662 #ifdef AFS_DARWIN80_ENV
1663                               | CDeadVnode
1664 #endif
1665                    )) {
1666                tvc->states &= ~(CVInit
1667 #ifdef AFS_DARWIN80_ENV
1668                                 | CDeadVnode
1669 #endif
1670                    );
1671                afs_osi_Wakeup(&tvc->states);
1672            }
1673            if (!error && vnode_fsnode(vp))
1674                panic("afs_reclaim: vnode not cleaned");
1675            if (!error && (tvc->v != NULL)) 
1676                panic("afs_reclaim: vcache not cleaned");
1677            ReleaseWriteLock(&afs_xvcache);
1678        }
1679        AFS_GUNLOCK();
1680     }
1681     return error;
1682 }
1683
1684 /*
1685  * Return POSIX pathconf information applicable to ufs filesystems.
1686  */
1687 afs_vop_pathconf(ap)
1688      struct VOPPROT(pathconf_args)      /* {
1689                                  * struct vnode *a_vp;
1690                                  * int a_name;
1691                                  * int *a_retval;
1692                                  * } */ *ap;
1693 {
1694     AFS_STATCNT(afs_cntl);
1695     switch (ap->a_name) {
1696     case _PC_LINK_MAX:
1697         *ap->a_retval = LINK_MAX;
1698         break;
1699     case _PC_NAME_MAX:
1700         *ap->a_retval = NAME_MAX;
1701         break;
1702     case _PC_PATH_MAX:
1703         *ap->a_retval = PATH_MAX;
1704         break;
1705     case _PC_CHOWN_RESTRICTED:
1706         *ap->a_retval = 1;
1707         break;
1708     case _PC_NO_TRUNC:
1709         *ap->a_retval = 1;
1710         break;
1711     case _PC_PIPE_BUF:
1712         return EINVAL;
1713         break;
1714 #if defined(AFS_DARWIN70_ENV)
1715     case _PC_NAME_CHARS_MAX:
1716         *ap->a_retval = NAME_MAX;
1717         break;
1718     case _PC_CASE_SENSITIVE:
1719         *ap->a_retval = 1;
1720         break;
1721     case _PC_CASE_PRESERVING:
1722         *ap->a_retval = 1;
1723         break;
1724 #endif /* defined(AFS_DARWIN70_ENV) */
1725     default:
1726         return EINVAL;
1727     }
1728     return 0;
1729 }
1730
1731 /*
1732  * Advisory record locking support (fcntl() POSIX style)
1733  */
1734 int
1735 afs_vop_advlock(ap)
1736      struct VOPPROT(advlock_args)       /* {
1737                                  * struct vnode *a_vp;
1738                                  * caddr_t  a_id;
1739                                  * int  a_op;
1740                                  * struct flock *a_fl;
1741                                  * int  a_flags;
1742                                  * } */ *ap;
1743 {
1744     int error;
1745     struct ucred *tcr;
1746 #ifdef AFS_DARWIN80_ENV
1747     tcr=vop_cred;
1748 #else
1749     struct proc *p = current_proc();
1750     struct ucred cr;
1751     pcred_readlock(p);
1752     cr = *p->p_cred->pc_ucred;
1753     pcred_unlock(p);
1754     tcr=&cr;
1755 #endif
1756     AFS_GLOCK();
1757     error =
1758         afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl,
1759                     ap->a_op == F_UNLCK ? F_SETLK : ap->a_op, tcr, 
1760                     (int)ap->a_id);
1761     AFS_GUNLOCK();
1762     return error;
1763 }
1764
1765 int
1766 afs_vop_blktooff(ap)
1767      struct VOPPROT(blktooff_args)      /* {
1768                                  * struct vnode *a_vp;
1769                                  * daddr_t a_lblkno;
1770                                  * off_t *a_offset;    
1771                                  * } */ *ap;
1772 {
1773     *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1774     return 0;
1775 }
1776
1777 int
1778 afs_vop_offtoblk(ap)
1779      struct VOPPROT(offtoblk_args)      /* {
1780                                  * struct vnode *a_vp;
1781                                  * off_t a_offset;    
1782                                  * daddr_t *a_lblkno;
1783                                  * } */ *ap;
1784 {
1785     *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1786
1787     return (0);
1788 }
1789
1790 #ifndef AFS_DARWIN80_ENV
1791 int
1792 afs_vop_lock(ap)
1793      struct VOPPROT(lock_args)  /* {
1794                                  * struct vnode *a_vp;
1795                                  * } */ *ap;
1796 {
1797     register struct vnode *vp = ap->a_vp;
1798     register struct vcache *avc = VTOAFS(vp);
1799
1800     if (vp->v_tag == VT_NON)
1801         return (ENOENT);
1802
1803     return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1804 }
1805
1806 int
1807 afs_vop_unlock(ap)
1808      struct VOPPROT(unlock_args)        /* {
1809                                  * struct vnode *a_vp;
1810                                  * } */ *ap;
1811 {
1812     struct vnode *vp = ap->a_vp;
1813     struct vcache *avc = VTOAFS(vp);
1814
1815     return (lockmgr
1816             (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1817              ap->a_p));
1818
1819 }
1820
1821 int
1822 afs_vop_truncate(ap)
1823      struct VOPPROT(truncate_args)      /* {
1824                                  * struct vnode *a_vp;
1825                                  * off_t a_length;
1826                                  * int a_flags;
1827                                  * struct ucred *a_cred;
1828                                  * struct proc *a_p;
1829                                  * } */ *ap;
1830 {
1831     printf("stray afs_vop_truncate\n");
1832     return EOPNOTSUPP;
1833 }
1834
1835 int
1836 afs_vop_update(ap)
1837      struct VOPPROT(update_args)        /* {
1838                                  * struct vnode *a_vp;
1839                                  * struct timeval *a_access;
1840                                  * struct timeval *a_modify;
1841                                  * int a_waitfor;
1842                                  * } */ *ap;
1843 {
1844     printf("stray afs_vop_update\n");
1845     return EOPNOTSUPP;
1846 }
1847
1848 int
1849 afs_vop_bmap(ap)
1850      struct VOPPROT(bmap_args)  /* {
1851                                  * struct vnode *a_vp;
1852                                  * daddr_t  a_bn;
1853                                  * struct vnode **a_vpp;
1854                                  * daddr_t *a_bnp;
1855                                  * int *a_runp;
1856                                  * int *a_runb;
1857                                  * } */ *ap;
1858 {
1859     int error;
1860     if (ap->a_bnp) {
1861         *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
1862     }
1863     if (ap->a_vpp) {
1864         *ap->a_vpp = ap->a_vp;
1865     }
1866     if (ap->a_runp != NULL)
1867         *ap->a_runp = 0;
1868 #ifdef notyet
1869     if (ap->a_runb != NULL)
1870         *ap->a_runb = 0;
1871 #endif
1872
1873     return 0;
1874 }
1875
1876 int
1877 afs_vop_strategy(ap)
1878      struct VOPPROT(strategy_args)      /* {
1879                                  * struct buf *a_bp;
1880                                  * } */ *ap;
1881 {
1882     int error;
1883     AFS_GLOCK();
1884     error = afs_ustrategy(ap->a_bp);
1885     AFS_GUNLOCK();
1886     return error;
1887 }
1888
1889 int
1890 afs_vop_print(ap)
1891      struct VOPPROT(print_args) /* {
1892                                  * struct vnode *a_vp;
1893                                  * } */ *ap;
1894 {
1895     register struct vnode *vp = ap->a_vp;
1896     register struct vcache *vc = VTOAFS(ap->a_vp);
1897     int s = vc->states;
1898     printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1899            vc->fid.Cell, vc->fid.Fid.Volume, vc->fid.Fid.Vnode,
1900            vc->fid.Fid.Unique, vc->opens, vc->execsOrWriters);
1901     printf("\n  states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1902            (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1903            (s & CMAPPED) ? " mapped" : "",
1904            (s & CVFlushed) ? " flush in progress" : "");
1905     if (UBCISVALID(vp)) {
1906         printf("\n  UBC: ");
1907         if (UBCINFOEXISTS(vp)) {
1908             printf("exists, ");
1909 #ifdef AFS_DARWIN14_ENV
1910             printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
1911                    ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
1912                    ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
1913 #else
1914             printf("holdcnt %d", vp->v_ubcinfo->ui_holdcnt);
1915 #endif
1916         } else
1917             printf("does not exist");
1918     }
1919     printf("\n");
1920     return 0;
1921 }
1922
1923 int
1924 afs_vop_islocked(ap)
1925      struct VOPPROT(islocked_args)      /* {
1926                                  * struct vnode *a_vp;
1927                                  * } */ *ap;
1928 {
1929     struct vcache *vc = VTOAFS(ap->a_vp);
1930     return lockstatus(&vc->rwlock);
1931 }
1932
1933 int
1934 afs_vop_cmap(ap)
1935      struct VOPPROT(cmap_args)  /* {
1936                                  * struct vnode *a_vp;
1937                                  * off_t a_foffset;    
1938                                  * size_t a_size;
1939                                  * daddr_t *a_bpn;
1940                                  * size_t *a_run;
1941                                  * void *a_poff;
1942                                  * } */ *ap;
1943 {
1944     *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
1945     *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));
1946     return 0;
1947 }
1948 #endif
1949
1950 int
1951 afs_darwin_getnewvnode(struct vcache *avc)
1952 {
1953 #ifdef AFS_DARWIN80_ENV
1954     vnode_t vp;
1955     int error, dead;
1956     struct vnode_fsparam par;
1957
1958     memset(&par, 0, sizeof(struct vnode_fsparam));
1959 #if 0
1960     AFS_GLOCK();
1961     ObtainWriteLock(&avc->lock,342);
1962     if (avc->states & CStatd) { 
1963        par.vnfs_vtype = avc->m.Type;
1964        par.vnfs_vops = afs_vnodeop_p;
1965        par.vnfs_filesize = avc->m.Length;
1966        if (!ac->cnp)
1967            par.vnfs_flags = VNFS_NOCACHE;
1968        dead = 0;
1969     } else {
1970        par.vnfs_vtype = VNON;
1971        par.vnfs_vops = afs_dead_vnodeop_p;
1972        par.vnfs_flags = VNFS_NOCACHE|VNFS_CANTCACHE;
1973        dead = 1;
1974     }
1975     ReleaseWriteLock(&avc->lock);
1976     AFS_GUNLOCK();
1977     par.vnfs_dvp = ac->dvp;
1978     par.vnfs_cnp = ac->cnp;
1979     par.vnfs_markroot = ac->markroot;
1980 #else
1981     par.vnfs_vtype = VNON;
1982     par.vnfs_vops = afs_dead_vnodeop_p;
1983     par.vnfs_flags = VNFS_NOCACHE|VNFS_CANTCACHE;
1984 #endif
1985     par.vnfs_mp = afs_globalVFS;
1986     par.vnfs_fsnode = avc;
1987
1988     error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &vp);
1989     if (!error) {
1990       vnode_addfsref(vp);
1991       vnode_ref(vp);
1992       avc->v = vp;
1993 #if 0
1994       if (dead) {
1995          vnode_recycle(vp); /* terminate as soon as iocount drops */
1996          avc->states |= CDeadVnode;
1997       } else if (!ac->markroot && !ac->cnp) {
1998        /* the caller doesn't know anything about this vnode. if markroot
1999           should have been set and wasn't, bad things may happen, so encourage
2000           it to recycle */
2001           vnode_recycle(vp);
2002       }
2003 #else
2004       vnode_recycle(vp); /* terminate as soon as iocount drops */
2005       avc->states |= CDeadVnode;
2006 #endif
2007     }
2008     return error;
2009 #else
2010     while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &avc->v)) {
2011         /* no vnodes available, force an alloc (limits be damned)! */
2012         printf("failed to get vnode\n");
2013     }
2014     avc->v->v_data = (void *)avc;
2015     return 0;
2016 #endif
2017 }
2018 #ifdef AFS_DARWIN80_ENV
2019 /* if this fails, then tvc has been unrefed and may have been freed. 
2020    Don't touch! */
2021 int 
2022 afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp, struct componentname *cnp, int isroot) {
2023    vnode_t ovp = AFSTOV(avc);
2024    vnode_t nvp;
2025    int error;
2026    struct vnode_fsparam par;
2027    AFS_GLOCK();
2028    ObtainWriteLock(&avc->lock,325);
2029    if (!(avc->states & CDeadVnode) && vnode_vtype(ovp) != VNON) {
2030         ReleaseWriteLock(&avc->lock);
2031         AFS_GUNLOCK();
2032 #if 0 /* unsupported */
2033         if (dvp && cnp)
2034         vnode_update_identity(ovp, dvp, cnp->cn_nameptr, cnp->cn_namelen,
2035                               cnp->cn_hash,
2036                               VNODE_UPDATE_PARENT|VNODE_UPDATE_NAME);
2037 #endif
2038         vnode_rele(ovp);
2039         return 0;
2040    }
2041    if ((avc->states & CDeadVnode) && vnode_vtype(ovp) != VNON) 
2042        panic("vcache %p should not be CDeadVnode", avc);
2043    AFS_GUNLOCK();
2044    memset(&par, 0, sizeof(struct vnode_fsparam));
2045    par.vnfs_mp = afs_globalVFS;
2046    par.vnfs_vtype = avc->m.Type;
2047    par.vnfs_vops = afs_vnodeop_p;
2048    par.vnfs_filesize = avc->m.Length;
2049    par.vnfs_fsnode = avc;
2050    par.vnfs_dvp = dvp;
2051    if (cnp && (cnp->cn_flags & ISDOTDOT) == 0)
2052        par.vnfs_cnp = cnp;
2053    if (!dvp || !cnp || (cnp->cn_flags & MAKEENTRY) == 0)
2054        par.vnfs_flags = VNFS_NOCACHE;
2055    if (isroot)
2056        par.vnfs_markroot = 1;
2057    error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &nvp);
2058    if (!error) {
2059      vnode_addfsref(nvp);
2060      avc->v = nvp;
2061      avc->states &=~ CDeadVnode;
2062      vnode_clearfsnode(ovp);
2063      vnode_removefsref(ovp);
2064    }
2065    AFS_GLOCK();
2066    ReleaseWriteLock(&avc->lock);
2067    if (!error)
2068       afs_osi_Wakeup(&avc->states);
2069    AFS_GUNLOCK();
2070    vnode_put(ovp);
2071    vnode_rele(ovp);
2072    return error;
2073 }
2074 #endif