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