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