macos-no-read-on-directories-20071127
[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, vop_proc);
542     else
543         code = afs_close(avc, ap->a_fflag, &afs_osi_cred, vop_proc);
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, (struct file *)0 /*Not used */ ,
1101                             ap->a_command, ap->a_data);
1102         AFS_GUNLOCK();
1103         return (error);
1104     } else {
1105         /* No-op call; just return. */
1106         return (ENOTTY);
1107     }
1108 }
1109
1110 /* ARGSUSED */
1111 int
1112 afs_vop_select(ap)
1113      struct VOPPROT(select_args)        /* {
1114                                  * struct vnode *a_vp;
1115                                  * int  a_which;
1116                                  * int  a_fflags;
1117                                  * struct ucred *a_cred;
1118                                  * struct proc *a_p;
1119                                  * } */ *ap;
1120 {
1121     /*
1122      * We should really check to see if I/O is possible.
1123      */
1124     return (1);
1125 }
1126
1127 /*
1128  * Mmap a file
1129  *
1130  * NB Currently unsupported.
1131  */
1132 /* ARGSUSED */
1133 int
1134 afs_vop_mmap(ap)
1135      struct VOPPROT(mmap_args)  /* {
1136                                  * struct vnode *a_vp;
1137                                  * int  a_fflags;
1138                                  * struct ucred *a_cred;
1139                                  * struct proc *a_p;
1140                                  * } */ *ap;
1141 {
1142     return (EINVAL);
1143 }
1144
1145 int
1146 afs_vop_fsync(ap)
1147      struct VOPPROT(fsync_args) /* {
1148                                  * struct vnode *a_vp;
1149                                  * struct ucred *a_cred;
1150                                  * int a_waitfor;
1151                                  * struct proc *a_p;
1152                                  * } */ *ap;
1153 {
1154     int wait = ap->a_waitfor == MNT_WAIT;
1155     int error;
1156     register struct vnode *vp = ap->a_vp;
1157     int haveGlock = ISAFS_GLOCK();
1158
1159     /* afs_vop_lookup glocks, can call us through vinvalbuf from GetVCache */
1160     if (!haveGlock) AFS_GLOCK();
1161     if (vop_cred)
1162         error = afs_fsync(VTOAFS(vp), vop_cred);
1163     else
1164         error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
1165     if (!haveGlock) AFS_GUNLOCK();
1166     return error;
1167 }
1168
1169 #ifndef AFS_DARWIN80_ENV
1170 int
1171 afs_vop_seek(ap)
1172      struct VOPPROT(seek_args)  /* {
1173                                  * struct vnode *a_vp;
1174                                  * off_t  a_oldoff;
1175                                  * off_t  a_newoff;
1176                                  * struct ucred *a_cred;
1177                                  * } */ *ap;
1178 {
1179     if (ap->a_newoff > ULONG_MAX)       /* AFS doesn't support 64-bit offsets */
1180         return EINVAL;
1181     return (0);
1182 }
1183 #endif
1184
1185 int
1186 afs_vop_remove(ap)
1187      struct VOPPROT(remove_args)        /* {
1188                                  * struct vnode *a_dvp;
1189                                  * struct vnode *a_vp;
1190                                  * struct componentname *a_cnp;
1191                                  * } */ *ap;
1192 {
1193     int error = 0;
1194     register struct vnode *vp = ap->a_vp;
1195     register struct vnode *dvp = ap->a_dvp;
1196
1197 #ifdef AFS_DARWIN80_ENV
1198     if (ap->a_flags & VNODE_REMOVE_NODELETEBUSY) {
1199             /* Caller requested Carbon delete semantics */
1200             if (vnode_isinuse(vp, 0)) {
1201                     return EBUSY;
1202             }
1203     }
1204 #endif
1205
1206     GETNAME();
1207     AFS_GLOCK();
1208     error = afs_remove(VTOAFS(dvp), name, vop_cn_cred);
1209     error = afs_CheckCode(error, NULL, 61);
1210     AFS_GUNLOCK();
1211     cache_purge(vp);
1212     if (!error) {
1213 #ifdef AFS_DARWIN80_ENV
1214         struct vcache *tvc = VTOAFS(vp);
1215         
1216         if (!(tvc->states & CUnlinked)) {
1217             ubc_setsize(vp, (off_t)0);
1218             vnode_recycle(vp);
1219         }
1220 #else
1221         /* necessary so we don't deadlock ourselves in vclean */
1222         VOP_UNLOCK(vp, 0, cnp->cn_proc);
1223
1224         /* If crashes continue in ubc_hold, comment this out */
1225         (void)ubc_uncache(vp);
1226 #endif
1227     } else {
1228         /* should check for PRSFS_INSERT and not PRSFS_DELETE, but the
1229            goal here is to deal with Finder's unhappiness with resource
1230            forks that have no resources in a dropbox setting */
1231         if (name[0] == '.' && name[1] == '_' && error == EACCES) 
1232             error = 0;
1233     }
1234
1235 #ifndef AFS_DARWIN80_ENV
1236     vput(dvp);
1237     if (dvp == vp)
1238         vrele(vp);
1239     else
1240         vput(vp);
1241 #endif
1242
1243 #ifndef AFS_DARWIN80_ENV
1244     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1245 #endif
1246     DROPNAME();
1247     return error;
1248 }
1249
1250 int
1251 afs_vop_link(ap)
1252      struct VOPPROT(link_args)  /* {
1253                                  * struct vnode *a_vp;
1254                                  * struct vnode *a_tdvp;
1255                                  * struct componentname *a_cnp;
1256                                  * } */ *ap;
1257 {
1258     int error = 0;
1259     register struct vnode *dvp = ap->a_tdvp;
1260     register struct vnode *vp = ap->a_vp;
1261     struct proc *p;
1262
1263     GETNAME();
1264     p = vop_cn_proc;
1265     if (vnode_isdir(vp)) {
1266         VOP_ABORTOP(vp, cnp);
1267         error = EISDIR;
1268         goto out;
1269     }
1270 #ifndef AFS_DARWIN80_ENV
1271     if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
1272         VOP_ABORTOP(dvp, cnp);
1273         goto out;
1274     }
1275 #endif
1276     AFS_GLOCK();
1277     error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, vop_cn_cred);
1278     AFS_GUNLOCK();
1279 #ifndef AFS_DARWIN80_ENV
1280     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1281 #endif
1282 #ifndef AFS_DARWIN80_ENV
1283     if (dvp != vp)
1284         VOP_UNLOCK(vp, 0, p);
1285 #endif
1286   out:
1287 #ifndef AFS_DARWIN80_ENV
1288     vput(dvp);
1289 #endif
1290     DROPNAME();
1291     return error;
1292 }
1293
1294 int
1295 afs_vop_rename(ap)
1296      struct VOPPROT(rename_args)        /* {
1297                                  * struct vnode *a_fdvp;
1298                                  * struct vnode *a_fvp;
1299                                  * struct componentname *a_fcnp;
1300                                  * struct vnode *a_tdvp;
1301                                  * struct vnode *a_tvp;
1302                                  * struct componentname *a_tcnp;
1303                                  * } */ *ap;
1304 {
1305     int error = 0;
1306     struct componentname *fcnp = ap->a_fcnp;
1307     char *fname;
1308     struct componentname *tcnp = ap->a_tcnp;
1309     char *tname;
1310     struct vnode *tvp = ap->a_tvp;
1311     register struct vnode *tdvp = ap->a_tdvp;
1312     struct vnode *fvp = ap->a_fvp;
1313     register struct vnode *fdvp = ap->a_fdvp;
1314     struct proc *p; 
1315
1316     p = cn_proc(fcnp);
1317
1318 #ifdef AFS_DARWIN80_ENV
1319 /* generic code tests for v_mount equality, so we don't have to, but we don't
1320    get the multiple-mount "benefits" of the old behavior
1321 */
1322 #else
1323     /* Check for cross-device rename.
1324      * For AFS, this means anything not in AFS-space
1325      */
1326     if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
1327         (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
1328         error = EXDEV;
1329         goto abortit;
1330     }
1331 #endif
1332
1333 #ifdef AFS_DARWIN80_ENV
1334    /* the generic code doesn't do this, so we really should, but all the
1335       vrele's are wrong... */
1336 #else
1337     /*
1338      * if fvp == tvp, we're just removing one name of a pair of
1339      * directory entries for the same element.  convert call into rename.
1340      ( (pinched from NetBSD 1.0's ufs_rename())
1341      */
1342     if (fvp == tvp) {
1343         if (vnode_isdir(fvp)) {
1344             error = EINVAL;
1345           abortit:
1346             VOP_ABORTOP(tdvp, tcnp);    /* XXX, why not in NFS? */
1347             if (tdvp == tvp)
1348                 vrele(tdvp);
1349             else
1350                 vput(tdvp);
1351             if (tvp)
1352                 vput(tvp);
1353             VOP_ABORTOP(fdvp, fcnp);    /* XXX, why not in NFS? */
1354             vrele(fdvp);
1355             vrele(fvp);
1356             return (error);
1357         }
1358
1359         /* Release destination completely. */
1360         VOP_ABORTOP(tdvp, tcnp);
1361         vput(tdvp);
1362         vput(tvp);
1363         /* Delete source. */
1364 #if defined(AFS_DARWIN80_ENV) 
1365
1366         MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1367         memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1368         fname[fcnp->cn_namelen] = '\0';
1369         AFS_GLOCK();
1370         error = afs_remove(VTOAFS(fdvp), fname, vop_cn_cred);
1371         AFS_GUNLOCK();
1372         FREE(fname, M_TEMP);
1373         cache_purge(fvp);
1374 #else
1375         vrele(fdvp);
1376         vrele(fvp);
1377         fcnp->cn_flags &= ~MODMASK;
1378         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1379         if ((fcnp->cn_flags & SAVESTART) == 0)
1380             panic("afs_rename: lost from startdir");
1381         fcnp->cn_nameiop = DELETE;
1382
1383         VREF(fdvp); 
1384         error=relookup(fdvp, &fvp, fcnp);
1385         if (error == 0)
1386             vrele(fdvp);
1387         if (fvp == NULL) {
1388             return (ENOENT);
1389         }
1390         error=VOP_REMOVE(fdvp, fvp, fcnp);
1391 #endif
1392         
1393         if (fdvp == fvp)
1394             vrele(fdvp);
1395         else
1396             vput(fdvp);
1397         vput(fvp);
1398         return (error);
1399     }
1400 #endif
1401 #if !defined(AFS_DARWIN80_ENV) 
1402     if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
1403         goto abortit;
1404 #endif
1405
1406     MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1407     memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1408     fname[fcnp->cn_namelen] = '\0';
1409     MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1410     memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
1411     tname[tcnp->cn_namelen] = '\0';
1412
1413
1414     AFS_GLOCK();
1415     /* XXX use "from" or "to" creds? NFS uses "to" creds */
1416     error =
1417         afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, cn_cred(tcnp));
1418     AFS_GUNLOCK();
1419
1420 #if !defined(AFS_DARWIN80_ENV) 
1421     VOP_UNLOCK(fvp, 0, p);
1422 #endif
1423     FREE(fname, M_TEMP);
1424     FREE(tname, M_TEMP);
1425 #ifdef AFS_DARWIN80_ENV
1426     cache_purge(fdvp);
1427     cache_purge(fvp);
1428     cache_purge(tdvp);
1429     if (tvp) {
1430        cache_purge(tvp);
1431        if (!error) {
1432           vnode_recycle(tvp);
1433        }
1434     }
1435     if (!error)
1436        cache_enter(tdvp, fvp, tcnp);
1437 #else
1438     if (error)
1439         goto abortit;           /* XXX */
1440     if (tdvp == tvp)
1441         vrele(tdvp);
1442     else
1443         vput(tdvp);
1444     if (tvp)
1445         vput(tvp);
1446     vrele(fdvp);
1447     vrele(fvp);
1448 #endif
1449     return error;
1450 }
1451
1452 int
1453 afs_vop_mkdir(ap)
1454      struct VOPPROT(mkdir_args) /* {
1455                                  * struct vnode *a_dvp;
1456                                  * struct vnode **a_vpp;
1457                                  * struct componentname *a_cnp;
1458                                  * struct vattr *a_vap;
1459                                  * } */ *ap;
1460 {
1461     register struct vnode *dvp = ap->a_dvp;
1462     register struct vattr *vap = ap->a_vap;
1463     int error = 0;
1464     struct vcache *vcp;
1465     struct proc *p;
1466
1467     GETNAME();
1468     p = vop_cn_proc;
1469 #if defined(DIAGNOSTIC) && !defined(AFS_DARWIN80_ENV)
1470     if ((cnp->cn_flags & HASBUF) == 0)
1471         panic("afs_vop_mkdir: no name");
1472 #endif
1473     AFS_GLOCK();
1474     error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, vop_cn_cred);
1475     AFS_GUNLOCK();
1476     if (error) {
1477 #ifndef AFS_DARWIN80_ENV
1478         VOP_ABORTOP(dvp, cnp);
1479         vput(dvp);
1480 #endif
1481         DROPNAME();
1482         return (error);
1483     }
1484     if (vcp) {
1485 #ifdef AFS_DARWIN80_ENV
1486         afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0);
1487 #endif
1488         *ap->a_vpp = AFSTOV(vcp);
1489 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
1490         (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1491         vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1492 #endif
1493     } else
1494         *ap->a_vpp = 0;
1495     DROPNAME();
1496 #ifndef AFS_DARWIN80_ENV
1497     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1498     vput(dvp);
1499 #endif
1500     return error;
1501 }
1502
1503 int
1504 afs_vop_rmdir(ap)
1505      struct VOPPROT(rmdir_args) /* {
1506                                  * struct vnode *a_dvp;
1507                                  * struct vnode *a_vp;
1508                                  * struct componentname *a_cnp;
1509                                  * } */ *ap;
1510 {
1511     int error = 0;
1512     register struct vnode *vp = ap->a_vp;
1513     register struct vnode *dvp = ap->a_dvp;
1514
1515     GETNAME();
1516     if (dvp == vp) {
1517 #ifndef AFS_DARWIN80_ENV
1518         vrele(dvp);
1519         vput(vp);
1520         FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1521 #endif
1522         DROPNAME();
1523         return (EINVAL);
1524     }
1525
1526     AFS_GLOCK();
1527     error = afs_rmdir(VTOAFS(dvp), name, vop_cn_cred);
1528     AFS_GUNLOCK();
1529     DROPNAME();
1530     cache_purge(dvp);
1531     cache_purge(vp);
1532 #ifndef AFS_DARWIN80_ENV
1533     vput(dvp);
1534     vput(vp);
1535 #endif
1536     return error;
1537 }
1538
1539 int
1540 afs_vop_symlink(ap)
1541      struct VOPPROT(symlink_args)       /* {
1542                                  * struct vnode *a_dvp;
1543                                  * struct vnode **a_vpp;
1544                                  * struct componentname *a_cnp;
1545                                  * struct vattr *a_vap;
1546                                  * char *a_target;
1547                                  * } */ *ap;
1548 {
1549     register struct vnode *dvp = ap->a_dvp;
1550     int error = 0;
1551     /* NFS ignores a_vpp; so do we. */
1552
1553     GETNAME();
1554     AFS_GLOCK();
1555     error =
1556         afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, vop_cn_cred);
1557     AFS_GUNLOCK();
1558     DROPNAME();
1559 #ifndef AFS_DARWIN80_ENV
1560     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1561     vput(dvp);
1562 #endif
1563     return error;
1564 }
1565
1566 int
1567 afs_vop_readdir(ap)
1568      struct VOPPROT(readdir_args)       /* {
1569                                  * struct vnode *a_vp;
1570                                  * struct uio *a_uio;
1571                                  * struct ucred *a_cred;
1572                                  * int *a_eofflag;
1573                                  * u_long *a_cookies;
1574                                  * int ncookies;
1575                                  * } */ *ap;
1576 {
1577     int error;
1578     off_t off;
1579 /*    printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1580            ap->a_ncookies); */
1581 #ifdef AFS_DARWIN80_ENV
1582     /* too much work for now */
1583     /* should only break nfs exports */
1584     if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
1585          return (EINVAL);
1586 #endif
1587     off = AFS_UIO_OFFSET(ap->a_uio);
1588     AFS_GLOCK();
1589     error =
1590         afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, vop_cred, ap->a_eofflag);
1591     AFS_GUNLOCK();
1592 #ifndef AFS_DARWIN80_ENV
1593     if (!error && ap->a_ncookies != NULL) {
1594         struct uio *uio = ap->a_uio;
1595         const struct dirent *dp, *dp_start, *dp_end;
1596         int ncookies;
1597         u_long *cookies, *cookiep;
1598
1599         if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1600             panic("afs_readdir: burned cookies");
1601         dp = (const struct dirent *)
1602             ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1603
1604         dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1605         for (dp_start = dp, ncookies = 0; dp < dp_end;
1606              dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1607             ncookies++;
1608
1609         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1610                M_WAITOK);
1611         for (dp = dp_start, cookiep = cookies; dp < dp_end;
1612              dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1613             off += dp->d_reclen;
1614             *cookiep++ = off;
1615         }
1616         *ap->a_cookies = cookies;
1617         *ap->a_ncookies = ncookies;
1618     }
1619 #endif
1620
1621     return error;
1622 }
1623
1624 int
1625 afs_vop_readlink(ap)
1626      struct VOPPROT(readlink_args)      /* {
1627                                  * struct vnode *a_vp;
1628                                  * struct uio *a_uio;
1629                                  * struct ucred *a_cred;
1630                                  * } */ *ap;
1631 {
1632     int error;
1633 /*    printf("readlink %x\n", ap->a_vp);*/
1634     AFS_GLOCK();
1635     error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, vop_cred);
1636     AFS_GUNLOCK();
1637     return error;
1638 }
1639
1640 extern int prtactive;
1641
1642 int
1643 afs_vop_inactive(ap)
1644      struct VOPPROT(inactive_args)      /* {
1645                                  * struct vnode *a_vp;
1646                                  * struct proc *a_p;
1647                                  * } */ *ap;
1648 {
1649     register struct vnode *vp = ap->a_vp;
1650     struct vcache *tvc = VTOAFS(vp);
1651 #ifndef AFS_DARWIN80_ENV
1652     if (prtactive && vp->v_usecount != 0)
1653         vprint("afs_vop_inactive(): pushing active", vp);
1654 #endif
1655     if (tvc) {
1656 #ifdef AFS_DARWIN80_ENV
1657         int unlinked = tvc->states & CUnlinked;
1658 #endif
1659         AFS_GLOCK();
1660         afs_InactiveVCache(tvc, 0);     /* decrs ref counts */
1661         AFS_GUNLOCK();
1662 #ifdef AFS_DARWIN80_ENV
1663         if (unlinked) {
1664             vnode_recycle(vp);
1665             cache_purge(vp);
1666         }
1667 #endif
1668     }
1669 #ifndef AFS_DARWIN80_ENV
1670     VOP_UNLOCK(vp, 0, ap->a_p);
1671 #endif
1672     return 0;
1673 }
1674
1675 int
1676 afs_vop_reclaim(ap)
1677      struct VOPPROT(reclaim_args)       /* {
1678                                  * struct vnode *a_vp;
1679                                  * } */ *ap;
1680 {
1681     int error = 0;
1682     int sl, writelocked;
1683     register struct vnode *vp = ap->a_vp;
1684     struct vcache *tvc = VTOAFS(vp);
1685
1686     osi_Assert(!ISAFS_GLOCK());
1687     cache_purge(vp);            /* just in case... */
1688     if (tvc) {
1689        AFS_GLOCK();
1690        writelocked = (0 == NBObtainWriteLock(&afs_xvcache, 335));
1691        if (!writelocked) {
1692            ObtainWriteLock(&afs_xvreclaim, 176);
1693 #ifdef AFS_DARWIN80_ENV
1694            vnode_clearfsnode(AFSTOV(tvc));
1695            vnode_removefsref(AFSTOV(tvc));
1696 #else
1697            tvc->v->v_data = NULL;  /* remove from vnode */
1698 #endif
1699            AFSTOV(tvc) = NULL;             /* also drop the ptr to vnode */
1700            tvc->states |= CVInit; /* also CDeadVnode? */
1701            tvc->nextfree = ReclaimedVCList;
1702            ReclaimedVCList = tvc;
1703            ReleaseWriteLock(&afs_xvreclaim);
1704        } else {
1705            error = afs_FlushVCache(tvc, &sl);   /* toss our stuff from vnode */
1706            if (tvc->states & (CVInit
1707 #ifdef AFS_DARWIN80_ENV
1708                               | CDeadVnode
1709 #endif
1710                    )) {
1711                tvc->states &= ~(CVInit
1712 #ifdef AFS_DARWIN80_ENV
1713                                 | CDeadVnode
1714 #endif
1715                    );
1716                afs_osi_Wakeup(&tvc->states);
1717            }
1718            if (!error && vnode_fsnode(vp))
1719                panic("afs_reclaim: vnode not cleaned");
1720            if (!error && (tvc->v != NULL)) 
1721                panic("afs_reclaim: vcache not cleaned");
1722            ReleaseWriteLock(&afs_xvcache);
1723        }
1724        AFS_GUNLOCK();
1725     }
1726     return error;
1727 }
1728
1729 /*
1730  * Return POSIX pathconf information applicable to ufs filesystems.
1731  */
1732 afs_vop_pathconf(ap)
1733      struct VOPPROT(pathconf_args)      /* {
1734                                  * struct vnode *a_vp;
1735                                  * int a_name;
1736                                  * int *a_retval;
1737                                  * } */ *ap;
1738 {
1739     AFS_STATCNT(afs_cntl);
1740     switch (ap->a_name) {
1741     case _PC_LINK_MAX:
1742         *ap->a_retval = LINK_MAX;
1743         break;
1744     case _PC_NAME_MAX:
1745         *ap->a_retval = NAME_MAX;
1746         break;
1747     case _PC_PATH_MAX:
1748         *ap->a_retval = PATH_MAX;
1749         break;
1750     case _PC_CHOWN_RESTRICTED:
1751         *ap->a_retval = 1;
1752         break;
1753     case _PC_NO_TRUNC:
1754         *ap->a_retval = 1;
1755         break;
1756     case _PC_PIPE_BUF:
1757         return EINVAL;
1758         break;
1759 #if defined(AFS_DARWIN70_ENV)
1760     case _PC_NAME_CHARS_MAX:
1761         *ap->a_retval = NAME_MAX;
1762         break;
1763     case _PC_CASE_SENSITIVE:
1764         *ap->a_retval = 1;
1765         break;
1766     case _PC_CASE_PRESERVING:
1767         *ap->a_retval = 1;
1768         break;
1769 #endif /* defined(AFS_DARWIN70_ENV) */
1770     default:
1771         return EINVAL;
1772     }
1773     return 0;
1774 }
1775
1776 /*
1777  * Advisory record locking support (fcntl() POSIX style)
1778  */
1779 int
1780 afs_vop_advlock(ap)
1781      struct VOPPROT(advlock_args)       /* {
1782                                  * struct vnode *a_vp;
1783                                  * caddr_t  a_id;
1784                                  * int  a_op;
1785                                  * struct flock *a_fl;
1786                                  * int  a_flags;
1787                                  * } */ *ap;
1788 {
1789     int error;
1790     struct ucred *tcr;
1791     int clid;
1792     int op;
1793 #ifdef AFS_DARWIN80_ENV
1794     proc_t p;
1795     tcr=vop_cred;
1796 #else
1797     struct proc *p = current_proc();
1798     struct ucred cr;
1799     pcred_readlock(p);
1800     cr = *p->p_cred->pc_ucred;
1801     pcred_unlock(p);
1802     tcr=&cr;
1803 #endif
1804     if (ap->a_flags & F_POSIX) {
1805 #ifdef AFS_DARWIN80_ENV
1806         p = (proc_t) ap->a_id;
1807         clid = proc_pid(p);
1808 #else
1809         p = (struct proc *) ap->a_id;
1810         clid = p->p_pid;
1811 #endif
1812     } else {
1813         clid = (int)ap->a_id;
1814     }
1815     if (ap->a_op == F_UNLCK) {
1816         op = F_SETLK;
1817     } else if (ap->a_op == F_SETLK && ap->a_flags & F_WAIT) {
1818         op = F_SETLKW;
1819     } else {
1820         op = ap->a_op;
1821     }
1822     AFS_GLOCK();
1823     error = afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, op, tcr, clid);
1824     AFS_GUNLOCK();
1825     return error;
1826 }
1827
1828 int
1829 afs_vop_blktooff(ap)
1830      struct VOPPROT(blktooff_args)      /* {
1831                                  * struct vnode *a_vp;
1832                                  * daddr_t a_lblkno;
1833                                  * off_t *a_offset;    
1834                                  * } */ *ap;
1835 {
1836     *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1837     return 0;
1838 }
1839
1840 int
1841 afs_vop_offtoblk(ap)
1842      struct VOPPROT(offtoblk_args)      /* {
1843                                  * struct vnode *a_vp;
1844                                  * off_t a_offset;    
1845                                  * daddr_t *a_lblkno;
1846                                  * } */ *ap;
1847 {
1848     *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1849
1850     return (0);
1851 }
1852
1853 #ifndef AFS_DARWIN80_ENV
1854 int
1855 afs_vop_lock(ap)
1856      struct VOPPROT(lock_args)  /* {
1857                                  * struct vnode *a_vp;
1858                                  * } */ *ap;
1859 {
1860     register struct vnode *vp = ap->a_vp;
1861     register struct vcache *avc = VTOAFS(vp);
1862
1863     if (vp->v_tag == VT_NON)
1864         return (ENOENT);
1865
1866     return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1867 }
1868
1869 int
1870 afs_vop_unlock(ap)
1871      struct VOPPROT(unlock_args)        /* {
1872                                  * struct vnode *a_vp;
1873                                  * } */ *ap;
1874 {
1875     struct vnode *vp = ap->a_vp;
1876     struct vcache *avc = VTOAFS(vp);
1877
1878     return (lockmgr
1879             (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1880              ap->a_p));
1881
1882 }
1883
1884 int
1885 afs_vop_truncate(ap)
1886      struct VOPPROT(truncate_args)      /* {
1887                                  * struct vnode *a_vp;
1888                                  * off_t a_length;
1889                                  * int a_flags;
1890                                  * struct ucred *a_cred;
1891                                  * struct proc *a_p;
1892                                  * } */ *ap;
1893 {
1894     printf("stray afs_vop_truncate\n");
1895     return EOPNOTSUPP;
1896 }
1897
1898 int
1899 afs_vop_update(ap)
1900      struct VOPPROT(update_args)        /* {
1901                                  * struct vnode *a_vp;
1902                                  * struct timeval *a_access;
1903                                  * struct timeval *a_modify;
1904                                  * int a_waitfor;
1905                                  * } */ *ap;
1906 {
1907     printf("stray afs_vop_update\n");
1908     return EOPNOTSUPP;
1909 }
1910
1911 int
1912 afs_vop_bmap(ap)
1913      struct VOPPROT(bmap_args)  /* {
1914                                  * struct vnode *a_vp;
1915                                  * daddr_t  a_bn;
1916                                  * struct vnode **a_vpp;
1917                                  * daddr_t *a_bnp;
1918                                  * int *a_runp;
1919                                  * int *a_runb;
1920                                  * } */ *ap;
1921 {
1922     int error;
1923     if (ap->a_bnp) {
1924         *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
1925     }
1926     if (ap->a_vpp) {
1927         *ap->a_vpp = ap->a_vp;
1928     }
1929     if (ap->a_runp != NULL)
1930         *ap->a_runp = 0;
1931 #ifdef notyet
1932     if (ap->a_runb != NULL)
1933         *ap->a_runb = 0;
1934 #endif
1935
1936     return 0;
1937 }
1938
1939 int
1940 afs_vop_strategy(ap)
1941      struct VOPPROT(strategy_args)      /* {
1942                                  * struct buf *a_bp;
1943                                  * } */ *ap;
1944 {
1945     int error;
1946     AFS_GLOCK();
1947     error = afs_ustrategy(ap->a_bp);
1948     AFS_GUNLOCK();
1949     return error;
1950 }
1951
1952 int
1953 afs_vop_print(ap)
1954      struct VOPPROT(print_args) /* {
1955                                  * struct vnode *a_vp;
1956                                  * } */ *ap;
1957 {
1958     register struct vnode *vp = ap->a_vp;
1959     register struct vcache *vc = VTOAFS(ap->a_vp);
1960     int s = vc->states;
1961     printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1962            vc->fid.Cell, vc->fid.Fid.Volume, vc->fid.Fid.Vnode,
1963            vc->fid.Fid.Unique, vc->opens, vc->execsOrWriters);
1964     printf("\n  states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1965            (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1966            (s & CMAPPED) ? " mapped" : "",
1967            (s & CVFlushed) ? " flush in progress" : "");
1968     if (UBCISVALID(vp)) {
1969         printf("\n  UBC: ");
1970         if (UBCINFOEXISTS(vp)) {
1971             printf("exists, ");
1972 #ifdef AFS_DARWIN14_ENV
1973             printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
1974                    ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
1975                    ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
1976 #else
1977             printf("holdcnt %d", vp->v_ubcinfo->ui_holdcnt);
1978 #endif
1979         } else
1980             printf("does not exist");
1981     }
1982     printf("\n");
1983     return 0;
1984 }
1985
1986 int
1987 afs_vop_islocked(ap)
1988      struct VOPPROT(islocked_args)      /* {
1989                                  * struct vnode *a_vp;
1990                                  * } */ *ap;
1991 {
1992     struct vcache *vc = VTOAFS(ap->a_vp);
1993     return lockstatus(&vc->rwlock);
1994 }
1995
1996 int
1997 afs_vop_cmap(ap)
1998      struct VOPPROT(cmap_args)  /* {
1999                                  * struct vnode *a_vp;
2000                                  * off_t a_foffset;    
2001                                  * size_t a_size;
2002                                  * daddr_t *a_bpn;
2003                                  * size_t *a_run;
2004                                  * void *a_poff;
2005                                  * } */ *ap;
2006 {
2007     *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
2008     *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));
2009     return 0;
2010 }
2011 #endif
2012
2013 int
2014 afs_darwin_getnewvnode(struct vcache *avc)
2015 {
2016 #ifdef AFS_DARWIN80_ENV
2017     vnode_t vp;
2018     int error, dead;
2019     struct vnode_fsparam par;
2020
2021     memset(&par, 0, sizeof(struct vnode_fsparam));
2022 #if 0
2023     AFS_GLOCK();
2024     ObtainWriteLock(&avc->lock,342);
2025     if (avc->states & CStatd) { 
2026        par.vnfs_vtype = avc->m.Type;
2027        par.vnfs_vops = afs_vnodeop_p;
2028        par.vnfs_filesize = avc->m.Length;
2029        if (!ac->cnp)
2030            par.vnfs_flags = VNFS_NOCACHE;
2031        dead = 0;
2032     } else {
2033        par.vnfs_vtype = VNON;
2034        par.vnfs_vops = afs_dead_vnodeop_p;
2035        par.vnfs_flags = VNFS_NOCACHE|VNFS_CANTCACHE;
2036        dead = 1;
2037     }
2038     ReleaseWriteLock(&avc->lock);
2039     AFS_GUNLOCK();
2040     par.vnfs_dvp = ac->dvp;
2041     par.vnfs_cnp = ac->cnp;
2042     par.vnfs_markroot = ac->markroot;
2043 #else
2044     par.vnfs_vtype = VNON;
2045     par.vnfs_vops = afs_dead_vnodeop_p;
2046     par.vnfs_flags = VNFS_NOCACHE|VNFS_CANTCACHE;
2047 #endif
2048     par.vnfs_mp = afs_globalVFS;
2049     par.vnfs_fsnode = avc;
2050
2051     error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &vp);
2052     if (!error) {
2053       vnode_addfsref(vp);
2054       vnode_ref(vp);
2055       avc->v = vp;
2056 #if 0
2057       if (dead) {
2058          vnode_recycle(vp); /* terminate as soon as iocount drops */
2059          avc->states |= CDeadVnode;
2060       } else if (!ac->markroot && !ac->cnp) {
2061        /* the caller doesn't know anything about this vnode. if markroot
2062           should have been set and wasn't, bad things may happen, so encourage
2063           it to recycle */
2064           vnode_recycle(vp);
2065       }
2066 #else
2067       vnode_recycle(vp); /* terminate as soon as iocount drops */
2068       avc->states |= CDeadVnode;
2069 #endif
2070     }
2071     return error;
2072 #else
2073     while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &avc->v)) {
2074         /* no vnodes available, force an alloc (limits be damned)! */
2075         printf("failed to get vnode\n");
2076     }
2077     avc->v->v_data = (void *)avc;
2078     return 0;
2079 #endif
2080 }
2081 #ifdef AFS_DARWIN80_ENV
2082 /* if this fails, then tvc has been unrefed and may have been freed. 
2083    Don't touch! */
2084 int 
2085 afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp, struct componentname *cnp, int isroot) {
2086    vnode_t ovp;
2087    vnode_t nvp;
2088    int error;
2089    struct vnode_fsparam par;
2090    AFS_GLOCK();
2091    ObtainWriteLock(&avc->lock,325);
2092    ovp = AFSTOV(avc);
2093    if (!(avc->states & CDeadVnode) && vnode_vtype(ovp) != VNON) {
2094         AFS_GUNLOCK();
2095 #if 0 /* unsupported */
2096         if (dvp && cnp)
2097         vnode_update_identity(ovp, dvp, cnp->cn_nameptr, cnp->cn_namelen,
2098                               cnp->cn_hash,
2099                               VNODE_UPDATE_PARENT|VNODE_UPDATE_NAME);
2100 #endif
2101         /* Can end up in reclaim... drop GLOCK */
2102         vnode_rele(ovp);
2103         AFS_GLOCK();
2104         ReleaseWriteLock(&avc->lock);
2105         AFS_GUNLOCK();
2106         return 0;
2107    }
2108    if ((avc->states & CDeadVnode) && vnode_vtype(ovp) != VNON) 
2109        panic("vcache %p should not be CDeadVnode", avc);
2110    AFS_GUNLOCK();
2111    memset(&par, 0, sizeof(struct vnode_fsparam));
2112    par.vnfs_mp = afs_globalVFS;
2113    par.vnfs_vtype = avc->m.Type;
2114    par.vnfs_vops = afs_vnodeop_p;
2115    par.vnfs_filesize = avc->m.Length;
2116    par.vnfs_fsnode = avc;
2117    par.vnfs_dvp = dvp;
2118    if (cnp && (cnp->cn_flags & ISDOTDOT) == 0)
2119        par.vnfs_cnp = cnp;
2120    if (!dvp || !cnp || (cnp->cn_flags & MAKEENTRY) == 0)
2121        par.vnfs_flags = VNFS_NOCACHE;
2122    if (isroot)
2123        par.vnfs_markroot = 1;
2124    error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &nvp);
2125    if (!error) {
2126        vnode_addfsref(nvp);
2127        if ((avc->states & CDeadVnode) && vnode_vtype(ovp) != VNON) 
2128            printf("vcache %p should not be CDeadVnode", avc);
2129        if (avc->v == ovp) {
2130            if (!(avc->states & CVInit)) {
2131                vnode_clearfsnode(ovp);
2132                vnode_removefsref(ovp);
2133            }
2134        }
2135        avc->v = nvp;
2136        avc->states &=~ CDeadVnode;
2137    }
2138    vnode_put(ovp);
2139    vnode_rele(ovp);
2140    AFS_GLOCK();
2141    ReleaseWriteLock(&avc->lock);
2142    if (!error)
2143       afs_osi_Wakeup(&avc->states);
2144    AFS_GUNLOCK();
2145    return error;
2146 }
2147 #endif