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