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"
15 #include "../afs/sysincludes.h" /* Standard vendor system headers */
16 #include "../afs/afsincludes.h" /* Afs-based standard headers */
17 #include "../afs/afs_stats.h" /* statistics */
20 /* Try to discard pages, in order to recycle a vcache entry.
22 * We also make some sanity checks: ref count, open count, held locks.
24 * We also do some non-VM-related chores, such as releasing the cred pointer
25 * (for AIX and Solaris) and releasing the gnode (for AIX).
27 * Locking: afs_xvcache lock is held. If it is dropped and re-acquired,
28 * *slept should be set to warn the caller.
30 * Formerly, afs_xvcache was dropped and re-acquired for Solaris, but now it
31 * is not dropped and re-acquired for any platform. It may be that *slept is
32 * therefore obsolescent.
34 * OSF/1 Locking: VN_LOCK has been called.
36 int osi_VM_FlushVCache(struct vcache *avc, int *slept)
38 struct vnode *vp=AFSTOV(avc);
39 #ifdef AFS_DARWIN14_ENV
40 if (UBCINFOEXISTS(vp))
49 /* if a lock is held, give up */
50 if (CheckLock(&avc->lock) || afs_CheckBozonLock(&avc->pvnLock))
55 #ifndef AFS_DARWIN14_ENV
56 if (UBCINFOEXISTS(vp))
71 /* Try to store pages to cache, in order to store a file back to the server.
73 * Locking: the vcache entry's lock is held. It will usually be dropped and
76 void osi_VM_StoreAllSegments(struct vcache *avc)
78 struct vnode *vp=AFSTOV(avc);
79 ReleaseWriteLock(&avc->lock);
81 if (UBCINFOEXISTS(vp)) {
85 ObtainWriteLock(&avc->lock,94);
88 /* Try to invalidate pages, for "fs flush" or "fs flushv"; or
89 * try to free pages, when deleting a file.
91 * Locking: the vcache entry's lock is held. It may be dropped and
94 * Since we drop and re-obtain the lock, we can't guarantee that there won't
95 * be some pages around when we return, newly created by concurrent activity.
97 void osi_VM_TryToSmush(struct vcache *avc, struct AFS_UCRED *acred,
100 struct vnode *vp=AFSTOV(avc);
105 ReleaseWriteLock(&avc->lock);
107 if (UBCINFOEXISTS(vp)) {
108 size=ubc_getsize(vp);
109 kret=ubc_invalidate(vp,0,size);
110 if (kret != 1) /* should be KERN_SUCCESS */
111 printf("TryToSmush: invalidate failed (error = %d)\n", kret);
114 ObtainWriteLock(&avc->lock,59);
117 /* Purge VM for a file when its callback is revoked.
119 * Locking: No lock is held, not even the global lock.
121 /* XXX this seems to not be referenced anywhere. *somebody* ought to be calling
122 this, and also making sure that ubc's idea of the filesize is right more
124 void osi_VM_FlushPages(struct vcache *avc, struct AFS_UCRED *credp)
126 struct vnode *vp=AFSTOV(avc);
130 if (UBCINFOEXISTS(vp)) {
131 size=ubc_getsize(vp);
132 kret=ubc_invalidate(vp,0,size);
133 if (kret != 1) /* Should be KERN_SUCCESS */
134 printf("VMFlushPages: invalidate failed (error = %d)\n", kret);
135 /* XXX what about when not CStatd */
136 if (avc->states & CStatd && size != avc->m.Length)
137 ubc_setsize(vp, avc->m.Length);
141 /* Purge pages beyond end-of-file, when truncating a file.
143 * Locking: no lock is held, not even the global lock.
144 * activeV is raised. This is supposed to block pageins, but at present
145 * it only works on Solaris.
147 void osi_VM_Truncate(struct vcache *avc, int alen, struct AFS_UCRED *acred)
149 struct vnode *vp=AFSTOV(avc);
150 if (UBCINFOEXISTS(vp)) {
151 ubc_setsize(vp, alen);
155 /* vnreclaim and vinactive are probably not aggressive enough to keep
156 enough afs vcaches free, so we try to do some of it ourselves */
157 /* XXX there's probably not nearly enough locking here */
158 void osi_VM_TryReclaim(struct vcache *avc, int *slept)
160 struct proc *p=current_proc();
161 struct vnode *vp=AFSTOV(avc);
166 VN_HOLD(vp); /* remove from inactive list */
167 if (!simple_lock_try(&vp->v_interlock)) {
171 if (!UBCINFOEXISTS(vp) || vp->v_count != 2) {
172 simple_unlock(&vp->v_interlock);
176 #ifdef AFS_DARWIN14_ENV
177 if (vp->v_ubcinfo->ui_refcount > 1 || vp->v_ubcinfo->ui_mapped) {
178 simple_unlock(&vp->v_interlock);
183 if (vp->v_ubcinfo->ui_holdcnt) {
184 simple_unlock(&vp->v_interlock);
189 if (slept && ubc_issetflags(vp, UI_WASMAPPED)) {
190 /* We can't possibly release this in time for this NewVCache to get it */
191 simple_unlock(&vp->v_interlock);
196 vp->v_usecount--; /* we want the usecount to be 1 */
199 ReleaseWriteLock(&afs_xvcache);
202 ReleaseReadLock(&afs_xvcache);
205 if (ubc_issetflags(vp, UI_WASMAPPED)) {
206 simple_unlock(&vp->v_interlock);
207 #ifdef AFS_DARWIN14_ENV
208 ubc_release_named(vp);
212 if (ubc_issetflags(vp, UI_HASOBJREF))
213 printf("ubc_release didn't release the reference?!\n");
214 } else if (!vn_lock(vp, LK_EXCLUSIVE|LK_INTERLOCK,current_proc())) {
215 #ifdef AFS_DARWIN14_ENV
216 obj = ubc_getobject(vp,UBC_HOLDOBJECT);
218 #ifdef AFS_DARWIN13_ENV
219 obj = ubc_getobject(vp,(UBC_NOREACTIVATE|UBC_HOLDOBJECT));
221 obj = ubc_getobject(vp);
224 (void)ubc_clean(vp, 1);
225 vinvalbuf(vp, V_SAVE, &afs_osi_cred, p, 0, 0);
226 if (vp->v_usecount == 1)
229 VOP_UNLOCK(vp, 0, p);
231 if (ISSET(vp->v_flag, VTERMINATE))
232 panic("afs_vnreclaim: already teminating");
233 SET(vp->v_flag, VTERMINATE);
234 memory_object_destroy(obj, 0);
235 while (ISSET(vp->v_flag, VTERMINATE)) {
236 SET(vp->v_flag, VTERMWANT);
237 tsleep((caddr_t)&vp->v_ubcinfo, PINOD, "afs_vnreclaim", 0);
241 if (simple_lock_try(&vp->v_interlock))
242 panic("afs_vnreclaim: slept, but did no work :(");
243 if (UBCINFOEXISTS(vp) && vp->v_count == 1) {
245 simple_unlock(&vp->v_interlock);
248 simple_unlock(&vp->v_interlock);
252 ObtainWriteLock(&afs_xvcache,175);
254 ObtainReadLock(&afs_xvcache);
257 void osi_VM_NukePages(struct vnode *vp, off_t offset, off_t size)
260 struct vcache *avc = VTOAFS(vp);
262 #ifdef AFS_DARWIN14_ENV
263 offset=trunc_page(offset);
264 size=round_page(size+1);
266 ubc_page_op(vp, (vm_offset_t)offset,
267 UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP,
274 #ifdef AFS_DARWIN13_ENV
275 if (UBCINFOEXISTS(vp))
276 object = ubc_getobject(vp, UBC_NOREACTIVATE);
278 if (UBCINFOEXISTS(vp))
279 object = ubc_getobject(vp);
284 offset=trunc_page(offset);
285 size=round_page(size+1);
287 #ifdef AFS_DARWIN13_ENV
289 memory_object_page_op(object, (vm_offset_t)offset,
290 UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP,
296 /* This is all we can do, and it's not enough. sucks to be us */
297 ubc_setsize(vp, offset);
298 size=(offset + size > avc->m.Length) ? offset + size : avc->m.Length;
299 ubc_setsize(vp, size);
304 int osi_VM_Setup(struct vcache *avc, int force) {
306 struct vnode *vp=AFSTOV(avc);
308 if (UBCISVALID(vp) && ((avc->states & CStatd) || force)) {
309 if (!UBCINFOEXISTS(vp) && !ISSET(vp->v_flag, VTERMINATE)) {
311 avc->states |= CUBCinit;
313 if ((error=ubc_info_init(&avc->v))) {
315 avc->states &= ~CUBCinit;
319 #ifndef AFS_DARWIN14_ENV
320 simple_lock(&avc->v.v_interlock);
321 if (!ubc_issetflags(&avc->v, UI_HASOBJREF))
322 #ifdef AFS_DARWIN13_ENV
323 if (ubc_getobject(&avc->v, (UBC_NOREACTIVATE|UBC_HOLDOBJECT)))
324 panic("VM_Setup: null object");
326 (void)_ubc_getobject(&avc->v, 1); /* return value not used */
328 simple_unlock(&avc->v.v_interlock);
331 avc->states &= ~CUBCinit;
334 if (UBCINFOEXISTS(&avc->v))
335 ubc_setsize(&avc->v, avc->m.Length);