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