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>
This commit is contained in:
David Howells 2013-09-04 17:10:39 +00:00 committed by Steve French
parent 62d228b8c6
commit 54afa99057
3 changed files with 28 additions and 0 deletions

View file

@ -3254,6 +3254,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
/* /*
* Reads as many pages as possible from fscache. Returns -ENOBUFS * Reads as many pages as possible from fscache. Returns -ENOBUFS
* immediately if the cookie is negative * immediately if the cookie is negative
*
* After this point, every page in the list might have PG_fscache set,
* so we will need to clean that up off of every page we don't use.
*/ */
rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list, rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
&num_pages); &num_pages);
@ -3376,6 +3379,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
kref_put(&rdata->refcount, cifs_readdata_release); kref_put(&rdata->refcount, cifs_readdata_release);
} }
/* Any pages that have been shown to fscache but didn't get added to
* the pagecache must be uncached before they get returned to the
* allocator.
*/
cifs_fscache_readpages_cancel(mapping->host, page_list);
return rc; return rc;
} }

View file

@ -223,6 +223,13 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
fscache_uncache_page(CIFS_I(inode)->fscache, page); fscache_uncache_page(CIFS_I(inode)->fscache, page);
} }
void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages)
{
cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n",
__func__, CIFS_I(inode)->fscache, inode);
fscache_readpages_cancel(CIFS_I(inode)->fscache, pages);
}
void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
{ {
struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifsInodeInfo *cifsi = CIFS_I(inode);

View file

@ -54,6 +54,7 @@ extern int __cifs_readpages_from_fscache(struct inode *,
struct address_space *, struct address_space *,
struct list_head *, struct list_head *,
unsigned *); unsigned *);
extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *);
extern void __cifs_readpage_to_fscache(struct inode *, struct page *); extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
@ -91,6 +92,13 @@ static inline void cifs_readpage_to_fscache(struct inode *inode,
__cifs_readpage_to_fscache(inode, page); __cifs_readpage_to_fscache(inode, page);
} }
static inline void cifs_fscache_readpages_cancel(struct inode *inode,
struct list_head *pages)
{
if (CIFS_I(inode)->fscache)
return __cifs_fscache_readpages_cancel(inode, pages);
}
#else /* CONFIG_CIFS_FSCACHE */ #else /* CONFIG_CIFS_FSCACHE */
static inline int cifs_fscache_register(void) { return 0; } static inline int cifs_fscache_register(void) { return 0; }
static inline void cifs_fscache_unregister(void) {} static inline void cifs_fscache_unregister(void) {}
@ -131,6 +139,11 @@ static inline int cifs_readpages_from_fscache(struct inode *inode,
static inline void cifs_readpage_to_fscache(struct inode *inode, static inline void cifs_readpage_to_fscache(struct inode *inode,
struct page *page) {} struct page *page) {}
static inline void cifs_fscache_readpages_cancel(struct inode *inode,
struct list_head *pages)
{
}
#endif /* CONFIG_CIFS_FSCACHE */ #endif /* CONFIG_CIFS_FSCACHE */
#endif /* _CIFS_FSCACHE_H */ #endif /* _CIFS_FSCACHE_H */