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