2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include "afs/param.h"
16 #include "afs/sysincludes.h" /* Standard vendor system headers */
17 #include "afsincludes.h" /* Afs-based standard headers */
18 #include "afs/afs_stats.h" /* statistics */
21 /* Try to discard pages, in order to recycle a vcache entry.
23 * We also make some sanity checks: ref count, open count, held locks.
25 * We also do some non-VM-related chores, such as releasing the cred pointer
26 * (for AIX and Solaris) and releasing the gnode (for AIX).
28 * Locking: afs_xvcache lock is held. If it is dropped and re-acquired,
29 * *slept should be set to warn the caller.
31 * Formerly, afs_xvcache was dropped and re-acquired for Solaris, but now it
32 * is not dropped and re-acquired for any platform. It may be that *slept is
33 * therefore obsolescent.
35 * OSF/1 Locking: VN_LOCK has been called.
38 osi_VM_FlushVCache(struct vcache *avc, int *slept)
40 struct vnode *vp = AFSTOV(avc);
41 #ifdef AFS_DARWIN14_ENV
42 if (UBCINFOEXISTS(vp))
45 if (avc->vrefCount > DARWIN_REFBASE)
51 /* if a lock is held, give up */
52 if (CheckLock(&avc->lock))
57 #ifndef AFS_DARWIN14_ENV
58 if (UBCINFOEXISTS(vp)) {
65 /* This is literally clean_up_name_parent_ptrs() */
66 /* Critical to clean up any state attached to the vnode here since it's
67 being recycled, and we're not letting refcnt drop to 0 to trigger
69 if (VNAME(vp) || VPARENT(vp)) {
73 /* do it this way so we don't block before clearing
96 /* Try to store pages to cache, in order to store a file back to the server.
98 * Locking: the vcache entry's lock is held. It will usually be dropped and
102 osi_VM_StoreAllSegments(struct vcache *avc)
104 struct vnode *vp = AFSTOV(avc);
105 ReleaseWriteLock(&avc->lock);
107 if (UBCINFOEXISTS(vp)) {
111 ObtainWriteLock(&avc->lock, 94);
114 /* Try to invalidate pages, for "fs flush" or "fs flushv"; or
115 * try to free pages, when deleting a file.
117 * Locking: the vcache entry's lock is held. It may be dropped and
120 * Since we drop and re-obtain the lock, we can't guarantee that there won't
121 * be some pages around when we return, newly created by concurrent activity.
124 osi_VM_TryToSmush(struct vcache *avc, struct AFS_UCRED *acred, int sync)
126 struct vnode *vp = AFSTOV(avc);
131 ReleaseWriteLock(&avc->lock);
133 if (UBCINFOEXISTS(vp)) {
134 size = ubc_getsize(vp);
135 kret = ubc_invalidate(vp, 0, size);
136 if (kret != 1) /* should be KERN_SUCCESS */
137 printf("TryToSmush: invalidate failed (error = %d)\n", kret);
140 ObtainWriteLock(&avc->lock, 59);
143 /* Purge VM for a file when its callback is revoked.
145 * Locking: No lock is held, not even the global lock.
147 /* XXX this seems to not be referenced anywhere. *somebody* ought to be calling
148 this, and also making sure that ubc's idea of the filesize is right more
151 osi_VM_FlushPages(struct vcache *avc, struct AFS_UCRED *credp)
153 struct vnode *vp = AFSTOV(avc);
157 if (UBCINFOEXISTS(vp)) {
158 size = ubc_getsize(vp);
159 kret = ubc_invalidate(vp, 0, size);
160 if (kret != 1) /* Should be KERN_SUCCESS */
161 printf("VMFlushPages: invalidate failed (error = %d)\n", kret);
162 /* XXX what about when not CStatd */
163 if (avc->states & CStatd && size != avc->m.Length)
164 ubc_setsize(vp, avc->m.Length);
168 /* Purge pages beyond end-of-file, when truncating a file.
170 * Locking: no lock is held, not even the global lock.
171 * activeV is raised. This is supposed to block pageins, but at present
172 * it only works on Solaris.
175 osi_VM_Truncate(struct vcache *avc, int alen, struct AFS_UCRED *acred)
177 struct vnode *vp = AFSTOV(avc);
178 if (UBCINFOEXISTS(vp)) {
179 ubc_setsize(vp, alen);
183 /* vnreclaim and vinactive are probably not aggressive enough to keep
184 enough afs vcaches free, so we try to do some of it ourselves */
185 /* XXX there's probably not nearly enough locking here */
187 osi_VM_TryReclaim(struct vcache *avc, int *slept)
189 struct proc *p = current_proc();
190 struct vnode *vp = AFSTOV(avc);
192 #ifdef AFS_DARWIN14_ENV
198 VN_HOLD(vp); /* remove from inactive list */
199 if (!simple_lock_try(&vp->v_interlock)) {
203 if (!UBCINFOEXISTS(vp) || vp->v_usecount != 2+DARWIN_REFBASE) {
204 simple_unlock(&vp->v_interlock);
208 if (ISSET(vp->v_flag, VUINACTIVE)) {
209 simple_unlock(&vp->v_interlock);
211 printf("vnode %x still inactive!", vp);
214 #ifdef AFS_DARWIN14_ENV
215 if (vp->v_ubcinfo->ui_refcount > 1 || vp->v_ubcinfo->ui_mapped) {
216 simple_unlock(&vp->v_interlock);
220 if (ISSET(vp->v_flag, VORECLAIM)) {
221 simple_unlock(&vp->v_interlock);
226 if (vp->v_ubcinfo->ui_holdcnt) {
227 simple_unlock(&vp->v_interlock);
232 if (slept && ubc_issetflags(vp, UI_WASMAPPED)) {
233 /* We can't possibly release this in time for this NewVCache to get it */
234 simple_unlock(&vp->v_interlock);
239 #ifndef AFS_DARWIN14_ENV
240 vp->v_usecount--; /* we want the usecount to be 1 */
244 ReleaseWriteLock(&afs_xvcache);
247 ReleaseReadLock(&afs_xvcache);
250 if (ubc_issetflags(vp, UI_WASMAPPED)) {
251 simple_unlock(&vp->v_interlock);
252 #ifdef AFS_DARWIN14_ENV
253 ubc_release_named(vp);
257 if (ubc_issetflags(vp, UI_HASOBJREF))
258 printf("ubc_release didn't release the reference?!\n");
260 #ifdef AFS_DARWIN14_ENV
261 SET(vp->v_flag, VORECLAIM);
263 if (!vn_lock(vp, LK_EXCLUSIVE|LK_INTERLOCK,current_proc())) {
264 #ifdef AFS_DARWIN14_ENV
265 obj = ubc_getobject(vp,UBC_HOLDOBJECT);
266 if ((didhold = ubc_hold(vp)))
267 (void)ubc_clean(vp, 0);
269 #ifdef AFS_DARWIN13_ENV
270 obj = ubc_getobject(vp,(UBC_NOREACTIVATE|UBC_HOLDOBJECT));
272 obj = ubc_getobject(vp);
274 (void)ubc_clean(vp, 1);
276 vinvalbuf(vp, V_SAVE, &afs_osi_cred, p, 0, 0);
277 if (vp->v_usecount ==
278 #ifdef AFS_DARWIN14_ENV
284 VOP_UNLOCK(vp, 0, p); /* was VOP_INACTIVE(vp, p); */
286 VOP_UNLOCK(vp, 0, p);
287 #ifdef AFS_DARWIN14_ENV
292 if (ISSET(vp->v_flag, VTERMINATE))
293 panic("afs_vnreclaim: already terminating");
294 SET(vp->v_flag, VTERMINATE);
295 memory_object_destroy(obj, 0);
296 while (ISSET(vp->v_flag, VTERMINATE)) {
297 SET(vp->v_flag, VTERMWANT);
298 tsleep((caddr_t)&vp->v_ubcinfo, PINOD, "afs_vnreclaim", 0);
301 #ifdef AFS_DARWIN14_ENV
302 simple_lock(&vp->v_interlock);
303 CLR(vp->v_flag, VORECLAIM);
304 if (ISSET((vp)->v_flag, VXWANT)) {
305 CLR((vp)->v_flag, VXWANT);
306 wakeup((caddr_t)(vp));
309 simple_unlock(&vp->v_interlock);
312 #ifdef AFS_DARWIN14_ENV
313 CLR(vp->v_flag, VORECLAIM);
315 if (simple_lock_try(&vp->v_interlock))
316 panic("afs_vnreclaim: slept, but did no work :(");
317 if (UBCINFOEXISTS(vp) && vp->v_count == DARWIN_REFBASE +
318 #ifdef AFS_DARWIN14_ENV
324 #ifndef AFS_DARWIN14_ENV
325 /* We left the refcount high in 1.4 */
328 simple_unlock(&vp->v_interlock);
331 #ifdef AFS_DARWIN14_ENV
332 /* We left the refcount high in 1.4 */
335 simple_unlock(&vp->v_interlock);
341 ObtainWriteLock(&afs_xvcache,175);
343 ObtainReadLock(&afs_xvcache);
347 osi_VM_NukePages(struct vnode *vp, off_t offset, off_t size)
350 struct vcache *avc = VTOAFS(vp);
352 #ifdef AFS_DARWIN14_ENV
353 offset = trunc_page(offset);
354 size = round_page(size + 1);
356 ubc_page_op(vp, (vm_offset_t) offset,
357 UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP, 0, 0);
363 #ifdef AFS_DARWIN13_ENV
364 if (UBCINFOEXISTS(vp))
365 object = ubc_getobject(vp, UBC_NOREACTIVATE);
367 if (UBCINFOEXISTS(vp))
368 object = ubc_getobject(vp);
373 offset = trunc_page(offset);
374 size = round_page(size + 1);
376 #ifdef AFS_DARWIN13_ENV
378 memory_object_page_op(object, (vm_offset_t) offset,
379 UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP, 0,
385 /* This is all we can do, and it's not enough. sucks to be us */
386 ubc_setsize(vp, offset);
387 size = (offset + size > avc->m.Length) ? offset + size : avc->m.Length;
388 ubc_setsize(vp, size);
394 osi_VM_Setup(struct vcache *avc, int force)
397 struct vnode *vp = AFSTOV(avc);
399 if (UBCISVALID(vp) && ((avc->states & CStatd) || force)) {
400 if (!UBCINFOEXISTS(vp) && !ISSET(vp->v_flag, VTERMINATE)) {
402 avc->states |= CUBCinit;
404 if ((error = ubc_info_init(&avc->v))) {
406 avc->states &= ~CUBCinit;
407 AFS_RELE(AFSTOV(avc));
410 #ifndef AFS_DARWIN14_ENV
411 simple_lock(&avc->v.v_interlock);
412 if (!ubc_issetflags(&avc->v, UI_HASOBJREF))
413 #ifdef AFS_DARWIN13_ENV
415 (&avc->v, (UBC_NOREACTIVATE | UBC_HOLDOBJECT)))
416 panic("VM_Setup: null object");
418 (void)_ubc_getobject(&avc->v, 1); /* return value not used */
420 simple_unlock(&avc->v.v_interlock);
423 avc->states &= ~CUBCinit;
424 AFS_RELE(AFSTOV(avc));
426 if (UBCINFOEXISTS(&avc->v))
427 ubc_setsize(&avc->v, avc->m.Length);