diff options
| author | David Howells <dhowells@redhat.com> | 2013-09-04 13:10:39 -0400 |
|---|---|---|
| committer | Steve French <smfrench@gmail.com> | 2013-09-18 11:17:03 -0400 |
| commit | 54afa99057ee2ffd3df0f5e891298bbbb65ea63c (patch) | |
| tree | bbe235d0310023e4c4eace892b1de10faee13c3f | |
| parent | 62d228b8c676232eca579f91cc0782b060a59097 (diff) | |
CIFS: FS-Cache: Uncache unread pages in cifs_readpages() before freeing them
In cifs_readpages(), we may decide we don't want to read a page after all -
but the page may already have passed through fscache_read_or_alloc_pages() and
thus have marks and reservations set. Thus we have to call
fscache_readpages_cancel() or fscache_uncache_page() on the pages we're
returning to clear the marks.
NFS, AFS and 9P should be unaffected by this as they call read_cache_pages()
which does the cleanup for you.
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
| -rw-r--r-- | fs/cifs/file.c | 8 | ||||
| -rw-r--r-- | fs/cifs/fscache.c | 7 | ||||
| -rw-r--r-- | fs/cifs/fscache.h | 13 |
3 files changed, 28 insertions, 0 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index eb955b525e55..7ddddf2e2504 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -3254,6 +3254,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
| 3254 | /* | 3254 | /* |
| 3255 | * Reads as many pages as possible from fscache. Returns -ENOBUFS | 3255 | * Reads as many pages as possible from fscache. Returns -ENOBUFS |
| 3256 | * immediately if the cookie is negative | 3256 | * immediately if the cookie is negative |
| 3257 | * | ||
| 3258 | * After this point, every page in the list might have PG_fscache set, | ||
| 3259 | * so we will need to clean that up off of every page we don't use. | ||
| 3257 | */ | 3260 | */ |
| 3258 | rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list, | 3261 | rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list, |
| 3259 | &num_pages); | 3262 | &num_pages); |
| @@ -3376,6 +3379,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
| 3376 | kref_put(&rdata->refcount, cifs_readdata_release); | 3379 | kref_put(&rdata->refcount, cifs_readdata_release); |
| 3377 | } | 3380 | } |
| 3378 | 3381 | ||
| 3382 | /* Any pages that have been shown to fscache but didn't get added to | ||
| 3383 | * the pagecache must be uncached before they get returned to the | ||
| 3384 | * allocator. | ||
| 3385 | */ | ||
| 3386 | cifs_fscache_readpages_cancel(mapping->host, page_list); | ||
| 3379 | return rc; | 3387 | return rc; |
| 3380 | } | 3388 | } |
| 3381 | 3389 | ||
diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index 2f4bc5a58054..b3258f35e88a 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c | |||
| @@ -223,6 +223,13 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page) | |||
| 223 | fscache_uncache_page(CIFS_I(inode)->fscache, page); | 223 | fscache_uncache_page(CIFS_I(inode)->fscache, page); |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages) | ||
| 227 | { | ||
| 228 | cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n", | ||
| 229 | __func__, CIFS_I(inode)->fscache, inode); | ||
| 230 | fscache_readpages_cancel(CIFS_I(inode)->fscache, pages); | ||
| 231 | } | ||
| 232 | |||
| 226 | void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) | 233 | void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) |
| 227 | { | 234 | { |
| 228 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 235 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 63539323e0b9..24794b6cd8ec 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h | |||
| @@ -54,6 +54,7 @@ extern int __cifs_readpages_from_fscache(struct inode *, | |||
| 54 | struct address_space *, | 54 | struct address_space *, |
| 55 | struct list_head *, | 55 | struct list_head *, |
| 56 | unsigned *); | 56 | unsigned *); |
| 57 | extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *); | ||
| 57 | 58 | ||
| 58 | extern void __cifs_readpage_to_fscache(struct inode *, struct page *); | 59 | extern void __cifs_readpage_to_fscache(struct inode *, struct page *); |
| 59 | 60 | ||
| @@ -91,6 +92,13 @@ static inline void cifs_readpage_to_fscache(struct inode *inode, | |||
| 91 | __cifs_readpage_to_fscache(inode, page); | 92 | __cifs_readpage_to_fscache(inode, page); |
| 92 | } | 93 | } |
| 93 | 94 | ||
| 95 | static inline void cifs_fscache_readpages_cancel(struct inode *inode, | ||
| 96 | struct list_head *pages) | ||
| 97 | { | ||
| 98 | if (CIFS_I(inode)->fscache) | ||
| 99 | return __cifs_fscache_readpages_cancel(inode, pages); | ||
| 100 | } | ||
| 101 | |||
| 94 | #else /* CONFIG_CIFS_FSCACHE */ | 102 | #else /* CONFIG_CIFS_FSCACHE */ |
| 95 | static inline int cifs_fscache_register(void) { return 0; } | 103 | static inline int cifs_fscache_register(void) { return 0; } |
| 96 | static inline void cifs_fscache_unregister(void) {} | 104 | static inline void cifs_fscache_unregister(void) {} |
| @@ -131,6 +139,11 @@ static inline int cifs_readpages_from_fscache(struct inode *inode, | |||
| 131 | static inline void cifs_readpage_to_fscache(struct inode *inode, | 139 | static inline void cifs_readpage_to_fscache(struct inode *inode, |
| 132 | struct page *page) {} | 140 | struct page *page) {} |
| 133 | 141 | ||
| 142 | static inline void cifs_fscache_readpages_cancel(struct inode *inode, | ||
| 143 | struct list_head *pages) | ||
| 144 | { | ||
| 145 | } | ||
| 146 | |||
| 134 | #endif /* CONFIG_CIFS_FSCACHE */ | 147 | #endif /* CONFIG_CIFS_FSCACHE */ |
| 135 | 148 | ||
| 136 | #endif /* _CIFS_FSCACHE_H */ | 149 | #endif /* _CIFS_FSCACHE_H */ |
