Commit | Line | Data |
---|---|---|
805e021f CE |
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 */ |