From 3767cf8bf420bd59c3426a4287259b1e97178e96 Mon Sep 17 00:00:00 2001 From: Marc Dionne Date: Wed, 22 May 2013 09:26:57 -0400 Subject: [PATCH] Linux: Fix tmpfs cache support As of kernel 3.1, tmpfs no longer has a readpage() operation in its address space operations. Some of the cache manager code relies on this, causing an oops if tmpfs is used as backing store for the cache. As a minimal fix, detect that there is no readpage() and disable the optimizations that depend on it. Change-Id: I6e2236cd53f893d77a8d6568eae7e200ad8d1ac0 Reviewed-on: http://gerrit.openafs.org/9949 Tested-by: BuildBot Reviewed-by: Derrick Brashear --- src/afs/LINUX/osi_vnodeops.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index f140d88..46fbb88 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -47,6 +47,8 @@ #define MAX_ERRNO 1000L #endif +int cachefs_noreadpage = 0; + extern struct backing_dev_info *afs_backing_dev_info; extern struct vcache *afs_globalVp; @@ -1873,6 +1875,10 @@ afs_linux_readpage_fastpath(struct file *fp, struct page *pp, int *codep) if (cacheDiskType != AFS_FCACHE_TYPE_UFS) return 0; + /* No readpage (ex: tmpfs) , skip */ + if (cachefs_noreadpage) + return 0; + /* Can't do anything if the vcache isn't statd , or if the read * crosses a chunk boundary. */ @@ -1932,12 +1938,8 @@ afs_linux_readpage_fastpath(struct file *fp, struct page *pp, int *codep) /* Is the dcache we've been given currently up to date */ if (!hsame(avc->f.m.DataVersion, tdc->f.versionNo) || - (tdc->dflags & DFFetching)) { - ReleaseWriteLock(&avc->lock); - ReleaseReadLock(&tdc->lock); - afs_PutDCache(tdc); - return 0; - } + (tdc->dflags & DFFetching)) + goto out; /* Update our hint for future abuse */ avc->dchint = tdc; @@ -1947,6 +1949,11 @@ afs_linux_readpage_fastpath(struct file *fp, struct page *pp, int *codep) /* XXX - I suspect we should be locking the inodes before we use them! */ AFS_GUNLOCK(); cacheFp = afs_linux_raw_open(&tdc->f.inode); + if (!cacheFp->f_dentry->d_inode->i_mapping->a_ops->readpage) { + cachefs_noreadpage = 1; + AFS_GLOCK(); + goto out; + } pagevec_init(&lrupv, 0); code = afs_linux_read_cache(cacheFp, pp, tdc->f.chunk, &lrupv, NULL); @@ -1963,6 +1970,12 @@ afs_linux_readpage_fastpath(struct file *fp, struct page *pp, int *codep) *codep = code; return 1; + +out: + ReleaseWriteLock(&avc->lock); + ReleaseReadLock(&tdc->lock); + afs_PutDCache(tdc); + return 0; } /* afs_linux_readpage @@ -2305,6 +2318,10 @@ afs_linux_readpages(struct file *fp, struct address_space *mapping, if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return 0; + /* No readpage (ex: tmpfs) , skip */ + if (cachefs_noreadpage) + return 0; + AFS_GLOCK(); if ((code = afs_linux_VerifyVCache(avc, NULL))) { AFS_GUNLOCK(); @@ -2339,14 +2356,20 @@ afs_linux_readpages(struct file *fp, struct address_space *mapping, ObtainReadLock(&tdc->lock); if (!hsame(avc->f.m.DataVersion, tdc->f.versionNo) || (tdc->dflags & DFFetching)) { + goto out; ReleaseReadLock(&tdc->lock); afs_PutDCache(tdc); tdc = NULL; } } AFS_GUNLOCK(); - if (tdc) + if (tdc) { cacheFp = afs_linux_raw_open(&tdc->f.inode); + if (!cacheFp->f_dentry->d_inode->i_mapping->a_ops->readpage) { + cachefs_noreadpage = 1; + goto out; + } + } } if (tdc && !add_to_page_cache(page, mapping, page->index, @@ -2362,6 +2385,7 @@ afs_linux_readpages(struct file *fp, struct address_space *mapping, if (pagevec_count(&lrupv)) __pagevec_lru_add_file(&lrupv); +out: if (tdc) filp_close(cacheFp, NULL); -- 1.9.4