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