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