aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/fscache.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-04-03 11:42:43 -0400
committerDavid Howells <dhowells@redhat.com>2009-04-03 11:42:43 -0400
commitef79c097bbe9724e13937271b3457df560e00370 (patch)
treea8671781cc0c9deb85fa76a8b4211c5e693b4343 /fs/nfs/fscache.c
parent10329a5d48f5abc14a37d30b706e330f8598297a (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.c162
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 */
173void 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 */
183static 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 */
205void 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 */
219void 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 */
235static 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 */
256static 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 */
265static 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 */
277static 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 */
293void 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 */
309void 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}