Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Howells and committed by
Steve French
54afa990 62d228b8

+28
+8
fs/cifs/file.c
··· 3254 3254 /* 3255 3255 * Reads as many pages as possible from fscache. Returns -ENOBUFS 3256 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 3261 rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list, 3259 3262 &num_pages); ··· 3379 3376 kref_put(&rdata->refcount, cifs_readdata_release); 3380 3377 } 3381 3378 3379 + /* Any pages that have been shown to fscache but didn't get added to 3380 + * the pagecache must be uncached before they get returned to the 3381 + * allocator. 3382 + */ 3383 + cifs_fscache_readpages_cancel(mapping->host, page_list); 3382 3384 return rc; 3383 3385 } 3384 3386
+7
fs/cifs/fscache.c
··· 223 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 233 void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) 227 234 { 228 235 struct cifsInodeInfo *cifsi = CIFS_I(inode);
+13
fs/cifs/fscache.h
··· 54 54 struct address_space *, 55 55 struct list_head *, 56 56 unsigned *); 57 + extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *); 57 58 58 59 extern void __cifs_readpage_to_fscache(struct inode *, struct page *); 59 60 ··· 90 89 { 91 90 if (PageFsCache(page)) 92 91 __cifs_readpage_to_fscache(inode, page); 92 + } 93 + 94 + static inline void cifs_fscache_readpages_cancel(struct inode *inode, 95 + struct list_head *pages) 96 + { 97 + if (CIFS_I(inode)->fscache) 98 + return __cifs_fscache_readpages_cancel(inode, pages); 93 99 } 94 100 95 101 #else /* CONFIG_CIFS_FSCACHE */ ··· 138 130 139 131 static inline void cifs_readpage_to_fscache(struct inode *inode, 140 132 struct page *page) {} 133 + 134 + static inline void cifs_fscache_readpages_cancel(struct inode *inode, 135 + struct list_head *pages) 136 + { 137 + } 141 138 142 139 #endif /* CONFIG_CIFS_FSCACHE */ 143 140