Commit fcbc329f authored by Andrew Morton's avatar Andrew Morton
Browse files

merge mm-hotfixes-stable into mm-stable to pick up depended-upon changes

parents a644b0ab e5548f85
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -4107,6 +4107,10 @@ static inline unsigned char mas_wr_new_end(struct ma_wr_state *wr_mas)
 * mas_wr_append: Attempt to append
 * @wr_mas: the maple write state
 *
 * This is currently unsafe in rcu mode since the end of the node may be cached
 * by readers while the node contents may be updated which could result in
 * inaccurate information.
 *
 * Return: True if appended, false otherwise
 */
static inline bool mas_wr_append(struct ma_wr_state *wr_mas,
@@ -4116,6 +4120,9 @@ static inline bool mas_wr_append(struct ma_wr_state *wr_mas,
	struct ma_state *mas = wr_mas->mas;
	unsigned char node_pivots = mt_pivots[wr_mas->type];

	if (mt_in_rcu(mas->tree))
		return false;

	if (mas->offset != wr_mas->node_end)
		return false;

+1 −1
Original line number Diff line number Diff line
@@ -1607,7 +1607,7 @@ bool madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
	 * If other processes are mapping this folio, we couldn't discard
	 * the folio unless they all do MADV_FREE so let's skip the folio.
	 */
	if (folio_mapcount(folio) != 1)
	if (folio_estimated_sharers(folio) != 1)
		goto out;

	if (!folio_trylock(folio))
+3 −3
Original line number Diff line number Diff line
@@ -383,7 +383,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
		folio = pfn_folio(pmd_pfn(orig_pmd));

		/* Do not interfere with other mappings of this folio */
		if (folio_mapcount(folio) != 1)
		if (folio_estimated_sharers(folio) != 1)
			goto huge_unlock;

		if (pageout_anon_only_filter && !folio_test_anon(folio))
@@ -459,7 +459,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
		if (folio_test_large(folio)) {
			int err;

			if (folio_mapcount(folio) != 1)
			if (folio_estimated_sharers(folio) != 1)
				break;
			if (pageout_anon_only_filter && !folio_test_anon(folio))
				break;
@@ -683,7 +683,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
		if (folio_test_large(folio)) {
			int err;

			if (folio_mapcount(folio) != 1)
			if (folio_estimated_sharers(folio) != 1)
				break;
			if (!folio_trylock(folio))
				break;
+4 −2
Original line number Diff line number Diff line
@@ -806,14 +806,16 @@ unsigned long shmem_partial_swap_usage(struct address_space *mapping,
	XA_STATE(xas, &mapping->i_pages, start);
	struct page *page;
	unsigned long swapped = 0;
	unsigned long max = end - 1;

	rcu_read_lock();
	xas_for_each(&xas, page, end - 1) {
	xas_for_each(&xas, page, max) {
		if (xas_retry(&xas, page))
			continue;
		if (xa_is_value(page))
			swapped++;

		if (xas.xa_index == max)
			break;
		if (need_resched()) {
			xas_pause(&xas);
			cond_resched_rcu();
+65 −15
Original line number Diff line number Diff line
@@ -4,10 +4,12 @@
#include <stdio.h>
#include <stdbool.h>
#include <linux/kernel.h>
#include <linux/magic.h>
#include <linux/mman.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/syscall.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
@@ -15,6 +17,8 @@

#include "../kselftest.h"

#define NR_TESTS	9

static const char * const dev_files[] = {
	"/dev/zero", "/dev/null", "/dev/urandom",
	"/proc/version", "/proc"
@@ -90,6 +94,20 @@ bool write_exactly(int fd, size_t filesize)
	return ret;
}

/*
 * fsync() is implemented via noop_fsync() on tmpfs. This makes the fsync()
 * test fail below, so we need to check for test file living on a tmpfs.
 */
static bool is_on_tmpfs(int fd)
{
	struct statfs statfs_buf;

	if (fstatfs(fd, &statfs_buf))
		return false;

	return statfs_buf.f_type == TMPFS_MAGIC;
}

/*
 * Open/create the file at filename, (optionally) write random data to it
 * (exactly num_pages), then test the cachestat syscall on this file.
@@ -97,13 +115,13 @@ bool write_exactly(int fd, size_t filesize)
 * If test_fsync == true, fsync the file, then check the number of dirty
 * pages.
 */
bool test_cachestat(const char *filename, bool write_random, bool create,
		bool test_fsync, unsigned long num_pages, int open_flags,
		mode_t open_mode)
static int test_cachestat(const char *filename, bool write_random, bool create,
			  bool test_fsync, unsigned long num_pages,
			  int open_flags, mode_t open_mode)
{
	size_t PS = sysconf(_SC_PAGESIZE);
	int filesize = num_pages * PS;
	bool ret = true;
	int ret = KSFT_PASS;
	long syscall_ret;
	struct cachestat cs;
	struct cachestat_range cs_range = { 0, filesize };
@@ -112,7 +130,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create,

	if (fd == -1) {
		ksft_print_msg("Unable to create/open file.\n");
		ret = false;
		ret = KSFT_FAIL;
		goto out;
	} else {
		ksft_print_msg("Create/open %s\n", filename);
@@ -121,7 +139,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create,
	if (write_random) {
		if (!write_exactly(fd, filesize)) {
			ksft_print_msg("Unable to access urandom.\n");
			ret = false;
			ret = KSFT_FAIL;
			goto out1;
		}
	}
@@ -132,7 +150,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create,

	if (syscall_ret) {
		ksft_print_msg("Cachestat returned non-zero.\n");
		ret = false;
		ret = KSFT_FAIL;
		goto out1;

	} else {
@@ -142,15 +160,17 @@ bool test_cachestat(const char *filename, bool write_random, bool create,
			if (cs.nr_cache + cs.nr_evicted != num_pages) {
				ksft_print_msg(
					"Total number of cached and evicted pages is off.\n");
				ret = false;
				ret = KSFT_FAIL;
			}
		}
	}

	if (test_fsync) {
		if (fsync(fd)) {
		if (is_on_tmpfs(fd)) {
			ret = KSFT_SKIP;
		} else if (fsync(fd)) {
			ksft_print_msg("fsync fails.\n");
			ret = false;
			ret = KSFT_FAIL;
		} else {
			syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0);

@@ -161,13 +181,13 @@ bool test_cachestat(const char *filename, bool write_random, bool create,
				print_cachestat(&cs);

				if (cs.nr_dirty) {
					ret = false;
					ret = KSFT_FAIL;
					ksft_print_msg(
						"Number of dirty should be zero after fsync.\n");
				}
			} else {
				ksft_print_msg("Cachestat (after fsync) returned non-zero.\n");
				ret = false;
				ret = KSFT_FAIL;
				goto out1;
			}
		}
@@ -236,13 +256,29 @@ bool test_cachestat_shmem(void)

int main(void)
{
	int ret = 0;
	int ret;

	ksft_print_header();

	ret = syscall(__NR_cachestat, -1, NULL, NULL, 0);
	if (ret == -1 && errno == ENOSYS)
		ksft_exit_skip("cachestat syscall not available\n");

	ksft_set_plan(NR_TESTS);

	if (ret == -1 && errno == EBADF) {
		ksft_test_result_pass("bad file descriptor recognized\n");
		ret = 0;
	} else {
		ksft_test_result_fail("bad file descriptor ignored\n");
		ret = 1;
	}

	for (int i = 0; i < 5; i++) {
		const char *dev_filename = dev_files[i];

		if (test_cachestat(dev_filename, false, false, false,
			4, O_RDONLY, 0400))
			4, O_RDONLY, 0400) == KSFT_PASS)
			ksft_test_result_pass("cachestat works with %s\n", dev_filename);
		else {
			ksft_test_result_fail("cachestat fails with %s\n", dev_filename);
@@ -251,13 +287,27 @@ int main(void)
	}

	if (test_cachestat("tmpfilecachestat", true, true,
		true, 4, O_CREAT | O_RDWR, 0400 | 0600))
		false, 4, O_CREAT | O_RDWR, 0600) == KSFT_PASS)
		ksft_test_result_pass("cachestat works with a normal file\n");
	else {
		ksft_test_result_fail("cachestat fails with normal file\n");
		ret = 1;
	}

	switch (test_cachestat("tmpfilecachestat", true, true,
		true, 4, O_CREAT | O_RDWR, 0600)) {
	case KSFT_FAIL:
		ksft_test_result_fail("cachestat fsync fails with normal file\n");
		ret = KSFT_FAIL;
		break;
	case KSFT_PASS:
		ksft_test_result_pass("cachestat fsync works with a normal file\n");
		break;
	case KSFT_SKIP:
		ksft_test_result_skip("tmpfilecachestat is on tmpfs\n");
		break;
	}

	if (test_cachestat_shmem())
		ksft_test_result_pass("cachestat works with a shmem file\n");
	else {