Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / afs / DUX / osi_vnodeops.c
1 /* Copyright (C) 1998 Transarc Corporation - All rights reserved. */
2 /*
3  * vnodeops structure and Digital Unix specific ops and support routines.
4  */
5
6 #include "../afs/param.h"       /* Should be always first */
7
8 #include "../afs/sysincludes.h" /* Standard vendor system headers */
9 #include "../afs/afsincludes.h" /* Afs-based standard headers */
10 #include "../afs/afs_stats.h" /* statistics */
11 #include <vm/vm_mmap.h>
12 #include <vm/vm_ubc.h>
13 #include "../afs/afs_cbqueue.h"
14 #include "../afs/nfsclient.h"
15 #include "../afs/afs_osidnlc.h"
16
17
18 extern int afs_lookup(), afs_create(), afs_noop(), afs_open(), afs_close();
19 extern int afs_access(), afs_getattr(), afs_setattr(), afs_badop();
20 extern int afs_fsync(), afs_seek(), afs_remove(), afs_link(), afs_rename();
21 extern int afs_mkdir(), afs_rmdir(), afs_symlink(), afs_readdir();
22 extern int afs_readlink(), afs_lockctl();
23 extern int vn_pathconf_default(), seltrue();
24
25 int mp_afs_lookup(), mp_afs_create(), mp_afs_open();
26 int mp_afs_access(), mp_afs_getattr(), mp_afs_setattr(), mp_afs_ubcrdwr();
27 int mp_afs_ubcrdwr(), mp_afs_mmap();
28 int mp_afs_fsync(), mp_afs_seek(), mp_afs_remove(), mp_afs_link();
29 int mp_afs_rename(), mp_afs_mkdir(), mp_afs_rmdir(), mp_afs_symlink();
30 int mp_afs_readdir(), mp_afs_readlink(), mp_afs_abortop(), mp_afs_inactive();
31 int mp_afs_reclaim(), mp_afs_bmap(), mp_afs_strategy(), mp_afs_print();
32 int mp_afs_page_read(), mp_afs_page_write(), mp_afs_swap(), mp_afs_bread();
33 int mp_afs_brelse(), mp_afs_lockctl(), mp_afs_syncdata(), mp_afs_close();
34 int mp_afs_closex();
35
36 /* AFS vnodeops */
37 struct vnodeops Afs_vnodeops = {
38         mp_afs_lookup,
39         mp_afs_create,
40         afs_noop,       /* vn_mknod */
41         mp_afs_open,
42         mp_afs_close,
43         mp_afs_access,
44         mp_afs_getattr,
45         mp_afs_setattr,
46         mp_afs_ubcrdwr,
47         mp_afs_ubcrdwr,
48         afs_badop,      /* vn_ioctl */
49         seltrue,        /* vn_select */
50         mp_afs_mmap,
51         mp_afs_fsync,
52         mp_afs_seek,
53         mp_afs_remove,
54         mp_afs_link,
55         mp_afs_rename,
56         mp_afs_mkdir,
57         mp_afs_rmdir,
58         mp_afs_symlink,
59         mp_afs_readdir,
60         mp_afs_readlink,
61         mp_afs_abortop,
62         mp_afs_inactive,
63         mp_afs_reclaim,
64         mp_afs_bmap,
65         mp_afs_strategy,
66         mp_afs_print,
67         mp_afs_page_read,
68         mp_afs_page_write,
69         mp_afs_swap,
70         mp_afs_bread,
71         mp_afs_brelse,
72         mp_afs_lockctl,
73         mp_afs_syncdata,
74         afs_noop,       /* Lock */
75         afs_noop,       /* unLock */
76         afs_noop,       /* get ext attrs */
77         afs_noop,       /* set ext attrs */
78         afs_noop,       /* del ext attrs */
79         vn_pathconf_default,
80 };
81 struct vnodeops *afs_ops = &Afs_vnodeops;
82
83 /* vnode file operations, and our own */
84 extern int vn_read();
85 extern int vn_write();
86 extern int vn_ioctl();
87 extern int vn_select();
88 extern int afs_closex();
89
90 struct fileops afs_fileops = {
91     vn_read,
92     vn_write,
93     vn_ioctl,
94     vn_select,
95     mp_afs_closex,
96 };
97
98 mp_afs_lookup(adp, ndp)
99     struct vcache *adp;
100     struct nameidata *ndp;
101 {
102     int code;
103     AFS_GLOCK();
104     code = afs_lookup(adp, ndp);
105     AFS_GUNLOCK();
106     return code;
107 }
108
109 mp_afs_create(ndp, attrs)
110     struct nameidata *ndp;
111     struct vattr *attrs;
112 {
113     int code;
114     AFS_GLOCK();
115     code = afs_create(ndp, attrs);
116     AFS_GUNLOCK();
117     return code;
118 }
119
120 mp_afs_open(avcp, aflags, acred)
121     struct vcache **avcp;
122     afs_int32 aflags;
123     struct AFS_UCRED *acred;
124 {
125     int code;
126     AFS_GLOCK();
127     code = afs_open(avcp, aflags, acred);
128     AFS_GUNLOCK();
129     return code;
130 }
131
132 mp_afs_access(avc, amode, acred)
133     struct vcache *avc;
134     afs_int32 amode;
135     struct AFS_UCRED *acred;
136 {
137     int code;
138     AFS_GLOCK();
139     code = afs_access(avc, amode, acred);
140     AFS_GUNLOCK();
141     return code;
142 }
143
144 mp_afs_close(avc, flags, cred)
145     struct vnode *avc;
146     int flags;
147     struct ucred *cred;
148 {
149     int code;
150     AFS_GLOCK();
151     code = afs_close(avc, flags, cred);
152     AFS_GUNLOCK();
153     return code;
154 }
155
156 mp_afs_getattr(avc, attrs, acred)
157     struct vcache *avc;
158     struct vattr *attrs;
159     struct AFS_UCRED *acred;
160 {
161     int code;
162     AFS_GLOCK();
163     code = afs_getattr(avc, attrs, acred);
164     AFS_GUNLOCK();
165     return code;
166 }
167
168 mp_afs_setattr(avc, attrs, acred)
169     struct vcache *avc;
170     struct vattr *attrs;
171     struct AFS_UCRED *acred;
172 {
173     int code;
174     AFS_GLOCK();
175     code = afs_setattr(avc, attrs, acred);
176     AFS_GUNLOCK();
177     return code;
178 }
179
180 mp_afs_fsync(avc, fflags, acred, waitfor)
181     struct vcache *avc;
182     int fflags;
183     struct AFS_UCRED *acred;
184     int waitfor;
185 {
186     int code;
187     AFS_GLOCK();
188     code = afs_fsync(avc, fflags, acred, waitfor);
189     AFS_GUNLOCK();
190     return code;
191 }
192
193 mp_afs_remove(ndp)
194     struct nameidata *ndp;
195 {
196     int code;
197     AFS_GLOCK();
198     code = afs_remove(ndp);
199     AFS_GUNLOCK();
200     return code;
201 }
202
203 mp_afs_link(avc, ndp)
204     struct vcache *avc;
205     struct nameidata *ndp;
206 {
207     int code;
208     AFS_GLOCK();
209     code = afs_link(avc, ndp);
210     AFS_GUNLOCK();
211     return code;
212 }
213
214 mp_afs_rename(fndp, tndp)
215     struct nameidata *fndp, *tndp;
216 {
217     int code;
218     AFS_GLOCK();
219     code = afs_rename(fndp, tndp);
220     AFS_GUNLOCK();
221     return code;
222 }
223
224 mp_afs_mkdir(ndp, attrs)
225     struct nameidata *ndp;
226     struct vattr *attrs;
227 {
228     int code;
229     AFS_GLOCK();
230     code = afs_mkdir(ndp, attrs);
231     AFS_GUNLOCK();
232     return code;
233 }
234
235 mp_afs_rmdir(ndp)
236     struct nameidata *ndp;
237 {
238     int code;
239     AFS_GLOCK();
240     code = afs_rmdir(ndp);
241     AFS_GUNLOCK();
242     return code;
243 }
244
245 mp_afs_symlink(ndp, attrs, atargetName)
246     struct nameidata *ndp;
247     struct vattr *attrs;
248     register char *atargetName;
249 {
250     int code;
251     AFS_GLOCK();
252     code = afs_symlink(ndp, attrs, atargetName);
253     AFS_GUNLOCK();
254     return code;
255 }
256
257 mp_afs_readdir(avc, auio, acred, eofp)
258     struct vcache *avc;
259     struct uio *auio;
260     struct AFS_UCRED *acred;
261     int *eofp;
262 {
263     int code;
264     AFS_GLOCK();
265     code = afs_readdir(avc, auio, acred, eofp);
266     AFS_GUNLOCK();
267     return code;
268 }
269
270 mp_afs_readlink(avc, auio, acred)
271     struct vcache *avc;
272     struct uio *auio;
273     struct AFS_UCRED *acred;
274 {
275     int code;
276     AFS_GLOCK();
277     code = afs_readlink(avc, auio, acred);
278     AFS_GUNLOCK();
279     return code;
280 }
281
282 mp_afs_lockctl(avc, af, flag, acred, clid, offset)
283     struct vcache *avc;
284     struct eflock *af;
285     struct AFS_UCRED *acred;
286     int flag;
287     pid_t clid;
288     off_t offset;
289 {
290     int code;
291     AFS_GLOCK();
292     code = afs_lockctl(avc, af, flag, acred, clid, offset);
293     AFS_GUNLOCK();
294     return code;
295 }
296
297 mp_afs_closex(afd)
298     struct file *afd;
299 {
300     int code;
301     AFS_GLOCK();
302     code = afs_closex(afd);
303     AFS_GUNLOCK();
304     return code;
305 }
306
307 mp_afs_seek(avc, oldoff, newoff, cred)
308     struct vcache *avc;
309     off_t oldoff, newoff;
310     struct ucred *cred;
311 {
312     if ((int) newoff < 0)
313         return(EINVAL);
314     else
315         return(0);
316 }
317
318 mp_afs_abortop(ndp)
319     struct nameidata *ndp;
320 {
321     return(0);
322 }
323
324 mp_afs_inactive(avc, acred)
325     register struct vcache *avc;
326     struct AFS_UCRED *acred;
327 {
328     AFS_GLOCK();
329     afs_InactiveVCache(avc, acred);
330     AFS_GUNLOCK();
331 }
332
333
334 mp_afs_reclaim(avc)
335     struct vcache *avc;
336 {
337     return(0);
338 }
339
340 mp_afs_print(avc)
341     struct vcache *avc;
342 {
343     return(0);
344 }
345
346 mp_afs_page_read(avc, uio, acred)
347     struct vcache *avc;
348     struct uio *uio;
349     struct ucred *acred;
350 {
351     int error;
352     struct vrequest treq;
353
354     AFS_GLOCK();
355     error = afs_rdwr(avc, uio, UIO_READ, 0, acred);
356     afs_Trace3(afs_iclSetp, CM_TRACE_PAGE_READ, ICL_TYPE_POINTER, avc,
357                ICL_TYPE_INT32, error,  ICL_TYPE_INT32, avc->states);
358     if (error) {
359         error = EIO;
360     } else if ((avc->states & CWired) == 0) {
361         afs_InitReq(&treq, acred);
362         ObtainWriteLock(&avc->lock,161);
363         afs_Wire(avc, &treq);
364         ReleaseWriteLock(&avc->lock);
365     }
366     AFS_GUNLOCK();
367     return(error);
368 }
369
370
371 mp_afs_page_write(avc, uio, acred, pager, offset)
372     struct vcache *avc;
373     struct uio *uio;
374     struct ucred *acred;
375     memory_object_t pager;
376     vm_offset_t     offset;
377 {
378     int error;
379
380     AFS_GLOCK();
381     error = afs_rdwr(avc, uio, UIO_WRITE, 0, acred);
382     afs_Trace3(afs_iclSetp, CM_TRACE_PAGE_WRITE, ICL_TYPE_POINTER, avc,
383                ICL_TYPE_INT32, error, ICL_TYPE_INT32, avc->states);
384     if (error) {
385         error = EIO;
386     }
387     AFS_GUNLOCK();
388     return(error);
389 }
390
391
392 int DO_FLUSH=1;
393 mp_afs_ubcrdwr(avc, uio, ioflag, cred)
394     struct vcache *avc;
395     struct uio *uio;
396     int ioflag;
397     struct ucred *cred;
398 {
399     register afs_int32 code;
400     register char *data;
401     afs_int32 fileBase, size, cnt=0;
402     afs_int32 pageBase;
403     register afs_int32 tsize;
404     register afs_int32 pageOffset;
405     int eof;
406     struct vrequest treq;
407     int rw = uio->uio_rw;
408     int rv, flags;
409     int newpage=0;
410     vm_page_t page;
411     afs_int32 save_resid;
412     struct dcache *tdc;
413     int didFakeOpen=0;
414     int counter=0;
415
416     AFS_GLOCK();
417     afs_InitReq(&treq, cred);
418     if (AFS_NFSXLATORREQ(cred) && rw == UIO_READ) {
419         if (!afs_AccessOK(avc, PRSFS_READ, &treq,
420                           CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ))  {
421             AFS_GUNLOCK();
422             return EACCES;
423         }
424     }
425     afs_Trace4(afs_iclSetp, CM_TRACE_VMRW, ICL_TYPE_POINTER, avc,
426                ICL_TYPE_INT32, (rw==UIO_WRITE? 1 : 0),
427                ICL_TYPE_LONG, uio->uio_offset,
428                ICL_TYPE_LONG, uio->uio_resid);
429     code = afs_VerifyVCache(avc, &treq);
430     if (code) {
431         code = afs_CheckCode(code, &treq, 35);
432         AFS_GUNLOCK();
433         return code;
434     }
435     if (vType(avc) != VREG) {
436         AFS_GUNLOCK();
437         return EISDIR;  /* can't read or write other things */
438     }
439     afs_BozonLock(&avc->pvnLock, avc);
440     osi_FlushPages(avc);        /* hold bozon lock, but not basic vnode lock */
441     ObtainWriteLock(&avc->lock,162);
442     /* adjust parameters when appending files */
443     if ((ioflag & IO_APPEND) && uio->uio_rw == UIO_WRITE)
444         uio->uio_offset = avc->m.Length;        /* write at EOF position */
445     if (uio->uio_rw == UIO_WRITE) {
446         avc->states |= CDirty;
447         afs_FakeOpen(avc);
448         didFakeOpen=1;
449         /*
450          * before starting any I/O, we must ensure that the file is big enough
451          * to hold the results (since afs_putpage will be called to force
452          * the I/O.
453          */
454         size = uio->afsio_resid + uio->afsio_offset;    /* new file size */
455         if (size > avc->m.Length) avc->m.Length = size; /* file grew */
456         avc->m.Date = osi_Time();       /* Set file date (for ranlib) */
457         if (uio->afsio_resid > PAGE_SIZE)
458             cnt = uio->afsio_resid / PAGE_SIZE;
459         save_resid = uio->afsio_resid;
460     }
461
462     while (1) {
463         /*
464          * compute the amount of data to move into this block,
465          * based on uio->afsio_resid.
466          */
467         size = uio->afsio_resid;                /* transfer size */
468         fileBase = uio->afsio_offset;           /* start file position */
469         pageBase = fileBase & ~(PAGE_SIZE-1);   /* file position of the page */
470         pageOffset = fileBase & (PAGE_SIZE-1);  /* start offset within page */
471         tsize = PAGE_SIZE-pageOffset;           /* amount left in this page */
472         /*
473          * we'll read tsize bytes,
474          * but first must make sure tsize isn't too big
475          */
476         if (tsize > size) tsize = size; /* don't read past end of request */
477         eof = 0;        /* flag telling us if we hit the EOF on the read */
478         if (uio->uio_rw == UIO_READ) {  /* we're doing a read operation */
479             /* don't read past EOF */
480             if (tsize + fileBase > avc->m.Length) {
481                 tsize = avc->m.Length - fileBase;
482                 eof = 1;        /* we did hit the EOF */
483                 if (tsize < 0) tsize = 0;       /* better safe than sorry */
484             }
485         }
486         if (tsize <= 0) break;  /* nothing to transfer, we're done */
487
488         /* Purge dirty chunks of file if there are too many dirty chunks.
489          * Inside the write loop, we only do this at a chunk boundary.
490          * Clean up partial chunk if necessary at end of loop.
491          */
492         if (uio->uio_rw == UIO_WRITE && counter > 0
493             && AFS_CHUNKOFFSET(fileBase) == 0) {
494             code = afs_DoPartialWrite(avc, &treq);
495             avc->states |= CDirty;
496         }
497
498         if (code) {
499             break;
500         }
501
502         flags = 0;
503         ReleaseWriteLock(&avc->lock);
504         AFS_GUNLOCK();
505         code = ubc_lookup(((struct vnode *)avc)->v_object, pageBase,
506                           PAGE_SIZE, PAGE_SIZE, &page, &flags);
507         AFS_GLOCK();
508         ObtainWriteLock(&avc->lock,163);
509
510         if (code) {
511             break;
512         }
513         if (flags & B_NOCACHE) {
514             /*
515                No page found. We should not read the page in if
516                1. the write starts on a page edge (ie, pageoffset == 0)
517                and either
518                      1. we will fill the page  (ie, size == PAGESIZE), or
519                      2. we are writing past eof
520              */
521             if ((uio->uio_rw == UIO_WRITE) &&
522                 ((pageOffset == 0 && (size == PAGE_SIZE || fileBase >= avc->m.Length)))) {
523                 struct vnode *vp = (struct vnode *)avc;
524                 /* we're doing a write operation past eof; no need to read it */
525                 newpage = 1;
526                 AFS_GUNLOCK();
527                 ubc_page_zero(page, 0, PAGE_SIZE);
528                 ubc_page_release(page, B_DONE);
529                 AFS_GLOCK();
530             } else {
531                 /* page wasn't cached, read it in. */
532                 struct buf *bp;
533
534                 AFS_GUNLOCK();
535                 bp = ubc_bufalloc(page, 1, PAGE_SIZE, 1, B_READ);
536                 AFS_GLOCK();
537                 bp->b_dev = 0;
538                 bp->b_vp = (struct vnode *)avc;
539                 bp->b_blkno = btodb(pageBase);
540                 ReleaseWriteLock(&avc->lock);
541                 code = afs_ustrategy(bp, cred); /* do the I/O */
542                 ObtainWriteLock(&avc->lock,164);
543                 AFS_GUNLOCK();
544                 ubc_sync_iodone(bp);
545                 AFS_GLOCK();
546                 if (code) {
547                     AFS_GUNLOCK();
548                     ubc_page_release(page, 0);
549                     AFS_GLOCK();
550                     break;
551                 }
552             }
553         }
554         AFS_GUNLOCK();
555         ubc_page_wait(page);
556         data = (char *)page->pg_addr; /* DUX 4.0D */
557         if (data == 0)
558             data = (char *)PHYS_TO_KSEG(page->pg_phys_addr);  /* DUX 4.0E */
559         AFS_GLOCK();
560         ReleaseWriteLock(&avc->lock);   /* uiomove may page fault */
561         AFS_GUNLOCK();
562         code = uiomove(data+pageOffset, tsize, uio);
563         ubc_unload(page, pageOffset, page_size);
564         if (uio->uio_rw == UIO_WRITE) {
565                 vm_offset_t toffset;
566
567                 /* Mark the page dirty and release it to avoid a deadlock
568                  * in ubc_dirty_kluster when more than one process writes
569                  * this page at the same time. */
570                 toffset = page->pg_offset;
571                 flags |= B_DIRTY;
572                 ubc_page_release(page, flags);
573
574                 if (cnt > 10) {
575                     vm_page_t pl;
576                     int kpcnt;
577                     struct buf *bp;
578
579                     /* We released the page, so we can get a null page
580                      * list if another thread calls the strategy routine.
581                      */
582                     pl = ubc_dirty_kluster(((struct vnode *)avc)->v_object, 
583                            NULL, toffset, 0, B_WANTED, FALSE, &kpcnt);
584                     if (pl) {
585                         bp = ubc_bufalloc(pl, 1, PAGE_SIZE, 1, B_WRITE);
586                         bp->b_dev = 0;
587                         bp->b_vp = (struct vnode *)avc;
588                         bp->b_blkno = btodb(pageBase);
589                         AFS_GLOCK();
590                         code = afs_ustrategy(bp, cred); /* do the I/O */
591                         AFS_GUNLOCK();
592                         ubc_sync_iodone(bp);
593                         if (code) {
594                             AFS_GLOCK();
595                             ObtainWriteLock(&avc->lock,415);
596                             break;
597                         }
598                     }
599                 }
600         } else {
601             ubc_page_release(page, flags);
602         }
603         AFS_GLOCK();
604         ObtainWriteLock(&avc->lock,165);
605         /*
606          * If reading at a chunk boundary, start prefetch of next chunk.
607          */
608         if (uio->uio_rw == UIO_READ
609             && (counter == 0 || AFS_CHUNKOFFSET(fileBase) == 0)) {
610             tdc = afs_FindDCache(avc, fileBase);
611             if (tdc) {
612                 if (!(tdc->flags & DFNextStarted))
613                     afs_PrefetchChunk(avc, tdc, cred, &treq);
614                 afs_PutDCache(tdc);
615             }
616         }
617         counter++;
618         if (code) break;
619     }
620     if (didFakeOpen)
621         afs_FakeClose(avc, cred);
622     if (uio->uio_rw == UIO_WRITE && code == 0 && (avc->states & CDirty)) {
623         code = afs_DoPartialWrite(avc, &treq);
624     }
625     ReleaseWriteLock(&avc->lock);
626     afs_BozonUnlock(&avc->pvnLock, avc);
627     if (DO_FLUSH || (!newpage && (cnt < 10))) {
628         AFS_GUNLOCK();
629         ubc_flush_dirty(((struct vnode *)avc)->v_object, flags); 
630         AFS_GLOCK();
631     }
632
633     ObtainSharedLock(&avc->lock, 409);
634     if (!code) {
635         if (avc->vc_error) {
636             code = avc->vc_error;
637         }
638     }
639     /* This is required since we may still have dirty pages after the write.
640      * I could just let close do the right thing, but stat's before the close
641      * return the wrong length.
642      */
643     if (code == EDQUOT || code == ENOSPC) {
644         uio->uio_resid = save_resid;
645         UpgradeSToWLock(&avc->lock, 410);
646         osi_ReleaseVM(avc, cred);
647         ConvertWToSLock(&avc->lock);
648     }
649     ReleaseSharedLock(&avc->lock);
650
651     if (!code && (ioflag & IO_SYNC) && (uio->uio_rw == UIO_WRITE)
652         && !AFS_NFSXLATORREQ(cred)) {
653         code = afs_fsync(avc, 0, cred, 0);
654     }
655 out:
656     code = afs_CheckCode(code, &treq, 36);
657     AFS_GUNLOCK();
658     return code;
659 }
660
661
662 /*
663  * Now for some bad news.  Since we artificially hold on to vnodes by doing
664  * and extra VNHOLD in afs_NewVCache(), there is no way for us to know
665  * when we need to flush the pages when a program exits.  Particularly
666  * if it closes the file after mapping it R/W.
667  *
668  */
669
670 mp_afs_mmap(avc, offset, map, addrp, len, prot, maxprot, flags, cred)
671     register struct vcache *avc;
672     vm_offset_t offset;
673     vm_map_t map;
674     vm_offset_t *addrp;
675     vm_size_t len;
676     vm_prot_t prot;
677     vm_prot_t maxprot;
678     int flags;
679     struct ucred *cred;
680 {
681     struct vp_mmap_args args;
682     register struct vp_mmap_args *ap = &args;
683     struct vnode *vp = (struct vnode *)avc;
684     int code;
685     struct vrequest treq;
686 #if     !defined(DYNEL)
687     extern kern_return_t u_vp_create();
688 #endif
689
690     AFS_GLOCK();
691     afs_InitReq(&treq, cred);
692     code = afs_VerifyVCache(avc, &treq);
693     if (code) {
694       code = afs_CheckCode(code, &treq, 37);
695       AFS_GUNLOCK();
696       return code;
697     }
698     afs_BozonLock(&avc->pvnLock, avc);
699     osi_FlushPages(avc);        /* ensure old pages are gone */
700     afs_BozonUnlock(&avc->pvnLock, avc);
701     ObtainWriteLock(&avc->lock,166);
702     avc->states |= CMAPPED;
703     ReleaseWriteLock(&avc->lock);
704     ap->a_offset = offset;
705     ap->a_vaddr = addrp;
706     ap->a_size = len;
707     ap->a_prot = prot,
708     ap->a_maxprot = maxprot;
709     ap->a_flags = flags;
710     AFS_GUNLOCK();
711     code = u_vp_create(map, vp->v_object, (vm_offset_t) ap);
712     AFS_GLOCK();
713     code = afs_CheckCode(code, &treq, 38);
714     AFS_GUNLOCK();
715     return code;
716 }
717
718
719 int mp_afs_getpage(vop, offset, len, protp, pl, plsz, mape, addr, rw, cred)
720     vm_ubc_object_t vop;
721     vm_offset_t offset;
722     vm_size_t len;
723     vm_prot_t *protp;
724     vm_page_t *pl;
725     int plsz;
726     vm_map_entry_t mape;
727     vm_offset_t addr;
728     int rw;
729     struct ucred *cred;
730 {
731     register afs_int32 code;
732     struct vrequest treq;
733     int flags = 0;
734     int i, pages = (len + PAGE_SIZE - 1) >> page_shift;
735     vm_page_t *pagep;
736     vm_offset_t off;
737
738    struct vcache *avc =  (struct vcache *)vop->vu_vp;
739
740     /* first, obtain the proper lock for the VM system */
741
742     AFS_GLOCK();
743     afs_InitReq(&treq, cred);
744     code = afs_VerifyVCache(avc, &treq);
745     if (code) {
746         *pl = VM_PAGE_NULL;
747         code = afs_CheckCode(code, &treq, 39); /* failed to get it */
748         AFS_GUNLOCK();
749         return code;
750     }
751         
752     /* clean all dirty pages for this vnode */
753     AFS_GUNLOCK();
754     ubc_flush_dirty(vop,0);
755     AFS_GLOCK();
756
757     afs_BozonLock(&avc->pvnLock, avc);
758     ObtainWriteLock(&avc->lock,167);
759     afs_Trace4(afs_iclSetp, CM_TRACE_PAGEIN, ICL_TYPE_POINTER, avc,
760                ICL_TYPE_LONG, offset, ICL_TYPE_LONG, len,
761                ICL_TYPE_INT32, (int) rw);
762     for (i = 0; i < pages; i++) {
763         pagep = &pl[i];
764         off = offset + PAGE_SIZE * i;
765         if (protp) protp[i] = 0;
766         flags = 0;
767         ReleaseWriteLock(&avc->lock);
768         AFS_GUNLOCK();
769         code = ubc_lookup(((struct vnode *)avc)->v_object, off,
770                         PAGE_SIZE, PAGE_SIZE, pagep, &flags);
771         AFS_GLOCK();
772         ObtainWriteLock(&avc->lock,168);
773         if (code) {
774             goto out;
775         }
776         if(flags & B_NOCACHE) {         /* if (page) */
777             if ((rw & B_WRITE) && (offset+len >= avc->m.Length)) {
778                 struct vnode *vp = (struct vnode *)avc;
779                 /* we're doing a write operation past eof; no need to read it */
780                 AFS_GUNLOCK();
781                 ubc_page_zero(*pagep, 0, PAGE_SIZE);
782                 ubc_page_release(*pagep, B_DONE);
783                 AFS_GLOCK();
784             } else {
785                 /* page wasn't cached, read it in. */
786                 struct buf *bp;
787
788                 AFS_GUNLOCK();
789                 bp = ubc_bufalloc(*pagep, 1, PAGE_SIZE, 1, B_READ);
790                 AFS_GLOCK();
791                 bp->b_dev = 0;
792                 bp->b_vp = (struct vnode *)avc;
793                 bp->b_blkno = btodb(off);
794                 ReleaseWriteLock(&avc->lock);
795                 code = afs_ustrategy(bp, cred); /* do the I/O */
796                 ObtainWriteLock(&avc->lock,169);
797                 AFS_GUNLOCK();
798                 ubc_sync_iodone(bp);
799                 AFS_GLOCK();
800                 if (code) {
801                     AFS_GUNLOCK();
802                     ubc_page_release(pl[i], 0);
803                     AFS_GLOCK();
804                     goto out;
805                 }
806             }
807         }
808         if ((rw & B_READ) == 0) {
809             AFS_GUNLOCK();
810             ubc_page_dirty(pl[i]);
811             AFS_GLOCK();
812         } else {
813             if (protp && (flags & B_DIRTY) == 0) {
814                 protp[i] = VM_PROT_WRITE;
815             }
816         }
817     }
818 out:
819     pl[i] = VM_PAGE_NULL;
820     ReleaseWriteLock(&avc->lock);
821     afs_BozonUnlock(&avc->pvnLock, avc);
822     afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_INT32, code,
823                ICL_TYPE_POINTER, *pagep, ICL_TYPE_INT32, flags);
824     code = afs_CheckCode(code, &treq, 40);
825     AFS_GUNLOCK();
826     return code;
827 }
828
829
830 int mp_afs_putpage(vop, pl, pcnt, flags, cred)
831     vm_ubc_object_t vop;
832     vm_page_t *pl;
833     int pcnt;
834     int flags;
835     struct ucred *cred;
836 {
837     register afs_int32 code=0;
838     struct vcache *avc = (struct vcache *)vop->vu_vp;
839     struct vnode *vp = (struct vnode *)avc;
840     int i;
841
842     AFS_GLOCK();
843     afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUT, ICL_TYPE_POINTER, avc,
844                ICL_TYPE_INT32, pcnt, ICL_TYPE_INT32, vp->v_flag,
845                ICL_TYPE_INT32, flags);
846     if (flags & B_UBC) {
847         AFS_GUNLOCK();
848         VN_LOCK(vp);
849         if (vp->v_flag & VXLOCK) {
850             VN_UNLOCK(vp);
851             for (i = 0; i < pcnt; i++) {
852                 ubc_page_release(pl[i], B_DONE|B_DIRTY);
853                 pl[i] = VM_PAGE_NULL;
854             }
855             return(0);
856         } else {
857             VN_UNLOCK(vp);
858         }
859         AFS_GLOCK();
860     }
861
862     /* first, obtain the proper lock for the VM system */
863     afs_BozonLock(&avc->pvnLock, avc);
864     ObtainWriteLock(&avc->lock,170);
865     for (i = 0; i < pcnt; i++) {
866         vm_page_t page = pl[i];
867         struct buf *bp;
868
869         /* write it out */
870         AFS_GUNLOCK();
871         bp = ubc_bufalloc(page, 1, PAGE_SIZE, 1, B_WRITE);
872         AFS_GLOCK();
873         bp->b_dev = 0;
874         bp->b_vp = (struct vnode *)avc;
875         bp->b_blkno = btodb(page->pg_offset);
876         ReleaseWriteLock(&avc->lock);
877         code = afs_ustrategy(bp, cred); /* do the I/O */
878         ObtainWriteLock(&avc->lock,171);
879         AFS_GUNLOCK();
880         ubc_sync_iodone(bp);
881         AFS_GLOCK();
882         if (code) {
883             goto done;
884         } else {
885             pl[i] = VM_PAGE_NULL;
886         }
887     }
888 done:
889     ReleaseWriteLock(&avc->lock);
890     afs_BozonUnlock(&avc->pvnLock, avc);
891     afs_Trace2(afs_iclSetp, CM_TRACE_PAGEOUTDONE, ICL_TYPE_INT32, code,
892                ICL_TYPE_INT32, avc->m.Length);
893     AFS_GUNLOCK();
894     return code;
895 }
896
897
898 int mp_afs_swap(avc, swapop, argp)
899     struct vcache *avc;
900     vp_swap_op_t swapop;
901     vm_offset_t argp;
902 {
903     return EIO;
904 }
905
906 int mp_afs_syncdata(avc, flag, offset, length, cred)
907     struct vcache *avc;
908     int flag;
909     vm_offset_t offset;
910     vm_size_t length;
911     struct ucred *cred;
912 {
913     /* NFS V3 makes this call, ignore it. We'll sync the data in afs_fsync. */
914     if (AFS_NFSXLATORREQ(cred))
915         return 0;
916     else
917         return EINVAL;
918 }
919
920 /* a freelist of one */
921 struct buf *afs_bread_freebp = 0;
922
923 /*
924  *  Only rfs_read calls this, and it only looks at bp->b_un.b_addr.
925  *  Thus we can use fake bufs (ie not from the real buffer pool).
926  */
927 mp_afs_bread(vp, lbn, bpp, cred)
928         struct ucred *cred;
929         struct vnode *vp;
930         daddr_t lbn;
931         struct buf **bpp;
932 {
933         int offset, fsbsize, error;
934         struct buf *bp;
935         struct iovec iov;
936         struct uio uio;
937
938         AFS_GLOCK();
939         AFS_STATCNT(afs_bread);
940         fsbsize = vp->v_vfsp->vfs_bsize;
941         offset = lbn * fsbsize;
942         if (afs_bread_freebp) {
943                 bp = afs_bread_freebp;
944                 afs_bread_freebp = 0;
945         } else {
946                 bp = (struct buf *) AFS_KALLOC(sizeof(*bp));
947                 bp->b_un.b_addr = (caddr_t) AFS_KALLOC(fsbsize);
948         }
949
950         iov.iov_base = bp->b_un.b_addr;
951         iov.iov_len = fsbsize;
952         uio.afsio_iov = &iov;
953         uio.afsio_iovcnt = 1;
954         uio.afsio_seg = AFS_UIOSYS;
955         uio.afsio_offset = offset;
956         uio.afsio_resid = fsbsize;
957         *bpp = 0;
958         error = afs_read((struct vcache *)vp, &uio, cred, lbn, bpp, 0);
959         if (error) {
960                 afs_bread_freebp = bp;
961                 AFS_GUNLOCK();
962                 return error;
963         }
964         if (*bpp) {
965                 afs_bread_freebp = bp;
966         } else {
967                 *(struct buf **)&bp->b_vp = bp; /* mark as fake */
968                 *bpp = bp;
969         }
970         AFS_GUNLOCK();
971         return 0;
972 }
973
974
975 mp_afs_brelse(vp, bp)
976 struct vnode *vp;
977 struct buf *bp;
978 {
979     AFS_GLOCK();
980     AFS_STATCNT(afs_brelse);
981         if ((struct buf *)bp->b_vp != bp) { /* not fake */
982             brelse(bp);
983         } else if (afs_bread_freebp) {
984                 AFS_KFREE(bp->b_un.b_addr, vp->v_vfsp->vfs_bsize);
985                 AFS_KFREE(bp, sizeof(*bp));
986         } else {
987                 afs_bread_freebp = bp;
988         }
989     AFS_GUNLOCK();
990 }
991
992
993 mp_afs_bmap(avc, abn, anvp, anbn)
994     register struct vcache *avc;
995     afs_int32 abn, *anbn;
996     struct vcache **anvp;
997 {
998     AFS_GLOCK();
999     AFS_STATCNT(afs_bmap);
1000     if (anvp)
1001         *anvp = avc;
1002     if (anbn)
1003         *anbn = abn * (8192 / DEV_BSIZE);   /* in 512 byte units */
1004     AFS_GUNLOCK();
1005     return 0;
1006 }
1007
1008
1009 /* real strategy */
1010 mp_afs_strategy (abp)
1011     register struct buf *abp;
1012 {
1013     register afs_int32 code;
1014
1015     AFS_GLOCK();
1016     AFS_STATCNT(afs_strategy);
1017     code = afs_osi_MapStrategy(afs_ustrategy, abp);
1018     AFS_GUNLOCK();
1019     return code;
1020 }
1021
1022
1023 mp_afs_refer(vm_ubc_object_t vop)
1024 {
1025         VREF(vop->vu_vp);
1026 }
1027
1028
1029 mp_afs_release(vm_ubc_object_t vop)
1030 {
1031         vrele(vop->vu_vp);
1032 }
1033
1034
1035 mp_afs_write_check(vm_ubc_object_t vop, vm_page_t pp)
1036 {
1037         return TRUE;
1038 }
1039
1040
1041
1042 struct vfs_ubcops afs_ubcops = {
1043         mp_afs_refer,              /* refer vnode */
1044         mp_afs_release,            /* release vnode */
1045         mp_afs_getpage,            /* get page */
1046         mp_afs_putpage,            /* put page */
1047         mp_afs_write_check,        /* check writablity */
1048 };
1049
1050
1051 /*
1052  * Cover function for lookup name using OSF equivalent, namei()
1053  *
1054  * Note, the result vnode (ni_vp) in the namei data structure is remains
1055  * locked after return.
1056  */
1057 lookupname(namep, seg, follow, dvpp, cvpp)
1058     char *namep;                /* path name */
1059     int seg;            /* address space containing name */
1060     int follow;         /* follow symbolic links */
1061     struct vnode **dvpp;        /* result, containing parent vnode */
1062     struct vnode **cvpp;        /* result, containing final component vnode */
1063 {
1064     /* Should I use free-bee in u-area? */
1065     struct nameidata *ndp = &u.u_nd;
1066     int error;
1067
1068     ndp->ni_nameiop = ((follow) ? (LOOKUP|FOLLOW) : (LOOKUP));
1069     ndp->ni_segflg = seg;
1070     ndp->ni_dirp = namep;
1071     error = namei(ndp);
1072     if (dvpp != (struct vnode **)0)
1073         *dvpp = ndp->ni_dvp;
1074     if (cvpp != (struct vnode **)0)
1075         *cvpp = ndp->ni_vp;
1076     return(error);
1077 }
1078