Loading lib/maple_tree.c +7 −0 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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; Loading mm/huge_memory.c +1 −1 Original line number Diff line number Diff line Loading @@ -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)) Loading mm/madvise.c +3 −3 Original line number Diff line number Diff line Loading @@ -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)) Loading Loading @@ -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; Loading Loading @@ -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; Loading mm/shmem.c +4 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading tools/testing/selftests/cachestat/test_cachestat.c +65 −15 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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" Loading Loading @@ -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. Loading @@ -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 }; Loading @@ -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); Loading @@ -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; } } Loading @@ -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 { Loading @@ -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); Loading @@ -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; } } Loading Loading @@ -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); Loading @@ -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 { Loading Loading
lib/maple_tree.c +7 −0 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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; Loading
mm/huge_memory.c +1 −1 Original line number Diff line number Diff line Loading @@ -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)) Loading
mm/madvise.c +3 −3 Original line number Diff line number Diff line Loading @@ -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)) Loading Loading @@ -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; Loading Loading @@ -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; Loading
mm/shmem.c +4 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading
tools/testing/selftests/cachestat/test_cachestat.c +65 −15 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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" Loading Loading @@ -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. Loading @@ -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 }; Loading @@ -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); Loading @@ -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; } } Loading @@ -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 { Loading @@ -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); Loading @@ -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; } } Loading Loading @@ -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); Loading @@ -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 { Loading