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