Unverified Commit 9ddc34ea authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!14324 mm: shmem: don't truncate page if memory failure happens

parents d7e5d3f9 c8794c1f
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@
#include <linux/kfifo.h>
#include <linux/ratelimit.h>
#include <linux/page-isolation.h>
#include <linux/shmem_fs.h>
#include "internal.h"
#include "ras/ras_event.h"

@@ -715,6 +716,7 @@ static int me_pagecache_clean(struct page_state *ps, struct page *p)
{
	int ret;
	struct address_space *mapping;
	bool extra_pins;

	delete_from_lru_cache(p);

@@ -743,18 +745,24 @@ static int me_pagecache_clean(struct page_state *ps, struct page *p)
		goto out;
	}

	/*
	 * The shmem page is kept in page cache instead of truncating
	 * so is expected to have an extra refcount after error-handling.
	 */
	extra_pins = shmem_mapping(mapping);

	/*
	 * Truncation is a bit tricky. Enable it per file system for now.
	 *
	 * Open: to take i_mutex or not for this? Right now we don't.
	 */
	ret = truncate_error_page(p, page_to_pfn(p), mapping);
	if (has_extra_refcount(ps, p, extra_pins))
		ret = MF_FAILED;

out:
	unlock_page(p);

	if (has_extra_refcount(ps, p, false))
		ret = MF_FAILED;

	return ret;
}

+45 −6
Original line number Diff line number Diff line
@@ -2565,6 +2565,7 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
	struct inode *inode = mapping->host;
	struct shmem_inode_info *info = SHMEM_I(inode);
	pgoff_t index = pos >> PAGE_SHIFT;
	int ret = 0;

	/* i_mutex is held by caller */
	if (unlikely(info->seals & (F_SEAL_WRITE | F_SEAL_GROW))) {
@@ -2574,7 +2575,19 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
			return -EPERM;
	}

	return shmem_getpage(inode, index, pagep, SGP_WRITE);
	ret = shmem_getpage(inode, index, pagep, SGP_WRITE);

	if (ret)
		return ret;

	if (PageHWPoison(*pagep)) {
		unlock_page(*pagep);
		put_page(*pagep);
		*pagep = NULL;
		return -EIO;
	}

	return 0;
}

static int
@@ -2661,6 +2674,12 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
			if (sgp == SGP_CACHE)
				set_page_dirty(page);
			unlock_page(page);

			if (PageHWPoison(page)) {
				put_page(page);
				error = -EIO;
				break;
			}
		}

		/*
@@ -3263,7 +3282,8 @@ static const char *shmem_get_link(struct dentry *dentry,
		page = find_get_page(inode->i_mapping, 0);
		if (!page)
			return ERR_PTR(-ECHILD);
		if (!PageUptodate(page)) {
		if (PageHWPoison(page) ||
		    !PageUptodate(page)) {
			put_page(page);
			return ERR_PTR(-ECHILD);
		}
@@ -3271,6 +3291,13 @@ static const char *shmem_get_link(struct dentry *dentry,
		error = shmem_getpage(inode, 0, &page, SGP_READ);
		if (error)
			return ERR_PTR(error);
		if (!page)
			return ERR_PTR(-ECHILD);
		if (PageHWPoison(page)) {
			unlock_page(page);
			put_page(page);
			return ERR_PTR(-ECHILD);
		}
		unlock_page(page);
	}
	set_delayed_call(done, shmem_put_link, page);
@@ -3832,6 +3859,13 @@ static void shmem_destroy_inodecache(void)
	kmem_cache_destroy(shmem_inode_cachep);
}

/* Keep the page in page cache instead of truncating it */
static int shmem_error_remove_page(struct address_space *mapping,
				   struct page *page)
{
	return 0;
}

static const struct address_space_operations shmem_aops = {
	.writepage	= shmem_writepage,
	.set_page_dirty	= __set_page_dirty_no_writeback,
@@ -3842,7 +3876,7 @@ static const struct address_space_operations shmem_aops = {
#ifdef CONFIG_MIGRATION
	.migratepage	= migrate_page,
#endif
	.error_remove_page = generic_error_remove_page,
	.error_remove_page = shmem_error_remove_page,
};

static const struct file_operations shmem_file_operations = {
@@ -4270,9 +4304,14 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
	error = shmem_getpage_gfp(inode, index, &page, SGP_CACHE,
				  gfp, NULL, NULL, NULL);
	if (error)
		page = ERR_PTR(error);
	else
		return ERR_PTR(error);

	unlock_page(page);
	if (PageHWPoison(page)) {
		put_page(page);
		return ERR_PTR(-EIO);
	}

	return page;
#else
	/*