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