diff options
author | David Howells <dhowells@redhat.com> | 2009-04-03 11:42:43 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2009-04-03 11:42:43 -0400 |
commit | ef79c097bbe9724e13937271b3457df560e00370 (patch) | |
tree | a8671781cc0c9deb85fa76a8b4211c5e693b4343 /fs/nfs/fscache.c | |
parent | 10329a5d48f5abc14a37d30b706e330f8598297a (diff) |
NFS: Use local disk inode cache
Bind data storage objects in the local cache to NFS inodes.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Steve Dickson <steved@redhat.com>
Acked-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Tested-by: Daire Byrne <Daire.Byrne@framestore.com>
Diffstat (limited to 'fs/nfs/fscache.c')
-rw-r--r-- | fs/nfs/fscache.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index ab2de2c92b21..e3816eb53fb8 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
@@ -166,3 +166,165 @@ void nfs_fscache_release_super_cookie(struct super_block *sb) | |||
166 | nfss->fscache_key = NULL; | 166 | nfss->fscache_key = NULL; |
167 | } | 167 | } |
168 | } | 168 | } |
169 | |||
170 | /* | ||
171 | * Initialise the per-inode cache cookie pointer for an NFS inode. | ||
172 | */ | ||
173 | void nfs_fscache_init_inode_cookie(struct inode *inode) | ||
174 | { | ||
175 | NFS_I(inode)->fscache = NULL; | ||
176 | if (S_ISREG(inode->i_mode)) | ||
177 | set_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Get the per-inode cache cookie for an NFS inode. | ||
182 | */ | ||
183 | static void nfs_fscache_enable_inode_cookie(struct inode *inode) | ||
184 | { | ||
185 | struct super_block *sb = inode->i_sb; | ||
186 | struct nfs_inode *nfsi = NFS_I(inode); | ||
187 | |||
188 | if (nfsi->fscache || !NFS_FSCACHE(inode)) | ||
189 | return; | ||
190 | |||
191 | if ((NFS_SB(sb)->options & NFS_OPTION_FSCACHE)) { | ||
192 | nfsi->fscache = fscache_acquire_cookie( | ||
193 | NFS_SB(sb)->fscache, | ||
194 | &nfs_fscache_inode_object_def, | ||
195 | nfsi); | ||
196 | |||
197 | dfprintk(FSCACHE, "NFS: get FH cookie (0x%p/0x%p/0x%p)\n", | ||
198 | sb, nfsi, nfsi->fscache); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Release a per-inode cookie. | ||
204 | */ | ||
205 | void nfs_fscache_release_inode_cookie(struct inode *inode) | ||
206 | { | ||
207 | struct nfs_inode *nfsi = NFS_I(inode); | ||
208 | |||
209 | dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", | ||
210 | nfsi, nfsi->fscache); | ||
211 | |||
212 | fscache_relinquish_cookie(nfsi->fscache, 0); | ||
213 | nfsi->fscache = NULL; | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * Retire a per-inode cookie, destroying the data attached to it. | ||
218 | */ | ||
219 | void nfs_fscache_zap_inode_cookie(struct inode *inode) | ||
220 | { | ||
221 | struct nfs_inode *nfsi = NFS_I(inode); | ||
222 | |||
223 | dfprintk(FSCACHE, "NFS: zapping cookie (0x%p/0x%p)\n", | ||
224 | nfsi, nfsi->fscache); | ||
225 | |||
226 | fscache_relinquish_cookie(nfsi->fscache, 1); | ||
227 | nfsi->fscache = NULL; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Turn off the cache with regard to a per-inode cookie if opened for writing, | ||
232 | * invalidating all the pages in the page cache relating to the associated | ||
233 | * inode to clear the per-page caching. | ||
234 | */ | ||
235 | static void nfs_fscache_disable_inode_cookie(struct inode *inode) | ||
236 | { | ||
237 | clear_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); | ||
238 | |||
239 | if (NFS_I(inode)->fscache) { | ||
240 | dfprintk(FSCACHE, | ||
241 | "NFS: nfsi 0x%p turning cache off\n", NFS_I(inode)); | ||
242 | |||
243 | /* Need to invalidate any mapped pages that were read in before | ||
244 | * turning off the cache. | ||
245 | */ | ||
246 | if (inode->i_mapping && inode->i_mapping->nrpages) | ||
247 | invalidate_inode_pages2(inode->i_mapping); | ||
248 | |||
249 | nfs_fscache_zap_inode_cookie(inode); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * wait_on_bit() sleep function for uninterruptible waiting | ||
255 | */ | ||
256 | static int nfs_fscache_wait_bit(void *flags) | ||
257 | { | ||
258 | schedule(); | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * Lock against someone else trying to also acquire or relinquish a cookie | ||
264 | */ | ||
265 | static inline void nfs_fscache_inode_lock(struct inode *inode) | ||
266 | { | ||
267 | struct nfs_inode *nfsi = NFS_I(inode); | ||
268 | |||
269 | while (test_and_set_bit(NFS_INO_FSCACHE_LOCK, &nfsi->flags)) | ||
270 | wait_on_bit(&nfsi->flags, NFS_INO_FSCACHE_LOCK, | ||
271 | nfs_fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * Unlock cookie management lock | ||
276 | */ | ||
277 | static inline void nfs_fscache_inode_unlock(struct inode *inode) | ||
278 | { | ||
279 | struct nfs_inode *nfsi = NFS_I(inode); | ||
280 | |||
281 | smp_mb__before_clear_bit(); | ||
282 | clear_bit(NFS_INO_FSCACHE_LOCK, &nfsi->flags); | ||
283 | smp_mb__after_clear_bit(); | ||
284 | wake_up_bit(&nfsi->flags, NFS_INO_FSCACHE_LOCK); | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Decide if we should enable or disable local caching for this inode. | ||
289 | * - For now, with NFS, only regular files that are open read-only will be able | ||
290 | * to use the cache. | ||
291 | * - May be invoked multiple times in parallel by parallel nfs_open() functions. | ||
292 | */ | ||
293 | void nfs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) | ||
294 | { | ||
295 | if (NFS_FSCACHE(inode)) { | ||
296 | nfs_fscache_inode_lock(inode); | ||
297 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) | ||
298 | nfs_fscache_disable_inode_cookie(inode); | ||
299 | else | ||
300 | nfs_fscache_enable_inode_cookie(inode); | ||
301 | nfs_fscache_inode_unlock(inode); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * Replace a per-inode cookie due to revalidation detecting a file having | ||
307 | * changed on the server. | ||
308 | */ | ||
309 | void nfs_fscache_reset_inode_cookie(struct inode *inode) | ||
310 | { | ||
311 | struct nfs_inode *nfsi = NFS_I(inode); | ||
312 | struct nfs_server *nfss = NFS_SERVER(inode); | ||
313 | struct fscache_cookie *old = nfsi->fscache; | ||
314 | |||
315 | nfs_fscache_inode_lock(inode); | ||
316 | if (nfsi->fscache) { | ||
317 | /* retire the current fscache cache and get a new one */ | ||
318 | fscache_relinquish_cookie(nfsi->fscache, 1); | ||
319 | |||
320 | nfsi->fscache = fscache_acquire_cookie( | ||
321 | nfss->nfs_client->fscache, | ||
322 | &nfs_fscache_inode_object_def, | ||
323 | nfsi); | ||
324 | |||
325 | dfprintk(FSCACHE, | ||
326 | "NFS: revalidation new cookie (0x%p/0x%p/0x%p/0x%p)\n", | ||
327 | nfss, nfsi, old, nfsi->fscache); | ||
328 | } | ||
329 | nfs_fscache_inode_unlock(inode); | ||
330 | } | ||