Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / SOLARIS / 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 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 /*
15 * SOLARIS/osi_vnodeops.c
16 *
17 * Implements:
18 *
19 * Functions: AFS_TRYUP, _init, _info, _fini, afs_addmap, afs_delmap,
20 * afs_vmread, afs_vmwrite, afs_getpage, afs_GetOnePage, afs_putpage,
21 * afs_putapage, afs_nfsrdwr, afs_map, afs_PageLeft, afs_pathconf/afs_cntl,
22 * afs_ioctl, afs_rwlock, afs_rwunlock, afs_seek, afs_space, afs_dump,
23 * afs_cmp, afs_realvp, afs_pageio, afs_dumpctl, afs_dispose, afs_setsecattr,
24 * afs_getsecattr, gafs_open, gafs_close, gafs_getattr, gafs_setattr,
25 * gafs_access, gafs_lookup, gafs_create, gafs_remove, gafs_link,
26 * gafs_rename, gafs_mkdir, gafs_rmdir, gafs_readdir, gafs_symlink,
27 * gafs_readlink, gafs_fsync, afs_inactive, gafs_inactive, gafs_fid
28 *
29 *
30 * Variables: Afs_vnodeops
31 *
32 */
33 #include "afs/sysincludes.h" /* Standard vendor system headers */
34 #include "afsincludes.h" /* Afs-based standard headers */
35 #include "afs/afs_stats.h" /* statistics */
36 #include "afs/nfsclient.h"
37
38
39 #include <sys/mman.h>
40 #include <vm/hat.h>
41 #include <vm/as.h>
42 #include <vm/page.h>
43 #include <vm/pvn.h>
44 #include <vm/seg.h>
45 #include <vm/seg_map.h>
46 #include <vm/seg_vn.h>
47 #include <vm/rm.h>
48 #if defined(AFS_SUN511_ENV)
49 #include <sys/vfs_opreg.h>
50 #endif
51 #include <sys/modctl.h>
52 #include <sys/syscall.h>
53 #include <sys/debug.h>
54 #include <sys/fs_subr.h>
55
56 /* Translate a faultcode_t as returned by some of the vm routines
57 * into a suitable errno value.
58 */
59 static int
60 afs_fc2errno(faultcode_t fc)
61 {
62 switch (FC_CODE(fc)) {
63 case 0:
64 return 0;
65
66 case FC_OBJERR:
67 return FC_ERRNO(fc);
68
69 default:
70 return EIO;
71 }
72 }
73
74
75 extern struct as kas; /* kernel addr space */
76 extern unsigned char *afs_indexFlags;
77 extern afs_lock_t afs_xdcache;
78
79 static int afs_nfsrdwr(struct vcache *avc, struct uio *auio, enum uio_rw arw,
80 int ioflag, afs_ucred_t *acred);
81 static int afs_GetOnePage(struct vnode *vp, u_offset_t off, u_int alen,
82 u_int *protp, struct page *pl[], u_int plsz,
83 struct seg *seg, caddr_t addr, enum seg_rw rw,
84 afs_ucred_t *acred);
85
86 int afs_pvn_vptrunc;
87
88 static int
89 afs_addmap(struct vnode *avp, offset_t offset, struct as *asp,
90 caddr_t addr, int length, int prot, int maxprot, int flags,
91 afs_ucred_t *credp)
92 {
93 /* XXX What should we do here?? XXX */
94 return (0);
95 }
96
97 static int
98 afs_delmap(struct vnode *avp, offset_t offset, struct as *asp,
99 caddr_t addr, int length, int prot, int maxprot, int flags,
100 afs_ucred_t *credp)
101 {
102 /* XXX What should we do here?? XXX */
103 return (0);
104 }
105
106 static int
107 #ifdef AFS_SUN510_ENV
108 afs_vmread(struct vnode *avp, struct uio *auio, int ioflag,
109 afs_ucred_t *acred, caller_context_t *ct)
110 #else
111 afs_vmread(struct vnode *avp, struct uio *auio, int ioflag,
112 afs_ucred_t *acred)
113 #endif
114 {
115 int code;
116
117 if (!RW_READ_HELD(&(VTOAFS(avp))->rwlock))
118 osi_Panic("afs_vmread: !rwlock");
119 AFS_GLOCK();
120 code = afs_nfsrdwr(VTOAFS(avp), auio, UIO_READ, ioflag, acred);
121 AFS_GUNLOCK();
122 return code;
123 }
124
125
126 static int
127 #ifdef AFS_SUN510_ENV
128 afs_vmwrite(struct vnode *avp, struct uio *auio, int ioflag,
129 afs_ucred_t *acred, caller_context_t *ct)
130 #else
131 afs_vmwrite(struct vnode *avp, struct uio *auio, int ioflag,
132 afs_ucred_t *acred)
133 #endif
134 {
135 int code;
136
137 if (!RW_WRITE_HELD(&(VTOAFS(avp))->rwlock))
138 osi_Panic("afs_vmwrite: !rwlock");
139 AFS_GLOCK();
140 code = afs_nfsrdwr(VTOAFS(avp), auio, UIO_WRITE, ioflag, acred);
141 AFS_GUNLOCK();
142 return code;
143 }
144
145 static int
146 afs_getpage(struct vnode *vp, offset_t off, u_int len, u_int *protp,
147 struct page *pl[], u_int plsz, struct seg *seg, caddr_t addr,
148 enum seg_rw rw, afs_ucred_t *acred)
149 {
150 afs_int32 code = 0;
151 AFS_STATCNT(afs_getpage);
152
153 if (vp->v_flag & VNOMAP) /* File doesn't allow mapping */
154 return (ENOSYS);
155
156 AFS_GLOCK();
157
158 if (len <= PAGESIZE)
159 code =
160 afs_GetOnePage(vp, off, len, protp, pl, plsz, seg, addr, rw, acred);
161 else {
162 struct multiPage_range range;
163 struct vcache *vcp = VTOAFS(vp);
164
165 /* We've been asked to get more than one page. We must return all
166 * requested pages at once, all of them locked, which means all of
167 * these dcache entries cannot be kicked out of the cache before we
168 * return (since their pages cannot be invalidated).
169 *
170 * afs_GetOnePage will be called multiple times by pvn_getpages in
171 * order to get all of the requested pages. One of the later
172 * afs_GetOnePage calls may need to evict some cache entries in order
173 * to perform its read. If we try to kick out one of the entries an
174 * earlier afs_GetOnePage call used, we will deadlock since we have
175 * the page locked. So, to tell afs_GetDownD that it should skip over
176 * any entries we've read in due to this afs_getpage call, record the
177 * offset and length in avc->multiPage.
178 *
179 * Ideally we would just set something in each dcache as we get it,
180 * but that is rather difficult, since pvn_getpages doesn't let us
181 * retain any information between calls to afs_GetOnePage. So instead
182 * just record the offset and length, and let afs_GetDownD calculate
183 * which dcache entries should be skipped. */
184
185 range.off = off;
186 range.len = len;
187
188 ObtainWriteLock(&vcp->vlock, 548);
189 QAdd(&vcp->multiPage, &range.q);
190 ReleaseWriteLock(&vcp->vlock);
191 code =
192 pvn_getpages(afs_GetOnePage, vp, off, len, protp, pl, plsz, seg, addr, rw, acred);
193 ObtainWriteLock(&vcp->vlock, 549);
194 QRemove(&range.q);
195 ReleaseWriteLock(&vcp->vlock);
196 }
197 AFS_GUNLOCK();
198 return code;
199 }
200
201 /* Return all the pages from [off..off+len) in file */
202 static int
203 afs_GetOnePage(struct vnode *vp, u_offset_t off, u_int alen, u_int *protp,
204 struct page *pl[], u_int plsz, struct seg *seg, caddr_t addr,
205 enum seg_rw rw, afs_ucred_t *acred)
206 {
207 struct page *page;
208 afs_int32 code = 0;
209 u_int len;
210 struct buf *buf;
211 afs_int32 tlen;
212 struct vcache *avc;
213 struct dcache *tdc;
214 int i, s, pexists;
215 int slot;
216 afs_size_t offset, nlen = 0;
217 struct vrequest treq;
218 afs_int32 mapForRead = 0, Code = 0;
219 u_offset_t toffset;
220
221 if (!acred)
222 osi_Panic("GetOnePage: !acred");
223
224 avc = VTOAFS(vp); /* cast to afs vnode */
225
226 if (avc->credp /*&& AFS_NFSXLATORREQ(acred) */
227 && AFS_NFSXLATORREQ(avc->credp)) {
228 acred = avc->credp;
229 }
230 if (code = afs_InitReq(&treq, acred))
231 return code;
232
233 if (!pl) {
234 /* This is a read-ahead request, e.g. due to madvise. */
235 int plen = alen;
236 ObtainReadLock(&avc->lock);
237
238 while (plen > 0 && !afs_BBusy()) {
239 /* Obtain a dcache entry at off. 2 means don't fetch data. */
240 tdc =
241 afs_GetDCache(avc, (afs_offs_t) off, &treq, &offset, &nlen,
242 2);
243 if (!tdc)
244 break;
245
246 /* Write-lock the dcache entry, if we don't succeed, just go on */
247 if (0 != NBObtainWriteLock(&tdc->lock, 642)) {
248 afs_PutDCache(tdc);
249 goto next_prefetch;
250 }
251
252 /* If we aren't already fetching this dcache entry, queue it */
253 if (!(tdc->mflags & DFFetchReq)) {
254 struct brequest *bp;
255
256 tdc->mflags |= DFFetchReq;
257 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
258 (afs_size_t) off, (afs_size_t) 1, tdc,
259 (void *)0, (void *)0);
260 if (!bp) {
261 /* Unable to start background fetch; might as well stop */
262 tdc->mflags &= ~DFFetchReq;
263 ReleaseWriteLock(&tdc->lock);
264 afs_PutDCache(tdc);
265 break;
266 }
267 ReleaseWriteLock(&tdc->lock);
268 } else {
269 ReleaseWriteLock(&tdc->lock);
270 afs_PutDCache(tdc);
271 }
272
273 next_prefetch:
274 /* Adjust our offset and remaining length values */
275 off += nlen;
276 plen -= nlen;
277
278 /* If we aren't making progress for some reason, bail out */
279 if (nlen <= 0)
280 break;
281 }
282
283 ReleaseReadLock(&avc->lock);
284 return 0;
285 }
286
287 len = PAGESIZE;
288 pl[0] = NULL; /* Make sure it's empty */
289
290 /* first, obtain the proper lock for the VM system */
291
292 /* if this is a read request, map the page in read-only. This will
293 * allow us to swap out the dcache entry if there are only read-only
294 * pages created for the chunk, which helps a *lot* when dealing
295 * with small caches. Otherwise, we have to invalidate the vm
296 * pages for the range covered by a chunk when we swap out the
297 * chunk.
298 */
299 if (rw == S_READ || rw == S_EXEC)
300 mapForRead = 1;
301
302 if (protp)
303 *protp = PROT_ALL;
304
305 retry:
306 if (rw == S_WRITE || rw == S_CREATE)
307 tdc = afs_GetDCache(avc, (afs_offs_t) off, &treq, &offset, &nlen, 5);
308 else
309 tdc = afs_GetDCache(avc, (afs_offs_t) off, &treq, &offset, &nlen, 1);
310 if (!tdc)
311 return afs_CheckCode(EINVAL, &treq, 62);
312 code = afs_VerifyVCache(avc, &treq);
313 if (code) {
314 afs_PutDCache(tdc);
315 return afs_CheckCode(code, &treq, 44); /* failed to get it */
316 }
317
318 ObtainReadLock(&avc->lock);
319
320 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEIN, ICL_TYPE_POINTER, (afs_int32) vp,
321 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(off), ICL_TYPE_LONG, len,
322 ICL_TYPE_LONG, (int)rw);
323
324 tlen = len;
325 slot = 0;
326 toffset = off;
327 /* Check to see if we're in the middle of a VM purge, and if we are, release
328 * the locks and try again when the VM purge is done. */
329 ObtainWriteLock(&avc->vlock, 550);
330 if (avc->activeV) {
331 ReleaseReadLock(&avc->lock);
332 ReleaseWriteLock(&avc->vlock);
333 afs_PutDCache(tdc);
334 /* Check activeV again, it may have been turned off
335 * while we were waiting for a lock in afs_PutDCache */
336 ObtainWriteLock(&avc->vlock, 574);
337 if (avc->activeV) {
338 avc->vstates |= VRevokeWait;
339 ReleaseWriteLock(&avc->vlock);
340 afs_osi_Sleep(&avc->vstates);
341 } else {
342 ReleaseWriteLock(&avc->vlock);
343 }
344 goto retry;
345 }
346 ReleaseWriteLock(&avc->vlock);
347
348 /* We're about to do stuff with our dcache entry.. Lock it. */
349 ObtainReadLock(&tdc->lock);
350
351 /* Check to see whether the cache entry is still valid */
352 if (!(avc->f.states & CStatd)
353 || !hsame(avc->f.m.DataVersion, tdc->f.versionNo)) {
354 ReleaseReadLock(&tdc->lock);
355 ReleaseReadLock(&avc->lock);
356 afs_PutDCache(tdc);
357 goto retry;
358 }
359
360 AFS_GUNLOCK();
361 while (1) { /* loop over all pages */
362 /* now, try to find the page in memory (it may already be intransit or laying
363 * around the free list */
364 page =
365 page_lookup(vp, toffset, (rw == S_CREATE ? SE_EXCL : SE_SHARED));
366 if (page)
367 goto nextpage;
368
369 /* if we make it here, we can't find the page in memory. Do a real disk read
370 * from the cache to get the data */
371 Code |= 0x200; /* XXX */
372 /* use PG_EXCL because we know the page does not exist already. If it
373 * actually does exist, we have somehow raced between lookup and create.
374 * As of 4/98, that shouldn't be possible, but we'll be defensive here
375 * in case someone tries to relax all the serialization of read and write
376 * operations with harmless things like stat. */
377 page =
378 page_create_va(vp, toffset, PAGESIZE, PG_WAIT | PG_EXCL, seg,
379 addr);
380 if (!page) {
381 continue;
382 }
383 if (alen < PAGESIZE)
384 pagezero(page, alen, PAGESIZE - alen);
385
386 if (rw == S_CREATE) {
387 /* XXX Don't read from AFS in write only cases XXX */
388 page_io_unlock(page);
389 } else
390 {
391 /* now it is time to start I/O operation */
392 buf = pageio_setup(page, PAGESIZE, vp, B_READ); /* allocate a buf structure */
393 buf->b_edev = 0;
394 buf->b_dev = 0;
395 buf->b_lblkno = lbtodb(toffset);
396 bp_mapin(buf); /* map it in to our address space */
397
398 AFS_GLOCK();
399 /* afs_ustrategy will want to lock the dcache entry */
400 ReleaseReadLock(&tdc->lock);
401 code = afs_ustrategy(buf, acred); /* do the I/O */
402 ObtainReadLock(&tdc->lock);
403 AFS_GUNLOCK();
404
405 /* Before freeing unmap the buffer */
406 bp_mapout(buf);
407 pageio_done(buf);
408 if (code) {
409 goto bad;
410 }
411 page_io_unlock(page);
412 }
413
414 /* come here when we have another page (already held) to enter */
415 nextpage:
416 /* put page in array and continue */
417 /* The p_selock must be downgraded to a shared lock after the page is read */
418 if ((rw != S_CREATE) && !(PAGE_SHARED(page))) {
419 page_downgrade(page);
420 }
421 pl[slot++] = page;
422 code = page_iolock_assert(page);
423 code = 0;
424 toffset += PAGESIZE;
425 addr += PAGESIZE;
426 tlen -= PAGESIZE;
427 if (tlen <= 0)
428 break; /* done all the pages */
429 } /* while (1) ... */
430
431 AFS_GLOCK();
432 pl[slot] = NULL;
433 ReleaseReadLock(&tdc->lock);
434
435 /* Prefetch next chunk if we're at a chunk boundary */
436 if (AFS_CHUNKOFFSET(off) == 0) {
437 if (!(tdc->mflags & DFNextStarted))
438 afs_PrefetchChunk(avc, tdc, acred, &treq);
439 }
440
441 ReleaseReadLock(&avc->lock);
442 ObtainWriteLock(&afs_xdcache, 246);
443 if (!mapForRead) {
444 /* track that we have dirty (or dirty-able) pages for this chunk. */
445 afs_indexFlags[tdc->index] |= IFDirtyPages;
446 }
447 afs_indexFlags[tdc->index] |= IFAnyPages;
448 ReleaseWriteLock(&afs_xdcache);
449 afs_PutDCache(tdc);
450 afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code,
451 ICL_TYPE_LONG, (int)page, ICL_TYPE_LONG, Code);
452 return 0;
453
454 bad:
455 AFS_GLOCK();
456 afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code,
457 ICL_TYPE_LONG, (int)page, ICL_TYPE_LONG, Code);
458 /* release all pages, drop locks, return code */
459 if (page)
460 pvn_read_done(page, B_ERROR);
461 ReleaseReadLock(&avc->lock);
462 ReleaseReadLock(&tdc->lock);
463 afs_PutDCache(tdc);
464 return code;
465 }
466
467 /**
468 * Dummy pvn_vplist_dirty() handler for non-writable vnodes.
469 */
470 static int
471 afs_never_putapage(struct vnode *vp, struct page *pages, u_offset_t * offp,
472 size_t * lenp, int flags, afs_ucred_t *credp)
473 {
474 struct vcache *avc = VTOAFS(vp);
475 osi_Assert((avc->f.states & CRO) != 0);
476 osi_Panic("Dirty pages while flushing a read-only volume vnode.");
477 return EIO; /* unreachable */
478 }
479
480 int
481 afs_putpage(struct vnode *vp, offset_t off, u_int len, int flags,
482 afs_ucred_t *cred)
483 {
484 struct vcache *avc;
485 struct page *pages;
486 afs_int32 code = 0;
487 size_t tlen;
488 afs_offs_t endPos;
489 afs_int32 NPages = 0;
490 u_offset_t toff = off;
491 int didLock = 0;
492
493 AFS_STATCNT(afs_putpage);
494 if (vp->v_flag & VNOMAP) /* file doesn't allow mapping */
495 return (ENOSYS);
496
497 /*
498 * Putpage (ASYNC) is called every sec to flush out dirty vm pages
499 */
500 AFS_GLOCK();
501 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUT, ICL_TYPE_POINTER,
502 (afs_int32) vp, ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(off),
503 ICL_TYPE_INT32, (afs_int32) len, ICL_TYPE_LONG, (int)flags);
504 avc = VTOAFS(vp);
505
506 /* Get a list of modified (or whatever) pages */
507 if (len) {
508 ObtainSharedLock(&avc->lock, 247);
509 didLock = SHARED_LOCK;
510 endPos = (afs_offs_t) off + len; /* position we're supposed to write up to */
511 while ((afs_offs_t) toff < endPos
512 && (afs_offs_t) toff < avc->f.m.Length) {
513 /* If not invalidating pages use page_lookup_nowait to avoid reclaiming
514 * them from the free list
515 */
516 AFS_GUNLOCK();
517 if (flags & (B_FREE | B_INVAL))
518 pages = page_lookup(vp, toff, SE_EXCL);
519 else
520 pages = page_lookup_nowait(vp, toff, SE_SHARED);
521 if (!pages || !pvn_getdirty(pages, flags))
522 tlen = PAGESIZE;
523 else {
524 if (didLock == SHARED_LOCK) {
525 AFS_GLOCK();
526 didLock = WRITE_LOCK;
527 UpgradeSToWLock(&avc->lock, 671);
528 AFS_GUNLOCK();
529 }
530 NPages++;
531 code = afs_putapage(vp, pages, &toff, &tlen, flags, cred);
532 if (code) {
533 AFS_GLOCK();
534 break;
535 }
536 }
537 toff += tlen;
538 AFS_GLOCK();
539 }
540 } else {
541 /*
542 * We normally arrive here due to a vm flush.
543 *
544 * If this vnode belongs to a writable volume, obtain a vcache lock
545 * then call pvn_vplist_dirty to free, invalidate, or to write out
546 * dirty pages with afs_putapage. The afs_putapage routine requires a
547 * vcache lock, so we obtain it here before any page locks are taken.
548 * This locking order is done to avoid deadlocking due to races with
549 * afs_getpage, which also takes vcache and page locks.
550 *
551 * If this vnode belongs to a non-writable volume, then it will not
552 * contain dirty pages, so we do not need to lock the vcache and since
553 * afs_putapage will not be called. Instead, forgo the vcache lock and
554 * call pvn_vplist_dirty to free, or invalidate pages. Pass a dummy
555 * page out handler to pvn_vplist_dirty which we do not expect to be
556 * called. Panic if the dummy handler is called, since something went
557 * horribly wrong.
558 */
559 if ((avc->f.states & CRO) == 0) {
560 ObtainWriteLock(&avc->lock, 670);
561 didLock = WRITE_LOCK;
562 }
563 AFS_GUNLOCK();
564 if ((avc->f.states & CRO) == 0)
565 code = pvn_vplist_dirty(vp, toff, afs_putapage, flags, cred);
566 else
567 code = pvn_vplist_dirty(vp, toff, afs_never_putapage, flags, cred);
568 AFS_GLOCK();
569 }
570
571 if (code && !avc->vc_error) {
572 if (didLock == 0) {
573 ObtainWriteLock(&avc->lock, 668);
574 didLock = WRITE_LOCK;
575 } else if (didLock == SHARED_LOCK) {
576 UpgradeSToWLock(&avc->lock, 669);
577 didLock = WRITE_LOCK;
578 }
579 avc->vc_error = code;
580 }
581
582 if (didLock == WRITE_LOCK)
583 ReleaseWriteLock(&avc->lock);
584 else if (didLock == SHARED_LOCK)
585 ReleaseSharedLock(&avc->lock);
586 afs_Trace2(afs_iclSetp, CM_TRACE_PAGEOUTDONE, ICL_TYPE_LONG, code,
587 ICL_TYPE_LONG, NPages);
588 AFS_GUNLOCK();
589 return (code);
590 }
591
592 int
593 afs_putapage(struct vnode *vp, struct page *pages, u_offset_t * offp,
594 size_t * lenp, int flags, afs_ucred_t *credp)
595 {
596 struct buf *tbuf;
597 struct vcache *avc = VTOAFS(vp);
598 afs_int32 code = 0;
599 u_int tlen = PAGESIZE;
600 afs_offs_t off = (pages->p_offset / PAGESIZE) * PAGESIZE;
601
602 /*
603 * Now we've got the modified pages. All pages are locked and held
604 * XXX Find a kluster that fits in one block (or page). We also
605 * adjust the i/o if the file space is less than a while page. XXX
606 */
607 if (off + tlen > avc->f.m.Length) {
608 tlen = avc->f.m.Length - off;
609 }
610 /* can't call mapout with 0 length buffers (rmfree panics) */
611 if (((tlen >> 24) & 0xff) == 0xff) {
612 tlen = 0;
613 }
614 if ((int)tlen > 0) {
615 /*
616 * Can't call mapout with 0 length buffers since we'll get rmfree panics
617 */
618 tbuf = pageio_setup(pages, tlen, vp, B_WRITE | flags);
619 if (!tbuf)
620 return (ENOMEM);
621
622 tbuf->b_dev = 0;
623 tbuf->b_lblkno = lbtodb(pages->p_offset);
624 bp_mapin(tbuf);
625 AFS_GLOCK();
626 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUTONE, ICL_TYPE_LONG, avc,
627 ICL_TYPE_LONG, pages, ICL_TYPE_LONG, tlen, ICL_TYPE_OFFSET,
628 ICL_HANDLE_OFFSET(off));
629 code = afs_ustrategy(tbuf, credp); /* unlocks page */
630 AFS_GUNLOCK();
631 bp_mapout(tbuf);
632 }
633 pvn_write_done(pages, ((code) ? B_ERROR : 0) | B_WRITE | flags);
634 if ((int)tlen > 0)
635 pageio_done(tbuf);
636 if (offp)
637 *offp = off;
638 if (lenp)
639 *lenp = tlen;
640 return code;
641 }
642
643 static int
644 afs_nfsrdwr(struct vcache *avc, struct uio *auio, enum uio_rw arw,
645 int ioflag, afs_ucred_t *acred)
646 {
647 afs_int32 code;
648 afs_int32 code2;
649 afs_int32 code_checkcode = 0;
650 int counter;
651 afs_int32 mode, sflags;
652 char *data;
653 struct dcache *dcp, *dcp_newpage;
654 afs_size_t fileBase, size;
655 afs_size_t pageBase;
656 afs_int32 tsize;
657 afs_int32 pageOffset, extraResid = 0;
658 afs_size_t origLength; /* length when reading/writing started */
659 long appendLength; /* length when this call will finish */
660 int created; /* created pages instead of faulting them */
661 int lockCode;
662 int didFakeOpen, eof;
663 struct vrequest treq;
664 caddr_t raddr;
665 u_int rsize;
666
667 AFS_STATCNT(afs_nfsrdwr);
668
669 /* can't read or write other things */
670 if (vType(avc) != VREG)
671 return EISDIR;
672
673 if (auio->uio_resid == 0)
674 return (0);
675
676 afs_Trace4(afs_iclSetp, CM_TRACE_VMRW, ICL_TYPE_POINTER, (afs_int32) avc,
677 ICL_TYPE_LONG, (arw == UIO_WRITE ? 1 : 0), ICL_TYPE_OFFSET,
678 ICL_HANDLE_OFFSET(auio->uio_loffset), ICL_TYPE_OFFSET,
679 ICL_HANDLE_OFFSET(auio->uio_resid));
680
681 #ifndef AFS_64BIT_CLIENT
682 if (AfsLargeFileUio(auio)) /* file is larger than 2 GB */
683 return (EFBIG);
684 #endif
685
686 if (!acred)
687 osi_Panic("rdwr: !acred");
688
689 if (code = afs_InitReq(&treq, acred))
690 return code;
691
692 /* It's not really possible to know if a write cause a growth in the
693 * cache size, we we wait for a cache drain for any write.
694 */
695 afs_MaybeWakeupTruncateDaemon();
696 while ((arw == UIO_WRITE)
697 && (afs_blocksUsed > PERCENT(CM_WAITFORDRAINPCT, afs_cacheBlocks))) {
698 if (afs_blocksUsed - afs_blocksDiscarded >
699 PERCENT(CM_WAITFORDRAINPCT, afs_cacheBlocks)) {
700 afs_WaitForCacheDrain = 1;
701 afs_osi_Sleep(&afs_WaitForCacheDrain);
702 }
703 afs_MaybeFreeDiscardedDCache();
704 afs_MaybeWakeupTruncateDaemon();
705 }
706 code = afs_VerifyVCache(avc, &treq);
707 if (code)
708 return afs_CheckCode(code, &treq, 45);
709
710 osi_FlushPages(avc, acred);
711
712 ObtainWriteLock(&avc->lock, 250);
713
714 /* adjust parameters when appending files */
715 if ((ioflag & IO_APPEND) && arw == UIO_WRITE) {
716 auio->uio_loffset = avc->f.m.Length; /* write at EOF position */
717 }
718 if (auio->afsio_offset < 0 || (auio->afsio_offset + auio->uio_resid) < 0) {
719 ReleaseWriteLock(&avc->lock);
720 return EINVAL;
721 }
722 #ifndef AFS_64BIT_CLIENT
723 /* file is larger than 2GB */
724 if (AfsLargeFileSize(auio->uio_offset, auio->uio_resid)) {
725 ReleaseWriteLock(&avc->lock);
726 return EFBIG;
727 }
728 #endif
729
730 didFakeOpen = 0; /* keep track of open so we can do close */
731 if (arw == UIO_WRITE) {
732 /* do ulimit processing; shrink resid or fail */
733 if (auio->uio_loffset + auio->afsio_resid > auio->uio_llimit) {
734 if (auio->uio_loffset >= auio->uio_llimit) {
735 ReleaseWriteLock(&avc->lock);
736 return EFBIG;
737 } else {
738 /* track # of bytes we should write, but won't because of
739 * ulimit; we must add this into the final resid value
740 * so caller knows we punted some data.
741 */
742 extraResid = auio->uio_resid;
743 auio->uio_resid = auio->uio_llimit - auio->uio_loffset;
744 extraResid -= auio->uio_resid;
745 }
746 }
747 mode = S_WRITE; /* segment map-in mode */
748 afs_FakeOpen(avc); /* do this for writes, so data gets put back
749 * when we want it to be put back */
750 didFakeOpen = 1; /* we'll be doing a fake open */
751 /* before starting any I/O, we must ensure that the file is big enough
752 * to hold the results (since afs_putpage will be called to force the I/O */
753 size = auio->afsio_resid + auio->afsio_offset; /* new file size */
754 appendLength = size;
755 origLength = avc->f.m.Length;
756 if (size > avc->f.m.Length) {
757 afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH, ICL_TYPE_STRING,
758 __FILE__, ICL_TYPE_LONG, __LINE__, ICL_TYPE_OFFSET,
759 ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_OFFSET,
760 ICL_HANDLE_OFFSET(size));
761 avc->f.m.Length = size; /* file grew */
762 }
763 avc->f.states |= CDirty; /* Set the dirty bit */
764 avc->f.m.Date = osi_Time(); /* Set file date (for ranlib) */
765 } else {
766 mode = S_READ; /* map-in read-only */
767 origLength = avc->f.m.Length;
768 }
769
770 if (acred && AFS_NFSXLATORREQ(acred)) {
771 if (arw == UIO_READ) {
772 if (!afs_AccessOK
773 (avc, PRSFS_READ, &treq,
774 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
775 ReleaseWriteLock(&avc->lock);
776 return EACCES;
777 }
778 }
779 crhold(acred);
780 if (avc->credp) {
781 crfree(avc->credp);
782 }
783 avc->credp = acred;
784 }
785 counter = 0; /* don't call afs_DoPartialWrite first time through. */
786 while (1) {
787 /* compute the amount of data to move into this block,
788 * based on auio->afsio_resid. Note that we copy data in units of
789 * MAXBSIZE, not PAGESIZE. This is because segmap_getmap panics if you
790 * call it with an offset based on blocks smaller than MAXBSIZE
791 * (implying that it should be named BSIZE, since it is clearly both a
792 * max and a min). */
793 size = auio->afsio_resid; /* transfer size */
794 fileBase = ((arw == UIO_READ) && (origLength < auio->uio_offset)) ?
795 origLength : auio->afsio_offset; /* start file position for xfr */
796 pageBase = fileBase & ~(MAXBSIZE - 1); /* file position of the page */
797 pageOffset = fileBase & (MAXBSIZE - 1); /* xfr start's offset within page */
798 tsize = MAXBSIZE - pageOffset; /* how much more fits in this page */
799 /* we'll read tsize bytes, but first must make sure tsize isn't too big */
800 if (tsize > size)
801 tsize = size; /* don't read past end of request */
802 eof = 0; /* flag telling us if we hit the EOF on the read */
803 if (arw == UIO_READ) { /* we're doing a read operation */
804 /* don't read past EOF */
805 if (fileBase + tsize > origLength) {
806 tsize = origLength - fileBase;
807 eof = 1; /* we did hit the EOF */
808 if (tsize < 0)
809 tsize = 0; /* better safe than sorry */
810 }
811 sflags = 0;
812 } else {
813 /* Purge dirty chunks of file if there are too many dirty
814 * chunks. Inside the write loop, we only do this at a chunk
815 * boundary. Clean up partial chunk if necessary at end of loop.
816 */
817 if (counter > 0 && code == 0 && AFS_CHUNKOFFSET(fileBase) == 0) {
818 code = afs_DoPartialWrite(avc, &treq);
819 if (code)
820 break;
821 }
822 /* write case, we ask segmap_release to call putpage. Really, we
823 * don't have to do this on every page mapin, but for now we're
824 * lazy, and don't modify the rest of AFS to scan for modified
825 * pages on a close or other "synchronize with file server"
826 * operation. This makes things a little cleaner, but probably
827 * hurts performance. */
828 sflags = SM_WRITE;
829 }
830 if (tsize <= 0) {
831 code = 0;
832 break; /* nothing to transfer, we're done */
833 }
834 if (arw == UIO_WRITE)
835 avc->f.states |= CDirty; /* may have been cleared by DoPartialWrite */
836
837 /* Before dropping lock, hold the chunk (create it if necessary). This
838 * serves two purposes: (1) Ensure Cache Truncate Daemon doesn't try
839 * to purge the chunk's pages while we have them locked. This would
840 * cause deadlock because we might be waiting for the CTD to free up
841 * a chunk. (2) If we're writing past the original EOF, and we're
842 * at the base of the chunk, then make sure it exists online
843 * before we do the uiomove, since the segmap_release will
844 * write out to the chunk, causing it to get fetched if it hasn't
845 * been created yet. The code that would otherwise notice that
846 * we're fetching a chunk past EOF won't work, since we've
847 * already adjusted the file size above.
848 */
849 ObtainWriteLock(&avc->vlock, 551);
850 while (avc->vstates & VPageCleaning) {
851 ReleaseWriteLock(&avc->vlock);
852 ReleaseWriteLock(&avc->lock);
853 afs_osi_Sleep(&avc->vstates);
854 ObtainWriteLock(&avc->lock, 334);
855 ObtainWriteLock(&avc->vlock, 552);
856 }
857 ReleaseWriteLock(&avc->vlock);
858 {
859 afs_size_t toff, tlen;
860 dcp = afs_GetDCache(avc, fileBase, &treq, &toff, &tlen, 2);
861 if (!dcp) {
862 code = EIO;
863 break;
864 }
865 }
866 ReleaseWriteLock(&avc->lock); /* uiomove may page fault */
867 AFS_GUNLOCK();
868 data = segmap_getmap(segkmap, AFSTOV(avc), (u_offset_t) pageBase);
869 raddr = (caddr_t) (((uintptr_t) data + pageOffset) & PAGEMASK);
870 rsize =
871 (((u_int) data + pageOffset + tsize + PAGEOFFSET) & PAGEMASK) -
872 (u_int) raddr;
873 if (code == 0) {
874 /* if we're doing a write, and we're starting at the rounded
875 * down page base, and we're writing enough data to cover all
876 * created pages, then we must be writing all of the pages
877 * in this MAXBSIZE window that we're creating.
878 */
879 created = 0;
880 if (arw == UIO_WRITE && ((long)raddr == (long)data + pageOffset)
881 && tsize >= rsize) {
882 /* probably the dcache backing this guy is around, but if
883 * not, we can't do this optimization, since we're creating
884 * writable pages, which must be backed by a chunk.
885 */
886 AFS_GLOCK();
887 dcp_newpage = afs_FindDCache(avc, pageBase);
888 if (dcp_newpage
889 && hsame(avc->f.m.DataVersion, dcp_newpage->f.versionNo)) {
890 ObtainWriteLock(&avc->lock, 251);
891 ObtainWriteLock(&avc->vlock, 576);
892 ObtainReadLock(&dcp_newpage->lock);
893 if ((avc->activeV == 0)
894 && hsame(avc->f.m.DataVersion, dcp_newpage->f.versionNo)
895 && !(dcp_newpage->dflags & (DFFetching))) {
896 AFS_GUNLOCK();
897 segmap_pagecreate(segkmap, raddr, rsize, 1);
898 AFS_GLOCK();
899 ObtainWriteLock(&afs_xdcache, 252);
900 /* Mark the pages as created and dirty */
901 afs_indexFlags[dcp_newpage->index]
902 |= (IFAnyPages | IFDirtyPages);
903 ReleaseWriteLock(&afs_xdcache);
904 created = 1;
905 }
906 ReleaseReadLock(&dcp_newpage->lock);
907 afs_PutDCache(dcp_newpage);
908 ReleaseWriteLock(&avc->vlock);
909 ReleaseWriteLock(&avc->lock);
910 } else if (dcp_newpage)
911 afs_PutDCache(dcp_newpage);
912 AFS_GUNLOCK();
913 }
914 if (!created)
915 code =
916 afs_fc2errno(segmap_fault
917 (kas.a_hat, segkmap, raddr, rsize,
918 F_SOFTLOCK, mode));
919 }
920 if (code == 0) {
921 AFS_UIOMOVE(data + pageOffset, tsize, arw, auio, code);
922 segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTUNLOCK,
923 mode);
924 }
925 if (code == 0) {
926 code = segmap_release(segkmap, data, sflags);
927 } else {
928 (void)segmap_release(segkmap, data, 0);
929 }
930 AFS_GLOCK();
931 ObtainWriteLock(&avc->lock, 253);
932 counter++;
933 if (dcp)
934 afs_PutDCache(dcp);
935 if (code)
936 break;
937 }
938 if (didFakeOpen) {
939 afs_FakeClose(avc, acred);
940 }
941 if (arw == UIO_WRITE && (avc->f.states & CDirty)) {
942 code2 = afs_DoPartialWrite(avc, &treq);
943 if (!code)
944 code = code2;
945 }
946
947 if (!code && avc->vc_error) {
948 code = code_checkcode = avc->vc_error;
949 }
950 ReleaseWriteLock(&avc->lock);
951 if (!code) {
952 if ((ioflag & FSYNC) && (arw == UIO_WRITE)
953 && !AFS_NFSXLATORREQ(acred))
954 code = afs_fsync(avc, 0, acred);
955 }
956 /*
957 * If things worked, add in as remaining in request any bytes
958 * we didn't write due to file size ulimit.
959 */
960 if (code == 0 && extraResid > 0)
961 auio->uio_resid += extraResid;
962 if (code_checkcode) {
963 return code_checkcode;
964 } else {
965 return afs_CheckCode(code, &treq, 46);
966 }
967 }
968
969 static int
970 afs_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addr, size_t len, u_char prot, u_char maxprot, u_int flags, afs_ucred_t *cred)
971 {
972 struct segvn_crargs crargs;
973 afs_int32 code;
974 struct vrequest treq;
975 struct vcache *avc = VTOAFS(vp);
976
977 AFS_STATCNT(afs_map);
978
979
980 /* check for reasonableness on segment bounds; apparently len can be < 0 */
981 if (off < 0 || off + len < 0) {
982 return (EINVAL);
983 }
984 #ifndef AFS_64BIT_CLIENT
985 if (AfsLargeFileSize(off, len)) { /* file is larger than 2 GB */
986 code = EFBIG;
987 goto out;
988 }
989 #endif
990
991 if (vp->v_flag & VNOMAP) /* File isn't allowed to be mapped */
992 return (ENOSYS);
993
994 if (vp->v_filocks) /* if locked, disallow mapping */
995 return (EAGAIN);
996
997 AFS_GLOCK();
998 if (code = afs_InitReq(&treq, cred))
999 goto out;
1000
1001 if (vp->v_type != VREG) {
1002 code = ENODEV;
1003 goto out;
1004 }
1005
1006 code = afs_VerifyVCache(avc, &treq);
1007 if (code) {
1008 goto out;
1009 }
1010 osi_FlushPages(avc, cred); /* ensure old pages are gone */
1011 avc->f.states |= CMAPPED; /* flag cleared at afs_inactive */
1012
1013 AFS_GUNLOCK();
1014 as_rangelock(as);
1015 if ((flags & MAP_FIXED) == 0) {
1016 #ifdef MAPADDR_LACKS_VACALIGN
1017 map_addr(addr, len, off, flags);
1018 #else
1019 map_addr(addr, len, off, 1, flags);
1020 #endif
1021 if (*addr == NULL) {
1022 as_rangeunlock(as);
1023 code = ENOMEM;
1024 goto out1;
1025 }
1026 } else
1027 (void)as_unmap(as, *addr, len); /* unmap old address space use */
1028 /* setup the create parameter block for the call */
1029 crargs.vp = AFSTOV(avc);
1030 crargs.offset = (u_offset_t)off;
1031 crargs.cred = cred;
1032 crargs.type = flags & MAP_TYPE;
1033 crargs.prot = prot;
1034 crargs.maxprot = maxprot;
1035 crargs.amp = (struct anon_map *)0;
1036 crargs.flags = flags & ~MAP_TYPE;
1037
1038 code = as_map(as, *addr, len, segvn_create, (char *)&crargs);
1039 as_rangeunlock(as);
1040 out1:
1041 AFS_GLOCK();
1042 code = afs_CheckCode(code, &treq, 47);
1043 AFS_GUNLOCK();
1044 return code;
1045 out:
1046 code = afs_CheckCode(code, &treq, 48);
1047 AFS_GUNLOCK();
1048 return code;
1049 }
1050
1051
1052 /*
1053 * For Now We use standard local kernel params for AFS system values. Change this
1054 * at some point.
1055 */
1056 static int
1057 #ifdef AFS_SUN511_ENV
1058 afs_pathconf(struct vnode *vp, int cmd, u_long *outdatap,
1059 afs_ucred_t *credp, caller_context_t *ct)
1060 #else
1061 afs_pathconf(struct vnode *vp, int cmd, u_long *outdatap,
1062 afs_ucred_t *credp)
1063 #endif /* AFS_SUN511_ENV */
1064 {
1065 AFS_STATCNT(afs_cntl);
1066 switch (cmd) {
1067 case _PC_LINK_MAX:
1068 *outdatap = MAXLINK;
1069 break;
1070 case _PC_NAME_MAX:
1071 *outdatap = MAXNAMLEN;
1072 break;
1073 case _PC_PATH_MAX:
1074 *outdatap = MAXPATHLEN;
1075 break;
1076 case _PC_CHOWN_RESTRICTED:
1077 *outdatap = 1;
1078 break;
1079 case _PC_NO_TRUNC:
1080 *outdatap = 1;
1081 break;
1082 case _PC_FILESIZEBITS:
1083 #ifdef AFS_64BIT_CLIENT
1084 *outdatap = 64;
1085 #else
1086 *outdatap = 32;
1087 #endif
1088 break;
1089 default:
1090 #ifdef AFS_SUN511_ENV
1091 return fs_pathconf(vp, cmd, outdatap, credp, ct);
1092 #else
1093 return fs_pathconf(vp, cmd, outdatap, credp);
1094 #endif /* AFS_SUN511_ENV */
1095 }
1096 return 0;
1097 }
1098
1099 static int
1100 afs_ioctl(struct vnode *vnp, int com, int arg, int flag, cred_t *credp,
1101 int *rvalp)
1102 {
1103 return (ENOTTY);
1104 }
1105
1106 static void
1107 afs_rwlock(struct vnode *vnp, int wlock)
1108 {
1109 rw_enter(&(VTOAFS(vnp))->rwlock, (wlock ? RW_WRITER : RW_READER));
1110 }
1111
1112
1113 static void
1114 afs_rwunlock(struct vnode *vnp, int wlock)
1115 {
1116 rw_exit(&(VTOAFS(vnp))->rwlock);
1117 }
1118
1119
1120 /* NOT SUPPORTED */
1121 static int
1122 afs_seek(struct vnode *vnp, offset_t ooff, offset_t *noffp)
1123 {
1124 int code = 0;
1125
1126 #ifndef AFS_64BIT_CLIENT
1127 # define __MAXOFF_T MAXOFF_T
1128 #else
1129 # define __MAXOFF_T MAXOFFSET_T
1130 #endif
1131
1132 if ((*noffp < 0 || *noffp > __MAXOFF_T))
1133 code = EINVAL;
1134 return code;
1135 }
1136
1137 static int
1138 #ifdef AFS_SUN59_ENV
1139 afs_frlock(struct vnode *vnp, int cmd, struct flock64 *ap, int flag,
1140 offset_t off, struct flk_callback *flkcb, afs_ucred_t *credp)
1141 #else
1142 afs_frlock(struct vnode *vnp, int cmd, struct flock64 *ap, int flag,
1143 offset_t off, afs_ucred_t *credp)
1144 #endif
1145 {
1146 afs_int32 code = 0;
1147 /*
1148 * Implement based on afs_lockctl
1149 */
1150 AFS_GLOCK();
1151 #ifdef AFS_SUN59_ENV
1152 if (flkcb)
1153 afs_warn("Don't know how to deal with flk_callback's!\n");
1154 #endif
1155 if ((cmd == F_GETLK) || (cmd == F_O_GETLK) || (cmd == F_SETLK)
1156 || (cmd == F_SETLKW)) {
1157 ap->l_pid = ttoproc(curthread)->p_pid;
1158 ap->l_sysid = 0;
1159
1160 AFS_GUNLOCK();
1161 code = convoff(vnp, ap, 0, off);
1162 if (code)
1163 return code;
1164 AFS_GLOCK();
1165 }
1166
1167 code = afs_lockctl(VTOAFS(vnp), ap, cmd, credp);
1168 AFS_GUNLOCK();
1169 return code;
1170 }
1171
1172
1173 static int
1174 afs_space(struct vnode *vnp, int cmd, struct flock64 *ap, int flag,
1175 offset_t off, afs_ucred_t *credp)
1176 {
1177 afs_int32 code = EINVAL;
1178 struct vattr vattr;
1179
1180 if ((cmd == F_FREESP)
1181 && ((code = convoff(vnp, ap, 0, off)) == 0)) {
1182 AFS_GLOCK();
1183 if (!ap->l_len) {
1184 vattr.va_mask = AT_SIZE;
1185 vattr.va_size = ap->l_start;
1186 code = afs_setattr(VTOAFS(vnp), &vattr, 0, credp);
1187 }
1188 AFS_GUNLOCK();
1189 }
1190 return (code);
1191 }
1192
1193 static int
1194 afs_dump(struct vnode *vp, caddr_t addr, int i1, int i2)
1195 {
1196 AFS_STATCNT(afs_dump);
1197 afs_warn("AFS_DUMP. MUST IMPLEMENT THIS!!!\n");
1198 return EINVAL;
1199 }
1200
1201
1202 /* Nothing fancy here; just compare if vnodes are identical ones */
1203 static int
1204 afs_cmp(struct vnode *vp1, struct vnode *vp2)
1205 {
1206 AFS_STATCNT(afs_cmp);
1207 return (vp1 == vp2);
1208 }
1209
1210
1211 static int
1212 afs_realvp(struct vnode *vp, struct vnode **vpp)
1213 {
1214 AFS_STATCNT(afs_realvp);
1215 return EINVAL;
1216 }
1217
1218
1219 static int
1220 afs_pageio(struct vnode *vp, struct page *pp, u_int ui1, u_int ui2, int i1,
1221 struct cred *credp)
1222 {
1223 afs_warn("afs_pageio: Not implemented\n");
1224 return EINVAL;
1225 }
1226
1227 static int
1228 #ifdef AFS_SUN59_ENV
1229 afs_dumpctl(struct vnode *vp, int i, int *blkp)
1230 #else
1231 afs_dumpctl(struct vnode *vp, int i)
1232 #endif
1233 {
1234 afs_warn("afs_dumpctl: Not implemented\n");
1235 return EINVAL;
1236 }
1237
1238 #ifdef AFS_SUN511_ENV
1239 static void
1240 afs_dispose(struct vnode *vp, struct page *p, int fl, int dn, struct cred *cr, struct caller_context_t *ct)
1241 {
1242 fs_dispose(vp, p, fl, dn, cr,ct);
1243 }
1244
1245 static int
1246 afs_setsecattr(struct vnode *vp, vsecattr_t *vsecattr, int flag, struct cred *creds, struct caller_context_t *ct)
1247 {
1248 return ENOSYS;
1249 }
1250
1251 static int
1252 afs_getsecattr(struct vnode *vp, vsecattr_t *vsecattr, int flag, struct cred *creds, struct caller_context_t *ct)
1253 {
1254 return fs_fab_acl(vp, vsecattr, flag, creds,ct);
1255 }
1256 #else
1257 static void
1258 afs_dispose(struct vnode *vp, struct page *p, int fl, int dn, struct cred *cr)
1259 {
1260 fs_dispose(vp, p, fl, dn, cr);
1261 }
1262
1263 static int
1264 afs_setsecattr(struct vnode *vp, vsecattr_t *vsecattr, int flag,
1265 struct cred *creds)
1266 {
1267 return ENOSYS;
1268 }
1269
1270 static int
1271 afs_getsecattr(struct vnode *vp, vsecattr_t *vsecattr, int flag, struct cred *creds)
1272 {
1273 return fs_fab_acl(vp, vsecattr, flag, creds);
1274 }
1275 #endif
1276
1277 #ifdef AFS_GLOBAL_SUNLOCK
1278
1279 static int
1280 gafs_open(struct vnode **vpp, afs_int32 aflags,
1281 afs_ucred_t *acred)
1282 {
1283 int code;
1284 struct vcache *avc = VTOAFS(*vpp);
1285
1286 AFS_GLOCK();
1287 code = afs_open(&avc, aflags, acred);
1288 AFS_GUNLOCK();
1289
1290 /* afs_open currently never changes avc, but just in case... */
1291 *vpp = AFSTOV(avc);
1292
1293 return (code);
1294 }
1295
1296 static int
1297 gafs_close(struct vnode *vp, afs_int32 aflags, int count,
1298 offset_t offset, afs_ucred_t *acred)
1299 {
1300 int code;
1301 AFS_GLOCK();
1302 code = afs_close(VTOAFS(vp), aflags, count, offset, acred);
1303 AFS_GUNLOCK();
1304 return (code);
1305 }
1306
1307 static int
1308 gafs_getattr(struct vnode *vp, struct vattr *attrs,
1309 int flags, afs_ucred_t *acred)
1310 {
1311 int code;
1312 AFS_GLOCK();
1313 code = afs_getattr(VTOAFS(vp), attrs, flags, acred);
1314 AFS_GUNLOCK();
1315 return (code);
1316 }
1317
1318
1319 static int
1320 gafs_setattr(struct vnode *vp, struct vattr *attrs,
1321 int flags, afs_ucred_t *acred)
1322 {
1323 int code;
1324 AFS_GLOCK();
1325 code = afs_setattr(VTOAFS(vp), attrs, flags, acred);
1326 AFS_GUNLOCK();
1327 return (code);
1328 }
1329
1330
1331 static int
1332 gafs_access(struct vnode *vp, afs_int32 amode, int flags,
1333 afs_ucred_t *acred)
1334 {
1335 int code;
1336 AFS_GLOCK();
1337 code = afs_access(VTOAFS(vp), amode, flags, acred);
1338 AFS_GUNLOCK();
1339 return (code);
1340 }
1341
1342
1343 static int
1344 gafs_lookup(struct vnode *dvp, char *aname,
1345 struct vnode **vpp, struct pathname *pnp, int flags,
1346 struct vnode *rdir, afs_ucred_t *acred)
1347 {
1348 int code;
1349 struct vcache *tvc = NULL;
1350
1351 AFS_GLOCK();
1352 code = afs_lookup(VTOAFS(dvp), aname, &tvc, pnp, flags, rdir, acred);
1353 AFS_GUNLOCK();
1354
1355 *vpp = NULL;
1356 if (tvc) {
1357 *vpp = AFSTOV(tvc);
1358 }
1359
1360 return (code);
1361 }
1362
1363
1364 static int
1365 gafs_create(struct vnode *dvp, char *aname, struct vattr *attrs,
1366 enum vcexcl aexcl, int amode, struct vnode **vpp,
1367 afs_ucred_t *acred)
1368 {
1369 int code;
1370 struct vcache *tvc = NULL;
1371
1372 AFS_GLOCK();
1373 code = afs_create(VTOAFS(dvp), aname, attrs, aexcl, amode, &tvc, acred);
1374 AFS_GUNLOCK();
1375
1376 *vpp = NULL;
1377 if (tvc) {
1378 *vpp = AFSTOV(tvc);
1379 }
1380
1381 return (code);
1382 }
1383
1384 static int
1385 gafs_remove(struct vnode *vp, char *aname, afs_ucred_t *acred)
1386 {
1387 int code;
1388 AFS_GLOCK();
1389 code = afs_remove(VTOAFS(vp), aname, acred);
1390 AFS_GUNLOCK();
1391 return (code);
1392 }
1393
1394 static int
1395 gafs_link(struct vnode *dvp, struct vnode *svp,
1396 char *aname, afs_ucred_t *acred)
1397 {
1398 int code;
1399 AFS_GLOCK();
1400 code = afs_link(VTOAFS(dvp), VTOAFS(svp), aname, acred);
1401 AFS_GUNLOCK();
1402 return (code);
1403 }
1404
1405 static int
1406 gafs_rename(struct vnode *odvp, char *aname1,
1407 struct vnode *ndvp, char *aname2,
1408 afs_ucred_t *acred)
1409 {
1410 int code;
1411 struct vcache *aodp = VTOAFS(odvp);
1412 struct vcache *andp = VTOAFS(ndvp);
1413
1414 AFS_GLOCK();
1415 code = afs_rename(aodp, aname1, andp, aname2, acred);
1416 #ifdef AFS_SUN510_ENV
1417 if (code == 0) {
1418 struct vcache *avcp = NULL;
1419
1420 (void) afs_lookup(andp, aname2, &avcp, NULL, 0, NULL, acred);
1421 if (avcp) {
1422 struct vnode *vp = AFSTOV(avcp), *pvp = AFSTOV(andp);
1423
1424 # ifdef HAVE_VN_RENAMEPATH
1425 vn_renamepath(pvp, vp, aname2, strlen(aname2));
1426 # else
1427 mutex_enter(&vp->v_lock);
1428 if (vp->v_path != NULL) {
1429 kmem_free(vp->v_path, strlen(vp->v_path) + 1);
1430 vp->v_path = NULL;
1431 }
1432 mutex_exit(&vp->v_lock);
1433 vn_setpath(afs_globalVp, pvp, vp, aname2, strlen(aname2));
1434 # endif /* !HAVE_VN_RENAMEPATH */
1435
1436 AFS_RELE(AFSTOV(avcp));
1437 }
1438 }
1439 #endif
1440 AFS_GUNLOCK();
1441 return (code);
1442 }
1443
1444 static int
1445 gafs_mkdir(struct vnode *dvp, char *aname, struct vattr *attrs,
1446 struct vnode **vpp, afs_ucred_t *acred)
1447 {
1448 int code;
1449 struct vcache *tvc = NULL;
1450
1451 AFS_GLOCK();
1452 code = afs_mkdir(VTOAFS(dvp), aname, attrs, &tvc, acred);
1453 AFS_GUNLOCK();
1454
1455 *vpp = NULL;
1456 if (tvc) {
1457 *vpp = AFSTOV(tvc);
1458 }
1459
1460 return (code);
1461 }
1462
1463 static int
1464 gafs_rmdir(struct vnode *vp, char *aname, struct vnode *cdirp,
1465 afs_ucred_t *acred)
1466 {
1467 int code;
1468 AFS_GLOCK();
1469 code = afs_rmdir(VTOAFS(vp), aname, cdirp, acred);
1470 AFS_GUNLOCK();
1471 return (code);
1472 }
1473
1474
1475 static int
1476 gafs_readdir(struct vnode *vp, struct uio *auio,
1477 afs_ucred_t *acred, int *eofp)
1478 {
1479 int code;
1480 AFS_GLOCK();
1481 code = afs_readdir(VTOAFS(vp), auio, acred, eofp);
1482 AFS_GUNLOCK();
1483 return (code);
1484 }
1485
1486 static int
1487 gafs_symlink(struct vnode *vp, char *aname, struct vattr *attrs,
1488 char *atargetName, afs_ucred_t *acred)
1489 {
1490 int code;
1491 AFS_GLOCK();
1492 code = afs_symlink(VTOAFS(vp), aname, attrs, atargetName, NULL, acred);
1493 AFS_GUNLOCK();
1494 return (code);
1495 }
1496
1497
1498 static int
1499 gafs_readlink(struct vnode *vp, struct uio *auio, afs_ucred_t *acred)
1500 {
1501 int code;
1502 AFS_GLOCK();
1503 code = afs_readlink(VTOAFS(vp), auio, acred);
1504 AFS_GUNLOCK();
1505 return (code);
1506 }
1507
1508 static int
1509 gafs_fsync(struct vnode *vp, int flag, afs_ucred_t *acred)
1510 {
1511 int code;
1512 AFS_GLOCK();
1513 code = afs_fsync(VTOAFS(vp), flag, acred);
1514 AFS_GUNLOCK();
1515 return (code);
1516 }
1517
1518 static int
1519 afs_inactive(struct vcache *avc, afs_ucred_t *acred)
1520 {
1521 struct vnode *vp = AFSTOV(avc);
1522 if (afs_shuttingdown != AFS_RUNNING)
1523 return 0;
1524
1525 /*
1526 * In Solaris and HPUX s800 and HP-UX10.0 they actually call us with
1527 * v_count 1 on last reference!
1528 */
1529 mutex_enter(&vp->v_lock);
1530 if (avc->vrefCount <= 0)
1531 osi_Panic("afs_inactive : v_count <=0\n");
1532
1533 /*
1534 * If more than 1 don't unmap the vnode but do decrement the ref count
1535 */
1536 vp->v_count--;
1537 if (vp->v_count > 0) {
1538 mutex_exit(&vp->v_lock);
1539 return 0;
1540 }
1541 mutex_exit(&vp->v_lock);
1542
1543 #ifndef AFS_SUN511_ENV
1544 /*
1545 * Solaris calls VOP_OPEN on exec, but doesn't call VOP_CLOSE when
1546 * the executable exits. So we clean up the open count here.
1547 *
1548 * Only do this for AFS_MVSTAT_FILE vnodes: when using fakestat, we can't
1549 * lose the open count for volume roots (AFS_MVSTAT_ROOT), even though they
1550 * will get VOP_INACTIVE'd when released by afs_PutFakeStat().
1551 */
1552 if (avc->opens > 0 && avc->mvstat == AFS_MVSTAT_FILE && !(avc->f.states & CCore))
1553 avc->opens = avc->execsOrWriters = 0;
1554 #endif
1555
1556 afs_InactiveVCache(avc, acred);
1557
1558 AFS_GUNLOCK();
1559 /* VFS_RELE must be called outside of GLOCK, since it can potentially
1560 * call afs_freevfs, which acquires GLOCK */
1561 VFS_RELE(afs_globalVFS);
1562 AFS_GLOCK();
1563
1564 return 0;
1565 }
1566
1567 static void
1568 gafs_inactive(struct vnode *vp, afs_ucred_t *acred)
1569 {
1570 AFS_GLOCK();
1571 (void)afs_inactive(VTOAFS(vp), acred);
1572 AFS_GUNLOCK();
1573 }
1574
1575
1576 static int
1577 gafs_fid(struct vnode *vp, struct fid **fidpp)
1578 {
1579 int code;
1580 AFS_GLOCK();
1581 code = afs_fid(VTOAFS(vp), fidpp);
1582 AFS_GUNLOCK();
1583 return (code);
1584 }
1585
1586 #if defined(AFS_SUN511_ENV)
1587 /* The following list must always be NULL-terminated */
1588 const fs_operation_def_t afs_vnodeops_template[] = {
1589 VOPNAME_OPEN, { .vop_open = gafs_open },
1590 VOPNAME_CLOSE, { .vop_close = gafs_close },
1591 VOPNAME_READ, { .vop_read = afs_vmread },
1592 VOPNAME_WRITE, { .vop_write = afs_vmwrite },
1593 VOPNAME_IOCTL, { .vop_ioctl = afs_ioctl },
1594 VOPNAME_SETFL, { .vop_setfl = fs_setfl },
1595 VOPNAME_GETATTR, { .vop_getattr = gafs_getattr },
1596 VOPNAME_SETATTR, { .vop_setattr = gafs_setattr },
1597 VOPNAME_ACCESS, { .vop_access = gafs_access },
1598 VOPNAME_LOOKUP, { .vop_lookup = gafs_lookup },
1599 VOPNAME_CREATE, { .vop_create = gafs_create },
1600 VOPNAME_REMOVE, { .vop_remove = gafs_remove },
1601 VOPNAME_LINK, { .vop_link = gafs_link },
1602 VOPNAME_RENAME, { .vop_rename = gafs_rename },
1603 VOPNAME_MKDIR, { .vop_mkdir = gafs_mkdir },
1604 VOPNAME_RMDIR, { .vop_rmdir = gafs_rmdir },
1605 VOPNAME_READDIR, { .vop_readdir = gafs_readdir },
1606 VOPNAME_SYMLINK, { .vop_symlink = gafs_symlink },
1607 VOPNAME_READLINK, { .vop_readlink = gafs_readlink },
1608 VOPNAME_FSYNC, { .vop_fsync = gafs_fsync },
1609 VOPNAME_INACTIVE, { .vop_inactive = gafs_inactive },
1610 VOPNAME_FID, { .vop_fid = gafs_fid },
1611 VOPNAME_RWLOCK, { .vop_rwlock = afs_rwlock },
1612 VOPNAME_RWUNLOCK, { .vop_rwunlock = afs_rwunlock },
1613 VOPNAME_SEEK, { .vop_seek = afs_seek },
1614 VOPNAME_CMP, { .vop_cmp = afs_cmp },
1615 VOPNAME_FRLOCK, { .vop_frlock = afs_frlock },
1616 VOPNAME_SPACE, { .vop_space = afs_space },
1617 VOPNAME_REALVP, { .vop_realvp = afs_realvp },
1618 VOPNAME_GETPAGE, { .vop_getpage = afs_getpage },
1619 VOPNAME_PUTPAGE, { .vop_putpage = afs_putpage },
1620 VOPNAME_MAP, { .vop_map = afs_map },
1621 VOPNAME_ADDMAP, { .vop_addmap = afs_addmap },
1622 VOPNAME_DELMAP, { .vop_delmap = afs_delmap },
1623 VOPNAME_POLL, { .vop_poll = fs_poll },
1624 VOPNAME_PATHCONF, { .vop_pathconf = afs_pathconf },
1625 VOPNAME_PAGEIO, { .vop_pageio = afs_pageio },
1626 VOPNAME_DUMP, { .vop_dump = afs_dump },
1627 VOPNAME_DUMPCTL, { .vop_dumpctl = afs_dumpctl },
1628 VOPNAME_DISPOSE, { .vop_dispose = afs_dispose },
1629 VOPNAME_GETSECATTR, { .vop_getsecattr = afs_getsecattr },
1630 VOPNAME_SETSECATTR, { .vop_setsecattr = afs_setsecattr },
1631 VOPNAME_SHRLOCK, { .vop_shrlock = fs_shrlock },
1632 NULL, NULL
1633 };
1634 vnodeops_t *afs_ops;
1635 #elif defined(AFS_SUN510_ENV)
1636 /* The following list must always be NULL-terminated */
1637 const fs_operation_def_t afs_vnodeops_template[] = {
1638 VOPNAME_OPEN, gafs_open,
1639 VOPNAME_CLOSE, gafs_close,
1640 VOPNAME_READ, afs_vmread,
1641 VOPNAME_WRITE, afs_vmwrite,
1642 VOPNAME_IOCTL, afs_ioctl,
1643 VOPNAME_SETFL, fs_setfl,
1644 VOPNAME_GETATTR, gafs_getattr,
1645 VOPNAME_SETATTR, gafs_setattr,
1646 VOPNAME_ACCESS, gafs_access,
1647 VOPNAME_LOOKUP, gafs_lookup,
1648 VOPNAME_CREATE, gafs_create,
1649 VOPNAME_REMOVE, gafs_remove,
1650 VOPNAME_LINK, gafs_link,
1651 VOPNAME_RENAME, gafs_rename,
1652 VOPNAME_MKDIR, gafs_mkdir,
1653 VOPNAME_RMDIR, gafs_rmdir,
1654 VOPNAME_READDIR, gafs_readdir,
1655 VOPNAME_SYMLINK, gafs_symlink,
1656 VOPNAME_READLINK, gafs_readlink,
1657 VOPNAME_FSYNC, gafs_fsync,
1658 VOPNAME_INACTIVE, gafs_inactive,
1659 VOPNAME_FID, gafs_fid,
1660 VOPNAME_RWLOCK, afs_rwlock,
1661 VOPNAME_RWUNLOCK, afs_rwunlock,
1662 VOPNAME_SEEK, afs_seek,
1663 VOPNAME_CMP, afs_cmp,
1664 VOPNAME_FRLOCK, afs_frlock,
1665 VOPNAME_SPACE, afs_space,
1666 VOPNAME_REALVP, afs_realvp,
1667 VOPNAME_GETPAGE, afs_getpage,
1668 VOPNAME_PUTPAGE, afs_putpage,
1669 VOPNAME_MAP, afs_map,
1670 VOPNAME_ADDMAP, afs_addmap,
1671 VOPNAME_DELMAP, afs_delmap,
1672 VOPNAME_POLL, fs_poll,
1673 VOPNAME_DUMP, afs_dump,
1674 VOPNAME_PATHCONF, afs_pathconf,
1675 VOPNAME_PAGEIO, afs_pageio,
1676 VOPNAME_DUMPCTL, afs_dumpctl,
1677 VOPNAME_DISPOSE, afs_dispose,
1678 VOPNAME_GETSECATTR, afs_getsecattr,
1679 VOPNAME_SETSECATTR, afs_setsecattr,
1680 VOPNAME_SHRLOCK, fs_shrlock,
1681 NULL, NULL
1682 };
1683 struct vnodeops *afs_ops;
1684 #else
1685 struct vnodeops Afs_vnodeops = {
1686 gafs_open,
1687 gafs_close,
1688 afs_vmread,
1689 afs_vmwrite,
1690 afs_ioctl,
1691 fs_setfl,
1692 gafs_getattr,
1693 gafs_setattr,
1694 gafs_access,
1695 gafs_lookup,
1696 gafs_create,
1697 gafs_remove,
1698 gafs_link,
1699 gafs_rename,
1700 gafs_mkdir,
1701 gafs_rmdir,
1702 gafs_readdir,
1703 gafs_symlink,
1704 gafs_readlink,
1705 gafs_fsync,
1706 gafs_inactive,
1707 gafs_fid,
1708 afs_rwlock,
1709 afs_rwunlock,
1710 afs_seek,
1711 afs_cmp,
1712 afs_frlock,
1713 afs_space,
1714 afs_realvp,
1715 afs_getpage,
1716 afs_putpage,
1717 afs_map,
1718 afs_addmap,
1719 afs_delmap,
1720 fs_poll,
1721 afs_dump,
1722 afs_pathconf,
1723 afs_pageio,
1724 afs_dumpctl,
1725 afs_dispose,
1726 afs_setsecattr,
1727 afs_getsecattr,
1728 fs_shrlock,
1729 };
1730 struct vnodeops *afs_ops = &Afs_vnodeops;
1731 #endif
1732
1733 #endif /* AFS_GLOBAL_SUNLOCK */