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 "../afs/param.h" /* Should be always first */
11 #include <afsconfig.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.
37 osi_VM_FlushVCache(avc, slept)
41 struct vnode *vp=(struct vnode *)avc;
48 /* if a lock is held, give up */
49 if (CheckLock(&avc->lock) || afs_CheckBozonLock(&avc->pvnLock))
54 if (UBCINFOEXISTS(vp))
68 /* Try to store pages to cache, in order to store a file back to the server.
70 * Locking: the vcache entry's lock is held. It will usually be dropped and
74 osi_VM_StoreAllSegments(avc)
77 struct vnode *vp=(struct vnode *)avc;
78 ReleaseWriteLock(&avc->lock);
80 if (UBCINFOEXISTS(vp)) {
84 ObtainWriteLock(&avc->lock,94);
87 /* Try to invalidate pages, for "fs flush" or "fs flushv"; or
88 * try to free pages, when deleting a file.
90 * Locking: the vcache entry's lock is held. It may be dropped and
93 * Since we drop and re-obtain the lock, we can't guarantee that there won't
94 * be some pages around when we return, newly created by concurrent activity.
97 osi_VM_TryToSmush(avc, acred, sync)
99 struct AFS_UCRED *acred;
102 struct vnode *vp=(struct vnode *)avc;
107 ReleaseWriteLock(&avc->lock);
109 if (UBCINFOEXISTS(vp)) {
110 size=ubc_getsize(vp);
111 kret=ubc_invalidate(vp,0,size);
112 if (kret != 1) /* should be KERN_SUCCESS */
113 printf("TryToSmush: invalidate failed (error = %d)\n", kret);
116 ObtainWriteLock(&avc->lock,59);
119 /* Purge VM for a file when its callback is revoked.
121 * Locking: No lock is held, not even the global lock.
123 /* XXX this seems to not be referenced anywhere. *somebody* ought to be calling
124 this, and also making sure that ubc's idea of the filesize is right more
127 osi_VM_FlushPages(avc, credp)
129 struct AFS_UCRED *credp;
131 struct vnode *vp=(struct vnode *)avc;
135 if (UBCINFOEXISTS(vp)) {
136 size=ubc_getsize(vp);
137 kret=ubc_invalidate(vp,0,size);
138 if (kret != 1) /* Should be KERN_SUCCESS */
139 printf("VMFlushPages: invalidate failed (error = %d)\n", kret);
140 /* XXX what about when not CStatd */
141 if (avc->states & CStatd && size != avc->m.Length)
142 ubc_setsize(vp, avc->m.Length);
146 /* Purge pages beyond end-of-file, when truncating a file.
148 * Locking: no lock is held, not even the global lock.
149 * activeV is raised. This is supposed to block pageins, but at present
150 * it only works on Solaris.
153 osi_VM_Truncate(avc, alen, acred)
156 struct AFS_UCRED *acred;
158 struct vnode *vp=(struct vnode *)avc;
159 if (UBCINFOEXISTS(vp)) {
160 ubc_setsize(vp, alen);
164 extern struct AFS_UCRED afs_osi_cred;
165 extern afs_rwlock_t afs_xvcache;
166 /* vnreclaim and vinactive are probably not aggressive enough to keep
167 enough afs vcaches free, so we try to do some of it ourselves */
168 /* XXX there's probably not nearly enough locking here */
169 void osi_VM_TryReclaim(avc, slept)
173 struct proc *p=current_proc();
174 struct vnode *vp=(struct vnode *)avc;
179 VN_HOLD(vp); /* remove from inactive list */
180 if (!simple_lock_try(&vp->v_interlock)) {
184 if (!UBCINFOEXISTS(vp) || vp->v_count != 2) {
185 simple_unlock(&vp->v_interlock);
189 if (vp->v_ubcinfo->ui_holdcnt) {
190 simple_unlock(&vp->v_interlock);
194 if (slept && ubc_issetflags(vp, UI_WASMAPPED)) {
195 /* We can't possibly release this in time for this NewVCache to get it */
196 simple_unlock(&vp->v_interlock);
201 vp->v_usecount--; /* we want the usecount to be 1 */
204 ReleaseWriteLock(&afs_xvcache);
207 ReleaseReadLock(&afs_xvcache);
210 if (ubc_issetflags(vp, UI_WASMAPPED)) {
211 simple_unlock(&vp->v_interlock);
213 if (ubc_issetflags(vp, UI_HASOBJREF))
214 printf("ubc_release didn't release the reference?!\n");
215 } else if (!vn_lock(vp, LK_EXCLUSIVE|LK_INTERLOCK,current_proc())) {
216 #ifdef UBC_NOREACTIVATE
217 obj = ubc_getobject(vp,(UBC_NOREACTIVATE|UBC_HOLDOBJECT));
219 obj = ubc_getobject(vp);
221 (void)ubc_clean(vp, 1);
222 vinvalbuf(vp, V_SAVE, &afs_osi_cred, p, 0, 0);
223 if (vp->v_usecount == 1)
226 VOP_UNLOCK(vp, 0, p);
227 if (ISSET(vp->v_flag, VTERMINATE))
228 panic("afs_vnreclaim: already teminating");
229 SET(vp->v_flag, VTERMINATE);
230 memory_object_destroy(obj, 0);
231 while (ISSET(vp->v_flag, VTERMINATE)) {
232 SET(vp->v_flag, VTERMWANT);
233 tsleep((caddr_t)&vp->v_ubcinfo, PINOD, "afs_vnreclaim", 0);
236 if (simple_lock_try(&vp->v_interlock))
237 panic("afs_vnreclaim: slept, but did no work :(");
238 if (UBCINFOEXISTS(vp) && vp->v_count == 1) {
240 simple_unlock(&vp->v_interlock);
243 simple_unlock(&vp->v_interlock);
247 ObtainWriteLock(&afs_xvcache,175);
249 ObtainReadLock(&afs_xvcache);
252 void osi_VM_NukePages(struct vnode *vp, off_t offset, off_t size) {
255 struct vcache *avc = (struct vcache *)vp;
258 #ifdef UBC_NOREACTIVATE
259 if (UBCINFOEXISTS(vp))
260 object = ubc_getobject(vp, UBC_NOREACTIVATE);
262 if (UBCINFOEXISTS(vp))
263 object = ubc_getobject(vp);
268 offset=trunc_page(offset);
269 size=round_page(size+1);
271 #ifdef UBC_NOREACTIVATE
273 memory_object_page_op(object, (vm_offset_t)offset,
274 UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP,
280 ubc_setsize(vp, offset);
281 size=(offset + size > avc->m.Length) ? offset + size : avc->m.Length;
282 ubc_setsize(vp, size);
286 int osi_VM_Setup(struct vcache *avc) {
288 struct vnode *vp=(struct vnode *)avc;
290 if (UBCISVALID(vp) && (avc->states & CStatd)) {
291 if (!UBCINFOEXISTS(vp) && !ISSET(vp->v_flag, VTERMINATE)) {
294 if ((error=ubc_info_init(&avc->v))) {
299 simple_lock(&avc->v.v_interlock);
300 if (!ubc_issetflags(&avc->v, UI_HASOBJREF))
301 #ifdef UBC_NOREACTIVATE
302 if (ubc_getobject(&avc->v, (UBC_NOREACTIVATE|UBC_HOLDOBJECT)))
303 panic("VM_Setup: null object");
305 (void)_ubc_getobject(&avc->v, 1); /* return value not used */
307 simple_unlock(&avc->v.v_interlock);
311 if (UBCINFOEXISTS(&avc->v))
312 ubc_setsize(&avc->v, avc->m.Length);