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