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