fix-havecallbacks-proto-20040608
[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)
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 #endif
65
66     AFS_GLOCK();
67
68     return 0;
69 }
70
71
72 /* Try to store pages to cache, in order to store a file back to the server.
73  *
74  * Locking:  the vcache entry's lock is held.  It will usually be dropped and
75  * re-obtained.
76  */
77 void
78 osi_VM_StoreAllSegments(struct vcache *avc)
79 {
80     struct vnode *vp = AFSTOV(avc);
81     ReleaseWriteLock(&avc->lock);
82     AFS_GUNLOCK();
83     if (UBCINFOEXISTS(vp)) {
84         ubc_pushdirty(vp);
85     }
86     AFS_GLOCK();
87     ObtainWriteLock(&avc->lock, 94);
88 }
89
90 /* Try to invalidate pages, for "fs flush" or "fs flushv"; or
91  * try to free pages, when deleting a file.
92  *
93  * Locking:  the vcache entry's lock is held.  It may be dropped and 
94  * re-obtained.
95  *
96  * Since we drop and re-obtain the lock, we can't guarantee that there won't
97  * be some pages around when we return, newly created by concurrent activity.
98  */
99 void
100 osi_VM_TryToSmush(struct vcache *avc, struct AFS_UCRED *acred, int sync)
101 {
102     struct vnode *vp = AFSTOV(avc);
103     void *object;
104     kern_return_t kret;
105     off_t size, lastpg;
106
107     ReleaseWriteLock(&avc->lock);
108     AFS_GUNLOCK();
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);
114     }
115     AFS_GLOCK();
116     ObtainWriteLock(&avc->lock, 59);
117 }
118
119 /* Purge VM for a file when its callback is revoked.
120  *
121  * Locking:  No lock is held, not even the global lock.
122  */
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
125    often */
126 void
127 osi_VM_FlushPages(struct vcache *avc, struct AFS_UCRED *credp)
128 {
129     struct vnode *vp = AFSTOV(avc);
130     void *object;
131     kern_return_t kret;
132     off_t size;
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("VMFlushPages: invalidate failed (error = %d)\n", kret);
138         /* XXX what about when not CStatd */
139         if (avc->states & CStatd && size != avc->m.Length)
140             ubc_setsize(vp, avc->m.Length);
141     }
142 }
143
144 /* Purge pages beyond end-of-file, when truncating a file.
145  *
146  * Locking:  no lock is held, not even the global lock.
147  * activeV is raised.  This is supposed to block pageins, but at present
148  * it only works on Solaris.
149  */
150 void
151 osi_VM_Truncate(struct vcache *avc, int alen, struct AFS_UCRED *acred)
152 {
153     struct vnode *vp = AFSTOV(avc);
154     if (UBCINFOEXISTS(vp)) {
155         ubc_setsize(vp, alen);
156     }
157 }
158
159 /* vnreclaim and vinactive are probably not aggressive enough to keep
160    enough afs vcaches free, so we try to do some of it ourselves */
161 /* XXX there's probably not nearly enough locking here */
162 void
163 osi_VM_TryReclaim(struct vcache *avc, int *slept)
164 {
165     struct proc *p = current_proc();
166     struct vnode *vp = AFSTOV(avc);
167     void *obj;
168
169     if (slept)
170         *slept = 0;
171     VN_HOLD(vp);                /* remove from inactive list */
172     if (!simple_lock_try(&vp->v_interlock)) {
173         AFS_RELE(vp);
174         return;
175     }
176     if (!UBCINFOEXISTS(vp) || vp->v_count != 2) {
177         simple_unlock(&vp->v_interlock);
178         AFS_RELE(vp);
179         return;
180     }
181 #ifdef AFS_DARWIN14_ENV
182     if (vp->v_ubcinfo->ui_refcount > 1 || vp->v_ubcinfo->ui_mapped) {
183         simple_unlock(&vp->v_interlock);
184         AFS_RELE(vp);
185         return;
186     }
187 #else
188     if (vp->v_ubcinfo->ui_holdcnt) {
189         simple_unlock(&vp->v_interlock);
190         AFS_RELE(vp);
191         return;
192     }
193 #endif
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);
197         AFS_RELE(vp);
198         return;
199     }
200
201     vp->v_usecount--;           /* we want the usecount to be 1 */
202
203     if (slept) {
204         ReleaseWriteLock(&afs_xvcache);
205         *slept = 1;
206     } else
207         ReleaseReadLock(&afs_xvcache);
208     AFS_GUNLOCK();
209     obj = 0;
210     if (ubc_issetflags(vp, UI_WASMAPPED)) {
211         simple_unlock(&vp->v_interlock);
212 #ifdef  AFS_DARWIN14_ENV
213         ubc_release_named(vp);
214 #else
215         ubc_release(vp);
216 #endif
217         if (ubc_issetflags(vp, UI_HASOBJREF))
218             printf("ubc_release didn't release the reference?!\n");
219     } else if (!vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, current_proc())) {
220 #ifdef AFS_DARWIN14_ENV
221         obj = ubc_getobject(vp, UBC_HOLDOBJECT);
222 #else
223 #ifdef AFS_DARWIN13_ENV
224         obj = ubc_getobject(vp, (UBC_NOREACTIVATE | UBC_HOLDOBJECT));
225 #else
226         obj = ubc_getobject(vp);
227 #endif
228 #endif
229         (void)ubc_clean(vp, 1);
230         vinvalbuf(vp, V_SAVE, &afs_osi_cred, p, 0, 0);
231         if (vp->v_usecount == 1)
232             VOP_INACTIVE(vp, p);
233         else
234             VOP_UNLOCK(vp, 0, p);
235         if (obj) {
236             if (ISSET(vp->v_flag, VTERMINATE))
237                 panic("afs_vnreclaim: already teminating");
238             SET(vp->v_flag, VTERMINATE);
239             memory_object_destroy(obj, 0);
240             while (ISSET(vp->v_flag, VTERMINATE)) {
241                 SET(vp->v_flag, VTERMWANT);
242                 tsleep((caddr_t) & vp->v_ubcinfo, PINOD, "afs_vnreclaim", 0);
243             }
244         }
245     } else {
246         if (simple_lock_try(&vp->v_interlock))
247             panic("afs_vnreclaim: slept, but did no work :(");
248         if (UBCINFOEXISTS(vp) && vp->v_count == 1) {
249             vp->v_usecount++;
250             simple_unlock(&vp->v_interlock);
251             VN_RELE(vp);
252         } else
253             simple_unlock(&vp->v_interlock);
254     }
255     AFS_GLOCK();
256     if (slept)
257         ObtainWriteLock(&afs_xvcache, 175);
258     else
259         ObtainReadLock(&afs_xvcache);
260 }
261
262 void
263 osi_VM_NukePages(struct vnode *vp, off_t offset, off_t size)
264 {
265     void *object;
266     struct vcache *avc = VTOAFS(vp);
267
268 #ifdef AFS_DARWIN14_ENV
269     offset = trunc_page(offset);
270     size = round_page(size + 1);
271     while (size) {
272         ubc_page_op(vp, (vm_offset_t) offset,
273                     UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP, 0, 0);
274         size -= PAGE_SIZE;
275         offset += PAGE_SIZE;
276     }
277 #else
278     object = NULL;
279 #ifdef AFS_DARWIN13_ENV
280     if (UBCINFOEXISTS(vp))
281         object = ubc_getobject(vp, UBC_NOREACTIVATE);
282 #else
283     if (UBCINFOEXISTS(vp))
284         object = ubc_getobject(vp);
285 #endif
286     if (!object)
287         return;
288
289     offset = trunc_page(offset);
290     size = round_page(size + 1);
291
292 #ifdef AFS_DARWIN13_ENV
293     while (size) {
294         memory_object_page_op(object, (vm_offset_t) offset,
295                               UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP, 0,
296                               0);
297         size -= PAGE_SIZE;
298         offset += PAGE_SIZE;
299     }
300 #else
301     /* This is all we can do, and it's not enough. sucks to be us */
302     ubc_setsize(vp, offset);
303     size = (offset + size > avc->m.Length) ? offset + size : avc->m.Length;
304     ubc_setsize(vp, size);
305 #endif
306 #endif
307 }
308
309 int
310 osi_VM_Setup(struct vcache *avc, int force)
311 {
312     int error;
313     struct vnode *vp = AFSTOV(avc);
314
315     if (UBCISVALID(vp) && ((avc->states & CStatd) || force)) {
316         if (!UBCINFOEXISTS(vp) && !ISSET(vp->v_flag, VTERMINATE)) {
317             osi_vnhold(avc, 0);
318             avc->states |= CUBCinit;
319             AFS_GUNLOCK();
320             if ((error = ubc_info_init(&avc->v))) {
321                 AFS_GLOCK();
322                 avc->states &= ~CUBCinit;
323                 AFS_RELE(avc);
324                 return error;
325             }
326 #ifndef AFS_DARWIN14_ENV
327             simple_lock(&avc->v.v_interlock);
328             if (!ubc_issetflags(&avc->v, UI_HASOBJREF))
329 #ifdef AFS_DARWIN13_ENV
330                 if (ubc_getobject
331                     (&avc->v, (UBC_NOREACTIVATE | UBC_HOLDOBJECT)))
332                     panic("VM_Setup: null object");
333 #else
334                 (void)_ubc_getobject(&avc->v, 1);       /* return value not used */
335 #endif
336             simple_unlock(&avc->v.v_interlock);
337 #endif
338             AFS_GLOCK();
339             avc->states &= ~CUBCinit;
340             AFS_RELE(avc);
341         }
342         if (UBCINFOEXISTS(&avc->v))
343             ubc_setsize(&avc->v, avc->m.Length);
344     }
345     return 0;
346 }