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