IRIX: Remove pre-65 code
[openafs.git] / src / afs / IRIX / 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  * SGI specific vnodeops + other misc interface glue
12  */
13 #include <afsconfig.h>
14 #include "afs/param.h"
15
16
17 #include "afs/sysincludes.h"    /* Standard vendor system headers */
18 #include "afsincludes.h"        /* Afs-based standard headers */
19 #include "afs/afs_stats.h"      /* statistics */
20 #include "sys/flock.h"
21 #include "afs/nfsclient.h"
22
23 /* AFSBSIZE must be at least the size of a page, else the client will hang.
24  * For 64 bit platforms, the page size is more than 8K.
25  */
26 #define AFSBSIZE        _PAGESZ
27 extern struct afs_exporter *root_exported;
28 extern void afs_chkpgoob(vnode_t *, pgno_t);
29
30 static void afs_strategy();
31 static int afs_xread(), afs_xwrite();
32 static int afs_xbmap(), afs_map(), afs_reclaim();
33 extern int afs_open(), afs_close(), afs_ioctl(), afs_getattr(), afs_setattr();
34 extern int afs_access(), afs_lookup();
35 extern int afs_create(), afs_remove(), afs_link(), afs_rename();
36 extern int afs_mkdir(), afs_rmdir(), afs_readdir();
37 extern int afs_symlink(), afs_readlink(), afs_fsync(), afs_fid(),
38 afs_frlock();
39 static int afs_seek(OSI_VC_DECL(a), off_t b, off_t * c);
40 extern int afs_xinactive();
41
42 extern void afs_rwlock(OSI_VN_DECL(vp), AFS_RWLOCK_T b);
43 extern void afs_rwunlock(OSI_VN_DECL(vp), AFS_RWLOCK_T b);
44
45 extern int afs_fid2();
46
47 static int afsrwvp(struct vcache *avc, struct uio *uio,
48                    enum uio_rw rw, int ioflag,
49                    struct cred *cr, struct flid *flp);
50 #ifdef MP
51 static void mp_afs_rwlock(OSI_VN_DECL(a), AFS_RWLOCK_T b);
52 static void mp_afs_rwunlock(OSI_VN_DECL(a), AFS_RWLOCK_T b);
53 struct vnodeops afs_lockedvnodeops =
54 #else
55 struct vnodeops Afs_vnodeops =
56 #endif
57 {
58     BHV_IDENTITY_INIT_POSITION(VNODE_POSITION_BASE),
59     afs_open,
60     afs_close,
61     afs_xread,
62     afs_xwrite,
63     afs_ioctl,
64     fs_setfl,
65     afs_getattr,
66     afs_setattr,
67     afs_access,
68     afs_lookup,
69     afs_create,
70     afs_remove,
71     afs_link,
72     afs_rename,
73     afs_mkdir,
74     afs_rmdir,
75     afs_readdir,
76     afs_symlink,
77     afs_readlink,
78     afs_fsync,
79     afs_xinactive,
80     afs_fid,
81     afs_fid2,
82     afs_rwlock,
83     afs_rwunlock,
84     afs_seek,
85     fs_cmp,
86     afs_frlock,
87     fs_nosys,                   /* realvp */
88     afs_xbmap,
89     afs_strategy,
90     afs_map,
91     fs_noerr,                   /* addmap - devices only */
92     fs_noerr,                   /* delmap - devices only */
93     fs_poll,                    /* poll */
94     fs_nosys,                   /* dump */
95     fs_pathconf,
96     fs_nosys,                   /* allocstore */
97     fs_nosys,                   /* fcntl */
98     afs_reclaim,                /* reclaim */
99     fs_nosys,                   /* attr_get */
100     fs_nosys,                   /* attr_set */
101     fs_nosys,                   /* attr_remove */
102     fs_nosys,                   /* attr_list */
103     fs_cover,
104     (vop_link_removed_t) fs_noval,
105     fs_vnode_change,
106     fs_tosspages,
107     fs_flushinval_pages,
108     fs_flush_pages,
109     fs_invalfree_pages,
110     fs_pages_sethole,
111     (vop_commit_t) fs_nosys,
112     (vop_readbuf_t) fs_nosys,
113     fs_strgetmsg,
114     fs_strputmsg,
115 };
116
117 #ifndef MP
118 struct vnodeops *afs_ops = &Afs_vnodeops;
119 #endif
120
121 int
122 afs_frlock(OSI_VN_DECL(vp), int cmd, struct flock *lfp, int flag,
123            off_t offset,
124            vrwlock_t vrwlock,
125            cred_t * cr)
126 {
127     int error;
128     OSI_VN_CONVERT(vp);
129     struct flid flid;
130     int pid;
131     get_current_flid(&flid);
132     pid = flid.fl_pid;
133
134     /*
135      * Since AFS doesn't support byte-wise locks (and simply
136      * says yes! we handle byte locking locally only.
137      * This makes lots of things work much better
138      * XXX This doesn't properly handle moving from a
139      * byte-wise lock up to a full file lock (we should
140      * remove the byte locks ..) Of course neither did the
141      * regular AFS way ...
142      *
143      * For GETLK we do a bit more - we first check any byte-wise
144      * locks - if none then check for full AFS file locks
145      */
146     if (cmd == F_GETLK || lfp->l_whence != 0 || lfp->l_start != 0
147         || (lfp->l_len != MAXEND && lfp->l_len != 0)) {
148         AFS_RWLOCK(vp, VRWLOCK_WRITE);
149         AFS_GUNLOCK();
150         error =
151             fs_frlock(OSI_VN_ARG(vp), cmd, lfp, flag, offset, vrwlock, cr);
152         AFS_GLOCK();
153         AFS_RWUNLOCK(vp, VRWLOCK_WRITE);
154         if (error || cmd != F_GETLK)
155             return error;
156         if (lfp->l_type != F_UNLCK)
157             /* found some blocking lock */
158             return 0;
159         /* fall through to check for full AFS file locks */
160     }
161
162     /* map BSD style to plain - we don't call reclock() 
163      * and its only there that the difference is important
164      */
165     switch (cmd) {
166     case F_GETLK:
167     case F_RGETLK:
168         break;
169     case F_SETLK:
170     case F_RSETLK:
171         break;
172     case F_SETBSDLK:
173         cmd = F_SETLK;
174         break;
175     case F_SETLKW:
176     case F_RSETLKW:
177         break;
178     case F_SETBSDLKW:
179         cmd = F_SETLKW;
180         break;
181     default:
182         return EINVAL;
183     }
184
185     AFS_GUNLOCK();
186
187     error = convoff(vp, lfp, 0, offset, SEEKLIMIT
188                     , OSI_GET_CURRENT_CRED()
189         );
190
191     AFS_GLOCK();
192     if (!error) {
193         error = afs_lockctl(vp, lfp, cmd, cr, pid);
194     }
195     return error;
196 }
197
198
199 /*
200  * We need to get the cache hierarchy right.
201  * First comes the page cache - pages are hashed based on afs
202  * vnode and offset. It is important to have things hashed here
203  * for the VM/paging system to work.
204  * Note that the paging system calls VOP_READ with the UIO_NOSPACE -
205  * it simply requires that somehow the page is hashed
206  * upon successful return.
207  * This means in afs_read we
208  * must call the 'chunk' code that handles page insertion. In order
209  * to actually get the data, 'chunk' calls the VOP_STRATEGY routine.
210  * This is basically the std afs_read routine - validating and
211  * getting the info into the Dcache, then calling VOP_READ.
212  * The only bad thing here is that by calling VOP_READ (and VOP_WRITE
213  * to fill the cache) we will get 2 copies of these pages into the
214  * page cache - one hashed on afs vnode and one on efs vnode. THis
215  * is wasteful but does no harm. A potential solution involves
216  * causing an ASYNC flush of the newly fetched cache data and
217  * doing direct I/O on the read side....
218  */
219 /* ARGSUSED */
220 static int
221 afs_xread(OSI_VC_ARG(avc), uiop, ioflag, cr, flp)
222      struct flid *flp;
223 OSI_VC_DECL(avc);
224      struct uio *uiop;
225      int ioflag;
226      struct cred *cr;
227 {
228     int code;
229     OSI_VC_CONVERT(avc);
230
231     osi_Assert(avc->v.v_count > 0);
232     if (avc->v.v_type != VREG)
233         return EISDIR;
234
235     if (!(ioflag & IO_ISLOCKED))
236         AFS_RWLOCK((vnode_t *) avc, VRWLOCK_READ);
237     code = afsrwvp(avc, uiop, UIO_READ, ioflag, cr, flp);
238     if (!(ioflag & IO_ISLOCKED))
239         AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_READ);
240     return code;
241 }
242
243 /* ARGSUSED */
244 static int
245 afs_xwrite(OSI_VC_ARG(avc), uiop, ioflag, cr, flp)
246      struct flid *flp;
247 OSI_VC_DECL(avc);
248      struct uio *uiop;
249      int ioflag;
250      struct cred *cr;
251 {
252     int code;
253     OSI_VC_CONVERT(avc);
254
255     osi_Assert(avc->v.v_count > 0);
256     if (avc->v.v_type != VREG)
257         return EISDIR;
258
259     if (ioflag & IO_APPEND)
260         uiop->uio_offset = avc->f.m.Length;
261     if (!(ioflag & IO_ISLOCKED))
262         AFS_RWLOCK(((vnode_t *) avc), VRWLOCK_WRITE);
263     code = afsrwvp(avc, uiop, UIO_WRITE, ioflag, cr, flp);
264     if (!(ioflag & IO_ISLOCKED))
265         AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
266     return code;
267 }
268
269 static int prra = 0;
270 static int prnra = 0;
271 static int acchk = 0;
272 static int acdrop = 0;
273
274 static int
275 afsrwvp(struct vcache *avc, struct uio *uio, enum uio_rw rw,
276         int ioflag,
277         struct cred *cr, struct flid *flp)
278 {
279     struct vnode *vp = AFSTOV(avc);
280     struct buf *bp;
281     daddr_t bn;
282     off_t acnt, cnt;
283     off_t off, newoff;
284     off_t bsize, rem, len;
285     int error;
286     struct bmapval bmv[2];
287     int nmaps, didFakeOpen = 0;
288     struct vrequest treq;
289     struct dcache *tdc;
290     int counter = 0;
291
292     osi_Assert((valusema(&avc->vc_rwlock) <= 0)
293                && (OSI_GET_LOCKID() == avc->vc_rwlockid));
294
295
296     newoff = uio->uio_resid + uio->uio_offset;
297     if (uio->uio_resid <= 0) {
298         return (0);
299     }
300     if (uio->uio_offset < 0 || newoff < 0)  {
301         return (EINVAL);
302     }
303     if (ioflag & IO_DIRECT)
304         return EINVAL;
305
306     if (rw == UIO_WRITE && vp->v_type == VREG && newoff > uio->uio_limit) {
307         return (EFBIG);
308     }
309
310     afs_Trace4(afs_iclSetp, CM_TRACE_GRDWR, ICL_TYPE_POINTER, avc,
311                ICL_TYPE_INT32, ioflag, ICL_TYPE_INT32, rw, ICL_TYPE_INT32, 0);
312
313     /* get a validated vcache entry */
314     error = afs_InitReq(&treq, cr);
315     if (error)
316         return afs_CheckCode(error, NULL, 63);
317
318     error = afs_VerifyVCache(avc, &treq);
319     if (error)
320         return afs_CheckCode(error, &treq, 51);
321
322     /*
323      * flush any stale pages - this will unmap
324      * and invalidate all pages for vp (NOT writing them back!)
325      */
326     osi_FlushPages(avc, cr);
327
328     if (cr && AFS_NFSXLATORREQ(cr) && rw == UIO_READ) {
329         if (!afs_AccessOK
330             (avc, PRSFS_READ, &treq,
331              CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ))
332             return EACCES;
333     }
334     /*
335      * To handle anonymous calls to VOP_STRATEGY from afs_sync/sync/bdflush
336      * we need better than the callers credentials. So we squirrel away
337      * the last writers credentials
338      */
339     if (rw == UIO_WRITE || (rw == UIO_READ && avc->cred == NULL)) {
340         ObtainWriteLock(&avc->lock, 92);
341         if (avc->cred)
342             crfree(avc->cred);
343         crhold(cr);
344         avc->cred = cr;
345         ReleaseWriteLock(&avc->lock);
346     }
347
348     /*
349      * We have to bump the open/exwriters field here
350      * courtesy of the nfs xlator
351      * because there're no open/close nfs rpc's to call our afs_open/close.
352      */
353     if (root_exported && rw == UIO_WRITE) {
354         ObtainWriteLock(&avc->lock, 234);
355         if (root_exported) {
356             didFakeOpen = 1;
357             afs_FakeOpen(avc);
358         }
359         ReleaseWriteLock(&avc->lock);
360     }
361     error = 0;
362
363     if (rw == UIO_WRITE) {
364         ObtainWriteLock(&avc->lock, 330);
365         avc->f.states |= CDirty;
366         ReleaseWriteLock(&avc->lock);
367     }
368
369     AFS_GUNLOCK();
370
371     do {
372         /* If v_dpages is set SGI 5.3 will convert those pages to
373          * B_DELWRI in chunkread and getchunk. Write the pages out
374          * before we trigger that behavior. For 6.1, dirty pages stay
375          * around too long and we should get rid of them as quickly
376          * as possible.
377          */
378         while (VN_GET_DPAGES(vp))
379             pdflush(vp, 0);
380
381         if (avc->vc_error) {
382             error = avc->vc_error;
383             break;
384         }
385         bsize = AFSBSIZE;       /* why not?? */
386         off = uio->uio_offset % bsize;
387         bn = BTOBBT(uio->uio_offset - off);
388         /*
389          * decrease bsize - otherwise we will
390          * get 'extra' pages in the cache for this
391          * vnode that we would need to flush when
392          * calling e.g. ptossvp.
393          * So we can use Length in ptossvp,
394          * we make sure we never go more than to the file size
395          * rounded up to a page boundary.
396          * That doesn't quite work, since we may get a page hashed to
397          * the vnode w/o updating the length. Thus we always use
398          * MAXLONG in ptossvp to be safe.
399          */
400         if (rw == UIO_READ) {
401             /*
402              * read/paging in a normal file
403              */
404             rem = avc->f.m.Length - uio->uio_offset;
405             if (rem <= 0)
406                 /* EOF */
407                 break;
408             /*
409              * compute minimum of rest of block and rest of file
410              */
411             cnt = MIN(bsize - off, rem);
412             osi_Assert((off + cnt) <= bsize);
413             bsize = ctob(btoc(off + cnt));
414             len = BTOBBT(bsize);
415             nmaps = 1;
416             bmv[0].bn = bmv[0].offset = bn;
417             bmv[0].length = len;
418             bmv[0].bsize = bsize;
419             bmv[0].pboff = off;
420             bmv[0].pbsize = MIN(cnt, uio->uio_resid);
421             bmv[0].eof = 0;
422             bmv[0].pbdev = vp->v_rdev;
423             bmv[0].pmp = uio->uio_pmp;
424             osi_Assert(cnt > 0);
425             /*
426              * initiate read-ahead if it looks like
427              * we are reading sequentially OR they want
428              * more than one 'bsize' (==AFSBSIZE) worth
429              * XXXHack - to avoid DELWRI buffers we can't
430              * do read-ahead on any file that has potentially
431              * dirty mmap pages.
432              */
433             if ((avc->lastr + BTOBB(AFSBSIZE) == bn
434                  || uio->uio_resid > AFSBSIZE)
435                 && (!AFS_VN_MAPPED(vp))
436                 ) {
437                 rem -= cnt;
438                 if (rem > 0) {
439                     bsize = AFSBSIZE;
440                     bmv[1].bn = bmv[1].offset = bn + len;
441                     osi_Assert((BBTOB(bn + len) % bsize) == 0);
442                     acnt = MIN(bsize, rem);
443                     bsize = ctob(btoc(acnt));
444                     len = BTOBBT(bsize);
445                     nmaps = 2;
446                     bmv[1].length = len;
447                     bmv[1].eof = 0;
448                     bmv[1].bsize = bsize;
449                     bmv[1].pboff = 0;
450                     bmv[1].pbsize = acnt;
451                     bmv[1].pmp = uio->uio_pmp;
452                     bmv[1].pbdev = vp->v_rdev;
453                 }
454             }
455 #ifdef DEBUG
456             else if (prnra)
457                 printf
458                     ("NRA:vp 0x%x lastr %d bn %d len %d cnt %d bsize %d rem %d resid %d\n",
459                      vp, avc->lastr, bn, len, cnt, bsize, rem,
460                      uio->uio_resid);
461 #endif
462
463             avc->lastr = bn;
464             bp = chunkread(vp, bmv, nmaps, cr);
465             /*
466              * If at a chunk boundary, start prefetch of next chunk.
467              */
468             if (counter == 0 || AFS_CHUNKOFFSET(off) == 0) {
469                 AFS_GLOCK();
470                 ObtainWriteLock(&avc->lock, 562);
471                 tdc = afs_FindDCache(avc, off);
472                 if (tdc) {
473                     if (!(tdc->mflags & DFNextStarted))
474                         afs_PrefetchChunk(avc, tdc, cr, &treq);
475                     afs_PutDCache(tdc);
476                 }
477                 ReleaseWriteLock(&avc->lock);
478                 AFS_GUNLOCK();
479             }
480             counter++;
481         } else {
482             /*
483              * writing a normal file
484              */
485             /*
486              * Purge dirty chunks of file if there are too many dirty chunks.
487              * Inside the write loop, we only do this at a chunk boundary.
488              * Clean up partial chunk if necessary at end of loop.
489              */
490             if (counter > 0 && AFS_CHUNKOFFSET(uio->uio_offset) == 0) {
491                 AFS_GLOCK();
492                 ObtainWriteLock(&avc->lock, 90);
493                 error = afs_DoPartialWrite(avc, &treq);
494                 if (error == 0)
495                     avc->f.states |= CDirty;
496                 ReleaseWriteLock(&avc->lock);
497                 AFS_GUNLOCK();
498                 if (error)
499                     break;
500             }
501             counter++;
502
503             cnt = MIN(bsize - off, uio->uio_resid);
504             bsize = ctob(btoc(off + cnt));
505             len = BTOBBT(bsize);
506             bmv[0].bn = bn;
507             bmv[0].offset = bn;
508             bmv[0].length = len;
509             bmv[0].eof = 0;
510             bmv[0].bsize = bsize;
511             bmv[0].pboff = off;
512             bmv[0].pbsize = cnt;
513             bmv[0].pmp = uio->uio_pmp;
514
515             if (cnt == bsize)
516                 bp = getchunk(vp, bmv, cr);
517             else
518                 bp = chunkread(vp, bmv, 1, cr);
519
520             avc->f.m.Date = osi_Time(); /* Set file date (for ranlib) */
521         }
522         if (bp->b_flags & B_ERROR) {
523             /*
524              * Since we compile -signed, b_error is a signed
525              * char when it should be an unsigned char.
526              * This can cause some errors codes to be interpreted
527              * as negative #s
528              */
529             error = (unsigned char)(bp->b_error);
530             if (!error)
531                 error = EIO;
532 #ifdef DEBUG
533             if (acchk && error) {
534                 cmn_err(CE_WARN, "bp 0x%x has error %d\n", bp, error);
535                 if (acdrop)
536                     debug("AFS");
537             }
538 #endif
539             brelse(bp);
540             break;
541         }
542
543         osi_Assert(bp->b_error == 0);
544
545         if (uio->uio_segflg != UIO_NOSPACE)
546             (void)bp_mapin(bp);
547         AFS_UIOMOVE(bp->b_un.b_addr + bmv[0].pboff, cnt, rw, uio, error);
548         if (rw == UIO_READ || error) {
549             if (bp->b_flags & B_DELWRI) {
550                 bawrite(bp);
551             } else
552                 brelse(bp);
553         } else {
554             /*
555              * m.Length is the maximum number of bytes known to be in the file.
556              * Make sure it is at least as high as the last byte we just wrote
557              * into the buffer.
558              */
559             if (avc->f.m.Length < uio->uio_offset)  {
560                 AFS_GLOCK();
561                 ObtainWriteLock(&avc->lock, 235);
562                 avc->f.m.Length = uio->uio_offset;
563                 ReleaseWriteLock(&avc->lock);
564                 AFS_GUNLOCK();
565             }
566             if (uio->uio_fmode & FSYNC) {
567                 error = bwrite(bp);
568             } else if (off + cnt < bsize) {
569                 bawrite(bp);    /* was bdwrite */
570             } else {
571                 bp->b_flags |= B_AGE;
572                 bawrite(bp);
573             }
574             /*
575              * Since EIO on an unlinked file is non-intuitive - give some
576              * explanation
577              */
578             if (error) {
579                 if (avc->f.m.LinkCount == 0)
580                     cmn_err(CE_WARN,
581                             "AFS: Process pid %d write error %d writing to unlinked file.",
582                             OSI_GET_CURRENT_PID(), error);
583             }
584         }
585     } while (!error && uio->uio_resid > 0);
586     afs_chkpgoob(&avc->v, btoc(avc->f.m.Length));
587
588     AFS_GLOCK();
589
590     if (rw == UIO_WRITE && error == 0 && (avc->f.states & CDirty)) {
591         ObtainWriteLock(&avc->lock, 405);
592         error = afs_DoPartialWrite(avc, &treq);
593         ReleaseWriteLock(&avc->lock);
594     }
595
596     if (!error) {
597         if (((ioflag & IO_SYNC) || (ioflag & IO_DSYNC)) && (rw == UIO_WRITE)
598             && !AFS_NFSXLATORREQ(cr)) {
599             error = afs_fsync(avc, 0, cr
600                               , 0, 0
601                               );
602         }
603     }
604     if (didFakeOpen) {
605         ObtainWriteLock(&avc->lock, 236);
606         afs_FakeClose(avc, cr); /* XXXX For nfs trans XXXX */
607         ReleaseWriteLock(&avc->lock);
608     }
609     afs_Trace4(afs_iclSetp, CM_TRACE_GRDWR, ICL_TYPE_POINTER, avc,
610                ICL_TYPE_INT32, ioflag, ICL_TYPE_INT32, rw, ICL_TYPE_INT32,
611                error);
612
613     return (error);
614 }
615
616 int
617 afs_xbmap(OSI_VC_ARG(avc), offset, count, flag, cr, bmv, nbmv)
618 OSI_VC_DECL(avc);
619      off_t offset;
620      ssize_t count;
621      int flag;
622      struct cred *cr;
623      struct bmapval *bmv;
624      int *nbmv;
625 {
626     int bsize;                  /* server's block size in bytes */
627     off_t off;
628     size_t rem, cnt;
629     OSI_VC_CONVERT(avc);
630
631     bsize = AFSBSIZE;
632     off = offset % bsize;       /* offset into block */
633     bmv->bn = BTOBBT(offset - off);
634     bmv->offset = bmv->bn;
635     bmv->pboff = off;
636     rem = avc->f.m.Length - offset;
637     if (rem <= 0)
638         cnt = 0;                /* EOF */
639     else
640         cnt = MIN(bsize - off, rem);
641
642     /*
643      * It is benign to ignore *nbmv > 1, since it is only for requesting
644      * readahead.
645      */
646
647     /*
648      * Don't map more than up to next page if at end of file
649      * See comment in afsrwvp
650      */
651     osi_Assert((off + cnt) <= bsize);
652     bsize = ctob(btoc(off + cnt));
653     bmv->pbsize = MIN(cnt, count);
654     bmv->eof = 0;
655     bmv->pmp = NULL;
656     bmv->pbdev = avc->v.v_rdev;
657     bmv->bsize = bsize;
658     bmv->length = BTOBBT(bsize);
659     *nbmv = 1;
660     return (0);
661 }
662
663 /*
664  * called out of chunkread from afs_xread & clusterwrite to push dirty
665  * pages back - this routine
666  * actually does the reading/writing by calling afs_read/afs_write
667  * bp points to a set of pages that have been inserted into
668  * the page cache hashed on afs vp.
669  */
670 static void
671 afs_strategy(OSI_VC_ARG(avc), bp)
672 OSI_VC_DECL(avc);
673      struct buf *bp;
674 {
675     uio_t auio;
676     uio_t *uio = &auio;
677     iovec_t aiovec;
678     int error;
679     struct cred *cr;
680     OSI_VC_CONVERT(avc);
681     vnode_t *vp = (vnode_t *) avc;
682
683     /*
684      * We can't afford DELWRI buffers for 2 reasons:
685      * 1) Since we can call underlying EFS, we can require a
686      *  buffer to flush a buffer. This leads to 2 potential
687      *  recursions/deadlocks
688      *          a) if all buffers are DELWRI afs buffers, then
689      *             ngeteblk -> bwrite -> afs_strategy -> afs_write ->
690      *             UFS_Write -> efs_write -> ngeteblk .... could
691      *             recurse a long ways!
692      *          b) brelse -> chunkhold which can call dchunkpush
693      *             will look for any DELWRI buffers and call strategy
694      *             on them. This can then end up via UFS_Write
695      *             recursing
696      * Current hack:
697      *  a) We never do bdwrite(s) on AFS buffers.
698      *  b) We call pdflush with B_ASYNC
699      *  c) in chunkhold where it can set a buffer DELWRI
700      *     we immediatly do a clusterwrite for AFS vp's
701      * XXX Alas, 'c' got dropped in 5.1 so its possible to get DELWRI
702      *  buffers if someone has mmaped the file and dirtied it then
703      *  reads/faults it again.
704      *  Instead - wherever we call chunkread/getchunk we check for a
705      *  returned bp with DELWRI set, and write it out immediately
706      */
707     if (CheckLock(&avc->lock) && VN_GET_DBUF(vp)) {
708         printf("WARN: afs_strategy vp=%x, v_dbuf=%x bp=%x\n", vp,
709                VN_GET_DBUF(vp), bp);
710         bp->b_error = EIO;
711         bp->b_flags |= B_ERROR;
712         iodone(bp);
713         return;
714     }
715     if (bp->b_error != 0)
716         printf("WARNING: afs_strategy3 vp=%x, bp=%x, err=%x\n", vp, bp,
717                bp->b_error);
718
719     /*
720      * To get credentials somewhat correct (we may be called from bdflush/
721      * sync) we use saved credentials in Vcache.
722      * We must hold them since someone else could change them
723      */
724     ObtainReadLock(&avc->lock);
725     if (bp->b_flags & B_READ) {
726         if (BBTOB(bp->b_blkno) >= avc->f.m.Length) {
727             /* we are responsible for zero'ing the page */
728             caddr_t c;
729             c = bp_mapin(bp);
730             memset(c, 0, bp->b_bcount);
731             iodone(bp);
732             ReleaseReadLock(&avc->lock);
733             return;
734         }
735     } else if ((avc->f.states & CWritingUFS) && (bp->b_flags & B_DELWRI)) {
736         bp->b_ref = 3;
737         ReleaseReadLock(&avc->lock);
738         iodone(bp);
739         return;
740     }
741     cr = avc->cred;
742     osi_Assert(cr);
743     crhold(cr);
744     ReleaseReadLock(&avc->lock);
745
746     aiovec.iov_base = bp_mapin(bp);
747     uio->uio_iov = &aiovec;
748     uio->uio_iovcnt = 1;
749     uio->uio_resid = aiovec.iov_len = bp->b_bcount;
750     uio->uio_offset = BBTOB(bp->b_blkno);
751     uio->uio_segflg = UIO_SYSSPACE;
752     uio->uio_limit = RLIM_INFINITY;     /* we checked the limit earlier */
753     uio->uio_pmp = NULL;
754
755     if (bp->b_flags & B_READ) {
756         uio->uio_fmode = FREAD;
757         error = afs_read(vp, uio, cr, 0);
758     } else {
759         uio->uio_fmode = FWRITE;
760         error = afs_write(vp, uio, 0, cr, 0);
761     }
762     crfree(cr);
763
764 #ifdef DEBUG
765     if (acchk && error) {
766         cmn_err(CE_WARN, "vp 0x%x has error %d\n", vp, error);
767         if (acdrop)
768             debug("AFS");
769     }
770 #endif
771     if (error) {
772         bp->b_error = error;
773         bp->b_flags |= B_ERROR;
774         if ((uio->uio_fmode == FWRITE) && !avc->vc_error)
775             avc->vc_error = error;
776     }
777     iodone(bp);
778     return;
779 }
780
781 /* ARGSUSED */
782 static int
783 afs_seek(OSI_VC_ARG(avc), ooff, noffp)
784 OSI_VC_DECL(avc);
785      off_t ooff;
786      off_t *noffp;
787 {
788     return *noffp < 0 ? EINVAL : 0;
789 }
790
791 /* ARGSUSED */
792 /*
793  * Note - if mapping in an ELF interpreter, one can get called without vp
794  * ever having been 'opened'
795  */
796 static int
797 afs_map(OSI_VC_ARG(avc), off, len, prot, flags, cr, vpp)
798      off_t off;
799 OSI_VC_DECL(avc);
800      size_t len;
801      mprot_t prot;
802      u_int flags;
803      struct cred *cr;
804      vnode_t **vpp;
805 {
806     OSI_VC_CONVERT(avc);
807     struct vnode *vp = AFSTOV(avc);
808     struct vrequest treq;
809     int error;
810
811     /* get a validated vcache entry */
812     error = afs_InitReq(&treq, cr);
813     if (error)
814         return afs_CheckCode(error, NULL, 65);
815
816     error = afs_VerifyVCache(avc, &treq);
817     if (error)
818         return afs_CheckCode(error, &treq, 53);
819
820     osi_FlushPages(avc, cr);    /* ensure old pages are gone */
821     /* If the vnode is currently opened for write, there's the potential
822      * that this mapping might (now or in the future) have PROT_WRITE.
823      * So assume it does and we'll have to call afs_StoreOnLastReference.
824      */
825     AFS_RWLOCK(vp, VRWLOCK_WRITE);
826     ObtainWriteLock(&avc->lock, 501);
827     if (avc->execsOrWriters > 0) {
828         avc->execsOrWriters++;
829         avc->opens++;
830         avc->mapcnt++;          /* count eow's due to mappings. */
831     }
832     ReleaseWriteLock(&avc->lock);
833     AFS_RWUNLOCK(vp, VRWLOCK_WRITE);
834     afs_Trace4(afs_iclSetp, CM_TRACE_GMAP, ICL_TYPE_POINTER, vp,
835                ICL_TYPE_POINTER, NULL,
836                ICL_TYPE_INT32, len, ICL_TYPE_INT32, off);
837     return error;
838 }
839
840
841 extern afs_rwlock_t afs_xvcache;
842 extern afs_lock_t afs_xdcache;
843 int
844 afs_xinactive(OSI_VC_ARG(avc), acred)
845 OSI_VC_DECL(avc);
846      struct ucred *acred;
847 {
848     int s;
849     OSI_VC_CONVERT(avc);
850     vnode_t *vp = (vnode_t *) avc;
851     int mapcnt = avc->mapcnt;   /* We just clear off this many. */
852
853     AFS_STATCNT(afs_inactive);
854
855     s = VN_LOCK(vp);
856     if (!(vp->v_flag & VINACT) || (vp->v_count > 0)) {
857         /* inactive was already done, or someone did a VN_HOLD; just return */
858         vp->v_flag &= ~VINACT;
859         VN_UNLOCK(vp, s);
860         return VN_INACTIVE_CACHE;
861     }
862     osi_Assert((vp->v_flag & VSHARE) == 0);
863     vp->v_flag &= ~VINACT;
864     /* Removed broadcast to waiters, since no one ever will. Only for vnodes
865      * in common pool.
866      */
867     VN_UNLOCK(vp, s);
868
869     /* In Irix 6.5, the last unmap of a dirty mmap'd file does not
870      * get an explicit vnode op. Instead we only find out at VOP_INACTIVE.
871      */
872     if (!afs_rwlock_nowait((vnode_t *) avc, VRWLOCK_WRITE)) {
873         return VN_INACTIVE_CACHE;
874     }
875     if (NBObtainWriteLock(&avc->lock, 502)) {
876         AFS_RWUNLOCK(vp, VRWLOCK_WRITE);
877         return VN_INACTIVE_CACHE;
878     }
879     if (avc->f.states & CUnlinked) {
880         if (CheckLock(&afs_xvcache) || CheckLock(&afs_xdcache)) {
881             avc->f.states |= CUnlinkedDel;
882             ReleaseWriteLock(&avc->lock);
883             AFS_RWUNLOCK(vp, VRWLOCK_WRITE);
884         } else {
885             ReleaseWriteLock(&avc->lock);
886             AFS_RWUNLOCK(vp, VRWLOCK_WRITE);
887             afs_remunlink(avc, 1);      /* ignore any return code */
888         }
889         return VN_INACTIVE_CACHE;
890     }
891     if ((avc->f.states & CDirty) || (avc->execsOrWriters > 0)) {
892         /* File either already has dirty chunks (CDirty) or was mapped at 
893          * time in its life with the potential for being written into. 
894          * Note that afs_close defers storebacks if the vnode's ref count
895          * if more than 1.
896          */
897         int code;
898         struct vrequest treq;
899         if (!afs_InitReq(&treq, acred)) {
900             int s;
901
902             VN_HOLD(vp);
903             avc->execsOrWriters -= mapcnt - 1;
904             avc->opens -= mapcnt - 1;
905             avc->mapcnt -= mapcnt;
906             code = afs_StoreOnLastReference(avc, &treq);
907             /* The following behavior mimics the behavior in afs_close. */
908             if (code == VNOVNODE)
909                 code = 0;
910             if (code) {
911                 if (mapcnt) {
912                     cmn_err(CE_WARN,
913                             "AFS: Failed to store FID (%x:%lu.%lu.%lu) in VOP_INACTIVE, error = %d\n",
914                             (int)(avc->f.fid.Cell) & 0xffffffff,
915                             avc->f.fid.Fid.Volume, avc->f.fid.Fid.Vnode,
916                             avc->f.fid.Fid.Unique, code);
917                 }
918                 afs_InvalidateAllSegments(avc);
919             }
920             s = VN_LOCK(vp);
921             vp->v_count--;
922             code = (vp->v_count == 0);
923             VN_UNLOCK(vp, s);
924             /* If the vnode is now in use by someone else, return early. */
925             if (!code) {
926                 ReleaseWriteLock(&avc->lock);
927                 AFS_RWUNLOCK(vp, VRWLOCK_WRITE);
928                 return VN_INACTIVE_CACHE;
929             }
930         }
931     }
932
933     osi_Assert((avc->f.states & (CCore | CMAPPED)) == 0);
934
935     if (avc->cred) {
936         crfree(avc->cred);
937         avc->cred = NULL;
938     }
939     ReleaseWriteLock(&avc->lock);
940     AFS_RWUNLOCK(vp, VRWLOCK_WRITE);
941
942     /*
943      * If someone unlinked a file and this is the last hurrah -
944      * nuke all the pages.
945      */
946     if (avc->f.m.LinkCount == 0) {
947         AFS_GUNLOCK();
948         PTOSSVP(vp, (off_t) 0, (off_t) MAXLONG);
949         AFS_GLOCK();
950     }
951     return VN_INACTIVE_CACHE;
952 }
953
954 static int
955 afs_reclaim(OSI_VC_DECL(avc), int flag)
956 {
957     /* Get's called via VOP_RELCAIM in afs_FlushVCache to clear repl_vnodeops */
958     return 0;
959 }
960
961 void
962 afs_rwlock(OSI_VN_DECL(vp), AFS_RWLOCK_T flag)
963 {
964     OSI_VN_CONVERT(vp);
965     struct vcache *avc = VTOAFS(vp);
966
967     if (OSI_GET_LOCKID() == avc->vc_rwlockid) {
968         avc->vc_locktrips++;
969         return;
970     }
971     AFS_GUNLOCK();
972     psema(&avc->vc_rwlock, PINOD);
973     AFS_GLOCK();
974     avc->vc_rwlockid = OSI_GET_LOCKID();
975 }
976
977 void
978 afs_rwunlock(OSI_VN_DECL(vp), AFS_RWLOCK_T flag)
979 {
980     OSI_VN_CONVERT(vp);
981     struct vcache *avc = VTOAFS(vp);
982
983     AFS_ASSERT_GLOCK();
984     osi_Assert(OSI_GET_LOCKID() == avc->vc_rwlockid);
985     if (avc->vc_locktrips > 0) {
986         --avc->vc_locktrips;
987         return;
988     }
989     avc->vc_rwlockid = OSI_NO_LOCKID;
990     vsema(&avc->vc_rwlock);
991 }
992
993
994 /* The flag argument is for symmetry with the afs_rwlock and afs_rwunlock
995  * calls. SGI currently only uses the flag to assert if the unlock flag
996  * does not match the corresponding lock flag. But they may start using this
997  * flag for a real rw lock at some time.
998  */
999 int
1000 afs_rwlock_nowait(vnode_t * vp, AFS_RWLOCK_T flag)
1001 {
1002     struct vcache *avc = VTOAFS(vp);
1003
1004     AFS_ASSERT_GLOCK();
1005     if (OSI_GET_LOCKID() == avc->vc_rwlockid) {
1006         avc->vc_locktrips++;
1007         return 1;
1008     }
1009     if (cpsema(&avc->vc_rwlock)) {
1010         avc->vc_rwlockid = OSI_GET_LOCKID();
1011         return 1;
1012     }
1013     return 0;
1014 }
1015
1016 #if defined(CKPT) && !defined(_R5000_CVT_WAR)
1017 int
1018 afs_fid2(OSI_VC_DECL(avc), struct fid *fidp)
1019 {
1020     struct cell *tcell;
1021     afs_fid2_t *afid = (afs_fid2_t *) fidp;
1022     OSI_VC_CONVERT(avc);
1023
1024     osi_Assert(sizeof(fid_t) >= sizeof(afs_fid2_t));
1025     afid->af_len = sizeof(afs_fid2_t) - sizeof(afid->af_len);
1026
1027     tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1028     afid->af_cell = tcell->cellIndex & 0xffff;
1029     afs_PutCell(tcell, READ_LOCK);
1030
1031     afid->af_volid = avc->f.fid.Fid.Volume;
1032     afid->af_vno = avc->f.fid.Fid.Vnode;
1033     afid->af_uniq = avc->f.fid.Fid.Unique;
1034
1035     return 0;
1036 }
1037 #else
1038 /* Only use so far is in checkpoint/restart for IRIX 6.4. In ckpt_fid, a
1039  * return of ENOSYS would make the code fail over to VOP_FID. We can't let
1040  * that happen, since we do a VN_HOLD there in the expectation that 
1041  * posthandle will be called to release the vnode.
1042  *
1043  * afs_fid2 is used to support the R5000 workarounds (_R5000_CVT_WAR)
1044  */
1045 int
1046 afs_fid2(OSI_VC_DECL(avc), struct fid *fidp)
1047 {
1048 #if defined(_R5000_CVT_WAR)
1049     extern int R5000_cvt_war;
1050
1051     if (R5000_cvt_war)
1052         return ENOSYS;
1053     else
1054         return EINVAL;
1055 #else
1056     return EINVAL;
1057 #endif
1058 }
1059 #endif /* CKPT */
1060
1061
1062 /*
1063  * check for any pages hashed that shouldn't be!
1064  * Only valid if PGCACHEDEBUG is set in os/page.c
1065  * Drop the global lock here, since we may not actually do the call.
1066  */
1067 void
1068 afs_chkpgoob(vnode_t * vp, pgno_t pgno)
1069 {
1070 #undef PGDEBUG
1071 #ifdef PGDEBUG
1072     AFS_GUNLOCK();
1073     pfindanyoob(vp, pgno);
1074     AFS_GLOCK();
1075 #endif
1076 }
1077
1078
1079 #ifdef MP
1080
1081 #define AFS_MP_VC_ARG(A) bhv_desc_t A
1082
1083 int
1084 mp_afs_open(bhv_desc_t * bhp, vnode_t ** a, mode_t b, struct cred *c)
1085 {
1086     int rv;
1087     AFS_GLOCK();
1088     rv = afs_lockedvnodeops.vop_open(bhp, a, b, c);
1089     AFS_GUNLOCK();
1090     return rv;
1091 }
1092
1093 int
1094 mp_afs_close(AFS_MP_VC_ARG(*a), int b, lastclose_t c, struct cred *d)
1095 {
1096     int rv;
1097     AFS_GLOCK();
1098     rv = afs_lockedvnodeops.vop_close(a, b, c, d
1099         );
1100
1101     AFS_GUNLOCK();
1102     return rv;
1103 }
1104
1105 int
1106 mp_afs_read(AFS_MP_VC_ARG(*a), struct uio *b, int c, struct cred *d,
1107             struct flid *f)
1108 {
1109     int rv;
1110     AFS_GLOCK();
1111     rv = afs_lockedvnodeops.vop_read(a, b, c, d, f);
1112     AFS_GUNLOCK();
1113     return rv;
1114 }
1115
1116
1117 int
1118 mp_afs_write(AFS_MP_VC_ARG(*a), struct uio *b, int c, struct cred *d,
1119              struct flid *f)
1120 {
1121     int rv;
1122     AFS_GLOCK();
1123     rv = afs_lockedvnodeops.vop_write(a, b, c, d, f);
1124     AFS_GUNLOCK();
1125     return rv;
1126 }
1127
1128 int
1129 mp_afs_ioctl(AFS_MP_VC_ARG(*a), int b, void *c, int d, struct cred *e, int *f
1130              , struct vopbd *vbds
1131     )
1132 {
1133     int rv;
1134     AFS_GLOCK();
1135     rv = afs_lockedvnodeops.vop_ioctl(a, b, c, d, e, f
1136                                       , vbds
1137         );
1138     AFS_GUNLOCK();
1139     return rv;
1140 }
1141
1142 int
1143 mp_fs_setfl(AFS_MP_VC_ARG(*a), int b, int c, struct cred *d)
1144 {
1145     int rv;
1146     AFS_GLOCK();
1147     rv = afs_lockedvnodeops.vop_setfl(a, b, c, d);
1148     AFS_GUNLOCK();
1149     return rv;
1150 }
1151
1152 int
1153 mp_afs_getattr(AFS_MP_VC_ARG(*a), struct vattr *b, int c, struct cred *d)
1154 {
1155     int rv;
1156     AFS_GLOCK();
1157     rv = afs_lockedvnodeops.vop_getattr(a, b, c, d);
1158     AFS_GUNLOCK();
1159     return rv;
1160 }
1161
1162 int
1163 mp_afs_setattr(AFS_MP_VC_ARG(*a), struct vattr *b, int c, struct cred *d)
1164 {
1165     int rv;
1166     AFS_GLOCK();
1167     rv = afs_lockedvnodeops.vop_setattr(a, b, c, d);
1168     AFS_GUNLOCK();
1169     return rv;
1170 }
1171
1172 int
1173 mp_afs_access(AFS_MP_VC_ARG(*a), int b,
1174               struct cred *d)
1175 {
1176     int rv;
1177     AFS_GLOCK();
1178     rv = afs_lockedvnodeops.vop_access(a, b,
1179                                        d);
1180     AFS_GUNLOCK();
1181     return rv;
1182 }
1183
1184 int
1185 mp_afs_lookup(AFS_MP_VC_ARG(*a), char *b, vnode_t ** c, struct pathname *d,
1186               int e, vnode_t * f, struct cred *g)
1187 {
1188     int rv;
1189     AFS_GLOCK();
1190     rv = afs_lockedvnodeops.vop_lookup(a, b, c, d, e, f, g);
1191     AFS_GUNLOCK();
1192     return rv;
1193 }
1194
1195 int
1196 mp_afs_create(AFS_MP_VC_ARG(*a), char *b, struct vattr *c, int d, int e,
1197               vnode_t ** f, struct cred *g)
1198 {
1199     int rv;
1200     AFS_GLOCK();
1201     rv = afs_lockedvnodeops.vop_create(a, b, c, d, e, f, g);
1202     AFS_GUNLOCK();
1203     return rv;
1204 }
1205
1206 int
1207 mp_afs_remove(AFS_MP_VC_ARG(*a), char *b, struct cred *c)
1208 {
1209     int rv;
1210     AFS_GLOCK();
1211     rv = afs_lockedvnodeops.vop_remove(a, b, c);
1212     AFS_GUNLOCK();
1213     return rv;
1214 }
1215
1216 int
1217 mp_afs_link(AFS_MP_VC_ARG(*a), vnode_t * b, char *c, struct cred *d)
1218 {
1219     int rv;
1220     AFS_GLOCK();
1221     rv = afs_lockedvnodeops.vop_link(a, b, c, d);
1222     AFS_GUNLOCK();
1223     return rv;
1224 }
1225
1226 int
1227 mp_afs_rename(AFS_MP_VC_ARG(*a), char *b, vnode_t * c, char *d,
1228               struct pathname *e, struct cred *f)
1229 {
1230     int rv;
1231     AFS_GLOCK();
1232     rv = afs_lockedvnodeops.vop_rename(a, b, c, d, e, f);
1233     AFS_GUNLOCK();
1234     return rv;
1235 }
1236
1237 int
1238 mp_afs_mkdir(AFS_MP_VC_ARG(*a), char *b, struct vattr *c, vnode_t ** d,
1239              struct cred *e)
1240 {
1241     int rv;
1242     AFS_GLOCK();
1243     rv = afs_lockedvnodeops.vop_mkdir(a, b, c, d, e);
1244     AFS_GUNLOCK();
1245     return rv;
1246 }
1247
1248 int
1249 mp_afs_rmdir(AFS_MP_VC_ARG(*a), char *b, vnode_t * c, struct cred *d)
1250 {
1251     int rv;
1252     AFS_GLOCK();
1253     rv = afs_lockedvnodeops.vop_rmdir(a, b, c, d);
1254     AFS_GUNLOCK();
1255     return rv;
1256 }
1257
1258 int
1259 mp_afs_readdir(AFS_MP_VC_ARG(*a), struct uio *b, struct cred *c, int *d)
1260 {
1261     int rv;
1262     AFS_GLOCK();
1263     rv = afs_lockedvnodeops.vop_readdir(a, b, c, d);
1264     AFS_GUNLOCK();
1265     return rv;
1266 }
1267
1268 int
1269 mp_afs_symlink(AFS_MP_VC_ARG(*a), char *b, struct vattr *c, char *d,
1270                struct cred *e)
1271 {
1272     int rv;
1273     AFS_GLOCK();
1274     rv = afs_lockedvnodeops.vop_symlink(a, b, c, d, e);
1275     AFS_GUNLOCK();
1276     return rv;
1277 }
1278
1279 int
1280 mp_afs_readlink(AFS_MP_VC_ARG(*a), struct uio *b, struct cred *c)
1281 {
1282     int rv;
1283     AFS_GLOCK();
1284     rv = afs_lockedvnodeops.vop_readlink(a, b, c);
1285     AFS_GUNLOCK();
1286     return rv;
1287 }
1288
1289 int
1290 mp_afs_fsync(AFS_MP_VC_ARG(*a), int b, struct cred *c
1291              , off_t start, off_t stop
1292     )
1293 {
1294     int rv;
1295     AFS_GLOCK();
1296     rv = afs_lockedvnodeops.vop_fsync(a, b, c
1297                                       , start, stop
1298         );
1299     AFS_GUNLOCK();
1300     return rv;
1301 }
1302
1303 void
1304 mp_afs_inactive(AFS_MP_VC_ARG(*a), struct cred *b)
1305 {
1306     AFS_GLOCK();
1307     afs_lockedvnodeops.vop_inactive(a, b);
1308     AFS_GUNLOCK();
1309     return;
1310 }
1311
1312 int
1313 mp_afs_fid(AFS_MP_VC_ARG(*a), struct fid **b)
1314 {
1315     int rv;
1316     AFS_GLOCK();
1317     rv = afs_lockedvnodeops.vop_fid(a, b);
1318     AFS_GUNLOCK();
1319     return rv;
1320 }
1321
1322 int
1323 mp_afs_fid2(AFS_MP_VC_ARG(*a), struct fid *b)
1324 {
1325     int rv;
1326     AFS_GLOCK();
1327     rv = afs_lockedvnodeops.vop_fid2(a, b);
1328     AFS_GUNLOCK();
1329     return rv;
1330 }
1331
1332 void
1333 mp_afs_rwlock(AFS_MP_VC_ARG(*a), AFS_RWLOCK_T b)
1334 {
1335     AFS_GLOCK();
1336     afs_rwlock(a, VRWLOCK_WRITE);
1337     AFS_GUNLOCK();
1338 }
1339
1340 void
1341 mp_afs_rwunlock(AFS_MP_VC_ARG(*a), AFS_RWLOCK_T b)
1342 {
1343     AFS_GLOCK();
1344     afs_rwunlock(a, VRWLOCK_WRITE);
1345     AFS_GUNLOCK();
1346 }
1347
1348 int
1349 mp_afs_seek(AFS_MP_VC_ARG(*a), off_t b, off_t * c)
1350 {
1351     int rv;
1352     AFS_GLOCK();
1353     rv = afs_lockedvnodeops.vop_seek(a, b, c);
1354     AFS_GUNLOCK();
1355     return rv;
1356 }
1357
1358 int
1359 mp_fs_cmp(AFS_MP_VC_ARG(*a), vnode_t * b)
1360 {
1361     int rv;
1362     AFS_GLOCK();
1363     rv = afs_lockedvnodeops.vop_cmp(a, b);
1364     AFS_GUNLOCK();
1365     return rv;
1366 }
1367
1368 int
1369 mp_afs_frlock(AFS_MP_VC_ARG(*a), int b, struct flock *c, int d, off_t e,
1370               vrwlock_t vrwlock,
1371               struct cred *f)
1372 {
1373     int rv;
1374     AFS_GLOCK();
1375     rv = afs_lockedvnodeops.vop_frlock(a, b, c, d, e,
1376                                        vrwlock,
1377                                        f);
1378     AFS_GUNLOCK();
1379     return rv;
1380 }
1381
1382 int
1383 mp_afs_realvp(AFS_MP_VC_ARG(*a), vnode_t ** b)
1384 {
1385     int rv;
1386     AFS_GLOCK();
1387     rv = afs_lockedvnodeops.vop_realvp(a, b);
1388     AFS_GUNLOCK();
1389     return rv;
1390 }
1391
1392 int
1393 mp_afs_bmap(AFS_MP_VC_ARG(*a), off_t b, ssize_t c, int d, struct cred *e,
1394             struct bmapval *f, int *g)
1395 {
1396     int rv;
1397     AFS_GLOCK();
1398     rv = afs_lockedvnodeops.vop_bmap(a, b, c, d, e, f, g);
1399     AFS_GUNLOCK();
1400     return rv;
1401 }
1402
1403 void
1404 mp_afs_strategy(AFS_MP_VC_ARG(*a), struct buf *b)
1405 {
1406     int rv;
1407     AFS_GLOCK();
1408     afs_lockedvnodeops.vop_strategy(a, b);
1409     AFS_GUNLOCK();
1410     return;
1411 }
1412
1413 int
1414 mp_afs_map(AFS_MP_VC_ARG(*a), off_t b, size_t c, mprot_t d, u_int e,
1415            struct cred *f, vnode_t ** g)
1416 {
1417     int rv;
1418     AFS_GLOCK();
1419     rv = afs_lockedvnodeops.vop_map(a, b, c, d, e, f, g
1420         );
1421     AFS_GUNLOCK();
1422     return rv;
1423 }
1424
1425
1426 int
1427 mp_fs_poll(AFS_MP_VC_ARG(*a), short b, int c, short *d, struct pollhead **e
1428            , unsigned int *f
1429     )
1430 {
1431     int rv;
1432     AFS_GLOCK();
1433     rv = afs_lockedvnodeops.vop_poll(a, b, c, d, e
1434                                      , f
1435         );
1436     AFS_GUNLOCK();
1437     return rv;
1438 }
1439
1440
1441 struct vnodeops Afs_vnodeops = {
1442     BHV_IDENTITY_INIT_POSITION(VNODE_POSITION_BASE),
1443     mp_afs_open,
1444     mp_afs_close,
1445     mp_afs_read,
1446     mp_afs_write,
1447     mp_afs_ioctl,
1448     mp_fs_setfl,
1449     mp_afs_getattr,
1450     mp_afs_setattr,
1451     mp_afs_access,
1452     mp_afs_lookup,
1453     mp_afs_create,
1454     mp_afs_remove,
1455     mp_afs_link,
1456     mp_afs_rename,
1457     mp_afs_mkdir,
1458     mp_afs_rmdir,
1459     mp_afs_readdir,
1460     mp_afs_symlink,
1461     mp_afs_readlink,
1462     mp_afs_fsync,
1463     mp_afs_inactive,
1464     mp_afs_fid,
1465     mp_afs_fid2,
1466     mp_afs_rwlock,
1467     mp_afs_rwunlock,
1468     mp_afs_seek,
1469     mp_fs_cmp,
1470     mp_afs_frlock,
1471     fs_nosys,                   /* realvp */
1472     mp_afs_bmap,
1473     mp_afs_strategy,
1474     mp_afs_map,
1475     fs_noerr,                   /* addmap - devices only */
1476     fs_noerr,                   /* delmap - devices only */
1477     mp_fs_poll,                 /* poll */
1478     fs_nosys,                   /* dump */
1479     fs_pathconf,
1480     fs_nosys,                   /* allocstore */
1481     fs_nosys,                   /* fcntl */
1482     afs_reclaim,                /* reclaim */
1483     fs_nosys,                   /* attr_get */
1484     fs_nosys,                   /* attr_set */
1485     fs_nosys,                   /* attr_remove */
1486     fs_nosys,                   /* attr_list */
1487     fs_cover,
1488     (vop_link_removed_t) fs_noval,
1489     fs_vnode_change,
1490     fs_tosspages,
1491     fs_flushinval_pages,
1492     fs_flush_pages,
1493     fs_invalfree_pages,
1494     fs_pages_sethole,
1495     (vop_commit_t) fs_nosys,
1496     (vop_readbuf_t) fs_nosys,
1497     fs_strgetmsg,
1498     fs_strputmsg,
1499 };
1500 struct vnodeops *afs_ops = &Afs_vnodeops;
1501 #endif /* MP */
1502
1503
1504 /* Support for XFS caches. The assumption here is that the size of
1505  * a cache file also does not exceed 32 bits. 
1506  */
1507
1508 /* Initialized in osi_InitCacheFSType(). Used to determine inode type. */
1509 vnodeops_t *afs_xfs_vnodeopsp;
1510
1511 ino_t
1512 VnodeToIno(vnode_t * vp)
1513 {
1514     int code;
1515     struct vattr vattr;
1516
1517     vattr.va_mask = AT_FSID | AT_NODEID;        /* quick return using this mask. */
1518     AFS_GUNLOCK();
1519     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
1520     AFS_GLOCK();
1521     if (code) {
1522         osi_Panic("VnodeToIno");
1523     }
1524     return vattr.va_nodeid;
1525 }
1526
1527 dev_t
1528 VnodeToDev(vnode_t * vp)
1529 {
1530     int code;
1531     struct vattr vattr;
1532
1533     vattr.va_mask = AT_FSID | AT_NODEID;        /* quick return using this mask. */
1534     AFS_GUNLOCK();
1535     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
1536     AFS_GLOCK();
1537     if (code) {
1538         osi_Panic("VnodeToDev");
1539     }
1540     return (dev_t) vattr.va_fsid;
1541 }
1542
1543 off_t
1544 VnodeToSize(vnode_t * vp)
1545 {
1546     int code;
1547     struct vattr vattr;
1548
1549     vattr.va_mask = AT_SIZE;
1550     AFS_GUNLOCK();
1551     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
1552     AFS_GLOCK();
1553     if (code) {
1554         osi_Panic("VnodeToSize");
1555     }
1556     return vattr.va_size;
1557 }