darwin-updates-20040623
[openafs.git] / src / afs / DARWIN / osi_vm.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 RCSID
14     ("$Header$");
15
16 #include "afs/sysincludes.h"    /* Standard vendor system headers */
17 #include "afsincludes.h"        /* Afs-based standard headers */
18 #include "afs/afs_stats.h"      /* statistics */
19 #include <sys/ubc.h>
20
21 /* Try to discard pages, in order to recycle a vcache entry.
22  *
23  * We also make some sanity checks:  ref count, open count, held locks.
24  *
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).
27  *
28  * Locking:  afs_xvcache lock is held.  If it is dropped and re-acquired,
29  *   *slept should be set to warn the caller.
30  *
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.
34  *
35  * OSF/1 Locking:  VN_LOCK has been called.
36  */
37 int
38 osi_VM_FlushVCache(struct vcache *avc, int *slept)
39 {
40     struct vnode *vp = AFSTOV(avc);
41 #ifdef AFS_DARWIN14_ENV
42     if (UBCINFOEXISTS(vp))
43         return EBUSY;
44 #endif
45     if (avc->vrefCount > DARWIN_REFBASE)
46         return EBUSY;
47
48     if (avc->opens)
49         return EBUSY;
50
51     /* if a lock is held, give up */
52     if (CheckLock(&avc->lock) || afs_CheckBozonLock(&avc->pvnLock))
53         return EBUSY;
54
55     AFS_GUNLOCK();
56     cache_purge(vp);
57 #ifndef AFS_DARWIN14_ENV
58     if (UBCINFOEXISTS(vp)) {
59         ubc_clean(vp, 1);
60         ubc_uncache(vp);
61         ubc_release(vp);
62         ubc_info_free(vp);
63     }
64 #else
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
68        normal recycling. */
69     if (VNAME(vp) || VPARENT(vp)) {
70         char *tmp1;
71         struct vnode *tmp2;
72
73         /* do it this way so we don't block before clearing 
74            these fields. */
75         tmp1 = VNAME(vp);
76         tmp2 = VPARENT(vp);
77         VNAME(vp) = NULL;
78         VPARENT(vp) = NULL;
79             
80         if (tmp1) {
81             remove_name(tmp1);
82         }
83             
84         if (tmp2) {
85             vrele(tmp2);
86         }
87     }
88 #endif
89
90     AFS_GLOCK();
91
92     return 0;
93 }
94
95
96 /* Try to store pages to cache, in order to store a file back to the server.
97  *
98  * Locking:  the vcache entry's lock is held.  It will usually be dropped and
99  * re-obtained.
100  */
101 void
102 osi_VM_StoreAllSegments(struct vcache *avc)
103 {
104     struct vnode *vp = AFSTOV(avc);
105     ReleaseWriteLock(&avc->lock);
106     AFS_GUNLOCK();
107     if (UBCINFOEXISTS(vp)) {
108         ubc_pushdirty(vp);
109     }
110     AFS_GLOCK();
111     ObtainWriteLock(&avc->lock, 94);
112 }
113
114 /* Try to invalidate pages, for "fs flush" or "fs flushv"; or
115  * try to free pages, when deleting a file.
116  *
117  * Locking:  the vcache entry's lock is held.  It may be dropped and 
118  * re-obtained.
119  *
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.
122  */
123 void
124 osi_VM_TryToSmush(struct vcache *avc, struct AFS_UCRED *acred, int sync)
125 {
126     struct vnode *vp = AFSTOV(avc);
127     void *object;
128     kern_return_t kret;
129     off_t size, lastpg;
130
131     ReleaseWriteLock(&avc->lock);
132     AFS_GUNLOCK();
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);
138     }
139     AFS_GLOCK();
140     ObtainWriteLock(&avc->lock, 59);
141 }
142
143 /* Purge VM for a file when its callback is revoked.
144  *
145  * Locking:  No lock is held, not even the global lock.
146  */
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
149    often */
150 void
151 osi_VM_FlushPages(struct vcache *avc, struct AFS_UCRED *credp)
152 {
153     struct vnode *vp = AFSTOV(avc);
154     void *object;
155     kern_return_t kret;
156     off_t size;
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);
165     }
166 }
167
168 /* Purge pages beyond end-of-file, when truncating a file.
169  *
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.
173  */
174 void
175 osi_VM_Truncate(struct vcache *avc, int alen, struct AFS_UCRED *acred)
176 {
177     struct vnode *vp = AFSTOV(avc);
178     if (UBCINFOEXISTS(vp)) {
179         ubc_setsize(vp, alen);
180     }
181 }
182
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 */
186 void
187 osi_VM_TryReclaim(struct vcache *avc, int *slept)
188 {
189     struct proc *p = current_proc();
190     struct vnode *vp = AFSTOV(avc);
191     void *obj;
192 #ifdef AFS_DARWIN14_ENV
193     int didhold;
194 #endif
195
196     if (slept)
197         *slept = 0;
198     VN_HOLD(vp);                /* remove from inactive list */
199     if (!simple_lock_try(&vp->v_interlock)) {
200         AFS_RELE(vp);
201         return;
202     }
203     if (!UBCINFOEXISTS(vp) || vp->v_usecount != 2+DARWIN_REFBASE) {
204         simple_unlock(&vp->v_interlock);
205         AFS_RELE(vp);
206         return;
207     }
208     if (ISSET(vp->v_flag, VUINACTIVE)) {
209         simple_unlock(&vp->v_interlock);
210         AFS_RELE(vp);
211         printf("vnode %x still inactive!", vp);
212         return;
213     }
214 #ifdef AFS_DARWIN14_ENV
215     if (vp->v_ubcinfo->ui_refcount > 1 || vp->v_ubcinfo->ui_mapped) {
216         simple_unlock(&vp->v_interlock);
217         AFS_RELE(vp);
218         return;
219     }
220     if (ISSET(vp->v_flag, VORECLAIM)) {
221         simple_unlock(&vp->v_interlock);
222         AFS_RELE(vp);
223         return;
224     }
225 #else
226     if (vp->v_ubcinfo->ui_holdcnt) {
227         simple_unlock(&vp->v_interlock);
228         AFS_RELE(vp);
229         return;
230     }
231 #endif
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);
235         AFS_RELE(vp);
236         return;
237     }
238
239 #ifndef AFS_DARWIN14_ENV
240     vp->v_usecount--;           /* we want the usecount to be 1 */
241 #endif
242
243     if (slept) {
244         ReleaseWriteLock(&afs_xvcache);
245         *slept = 1;
246     } else
247         ReleaseReadLock(&afs_xvcache);
248     AFS_GUNLOCK();
249     obj = 0;
250     if (ubc_issetflags(vp, UI_WASMAPPED)) {
251         simple_unlock(&vp->v_interlock);
252 #ifdef  AFS_DARWIN14_ENV
253         ubc_release_named(vp);
254 #else
255         ubc_release(vp);
256 #endif
257         if (ubc_issetflags(vp, UI_HASOBJREF))
258             printf("ubc_release didn't release the reference?!\n");
259     } else {
260 #ifdef AFS_DARWIN14_ENV
261         SET(vp->v_flag, VORECLAIM);
262 #endif
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);
268 #else
269 #ifdef AFS_DARWIN13_ENV
270             obj = ubc_getobject(vp,(UBC_NOREACTIVATE|UBC_HOLDOBJECT));
271 #else
272             obj = ubc_getobject(vp);
273 #endif
274             (void)ubc_clean(vp, 1);
275 #endif
276             vinvalbuf(vp, V_SAVE, &afs_osi_cred, p, 0, 0);
277             if (vp->v_usecount ==
278 #ifdef AFS_DARWIN14_ENV
279                 2 + DARWIN_REFBASE
280 #else
281                 1
282 #endif
283                 )
284                 VOP_INACTIVE(vp, p);
285             else
286                 VOP_UNLOCK(vp, 0, p);
287 #ifdef AFS_DARWIN14_ENV
288             if (didhold)
289                 ubc_rele(vp);
290 #endif
291             if (obj) {
292                 if (ISSET(vp->v_flag, VTERMINATE))
293                     panic("afs_vnreclaim: already teminating");
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);
299                 }
300             }
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));
307             }       
308             vp->v_usecount--;
309             simple_unlock(&vp->v_interlock);
310 #endif
311         } else {
312 #ifdef AFS_DARWIN14_ENV
313             CLR(vp->v_flag, VORECLAIM);
314 #endif
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
319                 2
320 #else
321                 1
322 #endif
323                 ) {
324 #ifndef AFS_DARWIN14_ENV
325                 /* We left the refcount high in 1.4 */
326                 vp->v_usecount++;
327 #endif
328                 simple_unlock(&vp->v_interlock);
329                 VN_RELE(vp);
330             } else {
331 #ifdef AFS_DARWIN14_ENV
332                 /* We left the refcount high in 1.4 */
333                 vp->v_usecount--;
334 #endif
335                 simple_unlock(&vp->v_interlock);
336             }
337         }
338     }
339     AFS_GLOCK();
340     if (slept)
341         ObtainWriteLock(&afs_xvcache,175);
342     else
343         ObtainReadLock(&afs_xvcache);
344 }
345
346 void
347 osi_VM_NukePages(struct vnode *vp, off_t offset, off_t size)
348 {
349     void *object;
350     struct vcache *avc = VTOAFS(vp);
351
352 #ifdef AFS_DARWIN14_ENV
353     offset = trunc_page(offset);
354     size = round_page(size + 1);
355     while (size) {
356         ubc_page_op(vp, (vm_offset_t) offset,
357                     UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP, 0, 0);
358         size -= PAGE_SIZE;
359         offset += PAGE_SIZE;
360     }
361 #else
362     object = NULL;
363 #ifdef AFS_DARWIN13_ENV
364     if (UBCINFOEXISTS(vp))
365         object = ubc_getobject(vp, UBC_NOREACTIVATE);
366 #else
367     if (UBCINFOEXISTS(vp))
368         object = ubc_getobject(vp);
369 #endif
370     if (!object)
371         return;
372
373     offset = trunc_page(offset);
374     size = round_page(size + 1);
375
376 #ifdef AFS_DARWIN13_ENV
377     while (size) {
378         memory_object_page_op(object, (vm_offset_t) offset,
379                               UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP, 0,
380                               0);
381         size -= PAGE_SIZE;
382         offset += PAGE_SIZE;
383     }
384 #else
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);
389 #endif
390 #endif
391 }
392
393 int
394 osi_VM_Setup(struct vcache *avc, int force)
395 {
396     int error;
397     struct vnode *vp = AFSTOV(avc);
398
399     if (UBCISVALID(vp) && ((avc->states & CStatd) || force)) {
400         if (!UBCINFOEXISTS(vp) && !ISSET(vp->v_flag, VTERMINATE)) {
401             osi_vnhold(avc, 0);
402             avc->states |= CUBCinit;
403             AFS_GUNLOCK();
404             if ((error = ubc_info_init(&avc->v))) {
405                 AFS_GLOCK();
406                 avc->states &= ~CUBCinit;
407                 AFS_RELE(avc);
408                 return error;
409             }
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
414                 if (ubc_getobject
415                     (&avc->v, (UBC_NOREACTIVATE | UBC_HOLDOBJECT)))
416                     panic("VM_Setup: null object");
417 #else
418                 (void)_ubc_getobject(&avc->v, 1);       /* return value not used */
419 #endif
420             simple_unlock(&avc->v.v_interlock);
421 #endif
422             AFS_GLOCK();
423             avc->states &= ~CUBCinit;
424             AFS_RELE(avc);
425         }
426         if (UBCINFOEXISTS(&avc->v))
427             ubc_setsize(&avc->v, avc->m.Length);
428     }
429     return 0;
430 }