Commit | Line | Data |
---|---|---|
805e021f CE |
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 | ||
14 | #include "afs/sysincludes.h" /* Standard vendor system headers */ | |
15 | #include "afsincludes.h" /* Afs-based standard headers */ | |
16 | #include "afs/afs_stats.h" /* statistics */ | |
17 | #include "sys/flock.h" /* for IGN_PID */ | |
18 | ||
19 | extern struct vnodeops Afs_vnodeops; | |
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. It must not be dropped. | |
29 | */ | |
30 | int | |
31 | osi_VM_FlushVCache(struct vcache *avc) | |
32 | { | |
33 | int s, code; | |
34 | vnode_t *vp = &avc->v; | |
35 | ||
36 | if (avc->vrefCount != 0) | |
37 | return EBUSY; | |
38 | ||
39 | if (avc->opens != 0) | |
40 | return EBUSY; | |
41 | ||
42 | /* | |
43 | * Just in case someone is still referring to the vnode we give up | |
44 | * trying to get rid of this guy. | |
45 | */ | |
46 | if (CheckLock(&avc->lock) || LockWaiters(&avc->lock)) | |
47 | return EBUSY; | |
48 | ||
49 | s = VN_LOCK(vp); | |
50 | ||
51 | /* | |
52 | * we just need to avoid the race | |
53 | * in vn_rele between the ref count going to 0 and VOP_INACTIVE | |
54 | * finishing up. | |
55 | * Note that although we checked vcount above, we didn't have the lock | |
56 | */ | |
57 | if (vp->v_count > 0 || (vp->v_flag & VINACT)) { | |
58 | VN_UNLOCK(vp, s); | |
59 | return EBUSY; | |
60 | } | |
61 | VN_UNLOCK(vp, s); | |
62 | ||
63 | /* | |
64 | * Since we store on last close and on VOP_INACTIVE | |
65 | * there should be NO dirty pages | |
66 | * Note that we hold the xvcache lock the entire time. | |
67 | */ | |
68 | AFS_GUNLOCK(); | |
69 | PTOSSVP(vp, (off_t) 0, (off_t) MAXLONG); | |
70 | AFS_GLOCK(); | |
71 | ||
72 | /* afs_chkpgoob will drop and re-acquire the global lock. */ | |
73 | afs_chkpgoob(vp, 0); | |
74 | osi_Assert(!VN_GET_PGCNT(vp)); | |
75 | osi_Assert(!AFS_VN_MAPPED(vp)); | |
76 | osi_Assert(!AFS_VN_DIRTY(&avc->v)); | |
77 | ||
78 | #if defined(AFS_SGI65_ENV) | |
79 | if (vp->v_filocks) | |
80 | cleanlocks(vp, IGN_PID, 0); | |
81 | mutex_destroy(&vp->v_filocksem); | |
82 | #else /* AFS_SGI65_ENV */ | |
83 | if (vp->v_filocksem) { | |
84 | if (vp->v_filocks) | |
85 | #ifdef AFS_SGI64_ENV | |
86 | cleanlocks(vp, &curprocp->p_flid); | |
87 | #else | |
88 | cleanlocks(vp, IGN_PID, 0); | |
89 | #endif | |
90 | osi_Assert(vp->v_filocks == NULL); | |
91 | mutex_destroy(vp->v_filocksem); | |
92 | kmem_free(vp->v_filocksem, sizeof *vp->v_filocksem); | |
93 | vp->v_filocksem = NULL; | |
94 | } | |
95 | #endif /* AFS_SGI65_ENV */ | |
96 | ||
97 | if (avc->vrefCount) | |
98 | osi_Panic("flushVcache: vm race"); | |
99 | #ifdef AFS_SGI64_ENV | |
100 | AFS_GUNLOCK(); | |
101 | vnode_pcache_reclaim(vp); /* this can sleep */ | |
102 | vnode_pcache_free(vp); | |
103 | if (vp->v_op != &Afs_vnodeops) { | |
104 | VOP_RECLAIM(vp, FSYNC_WAIT, code); | |
105 | } | |
106 | AFS_GLOCK(); | |
107 | #ifdef AFS_SGI65_ENV | |
108 | #ifdef VNODE_TRACING | |
109 | ktrace_free(vp->v_trace); | |
110 | #endif /* VNODE_TRACING */ | |
111 | vn_bhv_remove(VN_BHV_HEAD(vp), &(avc->vc_bhv_desc)); | |
112 | vn_bhv_head_destroy(&(vp->v_bh)); | |
113 | destroy_bitlock(&vp->v_pcacheflag); | |
114 | mutex_destroy(&vp->v_buf_lock); | |
115 | #else | |
116 | bhv_remove(VN_BHV_HEAD(vp), &(avc->vc_bhv_desc)); | |
117 | bhv_head_destroy(&(vp->v_bh)); | |
118 | #endif | |
119 | vp->v_flag = 0; /* debug */ | |
120 | #if defined(DEBUG) && defined(VNODE_INIT_BITLOCK) | |
121 | destroy_bitlock(&vp->v_flag); | |
122 | #endif | |
123 | #ifdef INTR_KTHREADS | |
124 | AFS_VN_DESTROY_BUF_LOCK(vp); | |
125 | #endif | |
126 | #endif /* AFS_SGI64_ENV */ | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | /* Try to invalidate pages, for "fs flush" or "fs flushv"; or | |
132 | * try to free pages, when deleting a file. | |
133 | * | |
134 | * Locking: the vcache entry's lock is held. It may be dropped and | |
135 | * re-obtained. | |
136 | * | |
137 | * Since we drop and re-obtain the lock, we can't guarantee that there won't | |
138 | * be some pages around when we return, newly created by concurrent activity. | |
139 | */ | |
140 | void | |
141 | osi_VM_TryToSmush(struct vcache *avc, afs_ucred_t *acred, int sync) | |
142 | { | |
143 | ReleaseWriteLock(&avc->lock); | |
144 | AFS_GUNLOCK(); | |
145 | /* current remapf restriction - cannot have VOP_RWLOCK */ | |
146 | osi_Assert(OSI_GET_LOCKID() != avc->vc_rwlockid); | |
147 | if (((vnode_t *) avc)->v_type == VREG && AFS_VN_MAPPED(((vnode_t *) avc))) | |
148 | remapf(((vnode_t *) avc), 0, 0); | |
149 | PTOSSVP(AFSTOV(avc), (off_t) 0, (off_t) MAXLONG); | |
150 | AFS_GLOCK(); | |
151 | ObtainWriteLock(&avc->lock, 62); | |
152 | } | |
153 | ||
154 | /* Flush and invalidate pages, for fsync() with INVAL flag | |
155 | * | |
156 | * Locking: only the global lock is held. | |
157 | */ | |
158 | void | |
159 | osi_VM_FSyncInval(struct vcache *avc) | |
160 | { | |
161 | AFS_GUNLOCK(); | |
162 | PFLUSHINVALVP((vnode_t *) avc, (off_t) 0, (off_t) avc->f.m.Length); | |
163 | AFS_GLOCK(); | |
164 | } | |
165 | ||
166 | /* Try to store pages to cache, in order to store a file back to the server. | |
167 | * | |
168 | * Locking: the vcache entry's lock is held. It will usually be dropped and | |
169 | * re-obtained. | |
170 | */ | |
171 | void | |
172 | osi_VM_StoreAllSegments(struct vcache *avc) | |
173 | { | |
174 | int error; | |
175 | osi_Assert(valusema(&avc->vc_rwlock) <= 0); | |
176 | osi_Assert(OSI_GET_LOCKID() == avc->vc_rwlockid); | |
177 | osi_Assert(avc->vrefCount > 0); | |
178 | ReleaseWriteLock(&avc->lock); | |
179 | /* We may call back into AFS via: | |
180 | * pflushvp->chunkpush->do_pdflush->mp_afs_bmap | |
181 | */ | |
182 | AFS_GUNLOCK(); | |
183 | ||
184 | /* Write out dirty pages list to avoid B_DELWRI buffers. */ | |
185 | while (VN_GET_DPAGES((vnode_t *) avc)) { | |
186 | pdflush(AFSTOV(avc), 0); | |
187 | } | |
188 | ||
189 | PFLUSHVP(AFSTOV(avc), (off_t) avc->f.m.Length, (off_t) 0, error); | |
190 | AFS_GLOCK(); | |
191 | if (error) { | |
192 | /* | |
193 | * If this fails (due to quota overage, etc.) | |
194 | * what can we do?? we need to sure that | |
195 | * that the VM cache is cleared of dirty pages | |
196 | * We note that pinvalfree ignores write errors & otherwise | |
197 | * does what we want (we don't use this normally since | |
198 | * it also unhashes pages ..) | |
199 | */ | |
200 | PINVALFREE((vnode_t *) avc, avc->f.m.Length); | |
201 | } | |
202 | ObtainWriteLock(&avc->lock, 121); | |
203 | if (error && avc->f.m.LinkCount) | |
204 | cmn_err(CE_WARN, | |
205 | "AFS:Failed to push back pages for vnode 0x%x error %d (from afs_StoreOnLastReference)", | |
206 | avc, error); | |
207 | } | |
208 | ||
209 | /* Purge VM for a file when its callback is revoked. | |
210 | * | |
211 | * Locking: No lock is held, not even the global lock. | |
212 | */ | |
213 | void | |
214 | osi_VM_FlushPages(struct vcache *avc, afs_ucred_t *credp) | |
215 | { | |
216 | vnode_t *vp = (vnode_t *) avc; | |
217 | ||
218 | remapf(vp, /*avc->f.m.Length */ 0, 0); | |
219 | ||
220 | /* Used to grab locks and recheck avc->f.m.DataVersion and | |
221 | * avc->execsOrWriters here, but we have to drop locks before calling | |
222 | * ptossvp() anyway, so why bother. | |
223 | */ | |
224 | ||
225 | /* | |
226 | * ptossvp tosses all pages associated with this vnode | |
227 | * All in-use pages are marked BAD | |
228 | */ | |
229 | PTOSSVP(vp, (off_t) 0, (off_t) MAXLONG); | |
230 | } | |
231 | ||
232 | /* Purge pages beyond end-of-file, when truncating a file. | |
233 | * | |
234 | * Locking: no lock is held, not even the global lock. | |
235 | * activeV is raised. This is supposed to block pageins, but at present | |
236 | * it only works on Solaris. | |
237 | */ | |
238 | void | |
239 | osi_VM_Truncate(struct vcache *avc, int alen, afs_ucred_t *acred) | |
240 | { | |
241 | PTOSSVP(&avc->v, (off_t) alen, (off_t) MAXLONG); | |
242 | } |