convert-vcache-casts-to-macros-20020325
[openafs.git] / src / afs / DUX / 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 <vm/vm_ubc.h>
19 #include <values.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(avc, slept)
39     struct vcache *avc;
40     int *slept;
41 {
42     if (avc->vrefCount > 1)
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     ubc_invalidate(AFSTOV(avc)->v_object, 0, 0, B_INVAL);
54     AFS_GLOCK();
55
56     return 0;
57 }
58
59 /*
60  * osi_ubc_flush_dirty_and_wait -- ensure all dirty pages cleaned
61  *
62  * Alpha OSF/1 doesn't make it easy to wait for all dirty pages to be cleaned.
63  * NFS tries to do this by calling waitforio(), which waits for v_numoutput
64  * to go to zero.  But that isn't good enough, because afs_putpage() doesn't
65  * increment v_numoutput until it has obtained the vcache entry lock.  Suppose
66  * that Process A, trying to flush a page, is waiting for that lock, and
67  * Process B tries to close the file.  Process B calls waitforio() which thinks
68  * that everything is cool because v_numoutput is still zero.  Process B then
69  * proceeds to call afs_StoreAllSegments().  Finally when B is finished, A gets
70  * to proceed and flush its page.  But then it's too late because the file is
71  * already closed.
72  *
73  * (I suspect that waitforio() is not adequate for NFS, just as it isn't
74  * adequate for us.  But that's not my problem.)
75  *
76  * The only way we can be sure that there are no more dirty pages is if there
77  * are no more pages with pg_busy set.  We look for them on the cleanpl.
78  *
79  * For some reason, ubc_flush_dirty() only looks at the dirtypl, not the
80  * dirtywpl.  I don't know why this is good enough, but I assume it is.  By
81  * the same token, I only look for busy pages on the cleanpl, not the cleanwpl.
82  *
83  * Called with the global lock NOT held.
84  */
85 void
86 osi_ubc_flush_dirty_and_wait(vp, flags)
87 struct vnode *vp;
88 int flags; {
89     int retry;
90     vm_page_t pp;
91     int first;
92
93     do {
94         struct vm_ubc_object* vop;
95         vop = (struct vm_ubc_object*)(vp->v_object);
96         ubc_flush_dirty(vop, flags); 
97
98         vm_object_lock(vop);
99         if (vop->vu_dirtypl)
100             /* shouldn't happen, but who knows */
101             retry = 1;
102         else {
103             retry = 0;
104             if (vop->vu_cleanpl) {
105                 for (first = 1, pp = vop->vu_cleanpl;
106                      first || pp != vop->vu_cleanpl;
107                      first = 0, pp = pp->pg_onext) {
108                     if (pp->pg_busy) {
109                         retry = 1;
110                         pp->pg_wait = 1;
111                         assert_wait_mesg((vm_offset_t)pp, FALSE, "pg_wait");
112                         vm_object_unlock(vop);
113                         thread_block();
114                         break;
115                     }
116                 }
117             }
118             if (retry) continue;
119         }
120         vm_object_unlock(vop);
121     } while (retry);
122 }
123
124 /* Try to store pages to cache, in order to store a file back to the server.
125  *
126  * Locking:  the vcache entry's lock is held.  It will usually be dropped and
127  * re-obtained.
128  */
129 void
130 osi_VM_StoreAllSegments(avc)
131     struct vcache *avc;
132 {
133     ReleaseWriteLock(&avc->lock);
134     AFS_GUNLOCK();
135     osi_ubc_flush_dirty_and_wait(AFSTOV(avc), 0);
136     AFS_GLOCK();
137     ObtainWriteLock(&avc->lock,94);
138 }
139
140 /* Try to invalidate pages, for "fs flush" or "fs flushv"; or
141  * try to free pages, when deleting a file.
142  *
143  * Locking:  the vcache entry's lock is held.  It may be dropped and 
144  * re-obtained.
145  *
146  * Since we drop and re-obtain the lock, we can't guarantee that there won't
147  * be some pages around when we return, newly created by concurrent activity.
148  */
149 void
150 osi_VM_TryToSmush(avc, acred, sync)
151     struct vcache *avc;
152     struct AFS_UCRED *acred;
153     int sync;
154 {
155     ReleaseWriteLock(&avc->lock);
156     AFS_GUNLOCK();
157     osi_ubc_flush_dirty_and_wait(AFSTOV(avc), 0);
158     ubc_invalidate(AFSTOV(avc)->v_object, 0, 0, B_INVAL);
159     AFS_GLOCK();
160     ObtainWriteLock(&avc->lock,59);
161 }
162
163 /* Purge VM for a file when its callback is revoked.
164  *
165  * Locking:  No lock is held, not even the global lock.
166  */
167 void
168 osi_VM_FlushPages(avc, credp)
169     struct vcache *avc;
170     struct AFS_UCRED *credp;
171 {
172     ubc_flush_dirty(AFSTOV(avc)->v_object, 0);
173     ubc_invalidate(AFSTOV(avc)->v_object, 0, 0, B_INVAL);
174 }
175
176 /* Purge pages beyond end-of-file, when truncating a file.
177  *
178  * Locking:  no lock is held, not even the global lock.
179  * activeV is raised.  This is supposed to block pageins, but at present
180  * it only works on Solaris.
181  */
182 void
183 osi_VM_Truncate(avc, alen, acred)
184     struct vcache *avc;
185     int alen;
186     struct AFS_UCRED *acred;
187 {
188     ubc_invalidate(AFSTOV(avc)->v_object, alen,
189                         MAXINT - alen, B_INVAL);
190 }