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