Commit fcbc329f authored by Andrew Morton's avatar Andrew Morton

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

parents a644b0ab e5548f85
...@@ -4107,6 +4107,10 @@ static inline unsigned char mas_wr_new_end(struct ma_wr_state *wr_mas) ...@@ -4107,6 +4107,10 @@ static inline unsigned char mas_wr_new_end(struct ma_wr_state *wr_mas)
* mas_wr_append: Attempt to append * mas_wr_append: Attempt to append
* @wr_mas: the maple write state * @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 * Return: True if appended, false otherwise
*/ */
static inline bool mas_wr_append(struct ma_wr_state *wr_mas, 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, ...@@ -4116,6 +4120,9 @@ static inline bool mas_wr_append(struct ma_wr_state *wr_mas,
struct ma_state *mas = wr_mas->mas; struct ma_state *mas = wr_mas->mas;
unsigned char node_pivots = mt_pivots[wr_mas->type]; unsigned char node_pivots = mt_pivots[wr_mas->type];
if (mt_in_rcu(mas->tree))
return false;
if (mas->offset != wr_mas->node_end) if (mas->offset != wr_mas->node_end)
return false; return false;
......
...@@ -1607,7 +1607,7 @@ bool madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, ...@@ -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 * 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. * 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; goto out;
if (!folio_trylock(folio)) if (!folio_trylock(folio))
......
...@@ -383,7 +383,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd, ...@@ -383,7 +383,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
folio = pfn_folio(pmd_pfn(orig_pmd)); folio = pfn_folio(pmd_pfn(orig_pmd));
/* Do not interfere with other mappings of this folio */ /* Do not interfere with other mappings of this folio */
if (folio_mapcount(folio) != 1) if (folio_estimated_sharers(folio) != 1)
goto huge_unlock; goto huge_unlock;
if (pageout_anon_only_filter && !folio_test_anon(folio)) if (pageout_anon_only_filter && !folio_test_anon(folio))
...@@ -459,7 +459,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd, ...@@ -459,7 +459,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
if (folio_test_large(folio)) { if (folio_test_large(folio)) {
int err; int err;
if (folio_mapcount(folio) != 1) if (folio_estimated_sharers(folio) != 1)
break; break;
if (pageout_anon_only_filter && !folio_test_anon(folio)) if (pageout_anon_only_filter && !folio_test_anon(folio))
break; break;
...@@ -683,7 +683,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr, ...@@ -683,7 +683,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
if (folio_test_large(folio)) { if (folio_test_large(folio)) {
int err; int err;
if (folio_mapcount(folio) != 1) if (folio_estimated_sharers(folio) != 1)
break; break;
if (!folio_trylock(folio)) if (!folio_trylock(folio))
break; break;
......
...@@ -806,14 +806,16 @@ unsigned long shmem_partial_swap_usage(struct address_space *mapping, ...@@ -806,14 +806,16 @@ unsigned long shmem_partial_swap_usage(struct address_space *mapping,
XA_STATE(xas, &mapping->i_pages, start); XA_STATE(xas, &mapping->i_pages, start);
struct page *page; struct page *page;
unsigned long swapped = 0; unsigned long swapped = 0;
unsigned long max = end - 1;
rcu_read_lock(); rcu_read_lock();
xas_for_each(&xas, page, end - 1) { xas_for_each(&xas, page, max) {
if (xas_retry(&xas, page)) if (xas_retry(&xas, page))
continue; continue;
if (xa_is_value(page)) if (xa_is_value(page))
swapped++; swapped++;
if (xas.xa_index == max)
break;
if (need_resched()) { if (need_resched()) {
xas_pause(&xas); xas_pause(&xas);
cond_resched_rcu(); cond_resched_rcu();
......
...@@ -4,10 +4,12 @@ ...@@ -4,10 +4,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/magic.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/shm.h> #include <sys/shm.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/vfs.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
...@@ -15,6 +17,8 @@ ...@@ -15,6 +17,8 @@
#include "../kselftest.h" #include "../kselftest.h"
#define NR_TESTS 9
static const char * const dev_files[] = { static const char * const dev_files[] = {
"/dev/zero", "/dev/null", "/dev/urandom", "/dev/zero", "/dev/null", "/dev/urandom",
"/proc/version", "/proc" "/proc/version", "/proc"
...@@ -90,6 +94,20 @@ bool write_exactly(int fd, size_t filesize) ...@@ -90,6 +94,20 @@ bool write_exactly(int fd, size_t filesize)
return ret; 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 * Open/create the file at filename, (optionally) write random data to it
* (exactly num_pages), then test the cachestat syscall on this file. * (exactly num_pages), then test the cachestat syscall on this file.
...@@ -97,13 +115,13 @@ bool write_exactly(int fd, size_t filesize) ...@@ -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 * If test_fsync == true, fsync the file, then check the number of dirty
* pages. * pages.
*/ */
bool test_cachestat(const char *filename, bool write_random, bool create, static int test_cachestat(const char *filename, bool write_random, bool create,
bool test_fsync, unsigned long num_pages, int open_flags, bool test_fsync, unsigned long num_pages,
mode_t open_mode) int open_flags, mode_t open_mode)
{ {
size_t PS = sysconf(_SC_PAGESIZE); size_t PS = sysconf(_SC_PAGESIZE);
int filesize = num_pages * PS; int filesize = num_pages * PS;
bool ret = true; int ret = KSFT_PASS;
long syscall_ret; long syscall_ret;
struct cachestat cs; struct cachestat cs;
struct cachestat_range cs_range = { 0, filesize }; struct cachestat_range cs_range = { 0, filesize };
...@@ -112,7 +130,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create, ...@@ -112,7 +130,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create,
if (fd == -1) { if (fd == -1) {
ksft_print_msg("Unable to create/open file.\n"); ksft_print_msg("Unable to create/open file.\n");
ret = false; ret = KSFT_FAIL;
goto out; goto out;
} else { } else {
ksft_print_msg("Create/open %s\n", filename); ksft_print_msg("Create/open %s\n", filename);
...@@ -121,7 +139,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create, ...@@ -121,7 +139,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create,
if (write_random) { if (write_random) {
if (!write_exactly(fd, filesize)) { if (!write_exactly(fd, filesize)) {
ksft_print_msg("Unable to access urandom.\n"); ksft_print_msg("Unable to access urandom.\n");
ret = false; ret = KSFT_FAIL;
goto out1; goto out1;
} }
} }
...@@ -132,7 +150,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create, ...@@ -132,7 +150,7 @@ bool test_cachestat(const char *filename, bool write_random, bool create,
if (syscall_ret) { if (syscall_ret) {
ksft_print_msg("Cachestat returned non-zero.\n"); ksft_print_msg("Cachestat returned non-zero.\n");
ret = false; ret = KSFT_FAIL;
goto out1; goto out1;
} else { } else {
...@@ -142,15 +160,17 @@ bool test_cachestat(const char *filename, bool write_random, bool create, ...@@ -142,15 +160,17 @@ bool test_cachestat(const char *filename, bool write_random, bool create,
if (cs.nr_cache + cs.nr_evicted != num_pages) { if (cs.nr_cache + cs.nr_evicted != num_pages) {
ksft_print_msg( ksft_print_msg(
"Total number of cached and evicted pages is off.\n"); "Total number of cached and evicted pages is off.\n");
ret = false; ret = KSFT_FAIL;
} }
} }
} }
if (test_fsync) { if (test_fsync) {
if (fsync(fd)) { if (is_on_tmpfs(fd)) {
ret = KSFT_SKIP;
} else if (fsync(fd)) {
ksft_print_msg("fsync fails.\n"); ksft_print_msg("fsync fails.\n");
ret = false; ret = KSFT_FAIL;
} else { } else {
syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); 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, ...@@ -161,13 +181,13 @@ bool test_cachestat(const char *filename, bool write_random, bool create,
print_cachestat(&cs); print_cachestat(&cs);
if (cs.nr_dirty) { if (cs.nr_dirty) {
ret = false; ret = KSFT_FAIL;
ksft_print_msg( ksft_print_msg(
"Number of dirty should be zero after fsync.\n"); "Number of dirty should be zero after fsync.\n");
} }
} else { } else {
ksft_print_msg("Cachestat (after fsync) returned non-zero.\n"); ksft_print_msg("Cachestat (after fsync) returned non-zero.\n");
ret = false; ret = KSFT_FAIL;
goto out1; goto out1;
} }
} }
...@@ -236,13 +256,29 @@ bool test_cachestat_shmem(void) ...@@ -236,13 +256,29 @@ bool test_cachestat_shmem(void)
int main(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++) { for (int i = 0; i < 5; i++) {
const char *dev_filename = dev_files[i]; const char *dev_filename = dev_files[i];
if (test_cachestat(dev_filename, false, false, false, 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); ksft_test_result_pass("cachestat works with %s\n", dev_filename);
else { else {
ksft_test_result_fail("cachestat fails with %s\n", dev_filename); ksft_test_result_fail("cachestat fails with %s\n", dev_filename);
...@@ -251,13 +287,27 @@ int main(void) ...@@ -251,13 +287,27 @@ int main(void)
} }
if (test_cachestat("tmpfilecachestat", true, true, 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"); ksft_test_result_pass("cachestat works with a normal file\n");
else { else {
ksft_test_result_fail("cachestat fails with normal file\n"); ksft_test_result_fail("cachestat fails with normal file\n");
ret = 1; 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()) if (test_cachestat_shmem())
ksft_test_result_pass("cachestat works with a shmem file\n"); ksft_test_result_pass("cachestat works with a shmem file\n");
else { else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment