e29dc0df63b3203213d8ed2f4fb68e8f15368a9c
[openafs.git] / src / afs / FBSD / osi_vnodeops.c
1 #include <afsconfig.h>
2 #include <afs/param.h>
3
4 RCSID
5     ("$Header$");
6
7 #include <afs/sysincludes.h>    /* Standard vendor system headers */
8 #include <afsincludes.h>        /* Afs-based standard headers */
9 #include <afs/afs_stats.h>      /* statistics */
10 #include <sys/malloc.h>
11 #include <sys/namei.h>
12 #ifndef AFS_FBSD50_ENV
13 #include <vm/vm_zone.h>
14 #endif
15 #include <vm/vm_page.h>
16 #include <vm/vm_object.h>
17 #include <vm/vm_pager.h>
18 #include <vm/vnode_pager.h>
19 extern int afs_pbuf_freecnt;
20
21 int afs_vop_lookup(struct vop_lookup_args *);
22 int afs_vop_create(struct vop_create_args *);
23 int afs_vop_mknod(struct vop_mknod_args *);
24 int afs_vop_open(struct vop_open_args *);
25 int afs_vop_close(struct vop_close_args *);
26 int afs_vop_access(struct vop_access_args *);
27 int afs_vop_getattr(struct vop_getattr_args *);
28 int afs_vop_setattr(struct vop_setattr_args *);
29 int afs_vop_read(struct vop_read_args *);
30 int afs_vop_write(struct vop_write_args *);
31 int afs_vop_getpages(struct vop_getpages_args *);
32 int afs_vop_putpages(struct vop_putpages_args *);
33 int afs_vop_ioctl(struct vop_ioctl_args *);
34 int afs_vop_poll(struct vop_poll_args *);
35 #ifndef AFS_FBSD50_ENV
36 int afs_vop_mmap(struct vop_mmap_args *);
37 #endif
38 int afs_vop_fsync(struct vop_fsync_args *);
39 int afs_vop_remove(struct vop_remove_args *);
40 int afs_vop_link(struct vop_link_args *);
41 int afs_vop_rename(struct vop_rename_args *);
42 int afs_vop_mkdir(struct vop_mkdir_args *);
43 int afs_vop_rmdir(struct vop_rmdir_args *);
44 int afs_vop_symlink(struct vop_symlink_args *);
45 int afs_vop_readdir(struct vop_readdir_args *);
46 int afs_vop_readlink(struct vop_readlink_args *);
47 int afs_vop_inactive(struct vop_inactive_args *);
48 int afs_vop_reclaim(struct vop_reclaim_args *);
49 int afs_vop_lock(struct vop_lock_args *);
50 int afs_vop_unlock(struct vop_unlock_args *);
51 int afs_vop_bmap(struct vop_bmap_args *);
52 int afs_vop_strategy(struct vop_strategy_args *);
53 int afs_vop_print(struct vop_print_args *);
54 int afs_vop_islocked(struct vop_islocked_args *);
55 int afs_vop_advlock(struct vop_advlock_args *);
56
57
58
59 /* Global vfs data structures for AFS. */
60 vop_t **afs_vnodeop_p;
61 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
62     {&vop_default_desc, (vop_t *) vop_eopnotsupp},
63     {&vop_access_desc, (vop_t *) afs_vop_access},       /* access */
64     {&vop_advlock_desc, (vop_t *) afs_vop_advlock},     /* advlock */
65     {&vop_bmap_desc, (vop_t *) afs_vop_bmap},   /* bmap */
66 #ifndef AFS_FBSD50_ENV
67     {&vop_bwrite_desc, (vop_t *) vop_stdbwrite},
68 #endif
69     {&vop_close_desc, (vop_t *) afs_vop_close}, /* close */
70     {&vop_createvobject_desc, (vop_t *) vop_stdcreatevobject},
71     {&vop_destroyvobject_desc, (vop_t *) vop_stddestroyvobject},
72     {&vop_create_desc, (vop_t *) afs_vop_create},       /* create */
73     {&vop_fsync_desc, (vop_t *) afs_vop_fsync}, /* fsync */
74     {&vop_getattr_desc, (vop_t *) afs_vop_getattr},     /* getattr */
75     {&vop_getpages_desc, (vop_t *) afs_vop_getpages},   /* read */
76     {&vop_getvobject_desc, (vop_t *) vop_stdgetvobject},
77     {&vop_putpages_desc, (vop_t *) afs_vop_putpages},   /* write */
78     {&vop_inactive_desc, (vop_t *) afs_vop_inactive},   /* inactive */
79     {&vop_islocked_desc, (vop_t *) afs_vop_islocked},   /* islocked */
80     {&vop_lease_desc, (vop_t *) vop_null},
81     {&vop_link_desc, (vop_t *) afs_vop_link},   /* link */
82     {&vop_lock_desc, (vop_t *) afs_vop_lock},   /* lock */
83     {&vop_lookup_desc, (vop_t *) afs_vop_lookup},       /* lookup */
84     {&vop_mkdir_desc, (vop_t *) afs_vop_mkdir}, /* mkdir */
85     {&vop_mknod_desc, (vop_t *) afs_vop_mknod}, /* mknod */
86 #ifndef AFS_FBSD50_ENV
87     {&vop_mmap_desc, (vop_t *) afs_vop_mmap},   /* mmap */
88 #endif
89     {&vop_open_desc, (vop_t *) afs_vop_open},   /* open */
90     {&vop_poll_desc, (vop_t *) afs_vop_poll},   /* select */
91     {&vop_print_desc, (vop_t *) afs_vop_print}, /* print */
92     {&vop_read_desc, (vop_t *) afs_vop_read},   /* read */
93     {&vop_readdir_desc, (vop_t *) afs_vop_readdir},     /* readdir */
94     {&vop_readlink_desc, (vop_t *) afs_vop_readlink},   /* readlink */
95     {&vop_reclaim_desc, (vop_t *) afs_vop_reclaim},     /* reclaim */
96     {&vop_remove_desc, (vop_t *) afs_vop_remove},       /* remove */
97     {&vop_rename_desc, (vop_t *) afs_vop_rename},       /* rename */
98     {&vop_rmdir_desc, (vop_t *) afs_vop_rmdir}, /* rmdir */
99     {&vop_setattr_desc, (vop_t *) afs_vop_setattr},     /* setattr */
100     {&vop_strategy_desc, (vop_t *) afs_vop_strategy},   /* strategy */
101     {&vop_symlink_desc, (vop_t *) afs_vop_symlink},     /* symlink */
102     {&vop_unlock_desc, (vop_t *) afs_vop_unlock},       /* unlock */
103     {&vop_write_desc, (vop_t *) afs_vop_write}, /* write */
104     {&vop_ioctl_desc, (vop_t *) afs_vop_ioctl}, /* XXX ioctl */
105     /*{ &vop_seek_desc, afs_vop_seek }, *//* seek */
106     {NULL, NULL}
107 };
108 struct vnodeopv_desc afs_vnodeop_opv_desc =
109     { &afs_vnodeop_p, afs_vnodeop_entries };
110
111 #define GETNAME()       \
112     struct componentname *cnp = ap->a_cnp; \
113     char *name; \
114     MALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
115     memcpy(name, cnp->cn_nameptr, cnp->cn_namelen); \
116     name[cnp->cn_namelen] = '\0'
117
118 #define DROPNAME() FREE(name, M_TEMP)
119
120 /* This is a bit of a cheat... */
121 #ifdef AFS_FBSD50_ENV
122 #define a_p a_td
123 #endif
124
125
126
127 int
128 afs_vop_lookup(ap)
129      struct vop_lookup_args     /* {
130                                  * struct vnodeop_desc * a_desc;
131                                  * struct vnode *a_dvp;
132                                  * struct vnode **a_vpp;
133                                  * struct componentname *a_cnp;
134                                  * } */ *ap;
135 {
136     int error;
137     struct vcache *vcp;
138     struct vnode *vp, *dvp;
139     register int flags = ap->a_cnp->cn_flags;
140     int lockparent;             /* 1 => lockparent flag is set */
141     int wantparent;             /* 1 => wantparent or lockparent flag */
142 #ifdef AFS_FBSD50_ENV
143     struct thread *p = ap->a_cnp->cn_thread;
144 #else
145     struct proc *p = ap->a_cnp->cn_proc;
146 #endif
147     GETNAME();
148
149     lockparent = flags & LOCKPARENT;
150     wantparent = flags & (LOCKPARENT | WANTPARENT);
151
152     if (ap->a_dvp->v_type != VDIR) {
153         *ap->a_vpp = 0;
154         DROPNAME();
155         return ENOTDIR;
156     }
157     dvp = ap->a_dvp;
158     if (flags & ISDOTDOT)
159         VOP_UNLOCK(dvp, 0, p);
160     AFS_GLOCK();
161     error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
162     AFS_GUNLOCK();
163     if (error) {
164         if (flags & ISDOTDOT)
165             VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
166         if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
167             && (flags & ISLASTCN) && error == ENOENT)
168             error = EJUSTRETURN;
169         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
170             cnp->cn_flags |= SAVENAME;
171         DROPNAME();
172         *ap->a_vpp = 0;
173         return (error);
174     }
175     vp = AFSTOV(vcp);           /* always get a node if no error */
176
177     /* The parent directory comes in locked.  We unlock it on return
178      * unless the caller wants it left locked.
179      * we also always return the vnode locked. */
180
181     if (flags & ISDOTDOT) {
182         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
183         /* always return the child locked */
184         if (lockparent && (flags & ISLASTCN)
185             && (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
186             vput(vp);
187             DROPNAME();
188             return (error);
189         }
190     } else if (vp == dvp) {
191         /* they're the same; afs_lookup() already ref'ed the leaf.
192          * It came in locked, so we don't need to ref OR lock it */
193     } else {
194         if (!lockparent || !(flags & ISLASTCN))
195             VOP_UNLOCK(dvp, 0, p);      /* done with parent. */
196         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
197         /* always return the child locked */
198     }
199     *ap->a_vpp = vp;
200
201     if ((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN))
202         || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)))
203         cnp->cn_flags |= SAVENAME;
204
205     DROPNAME();
206     return error;
207 }
208
209 int
210 afs_vop_create(ap)
211      struct vop_create_args     /* {
212                                  * struct vnode *a_dvp;
213                                  * struct vnode **a_vpp;
214                                  * struct componentname *a_cnp;
215                                  * struct vattr *a_vap;
216                                  * } */ *ap;
217 {
218     int error = 0;
219     struct vcache *vcp;
220     register struct vnode *dvp = ap->a_dvp;
221 #ifdef AFS_FBSD50_ENV
222     struct thread *p = ap->a_cnp->cn_thread;
223 #else
224     struct proc *p = ap->a_cnp->cn_proc;
225 #endif
226     GETNAME();
227
228     AFS_GLOCK();
229     error =
230         afs_create(VTOAFS(dvp), name, ap->a_vap,
231                    ap->a_vap->va_vaflags & VA_EXCLUSIVE ? EXCL : NONEXCL,
232                    ap->a_vap->va_mode, &vcp, cnp->cn_cred);
233     AFS_GUNLOCK();
234     if (error) {
235         DROPNAME();
236         return (error);
237     }
238
239     if (vcp) {
240         *ap->a_vpp = AFSTOV(vcp);
241         vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p);
242     } else
243         *ap->a_vpp = 0;
244
245     DROPNAME();
246     return error;
247 }
248
249 int
250 afs_vop_mknod(ap)
251      struct vop_mknod_args      /* {
252                                  * struct vnode *a_dvp;
253                                  * struct vnode **a_vpp;
254                                  * struct componentname *a_cnp;
255                                  * struct vattr *a_vap;
256                                  * } */ *ap;
257 {
258     return (ENODEV);
259 }
260
261 #if 0
262 static int
263 validate_vops(struct vnode *vp, int after)
264 {
265     int ret = 0;
266     struct vnodeopv_entry_desc *this;
267     for (this = afs_vnodeop_entries; this->opve_op; this++) {
268         if (vp->v_op[this->opve_op->vdesc_offset] != this->opve_impl) {
269             if (!ret) {
270                 printf("v_op %d ", after);
271                 vprint("check", vp);
272             }
273             ret = 1;
274             printf("For oper %d (%s), func is %p, not %p",
275                    this->opve_op->vdesc_offset, this->opve_op->vdesc_name,
276                    vp->v_op[this->opve_op->vdesc_offset], this->opve_impl);
277         }
278     }
279     return ret;
280 }
281 #endif
282 int
283 afs_vop_open(ap)
284      struct vop_open_args       /* {
285                                  * struct vnode *a_vp;
286                                  * int  a_mode;
287                                  * struct ucred *a_cred;
288                                  * struct proc *a_p;
289                                  * } */ *ap;
290 {
291     int error;
292     int bad;
293     struct vcache *vc = VTOAFS(ap->a_vp);
294     bad = 0;
295     AFS_GLOCK();
296     error = afs_open(&vc, ap->a_mode, ap->a_cred);
297 #ifdef DIAGNOSTIC
298     if (AFSTOV(vc) != ap->a_vp)
299         panic("AFS open changed vnode!");
300 #endif
301     afs_BozonLock(&vc->pvnLock, vc);
302     osi_FlushPages(vc, ap->a_cred);
303     afs_BozonUnlock(&vc->pvnLock, vc);
304     AFS_GUNLOCK();
305     return error;
306 }
307
308 int
309 afs_vop_close(ap)
310      struct vop_close_args      /* {
311                                  * struct vnode *a_vp;
312                                  * int  a_fflag;
313                                  * struct ucred *a_cred;
314                                  * struct proc *a_p;
315                                  * } */ *ap;
316 {
317     int code;
318     struct vcache *avc = VTOAFS(ap->a_vp);
319     AFS_GLOCK();
320     if (ap->a_cred)
321         code = afs_close(avc, ap->a_fflag, ap->a_cred);
322     else
323         code = afs_close(avc, ap->a_fflag, afs_osi_credp);
324     afs_BozonLock(&avc->pvnLock, avc);
325     osi_FlushPages(avc, ap->a_cred);    /* hold bozon lock, but not basic vnode lock */
326     afs_BozonUnlock(&avc->pvnLock, avc);
327     AFS_GUNLOCK();
328     return code;
329 }
330
331 int
332 afs_vop_access(ap)
333      struct vop_access_args     /* {
334                                  * struct vnode *a_vp;
335                                  * int  a_mode;
336                                  * struct ucred *a_cred;
337                                  * struct proc *a_p;
338                                  * } */ *ap;
339 {
340     int code;
341     AFS_GLOCK();
342     code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
343     AFS_GUNLOCK();
344     return code;
345 }
346
347 int
348 afs_vop_getattr(ap)
349      struct vop_getattr_args    /* {
350                                  * struct vnode *a_vp;
351                                  * struct vattr *a_vap;
352                                  * struct ucred *a_cred;
353                                  * struct proc *a_p;
354                                  * } */ *ap;
355 {
356     int code;
357     AFS_GLOCK();
358     code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
359     AFS_GUNLOCK();
360     return code;
361 }
362
363 int
364 afs_vop_setattr(ap)
365      struct vop_setattr_args    /* {
366                                  * struct vnode *a_vp;
367                                  * struct vattr *a_vap;
368                                  * struct ucred *a_cred;
369                                  * struct proc *a_p;
370                                  * } */ *ap;
371 {
372     int code;
373     AFS_GLOCK();
374     code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
375     AFS_GUNLOCK();
376     return code;
377 }
378
379 int
380 afs_vop_read(ap)
381      struct vop_read_args       /* {
382                                  * struct vnode *a_vp;
383                                  * struct uio *a_uio;
384                                  * int a_ioflag;
385                                  * struct ucred *a_cred;
386                                  * 
387                                  * } */ *ap;
388 {
389     int code;
390     struct vcache *avc = VTOAFS(ap->a_vp);
391     AFS_GLOCK();
392     afs_BozonLock(&avc->pvnLock, avc);
393     osi_FlushPages(avc, ap->a_cred);    /* hold bozon lock, but not basic vnode lock */
394     code = afs_read(avc, ap->a_uio, ap->a_cred, 0, 0, 0);
395     afs_BozonUnlock(&avc->pvnLock, avc);
396     AFS_GUNLOCK();
397     return code;
398 }
399
400 int
401 afs_vop_getpages(ap)
402      struct vop_getpages_args   /* {
403                                  * struct vnode *a_vp;
404                                  * vm_page_t *a_m;
405                                  * int a_count;
406                                  * int a_reqpage;
407                                  * vm_oofset_t a_offset;
408                                  * } */ *ap;
409 {
410     int code;
411     int i, nextoff, size, toff, npages;
412     struct uio uio;
413     struct iovec iov;
414     struct buf *bp;
415     vm_offset_t kva;
416     struct vcache *avc = VTOAFS(ap->a_vp);
417
418     if (avc->v.v_object == NULL) {
419         printf("afs_getpages: called with non-merged cache vnode??\n");
420         return VM_PAGER_ERROR;
421     }
422     npages = btoc(ap->a_count);
423     /*
424      * If the requested page is partially valid, just return it and
425      * allow the pager to zero-out the blanks.  Partially valid pages
426      * can only occur at the file EOF.
427      */
428
429     {
430         vm_page_t m = ap->a_m[ap->a_reqpage];
431
432         if (m->valid != 0) {
433             /* handled by vm_fault now        */
434             /* vm_page_zero_invalid(m, TRUE); */
435             for (i = 0; i < npages; ++i) {
436                 if (i != ap->a_reqpage)
437                     vm_page_free(ap->a_m[i]);
438             }
439             return (0);
440         }
441     }
442     bp = getpbuf(&afs_pbuf_freecnt);
443     kva = (vm_offset_t) bp->b_data;
444     pmap_qenter(kva, ap->a_m, npages);
445     iov.iov_base = (caddr_t) kva;
446     iov.iov_len = ap->a_count;
447     uio.uio_iov = &iov;
448     uio.uio_iovcnt = 1;
449     uio.uio_offset = IDX_TO_OFF(ap->a_m[0]->pindex);
450     uio.uio_resid = ap->a_count;
451     uio.uio_segflg = UIO_SYSSPACE;
452     uio.uio_rw = UIO_READ;
453 #ifdef AFS_FBSD50_ENV
454     uio.uio_td = curthread;
455 #else
456     uio.uio_procp = curproc;
457 #endif
458     AFS_GLOCK();
459     afs_BozonLock(&avc->pvnLock, avc);
460     osi_FlushPages(avc, osi_curcred()); /* hold bozon lock, but not basic vnode lock */
461     code = afs_read(avc, &uio, osi_curcred(), 0, 0, 0);
462     afs_BozonUnlock(&avc->pvnLock, avc);
463     AFS_GUNLOCK();
464     pmap_qremove(kva, npages);
465
466     relpbuf(bp, &afs_pbuf_freecnt);
467     if (code && (uio.uio_resid == ap->a_count)) {
468         for (i = 0; i < npages; ++i) {
469             if (i != ap->a_reqpage)
470                 vm_page_free(ap->a_m[i]);
471         }
472         return VM_PAGER_ERROR;
473     }
474     size = ap->a_count - uio.uio_resid;
475     for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
476         vm_page_t m;
477         nextoff = toff + PAGE_SIZE;
478         m = ap->a_m[i];
479
480         m->flags &= ~PG_ZERO;
481
482         if (nextoff <= size) {
483             /*
484              * Read operation filled an entire page
485              */
486             m->valid = VM_PAGE_BITS_ALL;
487             vm_page_undirty(m);
488         } else if (size > toff) {
489             /*
490              * Read operation filled a partial page.
491              */
492             m->valid = 0;
493             vm_page_set_validclean(m, 0, size - toff);
494             /* handled by vm_fault now        */
495             /* vm_page_zero_invalid(m, TRUE); */
496         }
497
498         if (i != ap->a_reqpage) {
499             /*
500              * Whether or not to leave the page activated is up in
501              * the air, but we should put the page on a page queue
502              * somewhere (it already is in the object).  Result:
503              * It appears that emperical results show that
504              * deactivating pages is best.
505              */
506
507             /*
508              * Just in case someone was asking for this page we
509              * now tell them that it is ok to use.
510              */
511             if (!code) {
512                 if (m->flags & PG_WANTED)
513                     vm_page_activate(m);
514                 else
515                     vm_page_deactivate(m);
516                 vm_page_wakeup(m);
517             } else {
518                 vm_page_free(m);
519             }
520         }
521     }
522     return 0;
523 }
524
525 int
526 afs_vop_write(ap)
527      struct vop_write_args      /* {
528                                  * struct vnode *a_vp;
529                                  * struct uio *a_uio;
530                                  * int a_ioflag;
531                                  * struct ucred *a_cred;
532                                  * } */ *ap;
533 {
534     int code;
535     struct vcache *avc = VTOAFS(ap->a_vp);
536     AFS_GLOCK();
537     afs_BozonLock(&avc->pvnLock, avc);
538     osi_FlushPages(avc, ap->a_cred);    /* hold bozon lock, but not basic vnode lock */
539     code =
540         afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
541     afs_BozonUnlock(&avc->pvnLock, avc);
542     AFS_GUNLOCK();
543     return code;
544 }
545
546 int
547 afs_vop_putpages(ap)
548      struct vop_putpages_args   /* {
549                                  * struct vnode *a_vp;
550                                  * vm_page_t *a_m;
551                                  * int a_count;
552                                  * int a_sync;
553                                  * int *a_rtvals;
554                                  * vm_oofset_t a_offset;
555                                  * } */ *ap;
556 {
557     int code;
558     int i, size, npages, sync;
559     struct uio uio;
560     struct iovec iov;
561     struct buf *bp;
562     vm_offset_t kva;
563     struct vcache *avc = VTOAFS(ap->a_vp);
564
565     if (avc->v.v_object == NULL) {
566         printf("afs_putpages: called with non-merged cache vnode??\n");
567         return VM_PAGER_ERROR;
568     }
569     if (vType(avc) != VREG) {
570         printf("afs_putpages: not VREG");
571         return VM_PAGER_ERROR;
572     }
573     npages = btoc(ap->a_count);
574     for (i = 0; i < npages; i++)
575         ap->a_rtvals[i] = VM_PAGER_AGAIN;
576     bp = getpbuf(&afs_pbuf_freecnt);
577     kva = (vm_offset_t) bp->b_data;
578     pmap_qenter(kva, ap->a_m, npages);
579     iov.iov_base = (caddr_t) kva;
580     iov.iov_len = ap->a_count;
581     uio.uio_iov = &iov;
582     uio.uio_iovcnt = 1;
583     uio.uio_offset = IDX_TO_OFF(ap->a_m[0]->pindex);
584     uio.uio_resid = ap->a_count;
585     uio.uio_segflg = UIO_SYSSPACE;
586     uio.uio_rw = UIO_WRITE;
587 #ifdef AFS_FBSD50_ENV
588     uio.uio_td = curthread;
589 #else
590     uio.uio_procp = curproc;
591 #endif
592     sync = IO_VMIO;
593     if (ap->a_sync & VM_PAGER_PUT_SYNC)
594         sync |= IO_SYNC;
595     /*if (ap->a_sync & VM_PAGER_PUT_INVAL)
596      * sync |= IO_INVAL; */
597
598     AFS_GLOCK();
599     afs_BozonLock(&avc->pvnLock, avc);
600     code = afs_write(avc, &uio, sync, osi_curcred(), 0);
601     afs_BozonUnlock(&avc->pvnLock, avc);
602     AFS_GUNLOCK();
603     pmap_qremove(kva, npages);
604
605     relpbuf(bp, &afs_pbuf_freecnt);
606     if (!code) {
607         size = ap->a_count - uio.uio_resid;
608         for (i = 0; i < round_page(size) / PAGE_SIZE; i++) {
609             ap->a_rtvals[i] = VM_PAGER_OK;
610             ap->a_m[i]->dirty = 0;
611         }
612         return VM_PAGER_ERROR;
613     }
614     return ap->a_rtvals[0];
615 }
616
617 int
618 afs_vop_ioctl(ap)
619      struct vop_ioctl_args      /* {
620                                  * struct vnode *a_vp;
621                                  * int  a_command;
622                                  * caddr_t  a_data;
623                                  * int  a_fflag;
624                                  * struct ucred *a_cred;
625                                  * struct proc *a_p;
626                                  * } */ *ap;
627 {
628     struct vcache *tvc = VTOAFS(ap->a_vp);
629     int error = 0;
630
631     /* in case we ever get in here... */
632
633     AFS_STATCNT(afs_ioctl);
634     if (((ap->a_command >> 8) & 0xff) == 'V') {
635         /* This is a VICEIOCTL call */
636         AFS_GLOCK();
637         error = HandleIoctl(tvc, NULL /*Not used */ ,
638                             ap->a_command, ap->a_data);
639         AFS_GUNLOCK();
640         return (error);
641     } else {
642         /* No-op call; just return. */
643         return (ENOTTY);
644     }
645 }
646
647 /* ARGSUSED */
648 int
649 afs_vop_poll(ap)
650      struct vop_poll_args       /* {
651                                  * struct vnode *a_vp;
652                                  * int  a_events;
653                                  * struct ucred *a_cred;
654                                  * struct proc *a_p;
655                                  * } */ *ap;
656 {
657     /*
658      * We should really check to see if I/O is possible.
659      */
660     return (1);
661 }
662
663 /*
664  * Mmap a file
665  *
666  * NB Currently unsupported.
667  */
668 /* ARGSUSED */
669 int
670 afs_vop_mmap(ap)
671      struct vop_mmap_args       /* {
672                                  * struct vnode *a_vp;
673                                  * int  a_fflags;
674                                  * struct ucred *a_cred;
675                                  * struct proc *a_p;
676                                  * } */ *ap;
677 {
678     return (EINVAL);
679 }
680
681 int
682 afs_vop_fsync(ap)
683      struct vop_fsync_args      /* {
684                                  * struct vnode *a_vp;
685                                  * struct ucred *a_cred;
686                                  * int a_waitfor;
687                                  * struct proc *a_p;
688                                  * } */ *ap;
689 {
690     int error;
691     register struct vnode *vp = ap->a_vp;
692
693     AFS_GLOCK();
694     /*vflushbuf(vp, wait); */
695     if (ap->a_cred)
696         error = afs_fsync(VTOAFS(vp), ap->a_cred);
697     else
698         error = afs_fsync(VTOAFS(vp), afs_osi_credp);
699     AFS_GUNLOCK();
700     return error;
701 }
702
703 int
704 afs_vop_remove(ap)
705      struct vop_remove_args     /* {
706                                  * struct vnode *a_dvp;
707                                  * struct vnode *a_vp;
708                                  * struct componentname *a_cnp;
709                                  * } */ *ap;
710 {
711     int error = 0;
712     register struct vnode *vp = ap->a_vp;
713     register struct vnode *dvp = ap->a_dvp;
714
715     GETNAME();
716     AFS_GLOCK();
717     error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
718     AFS_GUNLOCK();
719     cache_purge(vp);
720     DROPNAME();
721     return error;
722 }
723
724 int
725 afs_vop_link(ap)
726      struct vop_link_args       /* {
727                                  * struct vnode *a_vp;
728                                  * struct vnode *a_tdvp;
729                                  * struct componentname *a_cnp;
730                                  * } */ *ap;
731 {
732     int error = 0;
733     register struct vnode *dvp = ap->a_tdvp;
734     register struct vnode *vp = ap->a_vp;
735 #ifdef AFS_FBSD50_ENV
736     struct thread *p = ap->a_cnp->cn_thread;
737 #else
738     struct proc *p = ap->a_cnp->cn_proc;
739 #endif
740
741     GETNAME();
742     if (dvp->v_mount != vp->v_mount) {
743         error = EXDEV;
744         goto out;
745     }
746     if (vp->v_type == VDIR) {
747         error = EISDIR;
748         goto out;
749     }
750     if ((error = vn_lock(vp, LK_EXCLUSIVE, p)) != 0) {
751         goto out;
752     }
753     AFS_GLOCK();
754     error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
755     AFS_GUNLOCK();
756     if (dvp != vp)
757         VOP_UNLOCK(vp, 0, p);
758   out:
759     DROPNAME();
760     return error;
761 }
762
763 int
764 afs_vop_rename(ap)
765      struct vop_rename_args     /* {
766                                  * struct vnode *a_fdvp;
767                                  * struct vnode *a_fvp;
768                                  * struct componentname *a_fcnp;
769                                  * struct vnode *a_tdvp;
770                                  * struct vnode *a_tvp;
771                                  * struct componentname *a_tcnp;
772                                  * } */ *ap;
773 {
774     int error = 0;
775     struct componentname *fcnp = ap->a_fcnp;
776     char *fname;
777     struct componentname *tcnp = ap->a_tcnp;
778     char *tname;
779     struct vnode *tvp = ap->a_tvp;
780     register struct vnode *tdvp = ap->a_tdvp;
781     struct vnode *fvp = ap->a_fvp;
782     register struct vnode *fdvp = ap->a_fdvp;
783 #ifdef AFS_FBSD50_ENV
784     struct thread *p = fcnp->cn_thread;
785 #else
786     struct proc *p = fcnp->cn_proc;
787 #endif
788
789     /*
790      * Check for cross-device rename.
791      */
792     if ((fvp->v_mount != tdvp->v_mount)
793         || (tvp && (fvp->v_mount != tvp->v_mount))) {
794         error = EXDEV;
795       abortit:
796         if (tdvp == tvp)
797             vrele(tdvp);
798         else
799             vput(tdvp);
800         if (tvp)
801             vput(tvp);
802         vrele(fdvp);
803         vrele(fvp);
804         return (error);
805     }
806     /*
807      * if fvp == tvp, we're just removing one name of a pair of
808      * directory entries for the same element.  convert call into rename.
809      ( (pinched from FreeBSD 4.4's ufs_rename())
810      
811      */
812     if (fvp == tvp) {
813         if (fvp->v_type == VDIR) {
814             error = EINVAL;
815             goto abortit;
816         }
817
818         /* Release destination completely. */
819         vput(tdvp);
820         vput(tvp);
821
822         /* Delete source. */
823         vrele(fdvp);
824         vrele(fvp);
825         fcnp->cn_flags &= ~MODMASK;
826         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
827         if ((fcnp->cn_flags & SAVESTART) == 0)
828             panic("afs_rename: lost from startdir");
829         fcnp->cn_nameiop = DELETE;
830         VREF(fdvp);
831         error = relookup(fdvp, &fvp, fcnp);
832         if (error == 0)
833             vrele(fdvp);
834         if (fvp == NULL) {
835             return (ENOENT);
836         }
837
838         error = VOP_REMOVE(fdvp, fvp, fcnp);
839         if (fdvp == fvp)
840             vrele(fdvp);
841         else
842             vput(fdvp);
843         vput(fvp);
844         return (error);
845     }
846     if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
847         goto abortit;
848
849     MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
850     memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
851     fname[fcnp->cn_namelen] = '\0';
852     MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
853     memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
854     tname[tcnp->cn_namelen] = '\0';
855
856
857     AFS_GLOCK();
858     /* XXX use "from" or "to" creds? NFS uses "to" creds */
859     error =
860         afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
861     AFS_GUNLOCK();
862
863     FREE(fname, M_TEMP);
864     FREE(tname, M_TEMP);
865     if (tdvp == tvp)
866         vrele(tdvp);
867     else
868         vput(tdvp);
869     if (tvp)
870         vput(tvp);
871     vrele(fdvp);
872     vput(fvp);
873     return error;
874 }
875
876 int
877 afs_vop_mkdir(ap)
878      struct vop_mkdir_args      /* {
879                                  * struct vnode *a_dvp;
880                                  * struct vnode **a_vpp;
881                                  * struct componentname *a_cnp;
882                                  * struct vattr *a_vap;
883                                  * } */ *ap;
884 {
885     register struct vnode *dvp = ap->a_dvp;
886     register struct vattr *vap = ap->a_vap;
887     int error = 0;
888     struct vcache *vcp;
889 #ifdef AFS_FBSD50_ENV
890     struct thread *p = ap->a_cnp->cn_thread;
891 #else
892     struct proc *p = ap->a_cnp->cn_proc;
893 #endif
894
895     GETNAME();
896 #ifdef DIAGNOSTIC
897     if ((cnp->cn_flags & HASBUF) == 0)
898         panic("afs_vop_mkdir: no name");
899 #endif
900     AFS_GLOCK();
901     error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
902     AFS_GUNLOCK();
903     if (error) {
904         vput(dvp);
905         DROPNAME();
906         return (error);
907     }
908     if (vcp) {
909         *ap->a_vpp = AFSTOV(vcp);
910         vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p);
911     } else
912         *ap->a_vpp = 0;
913     DROPNAME();
914     return error;
915 }
916
917 int
918 afs_vop_rmdir(ap)
919      struct vop_rmdir_args      /* {
920                                  * struct vnode *a_dvp;
921                                  * struct vnode *a_vp;
922                                  * struct componentname *a_cnp;
923                                  * } */ *ap;
924 {
925     int error = 0;
926     register struct vnode *dvp = ap->a_dvp;
927
928     GETNAME();
929     AFS_GLOCK();
930     error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
931     AFS_GUNLOCK();
932     DROPNAME();
933     return error;
934 }
935
936 int
937 afs_vop_symlink(ap)
938      struct vop_symlink_args    /* {
939                                  * struct vnode *a_dvp;
940                                  * struct vnode **a_vpp;
941                                  * struct componentname *a_cnp;
942                                  * struct vattr *a_vap;
943                                  * char *a_target;
944                                  * } */ *ap;
945 {
946     register struct vnode *dvp = ap->a_dvp;
947     int error = 0;
948     /* NFS ignores a_vpp; so do we. */
949
950     GETNAME();
951     AFS_GLOCK();
952     error =
953         afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
954     AFS_GUNLOCK();
955     DROPNAME();
956     return error;
957 }
958
959 int
960 afs_vop_readdir(ap)
961      struct vop_readdir_args    /* {
962                                  * struct vnode *a_vp;
963                                  * struct uio *a_uio;
964                                  * struct ucred *a_cred;
965                                  * int *a_eofflag;
966                                  * u_long *a_cookies;
967                                  * int ncookies;
968                                  * } */ *ap;
969 {
970     int error;
971     off_t off;
972 /*    printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
973            ap->a_ncookies); */
974     off = ap->a_uio->uio_offset;
975     AFS_GLOCK();
976     error =
977         afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
978     AFS_GUNLOCK();
979     if (!error && ap->a_ncookies != NULL) {
980         struct uio *uio = ap->a_uio;
981         const struct dirent *dp, *dp_start, *dp_end;
982         int ncookies;
983         u_long *cookies, *cookiep;
984
985         if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
986             panic("afs_readdir: burned cookies");
987         dp = (const struct dirent *)
988             ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
989
990         dp_end = (const struct dirent *)uio->uio_iov->iov_base;
991         for (dp_start = dp, ncookies = 0; dp < dp_end;
992              dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
993             ncookies++;
994
995         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
996                M_WAITOK);
997         for (dp = dp_start, cookiep = cookies; dp < dp_end;
998              dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
999             off += dp->d_reclen;
1000             *cookiep++ = off;
1001         }
1002         *ap->a_cookies = cookies;
1003         *ap->a_ncookies = ncookies;
1004     }
1005
1006     return error;
1007 }
1008
1009 int
1010 afs_vop_readlink(ap)
1011      struct vop_readlink_args   /* {
1012                                  * struct vnode *a_vp;
1013                                  * struct uio *a_uio;
1014                                  * struct ucred *a_cred;
1015                                  * } */ *ap;
1016 {
1017     int error;
1018 /*    printf("readlink %x\n", ap->a_vp);*/
1019     AFS_GLOCK();
1020     error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
1021     AFS_GUNLOCK();
1022     return error;
1023 }
1024
1025 extern int prtactive;
1026
1027 int
1028 afs_vop_inactive(ap)
1029      struct vop_inactive_args   /* {
1030                                  * struct vnode *a_vp;
1031                                  * struct proc *a_p;
1032                                  * } */ *ap;
1033 {
1034     register struct vnode *vp = ap->a_vp;
1035
1036     if (prtactive && vp->v_usecount != 0)
1037         vprint("afs_vop_inactive(): pushing active", vp);
1038
1039     AFS_GLOCK();
1040     afs_InactiveVCache(VTOAFS(vp), 0);  /* decrs ref counts */
1041     AFS_GUNLOCK();
1042     VOP_UNLOCK(vp, 0, ap->a_p);
1043     return 0;
1044 }
1045
1046 int
1047 afs_vop_reclaim(ap)
1048      struct vop_reclaim_args    /* {
1049                                  * struct vnode *a_vp;
1050                                  * } */ *ap;
1051 {
1052 #ifdef AFS_DO_FLUSH_IN_RECLAIM
1053     int error, sl;
1054 #endif
1055     register struct vnode *vp = ap->a_vp;
1056
1057     cache_purge(vp);            /* just in case... */
1058
1059 #ifdef AFS_DO_FLUSH_IN_RECLAIM
1060     AFS_GLOCK();
1061     error = afs_FlushVCache(VTOAFS(vp), &sl);   /* tosses our stuff from vnode */
1062     AFS_GUNLOCK();
1063     ubc_unlink(vp);
1064     if (!error && vp->v_data)
1065         panic("afs_reclaim: vnode not cleaned");
1066     return error;
1067 #else
1068     if (vp->v_usecount == 2) {
1069         vprint("reclaim count==2", vp);
1070     } else if (vp->v_usecount == 1) {
1071         vprint("reclaim count==1", vp);
1072     } else
1073         vprint("reclaim bad count", vp);
1074
1075     return 0;
1076 #endif
1077 }
1078
1079 int
1080 afs_vop_lock(ap)
1081      struct vop_lock_args       /* {
1082                                  * struct vnode *a_vp;
1083                                  * } */ *ap;
1084 {
1085     register struct vnode *vp = ap->a_vp;
1086     register struct vcache *avc = VTOAFS(vp);
1087
1088 #ifdef AFS_FBSD50_ENV
1089     if (!strcmp(vp->v_tag, "none"))
1090 #else
1091     if (vp->v_tag == VT_NON)
1092 #endif
1093         return (ENOENT);
1094     return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1095 }
1096
1097 int
1098 afs_vop_unlock(ap)
1099      struct vop_unlock_args     /* {
1100                                  * struct vnode *a_vp;
1101                                  * } */ *ap;
1102 {
1103     struct vnode *vp = ap->a_vp;
1104     struct vcache *avc = VTOAFS(vp);
1105     return (lockmgr
1106             (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1107              ap->a_p));
1108
1109 }
1110
1111 int
1112 afs_vop_bmap(ap)
1113      struct vop_bmap_args       /* {
1114                                  * struct vnode *a_vp;
1115                                  * daddr_t  a_bn;
1116                                  * struct vnode **a_vpp;
1117                                  * daddr_t *a_bnp;
1118                                  * int *a_runp;
1119                                  * int *a_runb;
1120                                  * } */ *ap;
1121 {
1122     if (ap->a_bnp) {
1123         *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
1124     }
1125     if (ap->a_vpp) {
1126         *ap->a_vpp = ap->a_vp;
1127     }
1128     if (ap->a_runp != NULL)
1129         *ap->a_runp = 0;
1130     if (ap->a_runb != NULL)
1131         *ap->a_runb = 0;
1132
1133     return 0;
1134 }
1135
1136 int
1137 afs_vop_strategy(ap)
1138      struct vop_strategy_args   /* {
1139                                  * struct buf *a_bp;
1140                                  * } */ *ap;
1141 {
1142     int error;
1143     AFS_GLOCK();
1144     error = afs_ustrategy(ap->a_bp);
1145     AFS_GUNLOCK();
1146     return error;
1147 }
1148
1149 int
1150 afs_vop_print(ap)
1151      struct vop_print_args      /* {
1152                                  * struct vnode *a_vp;
1153                                  * } */ *ap;
1154 {
1155     register struct vnode *vp = ap->a_vp;
1156     register struct vcache *vc = VTOAFS(ap->a_vp);
1157     int s = vc->states;
1158
1159 #ifdef AFS_FBSD50_ENV
1160     printf("tag %s, fid: %d.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1161            (int)vc->fid.Cell, (u_int) vc->fid.Fid.Volume,
1162            (u_int) vc->fid.Fid.Vnode, (u_int) vc->fid.Fid.Unique, vc->opens,
1163            vc->execsOrWriters);
1164 #else
1165     printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1166            vc->fid.Cell, (u_int) vc->fid.Fid.Volume,
1167            (u_int) vc->fid.Fid.Vnode, (u_int) vc->fid.Fid.Unique, vc->opens,
1168            vc->execsOrWriters);
1169 #endif
1170     printf("\n  states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1171            (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1172            (s & CMAPPED) ? " mapped" : "",
1173            (s & CVFlushed) ? " flush in progress" : "");
1174     printf("\n");
1175     return 0;
1176 }
1177
1178 int
1179 afs_vop_islocked(ap)
1180      struct vop_islocked_args   /* {
1181                                  * struct vnode *a_vp;
1182                                  * } */ *ap;
1183 {
1184     struct vcache *vc = VTOAFS(ap->a_vp);
1185     return lockstatus(&vc->rwlock, ap->a_p);
1186 }
1187
1188 /*
1189  * Advisory record locking support (fcntl() POSIX style)
1190  */
1191 int
1192 afs_vop_advlock(ap)
1193      struct vop_advlock_args    /* {
1194                                  * struct vnode *a_vp;
1195                                  * caddr_t  a_id;
1196                                  * int  a_op;
1197                                  * struct flock *a_fl;
1198                                  * int  a_flags;
1199                                  * } */ *ap;
1200 {
1201     int error;
1202     struct ucred cr = *osi_curcred();
1203
1204     AFS_GLOCK();
1205     error =
1206         afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, &cr, (int)ap->a_id);
1207     AFS_GUNLOCK();
1208     return error;
1209 }