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