tmpfs: remove_shmem_readpage
Remove that pernicious shmem_readpage() at last: the things we needed it for (splice, loop, sendfile, i915 GEM) are now fully taken care of by shmem_file_splice_read() and shmem_read_mapping_page_gfp(). This removal clears the way for a simpler shmem_getpage_gfp(), since page is never passed in; but leave most of that cleanup until after. sys_readahead() and sys_fadvise(POSIX_FADV_WILLNEED) will now EINVAL, instead of unexpectedly trying to read ahead on tmpfs: if that proves to be an issue for someone, then we can either arrange for them to return success instead, or try to implement async readahead on tmpfs. Signed-off-by: Hugh Dickins <hughd@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
68da9f0557
commit
9276aad6c8
40
mm/shmem.c
40
mm/shmem.c
|
@ -1246,7 +1246,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx,
|
||||||
struct address_space *mapping = inode->i_mapping;
|
struct address_space *mapping = inode->i_mapping;
|
||||||
struct shmem_inode_info *info = SHMEM_I(inode);
|
struct shmem_inode_info *info = SHMEM_I(inode);
|
||||||
struct shmem_sb_info *sbinfo;
|
struct shmem_sb_info *sbinfo;
|
||||||
struct page *filepage = *pagep;
|
struct page *filepage;
|
||||||
struct page *swappage;
|
struct page *swappage;
|
||||||
struct page *prealloc_page = NULL;
|
struct page *prealloc_page = NULL;
|
||||||
swp_entry_t *entry;
|
swp_entry_t *entry;
|
||||||
|
@ -1255,18 +1255,8 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx,
|
||||||
|
|
||||||
if (idx >= SHMEM_MAX_INDEX)
|
if (idx >= SHMEM_MAX_INDEX)
|
||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
|
|
||||||
/*
|
|
||||||
* Normally, filepage is NULL on entry, and either found
|
|
||||||
* uptodate immediately, or allocated and zeroed, or read
|
|
||||||
* in under swappage, which is then assigned to filepage.
|
|
||||||
* But shmem_readpage (required for splice) passes in a locked
|
|
||||||
* filepage, which may be found not uptodate by other callers
|
|
||||||
* too, and may need to be copied from the swappage read in.
|
|
||||||
*/
|
|
||||||
repeat:
|
repeat:
|
||||||
if (!filepage)
|
filepage = find_lock_page(mapping, idx);
|
||||||
filepage = find_lock_page(mapping, idx);
|
|
||||||
if (filepage && PageUptodate(filepage))
|
if (filepage && PageUptodate(filepage))
|
||||||
goto done;
|
goto done;
|
||||||
if (!filepage) {
|
if (!filepage) {
|
||||||
|
@ -1513,8 +1503,7 @@ nospace:
|
||||||
* Perhaps the page was brought in from swap between find_lock_page
|
* Perhaps the page was brought in from swap between find_lock_page
|
||||||
* and taking info->lock? We allow for that at add_to_page_cache_lru,
|
* and taking info->lock? We allow for that at add_to_page_cache_lru,
|
||||||
* but must also avoid reporting a spurious ENOSPC while working on a
|
* but must also avoid reporting a spurious ENOSPC while working on a
|
||||||
* full tmpfs. (When filepage has been passed in to shmem_getpage, it
|
* full tmpfs.
|
||||||
* is already in page cache, which prevents this race from occurring.)
|
|
||||||
*/
|
*/
|
||||||
if (!filepage) {
|
if (!filepage) {
|
||||||
struct page *page = find_get_page(mapping, idx);
|
struct page *page = find_get_page(mapping, idx);
|
||||||
|
@ -1527,7 +1516,7 @@ nospace:
|
||||||
spin_unlock(&info->lock);
|
spin_unlock(&info->lock);
|
||||||
error = -ENOSPC;
|
error = -ENOSPC;
|
||||||
failed:
|
failed:
|
||||||
if (*pagep != filepage) {
|
if (filepage) {
|
||||||
unlock_page(filepage);
|
unlock_page(filepage);
|
||||||
page_cache_release(filepage);
|
page_cache_release(filepage);
|
||||||
}
|
}
|
||||||
|
@ -1673,19 +1662,6 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
|
||||||
static const struct inode_operations shmem_symlink_inode_operations;
|
static const struct inode_operations shmem_symlink_inode_operations;
|
||||||
static const struct inode_operations shmem_symlink_inline_operations;
|
static const struct inode_operations shmem_symlink_inline_operations;
|
||||||
|
|
||||||
/*
|
|
||||||
* Normally tmpfs avoids the use of shmem_readpage and shmem_write_begin;
|
|
||||||
* but providing them allows a tmpfs file to be used for splice, sendfile, and
|
|
||||||
* below the loop driver, in the generic fashion that many filesystems support.
|
|
||||||
*/
|
|
||||||
static int shmem_readpage(struct file *file, struct page *page)
|
|
||||||
{
|
|
||||||
struct inode *inode = page->mapping->host;
|
|
||||||
int error = shmem_getpage(inode, page->index, &page, SGP_CACHE, NULL);
|
|
||||||
unlock_page(page);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
shmem_write_begin(struct file *file, struct address_space *mapping,
|
shmem_write_begin(struct file *file, struct address_space *mapping,
|
||||||
loff_t pos, unsigned len, unsigned flags,
|
loff_t pos, unsigned len, unsigned flags,
|
||||||
|
@ -1693,7 +1669,6 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
|
||||||
{
|
{
|
||||||
struct inode *inode = mapping->host;
|
struct inode *inode = mapping->host;
|
||||||
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
|
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
|
||||||
*pagep = NULL;
|
|
||||||
return shmem_getpage(inode, index, pagep, SGP_WRITE, NULL);
|
return shmem_getpage(inode, index, pagep, SGP_WRITE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1893,7 +1868,6 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
|
||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
while (spd.nr_pages < nr_pages) {
|
while (spd.nr_pages < nr_pages) {
|
||||||
page = NULL;
|
|
||||||
error = shmem_getpage(inode, index, &page, SGP_CACHE, NULL);
|
error = shmem_getpage(inode, index, &page, SGP_CACHE, NULL);
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
|
@ -1916,7 +1890,6 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
|
||||||
page = spd.pages[page_nr];
|
page = spd.pages[page_nr];
|
||||||
|
|
||||||
if (!PageUptodate(page) || page->mapping != mapping) {
|
if (!PageUptodate(page) || page->mapping != mapping) {
|
||||||
page = NULL;
|
|
||||||
error = shmem_getpage(inode, index, &page,
|
error = shmem_getpage(inode, index, &page,
|
||||||
SGP_CACHE, NULL);
|
SGP_CACHE, NULL);
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -2125,7 +2098,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
|
||||||
int error;
|
int error;
|
||||||
int len;
|
int len;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct page *page = NULL;
|
struct page *page;
|
||||||
char *kaddr;
|
char *kaddr;
|
||||||
struct shmem_inode_info *info;
|
struct shmem_inode_info *info;
|
||||||
|
|
||||||
|
@ -2803,7 +2776,6 @@ static const struct address_space_operations shmem_aops = {
|
||||||
.writepage = shmem_writepage,
|
.writepage = shmem_writepage,
|
||||||
.set_page_dirty = __set_page_dirty_no_writeback,
|
.set_page_dirty = __set_page_dirty_no_writeback,
|
||||||
#ifdef CONFIG_TMPFS
|
#ifdef CONFIG_TMPFS
|
||||||
.readpage = shmem_readpage,
|
|
||||||
.write_begin = shmem_write_begin,
|
.write_begin = shmem_write_begin,
|
||||||
.write_end = shmem_write_end,
|
.write_end = shmem_write_end,
|
||||||
#endif
|
#endif
|
||||||
|
@ -3175,7 +3147,7 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SHMEM
|
#ifdef CONFIG_SHMEM
|
||||||
struct inode *inode = mapping->host;
|
struct inode *inode = mapping->host;
|
||||||
struct page *page = NULL;
|
struct page *page;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
BUG_ON(mapping->a_ops != &shmem_aops);
|
BUG_ON(mapping->a_ops != &shmem_aops);
|
||||||
|
|
Loading…
Reference in New Issue