[Linux-cachefs] 'bad page state' error

David Howells dhowells at redhat.com
Thu Sep 5 11:32:36 UTC 2013


Can you try this patch?  It's against 2.6.32-358.el6.

The problem appears to be that any page that goes through
fscache_read_or_alloc_pages() but that doesn't get read from the cache marks
the page with PG_fscache as it may now be pinning cache resources.  This is
done in the expectation that the page will then be read from the server and
written to the cache.

To fix this, if the netfs doesn't then manage to read the page from the server
(say a local ENOMEM occurs), then the page must be uncached before we release
it - assuming it isn't added to the pagecache.

David
---
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 0971ffc..72da122 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2041,6 +2041,7 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
 
 		if (add_to_page_cache_lru(page, mapping, page->index,
 				      GFP_KERNEL)) {
+			cifs_fscache_uncache_page(page, mapping->host);
 			page_cache_release(page);
 			cFYI(1, "Add page cache failed");
 			data += PAGE_CACHE_SIZE;
@@ -2226,6 +2227,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 		smb_read_data = NULL;
 	}
 
+	list_for_each_entry(page, page_list, lru) {
+		cifs_fscache_uncache_page(page, mapping->host);
+	}
+
 read_complete:
 	FreeXid(xid);
 	return rc;
diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c
index 42e5363..9b05aa2 100644
--- a/fs/cifs/fscache.c
+++ b/fs/cifs/fscache.c
@@ -233,3 +233,11 @@ void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
 	fscache_uncache_page(cookie, page);
 }
 
+void __cifs_fscache_uncache_page(struct page *page, struct inode *inode)
+{
+	struct cifsInodeInfo *cifsi = CIFS_I(inode);
+	struct fscache_cookie *cookie = cifsi->fscache;
+
+	cFYI(1, "%s: (0x%p/0x%p)", __func__, page, cookie);
+	fscache_uncache_page(cookie, page);
+}
diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h
index 6353932..c590c50 100644
--- a/fs/cifs/fscache.h
+++ b/fs/cifs/fscache.h
@@ -48,6 +48,7 @@ extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *);
 extern void cifs_fscache_reset_inode_cookie(struct inode *);
 
 extern void __cifs_fscache_invalidate_page(struct page *, struct inode *);
+extern void __cifs_fscache_uncache_page(struct page *, struct inode *);
 extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
 extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
 extern int __cifs_readpages_from_fscache(struct inode *,
@@ -64,6 +65,13 @@ static inline void cifs_fscache_invalidate_page(struct page *page,
 		__cifs_fscache_invalidate_page(page, inode);
 }
 
+static inline void cifs_fscache_uncache_page(struct page *page,
+					     struct inode *inode)
+{
+	if (PageFsCache(page))
+		__cifs_fscache_uncache_page(page, inode);
+}
+
 static inline int cifs_readpage_from_fscache(struct inode *inode,
 					     struct page *page)
 {
@@ -114,6 +122,9 @@ static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
 
 static inline void cifs_fscache_invalidate_page(struct page *page,
 			struct inode *inode) {}
+static inline void cifs_fscache_uncache_page(struct page *page,
+					     struct inode *inode) {}
+
 static inline int
 cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 {




More information about the Linux-cachefs mailing list