cd49634ffc3ae37450b6e21cb7dc2154423670c9
[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
20 int afs_vop_lookup(struct vop_lookup_args *);
21 int afs_vop_create(struct vop_create_args *);
22 int afs_vop_mknod(struct vop_mknod_args *);
23 int afs_vop_open(struct vop_open_args *);
24 int afs_vop_close(struct vop_close_args *);
25 int afs_vop_access(struct vop_access_args *);
26 int afs_vop_getattr(struct vop_getattr_args *);
27 int afs_vop_setattr(struct vop_setattr_args *);
28 int afs_vop_read(struct vop_read_args *);
29 int afs_vop_write(struct vop_write_args *);
30 int afs_vop_pagein(struct vop_pagein_args *);
31 int afs_vop_pageout(struct vop_pageout_args *);
32 int afs_vop_ioctl(struct vop_ioctl_args *);
33 int afs_vop_select(struct vop_select_args *);
34 int afs_vop_mmap(struct vop_mmap_args *);
35 int afs_vop_fsync(struct vop_fsync_args *);
36 int afs_vop_seek(struct vop_seek_args *);
37 int afs_vop_remove(struct vop_remove_args *);
38 int afs_vop_link(struct vop_link_args *);
39 int afs_vop_rename(struct vop_rename_args *);
40 int afs_vop_mkdir(struct vop_mkdir_args *);
41 int afs_vop_rmdir(struct vop_rmdir_args *);
42 int afs_vop_symlink(struct vop_symlink_args *);
43 int afs_vop_readdir(struct vop_readdir_args *);
44 int afs_vop_readlink(struct vop_readlink_args *);
45 #if !defined(AFS_DARWIN70_ENV)
46 extern int ufs_abortop(struct vop_abortop_args *);
47 #endif /* !defined(AFS_DARWIN70_ENV) */
48 int afs_vop_inactive(struct vop_inactive_args *);
49 int afs_vop_reclaim(struct vop_reclaim_args *);
50 int afs_vop_lock(struct vop_lock_args *);
51 int afs_vop_unlock(struct vop_unlock_args *);
52 int afs_vop_bmap(struct vop_bmap_args *);
53 int afs_vop_strategy(struct vop_strategy_args *);
54 int afs_vop_print(struct vop_print_args *);
55 int afs_vop_islocked(struct vop_islocked_args *);
56 int afs_vop_pathconf(struct vop_pathconf_args *);
57 int afs_vop_advlock(struct vop_advlock_args *);
58 int afs_vop_truncate(struct vop_truncate_args *);
59 int afs_vop_update(struct vop_update_args *);
60 int afs_vop_blktooff __P((struct vop_blktooff_args *));
61 int afs_vop_offtoblk __P((struct vop_offtoblk_args *));
62 int afs_vop_cmap __P((struct vop_cmap_args *));
63
64
65 #define afs_vop_opnotsupp \
66         ((int (*) __P((struct  vop_reallocblks_args *)))eopnotsupp)
67 #define afs_vop_valloc afs_vop_opnotsupp
68 #define afs_vop_vfree afs_vop_opnotsupp
69 #define afs_vop_blkatoff afs_vop_opnotsupp
70 #define afs_vop_reallocblks afs_vop_opnotsupp
71
72 /* Global vfs data structures for AFS. */
73 int (**afs_vnodeop_p) ();
74 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
75     {&vop_default_desc, vn_default_error},
76     {&vop_lookup_desc, afs_vop_lookup}, /* lookup */
77     {&vop_create_desc, afs_vop_create}, /* create */
78     {&vop_mknod_desc, afs_vop_mknod},   /* mknod */
79     {&vop_open_desc, afs_vop_open},     /* open */
80     {&vop_close_desc, afs_vop_close},   /* close */
81     {&vop_access_desc, afs_vop_access}, /* access */
82     {&vop_getattr_desc, afs_vop_getattr},       /* getattr */
83     {&vop_setattr_desc, afs_vop_setattr},       /* setattr */
84     {&vop_read_desc, afs_vop_read},     /* read */
85     {&vop_write_desc, afs_vop_write},   /* write */
86     {&vop_pagein_desc, afs_vop_pagein}, /* read */
87     {&vop_pageout_desc, afs_vop_pageout},       /* write */
88     {&vop_ioctl_desc, afs_vop_ioctl},   /* XXX ioctl */
89     {&vop_select_desc, afs_vop_select}, /* select */
90     {&vop_mmap_desc, afs_vop_mmap},     /* mmap */
91     {&vop_fsync_desc, afs_vop_fsync},   /* fsync */
92     {&vop_seek_desc, afs_vop_seek},     /* seek */
93     {&vop_remove_desc, afs_vop_remove}, /* remove */
94     {&vop_link_desc, afs_vop_link},     /* link */
95     {&vop_rename_desc, afs_vop_rename}, /* rename */
96     {&vop_mkdir_desc, afs_vop_mkdir},   /* mkdir */
97     {&vop_rmdir_desc, afs_vop_rmdir},   /* rmdir */
98     {&vop_symlink_desc, afs_vop_symlink},       /* symlink */
99     {&vop_readdir_desc, afs_vop_readdir},       /* readdir */
100     {&vop_readlink_desc, afs_vop_readlink},     /* readlink */
101 #if defined(AFS_DARWIN70_ENV)
102     { &vop_abortop_desc, nop_abortop },             /* abortop */
103 #else /* ! defined(AFS_DARWIN70_ENV) */
104     /* Yes, we use the ufs_abortop call.  It just releases the namei
105      * buffer stuff */
106     {&vop_abortop_desc, ufs_abortop},   /* abortop */
107 #endif /* defined(AFS_DARWIN70_ENV) */
108     {&vop_inactive_desc, afs_vop_inactive},     /* inactive */
109     {&vop_reclaim_desc, afs_vop_reclaim},       /* reclaim */
110     {&vop_lock_desc, afs_vop_lock},     /* lock */
111     {&vop_unlock_desc, afs_vop_unlock}, /* unlock */
112     {&vop_bmap_desc, afs_vop_bmap},     /* bmap */
113     {&vop_strategy_desc, afs_vop_strategy},     /* strategy */
114     {&vop_print_desc, afs_vop_print},   /* print */
115     {&vop_islocked_desc, afs_vop_islocked},     /* islocked */
116     {&vop_pathconf_desc, afs_vop_pathconf},     /* pathconf */
117     {&vop_advlock_desc, afs_vop_advlock},       /* advlock */
118     {&vop_blkatoff_desc, afs_vop_blkatoff},     /* blkatoff */
119     {&vop_valloc_desc, afs_vop_valloc}, /* valloc */
120     {&vop_reallocblks_desc, afs_vop_reallocblks},       /* reallocblks */
121     {&vop_vfree_desc, afs_vop_vfree},   /* vfree */
122     {&vop_truncate_desc, afs_vop_truncate},     /* truncate */
123     {&vop_update_desc, afs_vop_update}, /* update */
124     {&vop_blktooff_desc, afs_vop_blktooff},     /* blktooff */
125     {&vop_offtoblk_desc, afs_vop_offtoblk},     /* offtoblk */
126     {&vop_cmap_desc, afs_vop_cmap},     /* cmap */
127     {&vop_bwrite_desc, vn_bwrite},
128     {(struct vnodeop_desc *)NULL, (int (*)())NULL}
129 };
130 struct vnodeopv_desc afs_vnodeop_opv_desc =
131     { &afs_vnodeop_p, afs_vnodeop_entries };
132
133 #define GETNAME()       \
134     struct componentname *cnp = ap->a_cnp; \
135     char *name; \
136     MALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
137     memcpy(name, cnp->cn_nameptr, cnp->cn_namelen); \
138     name[cnp->cn_namelen] = '\0'
139
140 #define DROPNAME() FREE(name, M_TEMP)
141
142 void 
143 darwin_vn_hold(struct vnode *vp)
144 {
145     int haveGlock=ISAFS_GLOCK(); 
146     struct vcache *tvc = VTOAFS(vp);
147
148     tvc->states |= CUBCinit;
149     if (haveGlock) AFS_GUNLOCK(); 
150
151     /* vget needed for 0 ref'd vnode in GetVCache to not panic in vref.
152        vref needed for multiref'd vnode in vnop_remove not to deadlock
153        ourselves during vop_inactive, except we also need to not reinst
154        the ubc... so we just call VREF there now anyway. */
155
156     if (VREFCOUNT(tvc) > 0)
157         VREF(((struct vnode *)(vp))); 
158     else
159         afs_vget(afs_globalVFS, 0, (vp));
160
161     if (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp)) {
162         ubc_info_init(vp); 
163     }
164
165     if (haveGlock) AFS_GLOCK(); 
166     tvc->states &= ~CUBCinit;
167 }
168
169 int
170 afs_vop_lookup(ap)
171      struct vop_lookup_args     /* {
172                                  * struct vnodeop_desc * a_desc;
173                                  * struct vnode *a_dvp;
174                                  * struct vnode **a_vpp;
175                                  * struct componentname *a_cnp;
176                                  * } */ *ap;
177 {
178     int error;
179     struct vcache *vcp;
180     struct vnode *vp, *dvp;
181     register int flags = ap->a_cnp->cn_flags;
182     int lockparent;             /* 1 => lockparent flag is set */
183     int wantparent;             /* 1 => wantparent or lockparent flag */
184     struct proc *p;
185     GETNAME();
186     p = cnp->cn_proc;
187     lockparent = flags & LOCKPARENT;
188     wantparent = flags & (LOCKPARENT | WANTPARENT);
189
190     if (ap->a_dvp->v_type != VDIR) {
191         *ap->a_vpp = 0;
192         DROPNAME();
193         return ENOTDIR;
194     }
195     dvp = ap->a_dvp;
196     if (flags & ISDOTDOT)
197         VOP_UNLOCK(dvp, 0, p);
198     AFS_GLOCK();
199     error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
200     AFS_GUNLOCK();
201     if (error) {
202         if (flags & ISDOTDOT)
203             VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
204         if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
205             && (flags & ISLASTCN) && error == ENOENT)
206             error = EJUSTRETURN;
207         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
208             cnp->cn_flags |= SAVENAME;
209         DROPNAME();
210         *ap->a_vpp = 0;
211         return (error);
212     }
213     vp = AFSTOV(vcp);           /* always get a node if no error */
214     vp->v_vfsp = dvp->v_vfsp;
215
216     if (UBCINFOMISSING(vp) ||
217         UBCINFORECLAIMED(vp)) {
218             ubc_info_init(vp);
219     }
220
221     /* The parent directory comes in locked.  We unlock it on return
222      * unless the caller wants it left locked.
223      * we also always return the vnode locked. */
224
225     if (flags & ISDOTDOT) {
226         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
227         /* always return the child locked */
228         if (lockparent && (flags & ISLASTCN)
229             && (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
230             vput(vp);
231             DROPNAME();
232             return (error);
233         }
234     } else if (vp == dvp) {
235         /* they're the same; afs_lookup() already ref'ed the leaf.
236          * It came in locked, so we don't need to ref OR lock it */
237     } else {
238         if (!lockparent || !(flags & ISLASTCN))
239             VOP_UNLOCK(dvp, 0, p);      /* done with parent. */
240         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
241         /* always return the child locked */
242     }
243     *ap->a_vpp = vp;
244
245     if ((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)
246          || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
247         cnp->cn_flags |= SAVENAME;
248
249     DROPNAME();
250     return error;
251 }
252
253 int
254 afs_vop_create(ap)
255      struct vop_create_args     /* {
256                                  * struct vnode *a_dvp;
257                                  * struct vnode **a_vpp;
258                                  * struct componentname *a_cnp;
259                                  * struct vattr *a_vap;
260                                  * } */ *ap;
261 {
262     int error = 0;
263     struct vcache *vcp;
264     register struct vnode *dvp = ap->a_dvp;
265     struct proc *p;
266     GETNAME();
267     p = cnp->cn_proc;
268
269     /* vnode layer handles excl/nonexcl */
270     AFS_GLOCK();
271     error =
272         afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
273                    &vcp, cnp->cn_cred);
274     AFS_GUNLOCK();
275     if (error) {
276         VOP_ABORTOP(dvp, cnp);
277         vput(dvp);
278         DROPNAME();
279         return (error);
280     }
281
282     if (vcp) {
283         *ap->a_vpp = AFSTOV(vcp);
284         (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
285         vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
286         if (UBCINFOMISSING(*ap->a_vpp) || UBCINFORECLAIMED(*ap->a_vpp)) {
287             vcp->states |= CUBCinit;
288             ubc_info_init(*ap->a_vpp);
289             vcp->states &= ~CUBCinit;
290         }
291     } else
292         *ap->a_vpp = 0;
293
294     if ((cnp->cn_flags & SAVESTART) == 0)
295         FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
296     vput(dvp);
297     DROPNAME();
298     return error;
299 }
300
301 int
302 afs_vop_mknod(ap)
303      struct vop_mknod_args      /* {
304                                  * struct vnode *a_dvp;
305                                  * struct vnode **a_vpp;
306                                  * struct componentname *a_cnp;
307                                  * struct vattr *a_vap;
308                                  * } */ *ap;
309 {
310     FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
311     vput(ap->a_dvp);
312     return (ENODEV);
313 }
314
315 int
316 afs_vop_open(ap)
317      struct vop_open_args       /* {
318                                  * struct vnode *a_vp;
319                                  * int  a_mode;
320                                  * struct ucred *a_cred;
321                                  * struct proc *a_p;
322                                  * } */ *ap;
323 {
324     int error;
325     struct vnode *vp = ap->a_vp;
326     struct vcache *vc = VTOAFS(vp);
327 #ifdef AFS_DARWIN14_ENV
328     int didhold = 0;
329     /*----------------------------------------------------------------
330      * osi_VM_TryReclaim() removes the ubcinfo of a vnode, but that vnode
331      * can later be passed to vn_open(), which will skip the call to
332      * ubc_hold(), and when the ubcinfo is later added, the ui_refcount
333      * will be off.  So we compensate by calling ubc_hold() ourselves
334      * when ui_refcount is less than 2.  If an error occurs in afs_open()
335      * we must call ubc_rele(), which is what vn_open() would do if it
336      * was able to call ubc_hold() in the first place.
337      *----------------------------------------------------------------*/
338     if (vp->v_type == VREG && !(vp->v_flag & VSYSTEM)
339       && vp->v_ubcinfo->ui_refcount < 2)
340         didhold = ubc_hold(vp);
341 #endif /* AFS_DARWIN14_ENV */
342     AFS_GLOCK();
343     error = afs_open(&vc, ap->a_mode, ap->a_cred);
344 #ifdef DIAGNOSTIC
345     if (AFSTOV(vc) != vp)
346         panic("AFS open changed vnode!");
347 #endif
348 #if 0
349     osi_FlushPages(vc, ap->a_cred);
350 #endif
351     AFS_GUNLOCK();
352 #ifdef AFS_DARWIN14_ENV
353     if (error && didhold)
354         ubc_rele(vp);
355 #endif /* AFS_DARWIN14_ENV */
356     return error;
357 }
358
359 int
360 afs_vop_close(ap)
361      struct vop_close_args      /* {
362                                  * struct vnode *a_vp;
363                                  * int  a_fflag;
364                                  * struct ucred *a_cred;
365                                  * struct proc *a_p;
366                                  * } */ *ap;
367 {
368     int code;
369     struct vnode *vp = ap->a_vp;
370     struct vcache *avc = VTOAFS(vp);
371     AFS_GLOCK();
372     if (ap->a_cred)
373         code = afs_close(avc, ap->a_fflag, ap->a_cred, ap->a_p);
374     else
375         code = afs_close(avc, ap->a_fflag, &afs_osi_cred, ap->a_p);
376 #if 0
377     osi_FlushPages(avc, ap->a_cred);    /* hold bozon lock, but not basic vnode lock */
378 #endif
379     AFS_GUNLOCK();
380
381     return code;
382 }
383
384 int
385 afs_vop_access(ap)
386      struct vop_access_args     /* {
387                                  * struct vnode *a_vp;
388                                  * int  a_mode;
389                                  * struct ucred *a_cred;
390                                  * struct proc *a_p;
391                                  * } */ *ap;
392 {
393     int code;
394     AFS_GLOCK();
395     code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
396     AFS_GUNLOCK();
397     return code;
398 }
399
400 int
401 afs_vop_getattr(ap)
402      struct vop_getattr_args    /* {
403                                  * struct vnode *a_vp;
404                                  * struct vattr *a_vap;
405                                  * struct ucred *a_cred;
406                                  * struct proc *a_p;
407                                  * } */ *ap;
408 {
409     int code;
410
411     AFS_GLOCK();
412     code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
413     AFS_GUNLOCK();
414     return code;
415 }
416
417 int
418 afs_vop_setattr(ap)
419      struct vop_setattr_args    /* {
420                                  * struct vnode *a_vp;
421                                  * struct vattr *a_vap;
422                                  * struct ucred *a_cred;
423                                  * struct proc *a_p;
424                                  * } */ *ap;
425 {
426     int code;
427     AFS_GLOCK();
428     code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
429     AFS_GUNLOCK();
430     return code;
431 }
432
433 int
434 afs_vop_read(ap)
435      struct vop_read_args       /* {
436                                  * struct vnode *a_vp;
437                                  * struct uio *a_uio;
438                                  * int a_ioflag;
439                                  * struct ucred *a_cred;
440                                  * } */ *ap;
441 {
442     int code;
443     struct vnode *vp = ap->a_vp;
444     struct vcache *avc = VTOAFS(vp);
445     AFS_GLOCK();
446 #if 0
447     osi_FlushPages(avc, ap->a_cred);    /* hold bozon lock, but not basic vnode lock */
448 #endif
449     code = afs_read(avc, ap->a_uio, ap->a_cred, 0, 0, 0);
450     AFS_GUNLOCK();
451     return code;
452 }
453
454 int
455 afs_vop_pagein(ap)
456      struct vop_pagein_args     /* {
457                                  * struct vnode *a_vp;
458                                  * upl_t a_pl;
459                                  * vm_offset_t a_pl_offset;
460                                  * off_t a_f_offset;
461                                  * size_t a_size;
462                                  * struct ucred *a_cred;
463                                  * int a_flags;
464                                  * } */ *ap;
465 {
466     register struct vnode *vp = ap->a_vp;
467     upl_t pl = ap->a_pl;
468     size_t size = ap->a_size;
469     off_t f_offset = ap->a_f_offset;
470     vm_offset_t pl_offset = ap->a_pl_offset;
471     int flags = ap->a_flags;
472     struct ucred *cred;
473     vm_offset_t ioaddr;
474     struct uio auio;
475     struct iovec aiov;
476     struct uio *uio = &auio;
477     int nocommit = flags & UPL_NOCOMMIT;
478
479     int code;
480     struct vcache *tvc = VTOAFS(vp);
481
482     if (UBCINVALID(vp)) {
483 #if DIAGNOSTIC
484         panic("afs_vop_pagein: invalid vp");
485 #endif /* DIAGNOSTIC */
486         return (EPERM);
487     }
488
489     UBCINFOCHECK("afs_vop_pagein", vp);
490     if (pl == (upl_t) NULL) {
491         panic("afs_vop_pagein: no upl");
492     }
493
494     cred = ubc_getcred(vp);
495     if (cred == NOCRED)
496         cred = ap->a_cred;
497
498     if (size == 0) {
499         if (!nocommit)
500             kernel_upl_abort_range(pl, pl_offset, size,
501                                    UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
502         return (0);
503     }
504     if (f_offset < 0) {
505         if (!nocommit)
506             kernel_upl_abort_range(pl, pl_offset, size,
507                                    UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
508         return (EINVAL);
509     }
510     if (f_offset & PAGE_MASK)
511         panic("afs_vop_pagein: offset not page aligned");
512
513     auio.uio_iov = &aiov;
514     auio.uio_iovcnt = 1;
515     auio.uio_offset = f_offset;
516     auio.uio_segflg = UIO_SYSSPACE;
517     auio.uio_rw = UIO_READ;
518     auio.uio_procp = NULL;
519     kernel_upl_map(kernel_map, pl, &ioaddr);
520     ioaddr += pl_offset;
521     auio.uio_resid = aiov.iov_len = size;
522     aiov.iov_base = (caddr_t) ioaddr;
523     AFS_GLOCK();
524 #if 0
525     osi_FlushPages(tvc, ap->a_cred);    /* hold bozon lock, but not basic vnode lock */
526 #endif
527     code = afs_read(tvc, uio, cred, 0, 0, 0);
528     if (code == 0) {
529         ObtainWriteLock(&tvc->lock, 2);
530         tvc->states |= CMAPPED;
531         ReleaseWriteLock(&tvc->lock);
532     }
533     AFS_GUNLOCK();
534
535     /* Zero out rest of last page if there wasn't enough data in the file */
536     if (code == 0 && auio.uio_resid > 0)
537         memset(aiov.iov_base, 0, auio.uio_resid);
538
539     kernel_upl_unmap(kernel_map, pl);
540     if (!nocommit) {
541         if (code)
542             kernel_upl_abort_range(pl, pl_offset, size,
543                                    UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
544         else
545             kernel_upl_commit_range(pl, pl_offset, size,
546                                     UPL_COMMIT_CLEAR_DIRTY |
547                                     UPL_COMMIT_FREE_ON_EMPTY,
548                                     UPL_GET_INTERNAL_PAGE_LIST(pl),
549                                     MAX_UPL_TRANSFER);
550     }
551     return code;
552 }
553
554 int
555 afs_vop_write(ap)
556      struct vop_write_args      /* {
557                                  * struct vnode *a_vp;
558                                  * struct uio *a_uio;
559                                  * int a_ioflag;
560                                  * struct ucred *a_cred;
561                                  * } */ *ap;
562 {
563     int code;
564     struct vcache *avc = VTOAFS(ap->a_vp);
565     void *object;
566     AFS_GLOCK();
567 #if 0
568     osi_FlushPages(avc, ap->a_cred);    /* hold bozon lock, but not basic vnode lock */
569 #endif
570     if (UBCINFOEXISTS(ap->a_vp)) {
571         ubc_clean(ap->a_vp, 1);
572     }
573     if (UBCINFOEXISTS(ap->a_vp))
574         osi_VM_NukePages(ap->a_vp, ap->a_uio->uio_offset,
575                          ap->a_uio->uio_resid);
576     code =
577         afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
578     AFS_GUNLOCK();
579     return code;
580 }
581
582 int
583 afs_vop_pageout(ap)
584      struct vop_pageout_args    /* {
585                                  * struct vnode *a_vp;
586                                  * upl_t   a_pl,
587                                  * vm_offset_t   a_pl_offset,
588                                  * off_t         a_f_offset,
589                                  * size_t        a_size,
590                                  * struct ucred *a_cred,
591                                  * int           a_flags
592                                  * } */ *ap;
593 {
594     register struct vnode *vp = ap->a_vp;
595     upl_t pl = ap->a_pl;
596     size_t size = ap->a_size;
597     off_t f_offset = ap->a_f_offset;
598     vm_offset_t pl_offset = ap->a_pl_offset;
599     int flags = ap->a_flags;
600     struct ucred *cred;
601     vm_offset_t ioaddr;
602     struct uio auio;
603     struct iovec aiov;
604     struct uio *uio = &auio;
605     int nocommit = flags & UPL_NOCOMMIT;
606     int iosize;
607
608     int code;
609     struct vcache *tvc = VTOAFS(vp);
610
611     if (UBCINVALID(vp)) {
612 #if DIAGNOSTIC
613         panic("afs_vop_pageout: invalid vp");
614 #endif /* DIAGNOSTIC */
615         return (EPERM);
616     }
617
618     UBCINFOCHECK("afs_vop_pageout", vp);
619     if (pl == (upl_t) NULL) {
620         panic("afs_vop_pageout: no upl");
621     }
622 #if 1
623     {
624         int lbn, s;
625         struct buf *bp;
626         int biosize = DEV_BSIZE;
627
628         lbn = f_offset / DEV_BSIZE;
629
630         for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
631
632             s = splbio();
633             if (bp = incore(vp, lbn)) {
634                 if (ISSET(bp->b_flags, B_BUSY))
635                     panic("nfs_pageout: found BUSY buffer incore\n");
636
637                 bremfree(bp);
638                 SET(bp->b_flags, (B_BUSY | B_INVAL));
639                 brelse(bp);
640             }
641             splx(s);
642         }
643     }
644 #endif
645     cred = ubc_getcred(vp);
646     if (cred == NOCRED)
647         cred = ap->a_cred;
648
649     if (size == 0) {
650         if (!nocommit)
651             kernel_upl_abort_range(pl, pl_offset, size,
652                                    UPL_ABORT_FREE_ON_EMPTY);
653         return (0);
654     }
655     if (flags & (IO_APPEND | IO_SYNC))
656         panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
657     if (f_offset < 0) {
658         if (!nocommit)
659             kernel_upl_abort_range(pl, pl_offset, size,
660                                    UPL_ABORT_FREE_ON_EMPTY);
661         return (EINVAL);
662     }
663     if (f_offset >= tvc->m.Length) {
664         if (!nocommit)
665             kernel_upl_abort_range(pl, pl_offset, size,
666                                    UPL_ABORT_FREE_ON_EMPTY);
667         return (EINVAL);
668     }
669
670     if (f_offset & PAGE_MASK)
671         panic("afs_vop_pageout: offset not page aligned");
672
673     /* size will always be a multiple of PAGE_SIZE */
674     /* pageout isn't supposed to extend files */
675     if (f_offset + size > tvc->m.Length) 
676         iosize = tvc->m.Length - f_offset;
677     else
678         iosize = size;
679
680     if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit)  {
681             int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
682             kernel_upl_abort_range(pl, pl_offset + iosize_rnd,
683                                    size - iosize_rnd,
684                                    UPL_ABORT_FREE_ON_EMPTY);
685     }
686     auio.uio_iov = &aiov;
687     auio.uio_iovcnt = 1;
688     auio.uio_offset = f_offset;
689     auio.uio_segflg = UIO_SYSSPACE;
690     auio.uio_rw = UIO_WRITE;
691     auio.uio_procp = NULL;
692     kernel_upl_map(kernel_map, pl, &ioaddr);
693     ioaddr += pl_offset;
694     auio.uio_resid = aiov.iov_len = iosize;
695     aiov.iov_base = (caddr_t) ioaddr;
696 #if 1                           /* USV [ */
697     {
698         /* 
699          * check for partial page and clear the
700          * contents past end of the file before
701          * releasing it in the VM page cache
702          */
703         if ((f_offset < tvc->m.Length) && (f_offset + size) > tvc->m.Length) {
704             size_t io = tvc->m.Length - f_offset;
705
706             memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
707         }
708     }
709 #endif /* ] USV */
710
711     AFS_GLOCK();
712 #if 0
713     osi_FlushPages(tvc, ap->a_cred);    /* hold bozon lock, but not basic vnode lock */
714 #endif
715     ObtainWriteLock(&tvc->lock, 1);
716     afs_FakeOpen(tvc);
717     ReleaseWriteLock(&tvc->lock);
718
719     code = afs_write(tvc, uio, flags, cred, 0);
720
721     ObtainWriteLock(&tvc->lock, 1);
722     afs_FakeClose(tvc, cred);
723     ReleaseWriteLock(&tvc->lock);
724     AFS_GUNLOCK();
725     kernel_upl_unmap(kernel_map, pl);
726     if (!nocommit) {
727         if (code)
728             kernel_upl_abort_range(pl, pl_offset, size,
729                                    UPL_ABORT_FREE_ON_EMPTY);
730         else
731             kernel_upl_commit_range(pl, pl_offset, size,
732                                     UPL_COMMIT_CLEAR_DIRTY |
733                                     UPL_COMMIT_FREE_ON_EMPTY,
734                                     UPL_GET_INTERNAL_PAGE_LIST(pl),
735                                     MAX_UPL_TRANSFER);
736     }
737
738     return code;
739 }
740
741 int
742 afs_vop_ioctl(ap)
743      struct vop_ioctl_args      /* {
744                                  * struct vnode *a_vp;
745                                  * int  a_command;
746                                  * caddr_t  a_data;
747                                  * int  a_fflag;
748                                  * struct ucred *a_cred;
749                                  * struct proc *a_p;
750                                  * } */ *ap;
751 {
752     struct vcache *tvc = VTOAFS(ap->a_vp);
753     struct afs_ioctl data;
754     int error = 0;
755
756     /* in case we ever get in here... */
757
758     AFS_STATCNT(afs_ioctl);
759     if (((ap->a_command >> 8) & 0xff) == 'V') {
760         /* This is a VICEIOCTL call */
761         AFS_GLOCK();
762         error = HandleIoctl(tvc, (struct file *)0 /*Not used */ ,
763                             ap->a_command, ap->a_data);
764         AFS_GUNLOCK();
765         return (error);
766     } else {
767         /* No-op call; just return. */
768         return (ENOTTY);
769     }
770 }
771
772 /* ARGSUSED */
773 int
774 afs_vop_select(ap)
775      struct vop_select_args     /* {
776                                  * struct vnode *a_vp;
777                                  * int  a_which;
778                                  * int  a_fflags;
779                                  * struct ucred *a_cred;
780                                  * struct proc *a_p;
781                                  * } */ *ap;
782 {
783     /*
784      * We should really check to see if I/O is possible.
785      */
786     return (1);
787 }
788
789 /*
790  * Mmap a file
791  *
792  * NB Currently unsupported.
793  */
794 /* ARGSUSED */
795 int
796 afs_vop_mmap(ap)
797      struct vop_mmap_args       /* {
798                                  * struct vnode *a_vp;
799                                  * int  a_fflags;
800                                  * struct ucred *a_cred;
801                                  * struct proc *a_p;
802                                  * } */ *ap;
803 {
804     return (EINVAL);
805 }
806
807 int
808 afs_vop_fsync(ap)
809      struct vop_fsync_args      /* {
810                                  * struct vnode *a_vp;
811                                  * struct ucred *a_cred;
812                                  * int a_waitfor;
813                                  * struct proc *a_p;
814                                  * } */ *ap;
815 {
816     int wait = ap->a_waitfor == MNT_WAIT;
817     int error;
818     register struct vnode *vp = ap->a_vp;
819     int haveGlock = ISAFS_GLOCK();
820
821     /* afs_vop_lookup glocks, can call us through vinvalbuf from GetVCache */
822     if (!haveGlock) AFS_GLOCK();
823     if (ap->a_cred)
824         error = afs_fsync(VTOAFS(vp), ap->a_cred);
825     else
826         error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
827     if (!haveGlock) AFS_GUNLOCK();
828     return error;
829 }
830
831 int
832 afs_vop_seek(ap)
833      struct vop_seek_args       /* {
834                                  * struct vnode *a_vp;
835                                  * off_t  a_oldoff;
836                                  * off_t  a_newoff;
837                                  * struct ucred *a_cred;
838                                  * } */ *ap;
839 {
840     if (ap->a_newoff > ULONG_MAX)       /* AFS doesn't support 64-bit offsets */
841         return EINVAL;
842     return (0);
843 }
844
845 int
846 afs_vop_remove(ap)
847      struct vop_remove_args     /* {
848                                  * struct vnode *a_dvp;
849                                  * struct vnode *a_vp;
850                                  * struct componentname *a_cnp;
851                                  * } */ *ap;
852 {
853     int error = 0;
854     register struct vnode *vp = ap->a_vp;
855     register struct vnode *dvp = ap->a_dvp;
856
857     GETNAME();
858     AFS_GLOCK();
859     error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
860     AFS_GUNLOCK();
861     cache_purge(vp);
862     vput(dvp);
863     if (!error) {
864         /* necessary so we don't deadlock ourselves in vclean */
865         VOP_UNLOCK(vp, 0, cnp->cn_proc);
866
867         /* If crashes continue in ubc_hold, comment this out */
868         (void)ubc_uncache(vp);
869     }
870
871     if (dvp == vp)
872         vrele(vp);
873     else
874         vput(vp);
875
876     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
877     DROPNAME();
878     return error;
879 }
880
881 int
882 afs_vop_link(ap)
883      struct vop_link_args       /* {
884                                  * struct vnode *a_vp;
885                                  * struct vnode *a_tdvp;
886                                  * struct componentname *a_cnp;
887                                  * } */ *ap;
888 {
889     int error = 0;
890     register struct vnode *dvp = ap->a_tdvp;
891     register struct vnode *vp = ap->a_vp;
892     struct proc *p;
893
894     GETNAME();
895     p = cnp->cn_proc;
896     if (vp->v_type == VDIR) {
897         VOP_ABORTOP(vp, cnp);
898         error = EISDIR;
899         goto out;
900     }
901     if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
902         VOP_ABORTOP(dvp, cnp);
903         goto out;
904     }
905     AFS_GLOCK();
906     error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
907     AFS_GUNLOCK();
908     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
909     if (dvp != vp)
910         VOP_UNLOCK(vp, 0, p);
911   out:
912     vput(dvp);
913     DROPNAME();
914     return error;
915 }
916
917 int
918 afs_vop_rename(ap)
919      struct vop_rename_args     /* {
920                                  * struct vnode *a_fdvp;
921                                  * struct vnode *a_fvp;
922                                  * struct componentname *a_fcnp;
923                                  * struct vnode *a_tdvp;
924                                  * struct vnode *a_tvp;
925                                  * struct componentname *a_tcnp;
926                                  * } */ *ap;
927 {
928     int error = 0;
929     struct componentname *fcnp = ap->a_fcnp;
930     char *fname;
931     struct componentname *tcnp = ap->a_tcnp;
932     char *tname;
933     struct vnode *tvp = ap->a_tvp;
934     register struct vnode *tdvp = ap->a_tdvp;
935     struct vnode *fvp = ap->a_fvp;
936     register struct vnode *fdvp = ap->a_fdvp;
937     struct proc *p = fcnp->cn_proc;
938
939     /* Check for cross-device rename.
940      * For AFS, this means anything not in AFS-space
941      */
942     if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
943         (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
944         error = EXDEV;
945         goto abortit;
946     }
947
948     /*
949      * if fvp == tvp, we're just removing one name of a pair of
950      * directory entries for the same element.  convert call into rename.
951      ( (pinched from NetBSD 1.0's ufs_rename())
952      */
953     if (fvp == tvp) {
954         if (fvp->v_type == VDIR) {
955             error = EINVAL;
956           abortit:
957             VOP_ABORTOP(tdvp, tcnp);    /* XXX, why not in NFS? */
958             if (tdvp == tvp)
959                 vrele(tdvp);
960             else
961                 vput(tdvp);
962             if (tvp)
963                 vput(tvp);
964             VOP_ABORTOP(fdvp, fcnp);    /* XXX, why not in NFS? */
965             vrele(fdvp);
966             vrele(fvp);
967             return (error);
968         }
969
970         /* Release destination completely. */
971         VOP_ABORTOP(tdvp, tcnp);
972         vput(tdvp);
973         vput(tvp);
974
975         /* Delete source. */
976         vrele(fdvp);
977         vrele(fvp);
978         fcnp->cn_flags &= ~MODMASK;
979         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
980         if ((fcnp->cn_flags & SAVESTART) == 0)
981             panic("afs_rename: lost from startdir");
982         fcnp->cn_nameiop = DELETE;
983
984         VREF(fdvp); 
985         error=relookup(fdvp, &fvp, fcnp);
986         if (error == 0)
987             vrele(fdvp);
988         if (fvp == NULL) {
989             return (ENOENT);
990         }
991         
992         error=VOP_REMOVE(fdvp, fvp, fcnp);
993         if (fdvp == fvp)
994             vrele(fdvp);
995         else
996             vput(fdvp);
997         vput(fvp);
998         return (error);
999     }
1000     if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
1001         goto abortit;
1002
1003     MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1004     memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1005     fname[fcnp->cn_namelen] = '\0';
1006     MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1007     memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
1008     tname[tcnp->cn_namelen] = '\0';
1009
1010
1011     AFS_GLOCK();
1012     /* XXX use "from" or "to" creds? NFS uses "to" creds */
1013     error =
1014         afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
1015     AFS_GUNLOCK();
1016
1017     VOP_UNLOCK(fvp, 0, p);
1018     FREE(fname, M_TEMP);
1019     FREE(tname, M_TEMP);
1020     if (error)
1021         goto abortit;           /* XXX */
1022     if (tdvp == tvp)
1023         vrele(tdvp);
1024     else
1025         vput(tdvp);
1026     if (tvp)
1027         vput(tvp);
1028     vrele(fdvp);
1029     vrele(fvp);
1030     return error;
1031 }
1032
1033 int
1034 afs_vop_mkdir(ap)
1035      struct vop_mkdir_args      /* {
1036                                  * struct vnode *a_dvp;
1037                                  * struct vnode **a_vpp;
1038                                  * struct componentname *a_cnp;
1039                                  * struct vattr *a_vap;
1040                                  * } */ *ap;
1041 {
1042     register struct vnode *dvp = ap->a_dvp;
1043     register struct vattr *vap = ap->a_vap;
1044     int error = 0;
1045     struct vcache *vcp;
1046     struct proc *p;
1047
1048     GETNAME();
1049     p = cnp->cn_proc;
1050 #ifdef DIAGNOSTIC
1051     if ((cnp->cn_flags & HASBUF) == 0)
1052         panic("afs_vop_mkdir: no name");
1053 #endif
1054     AFS_GLOCK();
1055     error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
1056     AFS_GUNLOCK();
1057     if (error) {
1058         VOP_ABORTOP(dvp, cnp);
1059         vput(dvp);
1060         DROPNAME();
1061         return (error);
1062     }
1063     if (vcp) {
1064         *ap->a_vpp = AFSTOV(vcp);
1065         (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1066         vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1067     } else
1068         *ap->a_vpp = 0;
1069     DROPNAME();
1070     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1071     vput(dvp);
1072     return error;
1073 }
1074
1075 int
1076 afs_vop_rmdir(ap)
1077      struct vop_rmdir_args      /* {
1078                                  * struct vnode *a_dvp;
1079                                  * struct vnode *a_vp;
1080                                  * struct componentname *a_cnp;
1081                                  * } */ *ap;
1082 {
1083     int error = 0;
1084     register struct vnode *vp = ap->a_vp;
1085     register struct vnode *dvp = ap->a_dvp;
1086
1087     GETNAME();
1088     if (dvp == vp) {
1089         vrele(dvp);
1090         vput(vp);
1091         FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1092         DROPNAME();
1093         return (EINVAL);
1094     }
1095
1096     AFS_GLOCK();
1097     error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
1098     AFS_GUNLOCK();
1099     DROPNAME();
1100     vput(dvp);
1101     vput(vp);
1102     return error;
1103 }
1104
1105 int
1106 afs_vop_symlink(ap)
1107      struct vop_symlink_args    /* {
1108                                  * struct vnode *a_dvp;
1109                                  * struct vnode **a_vpp;
1110                                  * struct componentname *a_cnp;
1111                                  * struct vattr *a_vap;
1112                                  * char *a_target;
1113                                  * } */ *ap;
1114 {
1115     register struct vnode *dvp = ap->a_dvp;
1116     int error = 0;
1117     /* NFS ignores a_vpp; so do we. */
1118
1119     GETNAME();
1120     AFS_GLOCK();
1121     error =
1122         afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
1123     AFS_GUNLOCK();
1124     DROPNAME();
1125     FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1126     vput(dvp);
1127     return error;
1128 }
1129
1130 int
1131 afs_vop_readdir(ap)
1132      struct vop_readdir_args    /* {
1133                                  * struct vnode *a_vp;
1134                                  * struct uio *a_uio;
1135                                  * struct ucred *a_cred;
1136                                  * int *a_eofflag;
1137                                  * u_long *a_cookies;
1138                                  * int ncookies;
1139                                  * } */ *ap;
1140 {
1141     int error;
1142     off_t off;
1143 /*    printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1144            ap->a_ncookies); */
1145     off = ap->a_uio->uio_offset;
1146     AFS_GLOCK();
1147     error =
1148         afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
1149     AFS_GUNLOCK();
1150     if (!error && ap->a_ncookies != NULL) {
1151         struct uio *uio = ap->a_uio;
1152         const struct dirent *dp, *dp_start, *dp_end;
1153         int ncookies;
1154         u_long *cookies, *cookiep;
1155
1156         if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1157             panic("afs_readdir: burned cookies");
1158         dp = (const struct dirent *)
1159             ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1160
1161         dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1162         for (dp_start = dp, ncookies = 0; dp < dp_end;
1163              dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1164             ncookies++;
1165
1166         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1167                M_WAITOK);
1168         for (dp = dp_start, cookiep = cookies; dp < dp_end;
1169              dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1170             off += dp->d_reclen;
1171             *cookiep++ = off;
1172         }
1173         *ap->a_cookies = cookies;
1174         *ap->a_ncookies = ncookies;
1175     }
1176
1177     return error;
1178 }
1179
1180 int
1181 afs_vop_readlink(ap)
1182      struct vop_readlink_args   /* {
1183                                  * struct vnode *a_vp;
1184                                  * struct uio *a_uio;
1185                                  * struct ucred *a_cred;
1186                                  * } */ *ap;
1187 {
1188     int error;
1189 /*    printf("readlink %x\n", ap->a_vp);*/
1190     AFS_GLOCK();
1191     error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
1192     AFS_GUNLOCK();
1193     return error;
1194 }
1195
1196 extern int prtactive;
1197
1198 int
1199 afs_vop_inactive(ap)
1200      struct vop_inactive_args   /* {
1201                                  * struct vnode *a_vp;
1202                                  * struct proc *a_p;
1203                                  * } */ *ap;
1204 {
1205     register struct vnode *vp = ap->a_vp;
1206
1207     if (prtactive && vp->v_usecount != 0)
1208         vprint("afs_vop_inactive(): pushing active", vp);
1209
1210     AFS_GLOCK();
1211     afs_InactiveVCache(VTOAFS(vp), 0);  /* decrs ref counts */
1212     AFS_GUNLOCK();
1213     VOP_UNLOCK(vp, 0, ap->a_p);
1214     return 0;
1215 }
1216
1217 int
1218 afs_vop_reclaim(ap)
1219      struct vop_reclaim_args    /* {
1220                                  * struct vnode *a_vp;
1221                                  * } */ *ap;
1222 {
1223     int error = 0;
1224     int sl;
1225     register struct vnode *vp = ap->a_vp;
1226     int haveGlock = ISAFS_GLOCK();
1227     struct vcache *tvc = VTOAFS(vp);
1228
1229     cache_purge(vp);            /* just in case... */
1230     if (!haveGlock)
1231         AFS_GLOCK();
1232     error = afs_FlushVCache(VTOAFS(vp), &sl);   /* toss our stuff from vnode */
1233     if (!haveGlock)
1234         AFS_GUNLOCK();
1235
1236     if (!error && vp->v_data)
1237         panic("afs_reclaim: vnode not cleaned");
1238     if (!error && (tvc->v != NULL)) 
1239         panic("afs_reclaim: vcache not cleaned");
1240
1241     return error;
1242 }
1243
1244 int
1245 afs_vop_lock(ap)
1246      struct vop_lock_args       /* {
1247                                  * struct vnode *a_vp;
1248                                  * } */ *ap;
1249 {
1250     register struct vnode *vp = ap->a_vp;
1251     register struct vcache *avc = VTOAFS(vp);
1252
1253     if (vp->v_tag == VT_NON)
1254         return (ENOENT);
1255
1256     return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1257 }
1258
1259 int
1260 afs_vop_unlock(ap)
1261      struct vop_unlock_args     /* {
1262                                  * struct vnode *a_vp;
1263                                  * } */ *ap;
1264 {
1265     struct vnode *vp = ap->a_vp;
1266     struct vcache *avc = VTOAFS(vp);
1267
1268     return (lockmgr
1269             (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1270              ap->a_p));
1271
1272 }
1273
1274 int
1275 afs_vop_bmap(ap)
1276      struct vop_bmap_args       /* {
1277                                  * struct vnode *a_vp;
1278                                  * daddr_t  a_bn;
1279                                  * struct vnode **a_vpp;
1280                                  * daddr_t *a_bnp;
1281                                  * int *a_runp;
1282                                  * int *a_runb;
1283                                  * } */ *ap;
1284 {
1285     int error;
1286     if (ap->a_bnp) {
1287         *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
1288     }
1289     if (ap->a_vpp) {
1290         *ap->a_vpp = ap->a_vp;
1291     }
1292     if (ap->a_runp != NULL)
1293         *ap->a_runp = 0;
1294 #ifdef notyet
1295     if (ap->a_runb != NULL)
1296         *ap->a_runb = 0;
1297 #endif
1298
1299     return 0;
1300 }
1301
1302 int
1303 afs_vop_strategy(ap)
1304      struct vop_strategy_args   /* {
1305                                  * struct buf *a_bp;
1306                                  * } */ *ap;
1307 {
1308     int error;
1309     AFS_GLOCK();
1310     error = afs_ustrategy(ap->a_bp);
1311     AFS_GUNLOCK();
1312     return error;
1313 }
1314
1315 int
1316 afs_vop_print(ap)
1317      struct vop_print_args      /* {
1318                                  * struct vnode *a_vp;
1319                                  * } */ *ap;
1320 {
1321     register struct vnode *vp = ap->a_vp;
1322     register struct vcache *vc = VTOAFS(ap->a_vp);
1323     int s = vc->states;
1324     printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1325            vc->fid.Cell, vc->fid.Fid.Volume, vc->fid.Fid.Vnode,
1326            vc->fid.Fid.Unique, vc->opens, vc->execsOrWriters);
1327     printf("\n  states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1328            (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1329            (s & CMAPPED) ? " mapped" : "",
1330            (s & CVFlushed) ? " flush in progress" : "");
1331     if (UBCISVALID(vp)) {
1332         printf("\n  UBC: ");
1333         if (UBCINFOEXISTS(vp)) {
1334             printf("exists, ");
1335 #ifdef AFS_DARWIN14_ENV
1336             printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
1337                    ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
1338                    ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
1339 #else
1340             printf("holdcnt %d", vp->v_ubcinfo->ui_holdcnt);
1341 #endif
1342         } else
1343             printf("does not exist");
1344     }
1345     printf("\n");
1346     return 0;
1347 }
1348
1349 int
1350 afs_vop_islocked(ap)
1351      struct vop_islocked_args   /* {
1352                                  * struct vnode *a_vp;
1353                                  * } */ *ap;
1354 {
1355     struct vcache *vc = VTOAFS(ap->a_vp);
1356     return lockstatus(&vc->rwlock);
1357 }
1358
1359 /*
1360  * Return POSIX pathconf information applicable to ufs filesystems.
1361  */
1362 afs_vop_pathconf(ap)
1363      struct vop_pathconf_args   /* {
1364                                  * struct vnode *a_vp;
1365                                  * int a_name;
1366                                  * int *a_retval;
1367                                  * } */ *ap;
1368 {
1369     AFS_STATCNT(afs_cntl);
1370     switch (ap->a_name) {
1371     case _PC_LINK_MAX:
1372         *ap->a_retval = LINK_MAX;
1373         break;
1374     case _PC_NAME_MAX:
1375         *ap->a_retval = NAME_MAX;
1376         break;
1377     case _PC_PATH_MAX:
1378         *ap->a_retval = PATH_MAX;
1379         break;
1380     case _PC_CHOWN_RESTRICTED:
1381         *ap->a_retval = 1;
1382         break;
1383     case _PC_NO_TRUNC:
1384         *ap->a_retval = 1;
1385         break;
1386     case _PC_PIPE_BUF:
1387         return EINVAL;
1388         break;
1389 #if defined(AFS_DARWIN70_ENV)
1390     case _PC_NAME_CHARS_MAX:
1391         *ap->a_retval = NAME_MAX;
1392         break;
1393     case _PC_CASE_SENSITIVE:
1394         *ap->a_retval = 1;
1395         break;
1396     case _PC_CASE_PRESERVING:
1397         *ap->a_retval = 1;
1398         break;
1399 #endif /* defined(AFS_DARWIN70_ENV) */
1400     default:
1401         return EINVAL;
1402     }
1403     return 0;
1404 }
1405
1406 /*
1407  * Advisory record locking support (fcntl() POSIX style)
1408  */
1409 int
1410 afs_vop_advlock(ap)
1411      struct vop_advlock_args    /* {
1412                                  * struct vnode *a_vp;
1413                                  * caddr_t  a_id;
1414                                  * int  a_op;
1415                                  * struct flock *a_fl;
1416                                  * int  a_flags;
1417                                  * } */ *ap;
1418 {
1419     int error;
1420     struct proc *p = current_proc();
1421     struct ucred cr;
1422     pcred_readlock(p);
1423     cr = *p->p_cred->pc_ucred;
1424     pcred_unlock(p);
1425     AFS_GLOCK();
1426     error =
1427         afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, &cr, (int)ap->a_id);
1428     AFS_GUNLOCK();
1429     return error;
1430 }
1431
1432 int
1433 afs_vop_truncate(ap)
1434      struct vop_truncate_args   /* {
1435                                  * struct vnode *a_vp;
1436                                  * off_t a_length;
1437                                  * int a_flags;
1438                                  * struct ucred *a_cred;
1439                                  * struct proc *a_p;
1440                                  * } */ *ap;
1441 {
1442     printf("stray afs_vop_truncate\n");
1443     return EOPNOTSUPP;
1444 }
1445
1446 int
1447 afs_vop_update(ap)
1448      struct vop_update_args     /* {
1449                                  * struct vnode *a_vp;
1450                                  * struct timeval *a_access;
1451                                  * struct timeval *a_modify;
1452                                  * int a_waitfor;
1453                                  * } */ *ap;
1454 {
1455     printf("stray afs_vop_update\n");
1456     return EOPNOTSUPP;
1457 }
1458
1459 int
1460 afs_vop_blktooff(ap)
1461      struct vop_blktooff_args   /* {
1462                                  * struct vnode *a_vp;
1463                                  * daddr_t a_lblkno;
1464                                  * off_t *a_offset;    
1465                                  * } */ *ap;
1466 {
1467     *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1468     return 0;
1469 }
1470
1471 int
1472 afs_vop_offtoblk(ap)
1473      struct vop_offtoblk_args   /* {
1474                                  * struct vnode *a_vp;
1475                                  * off_t a_offset;    
1476                                  * daddr_t *a_lblkno;
1477                                  * } */ *ap;
1478 {
1479     *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1480
1481     return (0);
1482 }
1483
1484 int
1485 afs_vop_cmap(ap)
1486      struct vop_cmap_args       /* {
1487                                  * struct vnode *a_vp;
1488                                  * off_t a_foffset;    
1489                                  * size_t a_size;
1490                                  * daddr_t *a_bpn;
1491                                  * size_t *a_run;
1492                                  * void *a_poff;
1493                                  * } */ *ap;
1494 {
1495     *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
1496     *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));
1497     return 0;
1498 }
1499
1500 void
1501 afs_darwin_getnewvnode(struct vcache *tvc)
1502 {
1503     while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &tvc->v)) {
1504         /* no vnodes available, force an alloc (limits be damned)! */
1505         printf("failed to get vnode\n");
1506     }
1507     tvc->v->v_data = (void *)tvc;
1508 }