include-afsconfig-before-param-h-20010712
[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 "../afs/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
37 osi_VM_FlushVCache(avc, slept)
38     struct vcache *avc;
39     int *slept;
40 {
41     struct vnode *vp=(struct vnode *)avc;
42     if (avc->vrefCount)
43         return EBUSY;
44
45     if (avc->opens)
46         return EBUSY;
47
48     /* if a lock is held, give up */
49     if (CheckLock(&avc->lock) || afs_CheckBozonLock(&avc->pvnLock))
50         return EBUSY;
51
52     AFS_GUNLOCK();
53     cache_purge(vp);
54     if (UBCINFOEXISTS(vp))
55         {
56                 ubc_clean(vp, 1);
57                 ubc_uncache(vp);
58                 ubc_release(vp);
59                 ubc_info_free(vp);
60         }
61
62     AFS_GLOCK();
63
64     return 0;
65 }
66
67
68 /* Try to store pages to cache, in order to store a file back to the server.
69  *
70  * Locking:  the vcache entry's lock is held.  It will usually be dropped and
71  * re-obtained.
72  */
73 void
74 osi_VM_StoreAllSegments(avc)
75     struct vcache *avc;
76 {
77     struct vnode *vp=(struct vnode *)avc;
78     ReleaseWriteLock(&avc->lock);
79     AFS_GUNLOCK();
80     if (UBCINFOEXISTS(vp)) {
81         ubc_pushdirty(vp);
82     }
83     AFS_GLOCK();
84     ObtainWriteLock(&avc->lock,94);
85 }
86
87 /* Try to invalidate pages, for "fs flush" or "fs flushv"; or
88  * try to free pages, when deleting a file.
89  *
90  * Locking:  the vcache entry's lock is held.  It may be dropped and 
91  * re-obtained.
92  *
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.
95  */
96 void
97 osi_VM_TryToSmush(avc, acred, sync)
98     struct vcache *avc;
99     struct AFS_UCRED *acred;
100     int sync;
101 {
102     struct vnode *vp=(struct vnode *)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(avc, credp)
128     struct vcache *avc;
129     struct AFS_UCRED *credp;
130 {
131     struct vnode *vp=(struct vnode *)avc;
132     void *object;
133     kern_return_t kret;
134     off_t size;
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);
143     }
144 }
145
146 /* Purge pages beyond end-of-file, when truncating a file.
147  *
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.
151  */
152 void
153 osi_VM_Truncate(avc, alen, acred)
154     struct vcache *avc;
155     int alen;
156     struct AFS_UCRED *acred;
157 {
158     struct vnode *vp=(struct vnode *)avc;
159     if (UBCINFOEXISTS(vp))  {
160         ubc_setsize(vp, alen);
161     }
162 }
163
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)
170      struct vcache *avc;
171      int *slept;
172 {
173     struct proc *p=current_proc();
174     struct vnode *vp=(struct vnode *)avc;
175     void *obj;
176
177     if (slept)
178        *slept=0;
179     VN_HOLD(vp); /* remove from inactive list */
180     if (!simple_lock_try(&vp->v_interlock)) {
181         AFS_RELE(vp);
182         return;
183     }
184     if (!UBCINFOEXISTS(vp) || vp->v_count != 2) {
185         simple_unlock(&vp->v_interlock);
186         AFS_RELE(vp);
187         return;
188     }
189     if (vp->v_ubcinfo->ui_holdcnt) {
190         simple_unlock(&vp->v_interlock);
191         AFS_RELE(vp);
192         return;
193     }
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         ubc_release(vp);
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));
218 #else
219         obj = ubc_getobject(vp);
220 #endif
221         (void)ubc_clean(vp, 1);
222         vinvalbuf(vp, V_SAVE, &afs_osi_cred, p, 0, 0);
223         if (vp->v_usecount == 1)
224            VOP_INACTIVE(vp, p);
225         else
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);
234         }
235    } else {
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) {
239            vp->v_usecount++;
240            simple_unlock(&vp->v_interlock);
241            AFS_RELE(vp);
242         } else 
243            simple_unlock(&vp->v_interlock);
244    }
245    AFS_GLOCK();
246    if (slept)
247       ObtainWriteLock(&afs_xvcache,175);
248    else
249       ObtainReadLock(&afs_xvcache);
250 }
251
252 void osi_VM_NukePages(struct vnode *vp, off_t offset, off_t size) {
253
254     void *object;
255     struct vcache *avc = (struct vcache *)vp;
256
257     object=NULL;
258 #ifdef UBC_NOREACTIVATE
259     if (UBCINFOEXISTS(vp))
260         object = ubc_getobject(vp, UBC_NOREACTIVATE);
261 #else
262     if (UBCINFOEXISTS(vp))
263         object = ubc_getobject(vp);
264 #endif
265     if (!object)
266         return;
267
268     offset=trunc_page(offset);
269     size=round_page(size+1);
270
271 #ifdef UBC_NOREACTIVATE
272     while (size) {
273         memory_object_page_op(object, (vm_offset_t)offset, 
274                               UPL_POP_SET | UPL_POP_BUSY | UPL_POP_DUMP,
275                               0, 0);
276         size-=PAGE_SIZE;
277         offset+=PAGE_SIZE;
278     }
279 #else 
280     ubc_setsize(vp, offset);
281     size=(offset + size > avc->m.Length) ? offset + size : avc->m.Length;
282     ubc_setsize(vp, size);
283 #endif
284
285 }
286 int osi_VM_Setup(struct vcache *avc) {
287    int error;
288    struct vnode *vp=(struct vnode *)avc;
289
290    if (UBCISVALID(vp) && (avc->states & CStatd)) {
291       if (!UBCINFOEXISTS(vp) && !ISSET(vp->v_flag, VTERMINATE)) {
292          osi_vnhold(avc,0);  
293          AFS_GUNLOCK();
294          if ((error=ubc_info_init(&avc->v)))  {
295              AFS_GLOCK();
296              AFS_RELE(avc);
297              return error;
298          }
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");
304 #else
305             (void)_ubc_getobject(&avc->v, 1); /* return value not used */
306 #endif
307          simple_unlock(&avc->v.v_interlock);
308          AFS_GLOCK();
309          AFS_RELE(avc);
310       }
311       if (UBCINFOEXISTS(&avc->v))
312           ubc_setsize(&avc->v, avc->m.Length);
313    }
314    return 0;
315 }