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