aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/nfs/fscache.c162
-rw-r--r--fs/nfs/fscache.h13
-rw-r--r--fs/nfs/inode.c6
-rw-r--r--include/linux/nfs_fs.h10
4 files changed, 191 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}
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h
index d21b5906ccf4..8b4299a0ad61 100644
--- a/fs/nfs/fscache.h
+++ b/fs/nfs/fscache.h
@@ -77,6 +77,12 @@ extern void nfs_fscache_get_super_cookie(struct super_block *,
77 struct nfs_parsed_mount_data *); 77 struct nfs_parsed_mount_data *);
78extern void nfs_fscache_release_super_cookie(struct super_block *); 78extern void nfs_fscache_release_super_cookie(struct super_block *);
79 79
80extern void nfs_fscache_init_inode_cookie(struct inode *);
81extern void nfs_fscache_release_inode_cookie(struct inode *);
82extern void nfs_fscache_zap_inode_cookie(struct inode *);
83extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *);
84extern void nfs_fscache_reset_inode_cookie(struct inode *);
85
80#else /* CONFIG_NFS_FSCACHE */ 86#else /* CONFIG_NFS_FSCACHE */
81static inline int nfs_fscache_register(void) { return 0; } 87static inline int nfs_fscache_register(void) { return 0; }
82static inline void nfs_fscache_unregister(void) {} 88static inline void nfs_fscache_unregister(void) {}
@@ -91,5 +97,12 @@ static inline void nfs_fscache_get_super_cookie(
91} 97}
92static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {} 98static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {}
93 99
100static inline void nfs_fscache_init_inode_cookie(struct inode *inode) {}
101static inline void nfs_fscache_release_inode_cookie(struct inode *inode) {}
102static inline void nfs_fscache_zap_inode_cookie(struct inode *inode) {}
103static inline void nfs_fscache_set_inode_cookie(struct inode *inode,
104 struct file *filp) {}
105static inline void nfs_fscache_reset_inode_cookie(struct inode *inode) {}
106
94#endif /* CONFIG_NFS_FSCACHE */ 107#endif /* CONFIG_NFS_FSCACHE */
95#endif /* _NFS_FSCACHE_H */ 108#endif /* _NFS_FSCACHE_H */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index cd29f410e941..64f87194d390 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -122,6 +122,7 @@ void nfs_clear_inode(struct inode *inode)
122 BUG_ON(!list_empty(&NFS_I(inode)->open_files)); 122 BUG_ON(!list_empty(&NFS_I(inode)->open_files));
123 nfs_zap_acl_cache(inode); 123 nfs_zap_acl_cache(inode);
124 nfs_access_zap_cache(inode); 124 nfs_access_zap_cache(inode);
125 nfs_fscache_release_inode_cookie(inode);
125} 126}
126 127
127/** 128/**
@@ -356,6 +357,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
356 nfsi->attrtimeo_timestamp = now; 357 nfsi->attrtimeo_timestamp = now;
357 nfsi->access_cache = RB_ROOT; 358 nfsi->access_cache = RB_ROOT;
358 359
360 nfs_fscache_init_inode_cookie(inode);
361
359 unlock_new_inode(inode); 362 unlock_new_inode(inode);
360 } else 363 } else
361 nfs_refresh_inode(inode, fattr); 364 nfs_refresh_inode(inode, fattr);
@@ -687,6 +690,7 @@ int nfs_open(struct inode *inode, struct file *filp)
687 ctx->mode = filp->f_mode; 690 ctx->mode = filp->f_mode;
688 nfs_file_set_open_context(filp, ctx); 691 nfs_file_set_open_context(filp, ctx);
689 put_nfs_open_context(ctx); 692 put_nfs_open_context(ctx);
693 nfs_fscache_set_inode_cookie(inode, filp);
690 return 0; 694 return 0;
691} 695}
692 696
@@ -787,6 +791,7 @@ static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_spa
787 memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); 791 memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
788 spin_unlock(&inode->i_lock); 792 spin_unlock(&inode->i_lock);
789 nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); 793 nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
794 nfs_fscache_reset_inode_cookie(inode);
790 dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", 795 dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
791 inode->i_sb->s_id, (long long)NFS_FILEID(inode)); 796 inode->i_sb->s_id, (long long)NFS_FILEID(inode));
792 return 0; 797 return 0;
@@ -1031,6 +1036,7 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
1031 spin_lock(&inode->i_lock); 1036 spin_lock(&inode->i_lock);
1032 status = nfs_refresh_inode_locked(inode, fattr); 1037 status = nfs_refresh_inode_locked(inode, fattr);
1033 spin_unlock(&inode->i_lock); 1038 spin_unlock(&inode->i_lock);
1039
1034 return status; 1040 return status;
1035} 1041}
1036 1042
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index fd3e7f9c6fd3..8a99e79d5ea5 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -185,6 +185,9 @@ struct nfs_inode {
185 fmode_t delegation_state; 185 fmode_t delegation_state;
186 struct rw_semaphore rwsem; 186 struct rw_semaphore rwsem;
187#endif /* CONFIG_NFS_V4*/ 187#endif /* CONFIG_NFS_V4*/
188#ifdef CONFIG_NFS_FSCACHE
189 struct fscache_cookie *fscache;
190#endif
188 struct inode vfs_inode; 191 struct inode vfs_inode;
189}; 192};
190 193
@@ -207,6 +210,8 @@ struct nfs_inode {
207#define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ 210#define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */
208#define NFS_INO_MOUNTPOINT (3) /* inode is remote mountpoint */ 211#define NFS_INO_MOUNTPOINT (3) /* inode is remote mountpoint */
209#define NFS_INO_FLUSHING (4) /* inode is flushing out data */ 212#define NFS_INO_FLUSHING (4) /* inode is flushing out data */
213#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
214#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */
210 215
211static inline struct nfs_inode *NFS_I(const struct inode *inode) 216static inline struct nfs_inode *NFS_I(const struct inode *inode)
212{ 217{
@@ -260,6 +265,11 @@ static inline int NFS_STALE(const struct inode *inode)
260 return test_bit(NFS_INO_STALE, &NFS_I(inode)->flags); 265 return test_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
261} 266}
262 267
268static inline int NFS_FSCACHE(const struct inode *inode)
269{
270 return test_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags);
271}
272
263static inline __u64 NFS_FILEID(const struct inode *inode) 273static inline __u64 NFS_FILEID(const struct inode *inode)
264{ 274{
265 return NFS_I(inode)->fileid; 275 return NFS_I(inode)->fileid;