FBSD: Remove unused 'wantparent' logic
[openafs.git] / src / afs / FBSD / osi_vnodeops.c
1 /*
2  * A large chunk of this file appears to be copied directly from
3  * sys/nfsclient/nfs_bio.c, which has the following license:
4  */
5 /*
6  * Copyright (c) 1989, 1993
7  *      The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Rick Macklem at The University of Guelph.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *      This product includes software developed by the University of
23  *      California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *      @(#)nfs_bio.c   8.9 (Berkeley) 3/30/95
41  */
42 /*
43  * Pursuant to a statement of U.C. Berkeley dated 1999-07-22, this license
44  * is amended to drop clause (3) above.
45  */
46
47 #include <afsconfig.h>
48 #include <afs/param.h>
49
50
51 #include <afs/sysincludes.h>    /* Standard vendor system headers */
52 #include <afsincludes.h>        /* Afs-based standard headers */
53 #include <afs/afs_stats.h>      /* statistics */
54 #include <sys/malloc.h>
55 #include <sys/namei.h>
56 #include <sys/unistd.h>
57 #if __FreeBSD_version >= 1000030
58 #include <sys/rwlock.h>
59 #endif
60 #include <vm/vm_page.h>
61 #include <vm/vm_object.h>
62 #include <vm/vm_pager.h>
63 #include <vm/vnode_pager.h>
64 extern int afs_pbuf_freecnt;
65
66 #define GETNAME()       \
67     struct componentname *cnp = ap->a_cnp; \
68     char *name; \
69     MALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
70     memcpy(name, cnp->cn_nameptr, cnp->cn_namelen); \
71     name[cnp->cn_namelen] = '\0'
72
73 #define DROPNAME() FREE(name, M_TEMP)
74
75 /*
76  * Here we define compatibility functions/macros for interfaces that
77  * have changed between different FreeBSD versions.
78  */
79 static __inline void ma_vm_page_lock_queues(void) {};
80 static __inline void ma_vm_page_unlock_queues(void) {};
81 static __inline void ma_vm_page_lock(vm_page_t m) { vm_page_lock(m); };
82 static __inline void ma_vm_page_unlock(vm_page_t m) { vm_page_unlock(m); };
83
84 #define ma_vn_lock(vp, flags, p) (vn_lock(vp, flags))
85 #define MA_VOP_LOCK(vp, flags, p) (VOP_LOCK(vp, flags))
86 #define MA_VOP_UNLOCK(vp, flags, p) (VOP_UNLOCK(vp, flags))
87
88 #define MA_PCPU_INC(c) PCPU_INC(c)
89 #define MA_PCPU_ADD(c, n) PCPU_ADD(c, n)
90
91 #if __FreeBSD_version >= 1000030
92 #define AFS_VM_OBJECT_WLOCK(o)  VM_OBJECT_WLOCK(o)
93 #define AFS_VM_OBJECT_WUNLOCK(o)        VM_OBJECT_WUNLOCK(o)
94 #else
95 #define AFS_VM_OBJECT_WLOCK(o)  VM_OBJECT_LOCK(o)
96 #define AFS_VM_OBJECT_WUNLOCK(o)        VM_OBJECT_UNLOCK(o)
97 #endif
98
99 /*
100  * Mosty copied from sys/ufs/ufs/ufs_vnops.c:ufs_pathconf().
101  * We should know the correct answers to these questions with
102  * respect to the AFS protocol (which may differ from the UFS
103  * values) but for the moment this will do.
104  */
105 static int
106 afs_vop_pathconf(struct vop_pathconf_args *ap)
107 {
108         int error;
109
110         error = 0;
111         switch (ap->a_name) {
112         case _PC_LINK_MAX:
113                 *ap->a_retval = LINK_MAX;
114                 break;
115         case _PC_NAME_MAX:
116                 *ap->a_retval = NAME_MAX;
117                 break;
118         case _PC_PATH_MAX:
119                 *ap->a_retval = PATH_MAX;
120                 break;
121         case _PC_PIPE_BUF:
122                 *ap->a_retval = PIPE_BUF;
123                 break;
124         case _PC_CHOWN_RESTRICTED:
125                 *ap->a_retval = 1;
126                 break;
127         case _PC_NO_TRUNC:
128                 *ap->a_retval = 1;
129                 break;
130 #ifdef _PC_ACL_EXTENDED
131         case _PC_ACL_EXTENDED:
132                 *ap->a_retval = 0;
133                 break;
134         case _PC_ACL_PATH_MAX:
135                 *ap->a_retval = 3;
136                 break;
137 #endif
138 #ifdef _PC_MAC_PRESENT
139         case _PC_MAC_PRESENT:
140                 *ap->a_retval = 0;
141                 break;
142 #endif
143 #ifdef _PC_ASYNC_IO
144         case _PC_ASYNC_IO:
145                 /* _PC_ASYNC_IO should have been handled by upper layers. */
146                 KASSERT(0, ("_PC_ASYNC_IO should not get here"));
147                 error = EINVAL;
148                 break;
149         case _PC_PRIO_IO:
150                 *ap->a_retval = 0;
151                 break;
152         case _PC_SYNC_IO:
153                 *ap->a_retval = 0;
154                 break;
155 #endif
156 #ifdef _PC_ALLOC_SIZE_MIN
157         case _PC_ALLOC_SIZE_MIN:
158                 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize;
159                 break;
160 #endif
161 #ifdef _PC_FILESIZEBITS
162         case _PC_FILESIZEBITS:
163                 *ap->a_retval = 32; /* XXX */
164                 break;
165 #endif
166 #ifdef _PC_REC_INCR_XFER_SIZE
167         case _PC_REC_INCR_XFER_SIZE:
168                 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
169                 break;
170         case _PC_REC_MAX_XFER_SIZE:
171                 *ap->a_retval = -1; /* means ``unlimited'' */
172                 break;
173         case _PC_REC_MIN_XFER_SIZE:
174                 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
175                 break;
176         case _PC_REC_XFER_ALIGN:
177                 *ap->a_retval = PAGE_SIZE;
178                 break;
179 #endif
180 #ifdef _PC_SYMLINK_MAX
181         case _PC_SYMLINK_MAX:
182                 *ap->a_retval = MAXPATHLEN;
183                 break;
184 #endif
185         default:
186                 error = EINVAL;
187                 break;
188         }
189         return (error);
190 }
191
192 static int
193 afs_vop_lookup(ap)
194      struct vop_lookup_args     /* {
195                                  * struct vnodeop_desc * a_desc;
196                                  * struct vnode *a_dvp;
197                                  * struct vnode **a_vpp;
198                                  * struct componentname *a_cnp;
199                                  * } */ *ap;
200 {
201     int error;
202     struct vcache *vcp;
203     struct vnode *vp, *dvp;
204     int flags = ap->a_cnp->cn_flags;
205     int lockparent;             /* 1 => lockparent flag is set */
206
207     dvp = ap->a_dvp;
208     if (dvp->v_type != VDIR) {
209         return ENOTDIR;
210     }
211
212     if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT))
213         return EIO;
214
215     GETNAME();
216
217     lockparent = flags & LOCKPARENT;
218
219 #if __FreeBSD_version < 1000021
220     cnp->cn_flags |= MPSAFE; /* steel */
221 #endif
222
223     if (flags & ISDOTDOT)
224         MA_VOP_UNLOCK(dvp, 0, p);
225
226     AFS_GLOCK();
227     error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
228     AFS_GUNLOCK();
229
230     if (error) {
231         if (flags & ISDOTDOT)
232             MA_VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
233         if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
234             && (flags & ISLASTCN) && error == ENOENT)
235             error = EJUSTRETURN;
236         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
237             cnp->cn_flags |= SAVENAME;
238         DROPNAME();
239         *ap->a_vpp = 0;
240         return (error);
241     }
242     vp = AFSTOV(vcp);           /* always get a node if no error */
243
244     /* The parent directory comes in locked.  We unlock it on return
245      * unless the caller wants it left locked.
246      * we also always return the vnode locked. */
247
248     if (flags & ISDOTDOT) {
249         /* vp before dvp since we go root to leaf, and .. comes first */
250         ma_vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
251         ma_vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
252         /* always return the child locked */
253         if (lockparent && (flags & ISLASTCN)
254             && (error = ma_vn_lock(dvp, LK_EXCLUSIVE, p))) {
255             vput(vp);
256             DROPNAME();
257             return (error);
258         }
259     } else if (vp == dvp) {
260         /* they're the same; afs_lookup() already ref'ed the leaf.
261          * It came in locked, so we don't need to ref OR lock it */
262     } else {
263         ma_vn_lock(vp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY, p);
264         /* always return the child locked */
265     }
266     *ap->a_vpp = vp;
267
268     if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
269         cnp->cn_flags |= SAVENAME;
270
271     DROPNAME();
272     return error;
273 }
274
275 static int
276 afs_vop_create(ap)
277      struct vop_create_args     /* {
278                                  * struct vnode *a_dvp;
279                                  * struct vnode **a_vpp;
280                                  * struct componentname *a_cnp;
281                                  * struct vattr *a_vap;
282                                  * } */ *ap;
283 {
284     int error = 0;
285     struct vcache *vcp;
286     struct vnode *dvp = ap->a_dvp;
287     GETNAME();
288
289     AFS_GLOCK();
290     error =
291         afs_create(VTOAFS(dvp), name, ap->a_vap,
292                    ap->a_vap->va_vaflags & VA_EXCLUSIVE ? EXCL : NONEXCL,
293                    ap->a_vap->va_mode, &vcp, cnp->cn_cred);
294     AFS_GUNLOCK();
295     if (error) {
296         DROPNAME();
297         return (error);
298     }
299
300     if (vcp) {
301         *ap->a_vpp = AFSTOV(vcp);
302         ma_vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p);
303     } else
304         *ap->a_vpp = 0;
305
306     DROPNAME();
307     return error;
308 }
309
310 static int
311 afs_vop_mknod(ap)
312      struct vop_mknod_args      /* {
313                                  * struct vnode *a_dvp;
314                                  * struct vnode **a_vpp;
315                                  * struct componentname *a_cnp;
316                                  * struct vattr *a_vap;
317                                  * } */ *ap;
318 {
319     return (ENODEV);
320 }
321
322 static int
323 afs_vop_open(ap)
324      struct vop_open_args       /* {
325                                  * struct vnode *a_vp;
326                                  * int  a_mode;
327                                  * struct ucred *a_cred;
328                                  * struct thread *a_td;
329                                  * struct file *a_fp;
330                                  * } */ *ap;
331 {
332     int error;
333     struct vcache *vc = VTOAFS(ap->a_vp);
334
335     AFS_GLOCK();
336     error = afs_open(&vc, ap->a_mode, ap->a_cred);
337 #ifdef DIAGNOSTIC
338     if (AFSTOV(vc) != ap->a_vp)
339         panic("AFS open changed vnode!");
340 #endif
341     AFS_GUNLOCK();
342     vnode_create_vobject(ap->a_vp, vc->f.m.Length, ap->a_td);
343     osi_FlushPages(vc, ap->a_cred);
344     return error;
345 }
346
347 static int
348 afs_vop_close(ap)
349      struct vop_close_args      /* {
350                                  * struct vnode *a_vp;
351                                  * int  a_fflag;
352                                  * struct ucred *a_cred;
353                                  * struct thread *a_td;
354                                  * } */ *ap;
355 {
356     int code, iflag;
357     struct vnode *vp = ap->a_vp;
358     struct vcache *avc = VTOAFS(vp);
359
360     VI_LOCK(vp);
361     iflag = vp->v_iflag & VI_DOOMED;
362     VI_UNLOCK(vp);
363     if (iflag & VI_DOOMED) {
364         /* osi_FlushVCache (correctly) calls vgone() on recycled vnodes, we don't
365          * have an afs_close to process, in that case */
366         if (avc->opens != 0)
367             panic("afs_vop_close: doomed vnode %p has vcache %p with non-zero opens %d\n",
368                   vp, avc, avc->opens);
369         return 0;
370     }
371
372     AFS_GLOCK();
373     if (ap->a_cred)
374         code = afs_close(avc, ap->a_fflag, ap->a_cred);
375     else
376         code = afs_close(avc, ap->a_fflag, afs_osi_credp);
377     osi_FlushPages(avc, ap->a_cred);    /* hold GLOCK, but not basic vnode lock */
378     AFS_GUNLOCK();
379     return code;
380 }
381
382 static int
383 afs_vop_access(ap)
384      struct vop_access_args     /* {
385                                  * struct vnode *a_vp;
386                                  * accmode_t a_accmode;
387                                  * struct ucred *a_cred;
388                                  * struct thread *a_td;
389                                  * } */ *ap;
390 {
391     int code;
392     AFS_GLOCK();
393     code = afs_access(VTOAFS(ap->a_vp), ap->a_accmode, ap->a_cred);
394     AFS_GUNLOCK();
395     return code;
396 }
397
398 static int
399 afs_vop_getattr(ap)
400      struct vop_getattr_args    /* {
401                                  * struct vnode *a_vp;
402                                  * struct vattr *a_vap;
403                                  * struct ucred *a_cred;
404                                  * } */ *ap;
405 {
406     int code;
407
408     AFS_GLOCK();
409     code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
410     AFS_GUNLOCK();
411
412     return code;
413 }
414
415 static int
416 afs_vop_setattr(ap)
417      struct vop_setattr_args    /* {
418                                  * struct vnode *a_vp;
419                                  * struct vattr *a_vap;
420                                  * struct ucred *a_cred;
421                                  * } */ *ap;
422 {
423     int code;
424     AFS_GLOCK();
425     code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
426     AFS_GUNLOCK();
427     return code;
428 }
429
430 static int
431 afs_vop_read(ap)
432      struct vop_read_args       /* {
433                                  * struct vnode *a_vp;
434                                  * struct uio *a_uio;
435                                  * int a_ioflag;
436                                  * struct ucred *a_cred;
437                                  * 
438                                  * } */ *ap;
439 {
440     int code;
441     struct vcache *avc = VTOAFS(ap->a_vp);
442     AFS_GLOCK();
443     osi_FlushPages(avc, ap->a_cred);    /* hold GLOCK, but not basic vnode lock */
444     code = afs_read(avc, ap->a_uio, ap->a_cred, 0);
445     AFS_GUNLOCK();
446     return code;
447 }
448
449 /* struct vop_getpages_args {
450  *      struct vnode *a_vp;
451  *      vm_page_t *a_m;
452  *      int a_count;
453  *      int *a_rbehind;
454  *      int *a_rahead;
455  * };
456  */
457 static int
458 afs_vop_getpages(struct vop_getpages_args *ap)
459 {
460     int code;
461     int i, nextoff, size, toff, npages, count;
462     struct uio uio;
463     struct iovec iov;
464     struct buf *bp;
465     vm_offset_t kva;
466     vm_object_t object;
467     vm_page_t *pages;
468     struct vnode *vp;
469     struct vcache *avc;
470
471     memset(&uio, 0, sizeof(uio));
472     memset(&iov, 0, sizeof(iov));
473
474     vp = ap->a_vp;
475     avc = VTOAFS(vp);
476     pages = ap->a_m;
477 #ifdef FBSD_VOP_GETPAGES_BUSIED
478     npages = ap->a_count;
479     if (ap->a_rbehind)
480         *ap->a_rbehind = 0;
481     if (ap->a_rahead)
482         *ap->a_rahead = 0;
483 #else
484     npages = btoc(ap->a_count);
485 #endif
486
487     if ((object = vp->v_object) == NULL) {
488         printf("afs_getpages: called with non-merged cache vnode??\n");
489         return VM_PAGER_ERROR;
490     }
491
492     /*
493      * If the requested page is partially valid, just return it and
494      * allow the pager to zero-out the blanks.  Partially valid pages
495      * can only occur at the file EOF.
496      */
497     {
498 #ifdef FBSD_VOP_GETPAGES_BUSIED
499         AFS_VM_OBJECT_WLOCK(object);
500         ma_vm_page_lock_queues();
501         if(pages[npages - 1]->valid != 0) {
502             if (--npages == 0) {
503                 ma_vm_page_unlock_queues();
504                 AFS_VM_OBJECT_WUNLOCK(object);
505                 return (VM_PAGER_OK);
506             }
507         }
508 #else
509         vm_page_t m = pages[ap->a_reqpage];
510         AFS_VM_OBJECT_WLOCK(object);
511         ma_vm_page_lock_queues();
512         if (m->valid != 0) {
513             /* handled by vm_fault now        */
514             /* vm_page_zero_invalid(m, TRUE); */
515             for (i = 0; i < npages; ++i) {
516                 if (i != ap->a_reqpage) {
517                     ma_vm_page_lock(pages[i]);
518                     vm_page_free(pages[i]);
519                     ma_vm_page_unlock(pages[i]);
520                 }
521             }
522             ma_vm_page_unlock_queues();
523             AFS_VM_OBJECT_WUNLOCK(object);
524             return (0);
525         }
526 #endif
527         ma_vm_page_unlock_queues();
528         AFS_VM_OBJECT_WUNLOCK(object);
529     }
530     bp = getpbuf(&afs_pbuf_freecnt);
531
532     kva = (vm_offset_t) bp->b_data;
533     pmap_qenter(kva, pages, npages);
534     MA_PCPU_INC(cnt.v_vnodein);
535     MA_PCPU_ADD(cnt.v_vnodepgsin, npages);
536
537 #ifdef FBSD_VOP_GETPAGES_BUSIED
538     count = ctob(npages);
539 #else
540     count = ap->a_count;
541 #endif
542     iov.iov_base = (caddr_t) kva;
543     iov.iov_len = count;
544     uio.uio_iov = &iov;
545     uio.uio_iovcnt = 1;
546     uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
547     uio.uio_resid = count;
548     uio.uio_segflg = UIO_SYSSPACE;
549     uio.uio_rw = UIO_READ;
550     uio.uio_td = curthread;
551
552     AFS_GLOCK();
553     osi_FlushPages(avc, osi_curcred()); /* hold GLOCK, but not basic vnode lock */
554     code = afs_read(avc, &uio, osi_curcred(), 0);
555     AFS_GUNLOCK();
556     pmap_qremove(kva, npages);
557
558     relpbuf(bp, &afs_pbuf_freecnt);
559
560     if (code && (uio.uio_resid == count)) {
561 #ifndef FBSD_VOP_GETPAGES_BUSIED
562         AFS_VM_OBJECT_WLOCK(object);
563         ma_vm_page_lock_queues();
564         for (i = 0; i < npages; ++i) {
565             if (i != ap->a_reqpage)
566                 vm_page_free(pages[i]);
567         }
568         ma_vm_page_unlock_queues();
569         AFS_VM_OBJECT_WUNLOCK(object);
570 #endif
571         return VM_PAGER_ERROR;
572     }
573
574     size = count - uio.uio_resid;
575     AFS_VM_OBJECT_WLOCK(object);
576     ma_vm_page_lock_queues();
577     for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
578         vm_page_t m;
579         nextoff = toff + PAGE_SIZE;
580         m = pages[i];
581
582         /* XXX not in nfsclient? */
583         m->flags &= ~PG_ZERO;
584
585         if (nextoff <= size) {
586             /*
587              * Read operation filled an entire page
588              */
589             m->valid = VM_PAGE_BITS_ALL;
590             KASSERT(m->dirty == 0, ("afs_getpages: page %p is dirty", m));
591         } else if (size > toff) {
592             /*
593              * Read operation filled a partial page.
594              */
595             m->valid = 0;
596             vm_page_set_validclean(m, 0, size - toff);
597             KASSERT(m->dirty == 0, ("afs_getpages: page %p is dirty", m));
598         }
599
600 #ifndef FBSD_VOP_GETPAGES_BUSIED
601         if (i != ap->a_reqpage) {
602 #if __FreeBSD_version >= 1000042
603             vm_page_readahead_finish(m);
604 #else
605             /*
606              * Whether or not to leave the page activated is up in
607              * the air, but we should put the page on a page queue
608              * somewhere (it already is in the object).  Result:
609              * It appears that emperical results show that
610              * deactivating pages is best.
611              */
612
613             /*
614              * Just in case someone was asking for this page we
615              * now tell them that it is ok to use.
616              */
617             if (!code) {
618                 if (m->oflags & VPO_WANTED) {
619                     ma_vm_page_lock(m);
620                     vm_page_activate(m);
621                     ma_vm_page_unlock(m);
622                 }
623                 else {
624                     ma_vm_page_lock(m);
625                     vm_page_deactivate(m);
626                     ma_vm_page_unlock(m);
627                 }
628                 vm_page_wakeup(m);
629             } else {
630                 ma_vm_page_lock(m);
631                 vm_page_free(m);
632                 ma_vm_page_unlock(m);
633             }
634 #endif  /* __FreeBSD_version 1000042 */
635         }
636 #endif   /* ndef FBSD_VOP_GETPAGES_BUSIED */
637     }
638     ma_vm_page_unlock_queues();
639     AFS_VM_OBJECT_WUNLOCK(object);
640     return VM_PAGER_OK;
641 }
642
643 static int
644 afs_vop_write(ap)
645      struct vop_write_args      /* {
646                                  * struct vnode *a_vp;
647                                  * struct uio *a_uio;
648                                  * int a_ioflag;
649                                  * struct ucred *a_cred;
650                                  * } */ *ap;
651 {
652     int code;
653     struct vcache *avc = VTOAFS(ap->a_vp);
654     AFS_GLOCK();
655     osi_FlushPages(avc, ap->a_cred);    /* hold GLOCK, but not basic vnode lock */
656     code =
657         afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
658     AFS_GUNLOCK();
659     return code;
660 }
661
662 /*-
663  * struct vop_putpages_args {
664  *      struct vnode *a_vp;
665  *      vm_page_t *a_m;
666  *      int a_count;
667  *      int a_sync;
668  *      int *a_rtvals;
669  *      vm_oofset_t a_offset;
670  * };
671  */
672 /*
673  * All of the pages passed to us in ap->a_m[] are already marked as busy,
674  * so there is no additional locking required to set their flags.  -GAW
675  */
676 static int
677 afs_vop_putpages(struct vop_putpages_args *ap)
678 {
679     int code;
680     int i, size, npages, sync;
681     struct uio uio;
682     struct iovec iov;
683     struct buf *bp;
684     vm_offset_t kva;
685     struct vnode *vp;
686     struct vcache *avc;
687
688     memset(&uio, 0, sizeof(uio));
689     memset(&iov, 0, sizeof(iov));
690
691     vp = ap->a_vp;
692     avc = VTOAFS(vp);
693     /* Perhaps these two checks should just be KASSERTs instead... */
694     if (vp->v_object == NULL) {
695         printf("afs_putpages: called with non-merged cache vnode??\n");
696         return VM_PAGER_ERROR;  /* XXX I think this is insufficient */
697     }
698     if (vType(avc) != VREG) {
699         printf("afs_putpages: not VREG");
700         return VM_PAGER_ERROR;  /* XXX I think this is insufficient */
701     }
702     npages = btoc(ap->a_count);
703     for (i = 0; i < npages; i++)
704         ap->a_rtvals[i] = VM_PAGER_AGAIN;
705     bp = getpbuf(&afs_pbuf_freecnt);
706
707     kva = (vm_offset_t) bp->b_data;
708     pmap_qenter(kva, ap->a_m, npages);
709     MA_PCPU_INC(cnt.v_vnodeout);
710     MA_PCPU_ADD(cnt.v_vnodepgsout, ap->a_count);
711
712     iov.iov_base = (caddr_t) kva;
713     iov.iov_len = ap->a_count;
714     uio.uio_iov = &iov;
715     uio.uio_iovcnt = 1;
716     uio.uio_offset = IDX_TO_OFF(ap->a_m[0]->pindex);
717     uio.uio_resid = ap->a_count;
718     uio.uio_segflg = UIO_SYSSPACE;
719     uio.uio_rw = UIO_WRITE;
720     uio.uio_td = curthread;
721     sync = IO_VMIO;
722     if (ap->a_sync & VM_PAGER_PUT_SYNC)
723         sync |= IO_SYNC;
724     /*if (ap->a_sync & VM_PAGER_PUT_INVAL)
725      * sync |= IO_INVAL; */
726
727     AFS_GLOCK();
728     code = afs_write(avc, &uio, sync, osi_curcred(), 0);
729     AFS_GUNLOCK();
730
731     pmap_qremove(kva, npages);
732     relpbuf(bp, &afs_pbuf_freecnt);
733
734     if (!code) {
735         size = ap->a_count - uio.uio_resid;
736         for (i = 0; i < round_page(size) / PAGE_SIZE; i++) {
737             ap->a_rtvals[i] = VM_PAGER_OK;
738             vm_page_undirty(ap->a_m[i]);
739         }
740     }
741     return ap->a_rtvals[0];
742 }
743
744 static int
745 afs_vop_ioctl(ap)
746      struct vop_ioctl_args      /* {
747                                  * struct vnode *a_vp;
748                                  * u_long a_command;
749                                  * void *a_data;
750                                  * int  a_fflag;
751                                  * struct ucred *a_cred;
752                                  * struct thread *a_td;
753                                  * } */ *ap;
754 {
755     struct vcache *tvc = VTOAFS(ap->a_vp);
756     int error = 0;
757
758     /* in case we ever get in here... */
759
760     AFS_STATCNT(afs_ioctl);
761     if (((ap->a_command >> 8) & 0xff) == 'V') {
762         /* This is a VICEIOCTL call */
763         AFS_GLOCK();
764         error = HandleIoctl(tvc, ap->a_command, ap->a_data);
765         AFS_GUNLOCK();
766         return (error);
767     } else {
768         /* No-op call; just return. */
769         return (ENOTTY);
770     }
771 }
772
773 static int
774 afs_vop_fsync(ap)
775      struct vop_fsync_args      /* {
776                                  * struct vnode *a_vp;
777                                  * int a_waitfor;
778                                  * struct thread *td;
779                                  * } */ *ap;
780 {
781     int error;
782     struct vnode *vp = ap->a_vp;
783
784     AFS_GLOCK();
785     /*vflushbuf(vp, wait); */
786     error = afs_fsync(VTOAFS(vp), ap->a_td->td_ucred);
787     AFS_GUNLOCK();
788     return error;
789 }
790
791 static int
792 afs_vop_remove(ap)
793      struct vop_remove_args     /* {
794                                  * struct vnode *a_dvp;
795                                  * struct vnode *a_vp;
796                                  * struct componentname *a_cnp;
797                                  * } */ *ap;
798 {
799     int error = 0;
800     struct vnode *vp = ap->a_vp;
801     struct vnode *dvp = ap->a_dvp;
802
803     GETNAME();
804     AFS_GLOCK();
805     error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
806     AFS_GUNLOCK();
807     cache_purge(vp);
808     DROPNAME();
809     return error;
810 }
811
812 static int
813 afs_vop_link(ap)
814      struct vop_link_args       /* {
815                                  * struct vnode *a_vp;
816                                  * struct vnode *a_tdvp;
817                                  * struct componentname *a_cnp;
818                                  * } */ *ap;
819 {
820     int error = 0;
821     struct vnode *dvp = ap->a_tdvp;
822     struct vnode *vp = ap->a_vp;
823
824     GETNAME();
825     if (dvp->v_mount != vp->v_mount) {
826         error = EXDEV;
827         goto out;
828     }
829     if (vp->v_type == VDIR) {
830         error = EISDIR;
831         goto out;
832     }
833     if ((error = ma_vn_lock(vp, LK_CANRECURSE | LK_EXCLUSIVE, p)) != 0) {
834         goto out;
835     }
836     AFS_GLOCK();
837     error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
838     AFS_GUNLOCK();
839     if (dvp != vp)
840         MA_VOP_UNLOCK(vp, 0, p);
841   out:
842     DROPNAME();
843     return error;
844 }
845
846 static int
847 afs_vop_rename(ap)
848      struct vop_rename_args     /* {
849                                  * struct vnode *a_fdvp;
850                                  * struct vnode *a_fvp;
851                                  * struct componentname *a_fcnp;
852                                  * struct vnode *a_tdvp;
853                                  * struct vnode *a_tvp;
854                                  * struct componentname *a_tcnp;
855                                  * } */ *ap;
856 {
857     int error = 0;
858     struct componentname *fcnp = ap->a_fcnp;
859     char *fname;
860     struct componentname *tcnp = ap->a_tcnp;
861     char *tname;
862     struct vnode *tvp = ap->a_tvp;
863     struct vnode *tdvp = ap->a_tdvp;
864     struct vnode *fvp = ap->a_fvp;
865     struct vnode *fdvp = ap->a_fdvp;
866
867     /*
868      * Check for cross-device rename.
869      */
870     if ((fvp->v_mount != tdvp->v_mount)
871         || (tvp && (fvp->v_mount != tvp->v_mount))) {
872         error = EXDEV;
873       abortit:
874         if (tdvp == tvp)
875             vrele(tdvp);
876         else
877             vput(tdvp);
878         if (tvp)
879             vput(tvp);
880         vrele(fdvp);
881         vrele(fvp);
882         return (error);
883     }
884     /*
885      * if fvp == tvp, we're just removing one name of a pair of
886      * directory entries for the same element.  convert call into rename.
887      ( (pinched from FreeBSD 4.4's ufs_rename())
888      
889      */
890     if (fvp == tvp) {
891         if (fvp->v_type == VDIR) {
892             error = EINVAL;
893             goto abortit;
894         }
895
896         /* Release destination completely. */
897         vput(tdvp);
898         vput(tvp);
899
900         /* Delete source. */
901         vrele(fdvp);
902         vrele(fvp);
903         fcnp->cn_flags &= ~MODMASK;
904         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
905         if ((fcnp->cn_flags & SAVESTART) == 0)
906             panic("afs_rename: lost from startdir");
907         fcnp->cn_nameiop = DELETE;
908         VREF(fdvp);
909         error = relookup(fdvp, &fvp, fcnp);
910         if (error == 0)
911             vrele(fdvp);
912         if (fvp == NULL) {
913             return (ENOENT);
914         }
915
916         error = VOP_REMOVE(fdvp, fvp, fcnp);
917         if (fdvp == fvp)
918             vrele(fdvp);
919         else
920             vput(fdvp);
921         vput(fvp);
922         return (error);
923     }
924     if ((error = ma_vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
925         goto abortit;
926
927     MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
928     memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
929     fname[fcnp->cn_namelen] = '\0';
930     MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
931     memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
932     tname[tcnp->cn_namelen] = '\0';
933
934
935     AFS_GLOCK();
936     /* XXX use "from" or "to" creds? NFS uses "to" creds */
937     error =
938         afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
939     AFS_GUNLOCK();
940
941     FREE(fname, M_TEMP);
942     FREE(tname, M_TEMP);
943     if (tdvp == tvp)
944         vrele(tdvp);
945     else
946         vput(tdvp);
947     if (tvp)
948         vput(tvp);
949     vrele(fdvp);
950     vput(fvp);
951     return error;
952 }
953
954 static int
955 afs_vop_mkdir(ap)
956      struct vop_mkdir_args      /* {
957                                  * struct vnode *a_dvp;
958                                  * struct vnode **a_vpp;
959                                  * struct componentname *a_cnp;
960                                  * struct vattr *a_vap;
961                                  * } */ *ap;
962 {
963     struct vnode *dvp = ap->a_dvp;
964     struct vattr *vap = ap->a_vap;
965     int error = 0;
966     struct vcache *vcp;
967
968     GETNAME();
969 #ifdef DIAGNOSTIC
970     if ((cnp->cn_flags & HASBUF) == 0)
971         panic("afs_vop_mkdir: no name");
972 #endif
973     AFS_GLOCK();
974     error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
975     AFS_GUNLOCK();
976     if (error) {
977         DROPNAME();
978         return (error);
979     }
980     if (vcp) {
981         *ap->a_vpp = AFSTOV(vcp);
982         ma_vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p);
983     } else
984         *ap->a_vpp = 0;
985     DROPNAME();
986     return error;
987 }
988
989 static int
990 afs_vop_rmdir(ap)
991      struct vop_rmdir_args      /* {
992                                  * struct vnode *a_dvp;
993                                  * struct vnode *a_vp;
994                                  * struct componentname *a_cnp;
995                                  * } */ *ap;
996 {
997     int error = 0;
998     struct vnode *dvp = ap->a_dvp;
999
1000     GETNAME();
1001     AFS_GLOCK();
1002     error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
1003     AFS_GUNLOCK();
1004     DROPNAME();
1005     return error;
1006 }
1007
1008 /* struct vop_symlink_args {
1009  *      struct vnode *a_dvp;
1010  *      struct vnode **a_vpp;
1011  *      struct componentname *a_cnp;
1012  *      struct vattr *a_vap;
1013  *      char *a_target;
1014  * };
1015  */
1016 static int
1017 afs_vop_symlink(struct vop_symlink_args *ap)
1018 {
1019     struct vnode *dvp;
1020     struct vnode *newvp;
1021     struct vcache *vcp;
1022     int error;
1023
1024     GETNAME();
1025     AFS_GLOCK();
1026
1027     dvp = ap->a_dvp;
1028     newvp = NULL;
1029
1030     error =
1031         afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, NULL,
1032                     cnp->cn_cred);
1033     if (error == 0) {
1034         error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
1035         if (error == 0) {
1036             newvp = AFSTOV(vcp);
1037             ma_vn_lock(newvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_thread);
1038         }
1039     }
1040     AFS_GUNLOCK();
1041     DROPNAME();
1042     *(ap->a_vpp) = newvp;
1043     return error;
1044 }
1045
1046 static int
1047 afs_vop_readdir(ap)
1048      struct vop_readdir_args    /* {
1049                                  * struct vnode *a_vp;
1050                                  * struct uio *a_uio;
1051                                  * struct ucred *a_cred;
1052                                  * int *a_eofflag;
1053                                  * u_long *a_cookies;
1054                                  * int ncookies;
1055                                  * } */ *ap;
1056 {
1057     int error;
1058     off_t off;
1059 /*    printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1060            ap->a_ncookies); */
1061     off = ap->a_uio->uio_offset;
1062     AFS_GLOCK();
1063     error =
1064         afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
1065     AFS_GUNLOCK();
1066     if (!error && ap->a_ncookies != NULL) {
1067         struct uio *uio = ap->a_uio;
1068         const struct dirent *dp, *dp_start, *dp_end;
1069         int ncookies;
1070         u_long *cookies, *cookiep;
1071
1072         if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1073             panic("afs_readdir: burned cookies");
1074         dp = (const struct dirent *)
1075             ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1076
1077         dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1078         for (dp_start = dp, ncookies = 0; dp < dp_end;
1079              dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1080             ncookies++;
1081
1082         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1083                M_WAITOK);
1084         for (dp = dp_start, cookiep = cookies; dp < dp_end;
1085              dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1086             off += dp->d_reclen;
1087             *cookiep++ = off;
1088         }
1089         *ap->a_cookies = cookies;
1090         *ap->a_ncookies = ncookies;
1091     }
1092
1093     return error;
1094 }
1095
1096 static int
1097 afs_vop_readlink(ap)
1098      struct vop_readlink_args   /* {
1099                                  * struct vnode *a_vp;
1100                                  * struct uio *a_uio;
1101                                  * struct ucred *a_cred;
1102                                  * } */ *ap;
1103 {
1104     int error;
1105 /*    printf("readlink %x\n", ap->a_vp);*/
1106     AFS_GLOCK();
1107     error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
1108     AFS_GUNLOCK();
1109     return error;
1110 }
1111
1112 static int
1113 afs_vop_inactive(ap)
1114      struct vop_inactive_args   /* {
1115                                  * struct vnode *a_vp;
1116                                  * struct thread *td;
1117                                  * } */ *ap;
1118 {
1119     struct vnode *vp = ap->a_vp;
1120
1121     AFS_GLOCK();
1122     afs_InactiveVCache(VTOAFS(vp), 0);  /* decrs ref counts */
1123     AFS_GUNLOCK();
1124     return 0;
1125 }
1126
1127 /*
1128  * struct vop_reclaim_args {
1129  *      struct vnode *a_vp;
1130  * };
1131  */
1132 static int
1133 afs_vop_reclaim(struct vop_reclaim_args *ap)
1134 {
1135     /* copied from ../OBSD/osi_vnodeops.c:afs_nbsd_reclaim() */
1136     int code, slept;
1137     struct vnode *vp = ap->a_vp;
1138     struct vcache *avc = VTOAFS(vp);
1139     int haveGlock = ISAFS_GLOCK();
1140     int haveVlock = CheckLock(&afs_xvcache);
1141
1142     if (!haveGlock)
1143         AFS_GLOCK();
1144     if (!haveVlock)
1145         ObtainWriteLock(&afs_xvcache, 901);
1146     /* reclaim the vnode and the in-memory vcache, but keep the on-disk vcache */
1147     code = afs_FlushVCache(avc, &slept);
1148
1149     if (avc->f.states & CVInit) {
1150         avc->f.states &= ~CVInit;
1151         afs_osi_Wakeup(&avc->f.states);
1152     }
1153
1154     if (!haveVlock)
1155         ReleaseWriteLock(&afs_xvcache);
1156     if (!haveGlock)
1157         AFS_GUNLOCK();
1158
1159     if (code) {
1160         afs_warn("afs_vop_reclaim: afs_FlushVCache failed code %d vnode\n", code);
1161         VOP_PRINT(vp);
1162     }
1163
1164     /* basically, it must not fail */
1165     vnode_destroy_vobject(vp);
1166     vp->v_data = 0;
1167
1168     return 0;
1169 }
1170
1171 static int
1172 afs_vop_strategy(ap)
1173      struct vop_strategy_args   /* {
1174                                  * struct buf *a_bp;
1175                                  * } */ *ap;
1176 {
1177     int error;
1178     AFS_GLOCK();
1179     error = afs_ustrategy(ap->a_bp, osi_curcred());
1180     AFS_GUNLOCK();
1181     return error;
1182 }
1183
1184 static int
1185 afs_vop_print(ap)
1186      struct vop_print_args      /* {
1187                                  * struct vnode *a_vp;
1188                                  * } */ *ap;
1189 {
1190     struct vnode *vp = ap->a_vp;
1191     struct vcache *vc = VTOAFS(ap->a_vp);
1192     int s = vc->f.states;
1193
1194     printf("vc %p vp %p tag %s, fid: %d.%d.%d.%d, opens %d, writers %d", vc, vp, vp->v_tag,
1195            (int)vc->f.fid.Cell, (u_int) vc->f.fid.Fid.Volume,
1196            (u_int) vc->f.fid.Fid.Vnode, (u_int) vc->f.fid.Fid.Unique, vc->opens,
1197            vc->execsOrWriters);
1198     printf("\n  states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1199            (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1200            (s & CMAPPED) ? " mapped" : "",
1201            (s & CVFlushed) ? " flush in progress" : "");
1202     printf("\n");
1203     return 0;
1204 }
1205
1206 /*
1207  * Advisory record locking support (fcntl() POSIX style)
1208  */
1209 static int
1210 afs_vop_advlock(ap)
1211      struct vop_advlock_args    /* {
1212                                  * struct vnode *a_vp;
1213                                  * caddr_t  a_id;
1214                                  * int  a_op;
1215                                  * struct flock *a_fl;
1216                                  * int  a_flags;
1217                                  * } */ *ap;
1218 {
1219     int error, a_op;
1220     struct ucred cr = *osi_curcred();
1221
1222     a_op = ap->a_op;
1223     if (a_op == F_UNLCK) {
1224         /*
1225          * When a_fl->type is F_UNLCK, FreeBSD passes in an a_op of F_UNLCK.
1226          * This is (confusingly) different than how you actually release a lock
1227          * with fcntl(), which is done with an a_op of F_SETLK and an l_type of
1228          * F_UNLCK. Pretend we were given an a_op of F_SETLK in this case,
1229          * since this is what afs_lockctl expects.
1230          */
1231         a_op = F_SETLK;
1232     }
1233
1234     AFS_GLOCK();
1235     error =
1236         afs_lockctl(VTOAFS(ap->a_vp),
1237                 ap->a_fl,
1238                 a_op, &cr,
1239                 (int)(intptr_t)ap->a_id);       /* XXX: no longer unique! */
1240     AFS_GUNLOCK();
1241     return error;
1242 }
1243
1244 struct vop_vector afs_vnodeops = {
1245         .vop_default =          &default_vnodeops,
1246         .vop_access =           afs_vop_access,
1247         .vop_advlock =          afs_vop_advlock,
1248         .vop_close =            afs_vop_close,
1249         .vop_create =           afs_vop_create,
1250         .vop_fsync =            afs_vop_fsync,
1251         .vop_getattr =          afs_vop_getattr,
1252         .vop_getpages =         afs_vop_getpages,
1253         .vop_inactive =         afs_vop_inactive,
1254         .vop_ioctl =            afs_vop_ioctl,
1255         .vop_link =             afs_vop_link,
1256         .vop_lookup =           afs_vop_lookup,
1257         .vop_mkdir =            afs_vop_mkdir,
1258         .vop_mknod =            afs_vop_mknod,
1259         .vop_open =             afs_vop_open,
1260         .vop_pathconf =         afs_vop_pathconf,
1261         .vop_print =            afs_vop_print,
1262         .vop_putpages =         afs_vop_putpages,
1263         .vop_read =             afs_vop_read,
1264         .vop_readdir =          afs_vop_readdir,
1265         .vop_readlink =         afs_vop_readlink,
1266         .vop_reclaim =          afs_vop_reclaim,
1267         .vop_remove =           afs_vop_remove,
1268         .vop_rename =           afs_vop_rename,
1269         .vop_rmdir =            afs_vop_rmdir,
1270         .vop_setattr =          afs_vop_setattr,
1271         .vop_strategy =         afs_vop_strategy,
1272         .vop_symlink =          afs_vop_symlink,
1273         .vop_write =            afs_vop_write,
1274 };