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