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 | |
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>
-rw-r--r-- | fs/nfs/fscache.c | 162 | ||||
-rw-r--r-- | fs/nfs/fscache.h | 13 | ||||
-rw-r--r-- | fs/nfs/inode.c | 6 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 10 |
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 | */ | ||
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 | } | ||
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 *); |
78 | extern void nfs_fscache_release_super_cookie(struct super_block *); | 78 | extern void nfs_fscache_release_super_cookie(struct super_block *); |
79 | 79 | ||
80 | extern void nfs_fscache_init_inode_cookie(struct inode *); | ||
81 | extern void nfs_fscache_release_inode_cookie(struct inode *); | ||
82 | extern void nfs_fscache_zap_inode_cookie(struct inode *); | ||
83 | extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *); | ||
84 | extern void nfs_fscache_reset_inode_cookie(struct inode *); | ||
85 | |||
80 | #else /* CONFIG_NFS_FSCACHE */ | 86 | #else /* CONFIG_NFS_FSCACHE */ |
81 | static inline int nfs_fscache_register(void) { return 0; } | 87 | static inline int nfs_fscache_register(void) { return 0; } |
82 | static inline void nfs_fscache_unregister(void) {} | 88 | static inline void nfs_fscache_unregister(void) {} |
@@ -91,5 +97,12 @@ static inline void nfs_fscache_get_super_cookie( | |||
91 | } | 97 | } |
92 | static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {} | 98 | static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {} |
93 | 99 | ||
100 | static inline void nfs_fscache_init_inode_cookie(struct inode *inode) {} | ||
101 | static inline void nfs_fscache_release_inode_cookie(struct inode *inode) {} | ||
102 | static inline void nfs_fscache_zap_inode_cookie(struct inode *inode) {} | ||
103 | static inline void nfs_fscache_set_inode_cookie(struct inode *inode, | ||
104 | struct file *filp) {} | ||
105 | static 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 | ||
211 | static inline struct nfs_inode *NFS_I(const struct inode *inode) | 216 | static 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 | ||
268 | static inline int NFS_FSCACHE(const struct inode *inode) | ||
269 | { | ||
270 | return test_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags); | ||
271 | } | ||
272 | |||
263 | static inline __u64 NFS_FILEID(const struct inode *inode) | 273 | static inline __u64 NFS_FILEID(const struct inode *inode) |
264 | { | 274 | { |
265 | return NFS_I(inode)->fileid; | 275 | return NFS_I(inode)->fileid; |