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