no-copy-libafs-builds-20021015
[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("$Header$");
14
15 #include "afs/sysincludes.h" /* Standard vendor system headers */
16 #include "afsincludes.h" /* Afs-based standard headers */
17 #include "afs/afs_stats.h"  /* statistics */
18 #include <sys/ubc.h>
19
20 /* Try to discard pages, in order to recycle a vcache entry.
21  *
22  * We also make some sanity checks:  ref count, open count, held locks.
23  *
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).
26  *
27  * Locking:  afs_xvcache lock is held.  If it is dropped and re-acquired,
28  *   *slept should be set to warn the caller.
29  *
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.
33  *
34  * OSF/1 Locking:  VN_LOCK has been called.
35  */
36 int osi_VM_FlushVCache(struct vcache *avc, int *slept)
37 {
38     struct vnode *vp=AFSTOV(avc);
39 #ifdef AFS_DARWIN14_ENV
40     if (UBCINFOEXISTS(vp))
41         return EBUSY;
42 #endif
43     if (avc->vrefCount)
44         return EBUSY;
45
46     if (avc->opens)
47         return EBUSY;
48
49     /* if a lock is held, give up */
50     if (CheckLock(&avc->lock) || afs_CheckBozonLock(&avc->pvnLock))
51         return EBUSY;
52
53     AFS_GUNLOCK();
54     cache_purge(vp);
55 #ifndef AFS_DARWIN14_ENV
56     if (UBCINFOEXISTS(vp))
57         {
58                 ubc_clean(vp, 1);
59                 ubc_uncache(vp);
60                 ubc_release(vp);
61                 ubc_info_free(vp);
62         }
63 #endif
64
65     AFS_GLOCK();
66
67     return 0;
68 }
69
70
71 /* Try to store pages to cache, in order to store a file back to the server.
72  *
73  * Locking:  the vcache entry's lock is held.  It will usually be dropped and
74  * re-obtained.
75  */
76 void osi_VM_StoreAllSegments(struct vcache *avc)
77 {
78     struct vnode *vp=AFSTOV(avc);
79     ReleaseWriteLock(&avc->lock);
80     AFS_GUNLOCK();
81     if (UBCINFOEXISTS(vp)) {
82         ubc_pushdirty(vp);
83     }
84     AFS_GLOCK();
85     ObtainWriteLock(&avc->lock,94);
86 }
87
88 /* Try to invalidate pages, for "fs flush" or "fs flushv"; or
89  * try to free pages, when deleting a file.
90  *
91  * Locking:  the vcache entry's lock is held.  It may be dropped and 
92  * re-obtained.
93  *
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.
96  */
97 void osi_VM_TryToSmush(struct vcache *avc, struct AFS_UCRED *acred, 
98         int sync)
99 {
100     struct vnode *vp=AFSTOV(avc);
101     void *object;
102     kern_return_t kret;
103     off_t size, lastpg;
104     
105     ReleaseWriteLock(&avc->lock);
106     AFS_GUNLOCK();
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);
112     }
113     AFS_GLOCK();
114     ObtainWriteLock(&avc->lock,59);
115 }
116
117 /* Purge VM for a file when its callback is revoked.
118  *
119  * Locking:  No lock is held, not even the global lock.
120  */
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
123    often */
124 void osi_VM_FlushPages(struct vcache *avc, struct AFS_UCRED *credp)
125 {
126     struct vnode *vp=AFSTOV(avc);
127     void *object;
128     kern_return_t kret;
129     off_t size;
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);
138     }
139 }
140
141 /* Purge pages beyond end-of-file, when truncating a file.
142  *
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.
146  */
147 void osi_VM_Truncate(struct vcache *avc, int alen, struct AFS_UCRED *acred)
148 {
149     struct vnode *vp=AFSTOV(avc);
150     if (UBCINFOEXISTS(vp))  {
151         ubc_setsize(vp, alen);
152     }
153 }
154
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)
159 {
160     struct proc *p=current_proc();
161     struct vnode *vp=AFSTOV(avc);
162     void *obj;
163
164     if (slept)
165        *slept=0;
166     VN_HOLD(vp); /* remove from inactive list */
167     if (!simple_lock_try(&vp->v_interlock)) {
168         AFS_RELE(vp);
169         return;
170     }
171     if (!UBCINFOEXISTS(vp) || vp->v_count != 2) {
172         simple_unlock(&vp->v_interlock);
173         AFS_RELE(vp);
174         return;
175     }
176 #ifdef AFS_DARWIN14_ENV
177     if (vp->v_ubcinfo->ui_refcount > 1 || vp->v_ubcinfo->ui_mapped) {
178         simple_unlock(&vp->v_interlock);
179         AFS_RELE(vp);
180         return;
181     }
182 #else
183     if (vp->v_ubcinfo->ui_holdcnt) {
184         simple_unlock(&vp->v_interlock);
185         AFS_RELE(vp);
186         return;
187     }
188 #endif
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);
192         AFS_RELE(vp);
193         return;
194     }
195
196     vp->v_usecount--; /* we want the usecount to be 1 */
197
198     if (slept) {
199         ReleaseWriteLock(&afs_xvcache);
200         *slept=1;
201     } else
202         ReleaseReadLock(&afs_xvcache);
203     AFS_GUNLOCK();
204     obj=0;
205     if (ubc_issetflags(vp, UI_WASMAPPED)) {
206         simple_unlock(&vp->v_interlock);
207 #ifdef  AFS_DARWIN14_ENV
208         ubc_release_named(vp);
209 #else
210         ubc_release(vp);
211 #endif
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);
217 #else
218 #ifdef AFS_DARWIN13_ENV
219         obj = ubc_getobject(vp,(UBC_NOREACTIVATE|UBC_HOLDOBJECT));
220 #else
221         obj = ubc_getobject(vp);
222 #endif
223 #endif
224         (void)ubc_clean(vp, 1);
225         vinvalbuf(vp, V_SAVE, &afs_osi_cred, p, 0, 0);
226         if (vp->v_usecount == 1)
227            VOP_INACTIVE(vp, p);
228         else
229            VOP_UNLOCK(vp, 0, p);
230         if (obj) {
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);
238             }
239         }
240    } else {
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) {
244            vp->v_usecount++;
245            simple_unlock(&vp->v_interlock);
246            VN_RELE(vp);
247         } else 
248            simple_unlock(&vp->v_interlock);
249    }
250    AFS_GLOCK();
251    if (slept)
252       ObtainWriteLock(&afs_xvcache,175);
253    else
254       ObtainReadLock(&afs_xvcache);
255 }
256
257 void osi_VM_NukePages(struct vnode *vp, off_t offset, off_t size)
258 {
259     void *object;
260     struct vcache *avc = VTOAFS(vp);
261
262 #ifdef AFS_DARWIN14_ENV
263     offset=trunc_page(offset);
264     size=round_page(size+1);
265     while (size) {
266         ubc_page_op(vp, (vm_offset_t)offset, 
267                               UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP,
268                               0, 0);
269         size-=PAGE_SIZE;
270         offset+=PAGE_SIZE;
271     }
272 #else
273     object=NULL;
274 #ifdef AFS_DARWIN13_ENV
275     if (UBCINFOEXISTS(vp))
276         object = ubc_getobject(vp, UBC_NOREACTIVATE);
277 #else
278     if (UBCINFOEXISTS(vp))
279         object = ubc_getobject(vp);
280 #endif
281     if (!object)
282         return;
283
284     offset=trunc_page(offset);
285     size=round_page(size+1);
286
287 #ifdef AFS_DARWIN13_ENV
288     while (size) {
289         memory_object_page_op(object, (vm_offset_t)offset, 
290                               UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP,
291                               0, 0);
292         size-=PAGE_SIZE;
293         offset+=PAGE_SIZE;
294     }
295 #else 
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);
300 #endif
301 #endif
302 }
303
304 int osi_VM_Setup(struct vcache *avc, int force) {
305     int error;
306     struct vnode *vp=AFSTOV(avc);
307   
308     if (UBCISVALID(vp) && ((avc->states & CStatd) || force)) {
309         if (!UBCINFOEXISTS(vp) && !ISSET(vp->v_flag, VTERMINATE)) {
310             osi_vnhold(avc,0);  
311             avc->states  |= CUBCinit;
312             AFS_GUNLOCK();
313             if ((error=ubc_info_init(&avc->v)))  {
314                 AFS_GLOCK();
315                 avc->states  &= ~CUBCinit;
316                 AFS_RELE(avc);
317                 return error;
318             }
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");
325 #else
326             (void)_ubc_getobject(&avc->v, 1); /* return value not used */
327 #endif
328             simple_unlock(&avc->v.v_interlock);
329 #endif
330             AFS_GLOCK();
331             avc->states  &= ~CUBCinit;
332             AFS_RELE(avc);
333         }
334         if (UBCINFOEXISTS(&avc->v))
335             ubc_setsize(&avc->v, avc->m.Length);
336     }
337     return 0;
338 }