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