mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
Merge tag 'mm-stable-2023-06-24-19-15' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull mm updates from Andrew Morton: - Yosry Ahmed brought back some cgroup v1 stats in OOM logs - Yosry has also eliminated cgroup's atomic rstat flushing - Nhat Pham adds the new cachestat() syscall. It provides userspace with the ability to query pagecache status - a similar concept to mincore() but more powerful and with improved usability - Mel Gorman provides more optimizations for compaction, reducing the prevalence of page rescanning - Lorenzo Stoakes has done some maintanance work on the get_user_pages() interface - Liam Howlett continues with cleanups and maintenance work to the maple tree code. Peng Zhang also does some work on maple tree - Johannes Weiner has done some cleanup work on the compaction code - David Hildenbrand has contributed additional selftests for get_user_pages() - Thomas Gleixner has contributed some maintenance and optimization work for the vmalloc code - Baolin Wang has provided some compaction cleanups, - SeongJae Park continues maintenance work on the DAMON code - Huang Ying has done some maintenance on the swap code's usage of device refcounting - Christoph Hellwig has some cleanups for the filemap/directio code - Ryan Roberts provides two patch series which yield some rationalization of the kernel's access to pte entries - use the provided APIs rather than open-coding accesses - Lorenzo Stoakes has some fixes to the interaction between pagecache and directio access to file mappings - John Hubbard has a series of fixes to the MM selftesting code - ZhangPeng continues the folio conversion campaign - Hugh Dickins has been working on the pagetable handling code, mainly with a view to reducing the load on the mmap_lock - Catalin Marinas has reduced the arm64 kmalloc() minimum alignment from 128 to 8 - Domenico Cerasuolo has improved the zswap reclaim mechanism by reorganizing the LRU management - Matthew Wilcox provides some fixups to make gfs2 work better with the buffer_head code - Vishal Moola also has done some folio conversion work - Matthew Wilcox has removed the remnants of the pagevec code - their functionality is migrated over to struct folio_batch * tag 'mm-stable-2023-06-24-19-15' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (380 commits) mm/hugetlb: remove hugetlb_set_page_subpool() mm: nommu: correct the range of mmap_sem_read_lock in task_mem() hugetlb: revert use of page_cache_next_miss() Revert "page cache: fix page_cache_next/prev_miss off by one" mm/vmscan: fix root proactive reclaim unthrottling unbalanced node mm: memcg: rename and document global_reclaim() mm: kill [add|del]_page_to_lru_list() mm: compaction: convert to use a folio in isolate_migratepages_block() mm: zswap: fix double invalidate with exclusive loads mm: remove unnecessary pagevec includes mm: remove references to pagevec mm: rename invalidate_mapping_pagevec to mapping_try_invalidate mm: remove struct pagevec net: convert sunrpc from pagevec to folio_batch i915: convert i915_gpu_error to use a folio_batch pagevec: rename fbatch_count() mm: remove check_move_unevictable_pages() drm: convert drm_gem_put_pages() to use a folio_batch i915: convert shmem_sg_free_table() to use a folio_batch scatterlist: add sg_set_folio() ...
This commit is contained in:
@@ -1 +1,2 @@
|
||||
#define __init
|
||||
#define __exit
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "test.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "linux/init.h"
|
||||
|
||||
#define module_init(x)
|
||||
#define module_exit(x)
|
||||
@@ -22,7 +23,6 @@
|
||||
#define dump_stack() assert(0)
|
||||
|
||||
#include "../../../lib/maple_tree.c"
|
||||
#undef CONFIG_DEBUG_MAPLE_TREE
|
||||
#include "../../../lib/test_maple_tree.c"
|
||||
|
||||
#define RCU_RANGE_COUNT 1000
|
||||
@@ -81,7 +81,7 @@ static void check_mas_alloc_node_count(struct ma_state *mas)
|
||||
* check_new_node() - Check the creation of new nodes and error path
|
||||
* verification.
|
||||
*/
|
||||
static noinline void check_new_node(struct maple_tree *mt)
|
||||
static noinline void __init check_new_node(struct maple_tree *mt)
|
||||
{
|
||||
|
||||
struct maple_node *mn, *mn2, *mn3;
|
||||
@@ -455,7 +455,7 @@ static noinline void check_new_node(struct maple_tree *mt)
|
||||
/*
|
||||
* Check erasing including RCU.
|
||||
*/
|
||||
static noinline void check_erase(struct maple_tree *mt, unsigned long index,
|
||||
static noinline void __init check_erase(struct maple_tree *mt, unsigned long index,
|
||||
void *ptr)
|
||||
{
|
||||
MT_BUG_ON(mt, mtree_test_erase(mt, index) != ptr);
|
||||
@@ -465,24 +465,24 @@ static noinline void check_erase(struct maple_tree *mt, unsigned long index,
|
||||
#define erase_check_insert(mt, i) check_insert(mt, set[i], entry[i%2])
|
||||
#define erase_check_erase(mt, i) check_erase(mt, set[i], entry[i%2])
|
||||
|
||||
static noinline void check_erase_testset(struct maple_tree *mt)
|
||||
static noinline void __init check_erase_testset(struct maple_tree *mt)
|
||||
{
|
||||
unsigned long set[] = { 5015, 5014, 5017, 25, 1000,
|
||||
1001, 1002, 1003, 1005, 0,
|
||||
6003, 6002, 6008, 6012, 6015,
|
||||
7003, 7002, 7008, 7012, 7015,
|
||||
8003, 8002, 8008, 8012, 8015,
|
||||
9003, 9002, 9008, 9012, 9015,
|
||||
10003, 10002, 10008, 10012, 10015,
|
||||
11003, 11002, 11008, 11012, 11015,
|
||||
12003, 12002, 12008, 12012, 12015,
|
||||
13003, 13002, 13008, 13012, 13015,
|
||||
14003, 14002, 14008, 14012, 14015,
|
||||
15003, 15002, 15008, 15012, 15015,
|
||||
};
|
||||
static const unsigned long set[] = { 5015, 5014, 5017, 25, 1000,
|
||||
1001, 1002, 1003, 1005, 0,
|
||||
6003, 6002, 6008, 6012, 6015,
|
||||
7003, 7002, 7008, 7012, 7015,
|
||||
8003, 8002, 8008, 8012, 8015,
|
||||
9003, 9002, 9008, 9012, 9015,
|
||||
10003, 10002, 10008, 10012, 10015,
|
||||
11003, 11002, 11008, 11012, 11015,
|
||||
12003, 12002, 12008, 12012, 12015,
|
||||
13003, 13002, 13008, 13012, 13015,
|
||||
14003, 14002, 14008, 14012, 14015,
|
||||
15003, 15002, 15008, 15012, 15015,
|
||||
};
|
||||
|
||||
|
||||
void *ptr = &set;
|
||||
void *ptr = &check_erase_testset;
|
||||
void *entry[2] = { ptr, mt };
|
||||
void *root_node;
|
||||
|
||||
@@ -739,7 +739,7 @@ static noinline void check_erase_testset(struct maple_tree *mt)
|
||||
int mas_ce2_over_count(struct ma_state *mas_start, struct ma_state *mas_end,
|
||||
void *s_entry, unsigned long s_min,
|
||||
void *e_entry, unsigned long e_max,
|
||||
unsigned long *set, int i, bool null_entry)
|
||||
const unsigned long *set, int i, bool null_entry)
|
||||
{
|
||||
int count = 0, span = 0;
|
||||
unsigned long retry = 0;
|
||||
@@ -969,8 +969,8 @@ retry:
|
||||
}
|
||||
|
||||
#if defined(CONFIG_64BIT)
|
||||
static noinline void check_erase2_testset(struct maple_tree *mt,
|
||||
unsigned long *set, unsigned long size)
|
||||
static noinline void __init check_erase2_testset(struct maple_tree *mt,
|
||||
const unsigned long *set, unsigned long size)
|
||||
{
|
||||
int entry_count = 0;
|
||||
int check = 0;
|
||||
@@ -1054,7 +1054,7 @@ static noinline void check_erase2_testset(struct maple_tree *mt,
|
||||
if (entry_count)
|
||||
MT_BUG_ON(mt, !mt_height(mt));
|
||||
#if check_erase2_debug > 1
|
||||
mt_dump(mt);
|
||||
mt_dump(mt, mt_dump_hex);
|
||||
#endif
|
||||
#if check_erase2_debug
|
||||
pr_err("Done\n");
|
||||
@@ -1085,7 +1085,7 @@ static noinline void check_erase2_testset(struct maple_tree *mt,
|
||||
mas_for_each(&mas, foo, ULONG_MAX) {
|
||||
if (xa_is_zero(foo)) {
|
||||
if (addr == mas.index) {
|
||||
mt_dump(mas.tree);
|
||||
mt_dump(mas.tree, mt_dump_hex);
|
||||
pr_err("retry failed %lu - %lu\n",
|
||||
mas.index, mas.last);
|
||||
MT_BUG_ON(mt, 1);
|
||||
@@ -1114,11 +1114,11 @@ static noinline void check_erase2_testset(struct maple_tree *mt,
|
||||
|
||||
|
||||
/* These tests were pulled from KVM tree modifications which failed. */
|
||||
static noinline void check_erase2_sets(struct maple_tree *mt)
|
||||
static noinline void __init check_erase2_sets(struct maple_tree *mt)
|
||||
{
|
||||
void *entry;
|
||||
unsigned long start = 0;
|
||||
unsigned long set[] = {
|
||||
static const unsigned long set[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140721266458624, 140737488351231,
|
||||
ERASE, 140721266458624, 140737488351231,
|
||||
@@ -1136,7 +1136,7 @@ ERASE, 140253902692352, 140253902864383,
|
||||
STORE, 140253902692352, 140253902696447,
|
||||
STORE, 140253902696448, 140253902864383,
|
||||
};
|
||||
unsigned long set2[] = {
|
||||
static const unsigned long set2[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140735933583360, 140737488351231,
|
||||
ERASE, 140735933583360, 140737488351231,
|
||||
@@ -1160,7 +1160,7 @@ STORE, 140277094813696, 140277094821887,
|
||||
STORE, 140277094821888, 140277094825983,
|
||||
STORE, 140735933906944, 140735933911039,
|
||||
};
|
||||
unsigned long set3[] = {
|
||||
static const unsigned long set3[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140735790264320, 140737488351231,
|
||||
ERASE, 140735790264320, 140737488351231,
|
||||
@@ -1203,7 +1203,7 @@ STORE, 47135835840512, 47135835885567,
|
||||
STORE, 47135835885568, 47135835893759,
|
||||
};
|
||||
|
||||
unsigned long set4[] = {
|
||||
static const unsigned long set4[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140728251703296, 140737488351231,
|
||||
ERASE, 140728251703296, 140737488351231,
|
||||
@@ -1224,7 +1224,7 @@ ERASE, 47646523277312, 47646523445247,
|
||||
STORE, 47646523277312, 47646523400191,
|
||||
};
|
||||
|
||||
unsigned long set5[] = {
|
||||
static const unsigned long set5[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140726874062848, 140737488351231,
|
||||
ERASE, 140726874062848, 140737488351231,
|
||||
@@ -1357,7 +1357,7 @@ STORE, 47884791619584, 47884791623679,
|
||||
STORE, 47884791623680, 47884791627775,
|
||||
};
|
||||
|
||||
unsigned long set6[] = {
|
||||
static const unsigned long set6[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140722999021568, 140737488351231,
|
||||
ERASE, 140722999021568, 140737488351231,
|
||||
@@ -1489,7 +1489,7 @@ ERASE, 47430432014336, 47430432022527,
|
||||
STORE, 47430432014336, 47430432018431,
|
||||
STORE, 47430432018432, 47430432022527,
|
||||
};
|
||||
unsigned long set7[] = {
|
||||
static const unsigned long set7[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140729808330752, 140737488351231,
|
||||
ERASE, 140729808330752, 140737488351231,
|
||||
@@ -1621,7 +1621,7 @@ ERASE, 47439987130368, 47439987138559,
|
||||
STORE, 47439987130368, 47439987134463,
|
||||
STORE, 47439987134464, 47439987138559,
|
||||
};
|
||||
unsigned long set8[] = {
|
||||
static const unsigned long set8[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140722482974720, 140737488351231,
|
||||
ERASE, 140722482974720, 140737488351231,
|
||||
@@ -1754,7 +1754,7 @@ STORE, 47708488638464, 47708488642559,
|
||||
STORE, 47708488642560, 47708488646655,
|
||||
};
|
||||
|
||||
unsigned long set9[] = {
|
||||
static const unsigned long set9[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140736427839488, 140737488351231,
|
||||
ERASE, 140736427839488, 140736427839488,
|
||||
@@ -5620,7 +5620,7 @@ ERASE, 47906195480576, 47906195480576,
|
||||
STORE, 94641242615808, 94641242750975,
|
||||
};
|
||||
|
||||
unsigned long set10[] = {
|
||||
static const unsigned long set10[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140736427839488, 140737488351231,
|
||||
ERASE, 140736427839488, 140736427839488,
|
||||
@@ -9484,7 +9484,7 @@ STORE, 139726599680000, 139726599684095,
|
||||
ERASE, 47906195480576, 47906195480576,
|
||||
STORE, 94641242615808, 94641242750975,
|
||||
};
|
||||
unsigned long set11[] = {
|
||||
static const unsigned long set11[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140732658499584, 140737488351231,
|
||||
ERASE, 140732658499584, 140732658499584,
|
||||
@@ -9510,7 +9510,7 @@ STORE, 140732658565120, 140732658569215,
|
||||
STORE, 140732658552832, 140732658565119,
|
||||
};
|
||||
|
||||
unsigned long set12[] = { /* contains 12 values. */
|
||||
static const unsigned long set12[] = { /* contains 12 values. */
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140732658499584, 140737488351231,
|
||||
ERASE, 140732658499584, 140732658499584,
|
||||
@@ -9537,7 +9537,7 @@ STORE, 140732658552832, 140732658565119,
|
||||
STORE, 140014592741375, 140014592741375, /* contrived */
|
||||
STORE, 140014592733184, 140014592741376, /* creates first entry retry. */
|
||||
};
|
||||
unsigned long set13[] = {
|
||||
static const unsigned long set13[] = {
|
||||
STORE, 140373516247040, 140373516251135,/*: ffffa2e7b0e10d80 */
|
||||
STORE, 140373516251136, 140373516255231,/*: ffffa2e7b1195d80 */
|
||||
STORE, 140373516255232, 140373516443647,/*: ffffa2e7b0e109c0 */
|
||||
@@ -9550,7 +9550,7 @@ STORE, 140373518684160, 140373518688254,/*: ffffa2e7b05fec00 */
|
||||
STORE, 140373518688256, 140373518692351,/*: ffffa2e7bfbdcd80 */
|
||||
STORE, 140373518692352, 140373518696447,/*: ffffa2e7b0749e40 */
|
||||
};
|
||||
unsigned long set14[] = {
|
||||
static const unsigned long set14[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140731667996672, 140737488351231,
|
||||
SNULL, 140731668000767, 140737488351231,
|
||||
@@ -9834,7 +9834,7 @@ SNULL, 139826136543232, 139826136809471,
|
||||
STORE, 139826136809472, 139826136842239,
|
||||
STORE, 139826136543232, 139826136809471,
|
||||
};
|
||||
unsigned long set15[] = {
|
||||
static const unsigned long set15[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140722061451264, 140737488351231,
|
||||
SNULL, 140722061455359, 140737488351231,
|
||||
@@ -10119,7 +10119,7 @@ STORE, 139906808958976, 139906808991743,
|
||||
STORE, 139906808692736, 139906808958975,
|
||||
};
|
||||
|
||||
unsigned long set16[] = {
|
||||
static const unsigned long set16[] = {
|
||||
STORE, 94174808662016, 94174809321471,
|
||||
STORE, 94174811414528, 94174811426815,
|
||||
STORE, 94174811426816, 94174811430911,
|
||||
@@ -10330,7 +10330,7 @@ STORE, 139921865613312, 139921865617407,
|
||||
STORE, 139921865547776, 139921865564159,
|
||||
};
|
||||
|
||||
unsigned long set17[] = {
|
||||
static const unsigned long set17[] = {
|
||||
STORE, 94397057224704, 94397057646591,
|
||||
STORE, 94397057650688, 94397057691647,
|
||||
STORE, 94397057691648, 94397057695743,
|
||||
@@ -10392,7 +10392,7 @@ STORE, 140720477511680, 140720477646847,
|
||||
STORE, 140720478302208, 140720478314495,
|
||||
STORE, 140720478314496, 140720478318591,
|
||||
};
|
||||
unsigned long set18[] = {
|
||||
static const unsigned long set18[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140724953673728, 140737488351231,
|
||||
SNULL, 140724953677823, 140737488351231,
|
||||
@@ -10425,7 +10425,7 @@ STORE, 140222970597376, 140222970605567,
|
||||
ERASE, 140222970597376, 140222970605567,
|
||||
STORE, 140222970597376, 140222970605567,
|
||||
};
|
||||
unsigned long set19[] = {
|
||||
static const unsigned long set19[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140725182459904, 140737488351231,
|
||||
SNULL, 140725182463999, 140737488351231,
|
||||
@@ -10694,7 +10694,7 @@ STORE, 140656836775936, 140656836780031,
|
||||
STORE, 140656787476480, 140656791920639,
|
||||
ERASE, 140656774639616, 140656779083775,
|
||||
};
|
||||
unsigned long set20[] = {
|
||||
static const unsigned long set20[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140735952392192, 140737488351231,
|
||||
SNULL, 140735952396287, 140737488351231,
|
||||
@@ -10850,7 +10850,7 @@ STORE, 140590386819072, 140590386823167,
|
||||
STORE, 140590386823168, 140590386827263,
|
||||
SNULL, 140590376591359, 140590376595455,
|
||||
};
|
||||
unsigned long set21[] = {
|
||||
static const unsigned long set21[] = {
|
||||
STORE, 93874710941696, 93874711363583,
|
||||
STORE, 93874711367680, 93874711408639,
|
||||
STORE, 93874711408640, 93874711412735,
|
||||
@@ -10920,7 +10920,7 @@ ERASE, 140708393312256, 140708393316351,
|
||||
ERASE, 140708393308160, 140708393312255,
|
||||
ERASE, 140708393291776, 140708393308159,
|
||||
};
|
||||
unsigned long set22[] = {
|
||||
static const unsigned long set22[] = {
|
||||
STORE, 93951397134336, 93951397183487,
|
||||
STORE, 93951397183488, 93951397728255,
|
||||
STORE, 93951397728256, 93951397826559,
|
||||
@@ -11047,7 +11047,7 @@ STORE, 140551361253376, 140551361519615,
|
||||
ERASE, 140551361253376, 140551361519615,
|
||||
};
|
||||
|
||||
unsigned long set23[] = {
|
||||
static const unsigned long set23[] = {
|
||||
STORE, 94014447943680, 94014448156671,
|
||||
STORE, 94014450253824, 94014450257919,
|
||||
STORE, 94014450257920, 94014450266111,
|
||||
@@ -14371,7 +14371,7 @@ SNULL, 140175956627455, 140175985139711,
|
||||
STORE, 140175927242752, 140175956627455,
|
||||
STORE, 140175956627456, 140175985139711,
|
||||
};
|
||||
unsigned long set24[] = {
|
||||
static const unsigned long set24[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140735281639424, 140737488351231,
|
||||
SNULL, 140735281643519, 140737488351231,
|
||||
@@ -15533,7 +15533,7 @@ ERASE, 139635393024000, 139635401412607,
|
||||
ERASE, 139635384627200, 139635384631295,
|
||||
ERASE, 139635384631296, 139635393019903,
|
||||
};
|
||||
unsigned long set25[] = {
|
||||
static const unsigned long set25[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140737488343040, 140737488351231,
|
||||
STORE, 140722547441664, 140737488351231,
|
||||
@@ -22321,7 +22321,7 @@ STORE, 140249652703232, 140249682087935,
|
||||
STORE, 140249682087936, 140249710600191,
|
||||
};
|
||||
|
||||
unsigned long set26[] = {
|
||||
static const unsigned long set26[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140729464770560, 140737488351231,
|
||||
SNULL, 140729464774655, 140737488351231,
|
||||
@@ -22345,7 +22345,7 @@ ERASE, 140109040951296, 140109040959487,
|
||||
STORE, 140109040955392, 140109040959487,
|
||||
ERASE, 140109040955392, 140109040959487,
|
||||
};
|
||||
unsigned long set27[] = {
|
||||
static const unsigned long set27[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140726128070656, 140737488351231,
|
||||
SNULL, 140726128074751, 140737488351231,
|
||||
@@ -22741,7 +22741,7 @@ STORE, 140415509696512, 140415535910911,
|
||||
ERASE, 140415537422336, 140415562588159,
|
||||
STORE, 140415482433536, 140415509696511,
|
||||
};
|
||||
unsigned long set28[] = {
|
||||
static const unsigned long set28[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140722475622400, 140737488351231,
|
||||
SNULL, 140722475626495, 140737488351231,
|
||||
@@ -22809,7 +22809,7 @@ STORE, 139918413348864, 139918413352959,
|
||||
ERASE, 139918413316096, 139918413344767,
|
||||
STORE, 93865848528896, 93865848664063,
|
||||
};
|
||||
unsigned long set29[] = {
|
||||
static const unsigned long set29[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140734467944448, 140737488351231,
|
||||
SNULL, 140734467948543, 140737488351231,
|
||||
@@ -23684,7 +23684,7 @@ ERASE, 140143079972864, 140143088361471,
|
||||
ERASE, 140143205793792, 140143205797887,
|
||||
ERASE, 140143205797888, 140143214186495,
|
||||
};
|
||||
unsigned long set30[] = {
|
||||
static const unsigned long set30[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140733436743680, 140737488351231,
|
||||
SNULL, 140733436747775, 140737488351231,
|
||||
@@ -24566,7 +24566,7 @@ ERASE, 140165225893888, 140165225897983,
|
||||
ERASE, 140165225897984, 140165234286591,
|
||||
ERASE, 140165058105344, 140165058109439,
|
||||
};
|
||||
unsigned long set31[] = {
|
||||
static const unsigned long set31[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140730890784768, 140737488351231,
|
||||
SNULL, 140730890788863, 140737488351231,
|
||||
@@ -25379,7 +25379,7 @@ ERASE, 140623906590720, 140623914979327,
|
||||
ERASE, 140622950277120, 140622950281215,
|
||||
ERASE, 140622950281216, 140622958669823,
|
||||
};
|
||||
unsigned long set32[] = {
|
||||
static const unsigned long set32[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140731244212224, 140737488351231,
|
||||
SNULL, 140731244216319, 140737488351231,
|
||||
@@ -26175,7 +26175,7 @@ ERASE, 140400417288192, 140400425676799,
|
||||
ERASE, 140400283066368, 140400283070463,
|
||||
ERASE, 140400283070464, 140400291459071,
|
||||
};
|
||||
unsigned long set33[] = {
|
||||
static const unsigned long set33[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140734562918400, 140737488351231,
|
||||
SNULL, 140734562922495, 140737488351231,
|
||||
@@ -26317,7 +26317,7 @@ STORE, 140582961786880, 140583003750399,
|
||||
ERASE, 140582961786880, 140583003750399,
|
||||
};
|
||||
|
||||
unsigned long set34[] = {
|
||||
static const unsigned long set34[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140731327180800, 140737488351231,
|
||||
SNULL, 140731327184895, 140737488351231,
|
||||
@@ -27198,7 +27198,7 @@ ERASE, 140012522094592, 140012530483199,
|
||||
ERASE, 140012033142784, 140012033146879,
|
||||
ERASE, 140012033146880, 140012041535487,
|
||||
};
|
||||
unsigned long set35[] = {
|
||||
static const unsigned long set35[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140730536939520, 140737488351231,
|
||||
SNULL, 140730536943615, 140737488351231,
|
||||
@@ -27955,7 +27955,7 @@ ERASE, 140474471936000, 140474480324607,
|
||||
ERASE, 140474396430336, 140474396434431,
|
||||
ERASE, 140474396434432, 140474404823039,
|
||||
};
|
||||
unsigned long set36[] = {
|
||||
static const unsigned long set36[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140723893125120, 140737488351231,
|
||||
SNULL, 140723893129215, 140737488351231,
|
||||
@@ -28816,7 +28816,7 @@ ERASE, 140121890357248, 140121898745855,
|
||||
ERASE, 140121269587968, 140121269592063,
|
||||
ERASE, 140121269592064, 140121277980671,
|
||||
};
|
||||
unsigned long set37[] = {
|
||||
static const unsigned long set37[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140722404016128, 140737488351231,
|
||||
SNULL, 140722404020223, 140737488351231,
|
||||
@@ -28942,7 +28942,7 @@ STORE, 139759821246464, 139759888355327,
|
||||
ERASE, 139759821246464, 139759888355327,
|
||||
ERASE, 139759888355328, 139759955464191,
|
||||
};
|
||||
unsigned long set38[] = {
|
||||
static const unsigned long set38[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140730666221568, 140737488351231,
|
||||
SNULL, 140730666225663, 140737488351231,
|
||||
@@ -29752,7 +29752,7 @@ ERASE, 140613504712704, 140613504716799,
|
||||
ERASE, 140613504716800, 140613513105407,
|
||||
};
|
||||
|
||||
unsigned long set39[] = {
|
||||
static const unsigned long set39[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140736271417344, 140737488351231,
|
||||
SNULL, 140736271421439, 140737488351231,
|
||||
@@ -30124,7 +30124,7 @@ STORE, 140325364428800, 140325372821503,
|
||||
STORE, 140325356036096, 140325364428799,
|
||||
SNULL, 140325364432895, 140325372821503,
|
||||
};
|
||||
unsigned long set40[] = {
|
||||
static const unsigned long set40[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140734309167104, 140737488351231,
|
||||
SNULL, 140734309171199, 140737488351231,
|
||||
@@ -30875,7 +30875,7 @@ ERASE, 140320289300480, 140320289304575,
|
||||
ERASE, 140320289304576, 140320297693183,
|
||||
ERASE, 140320163409920, 140320163414015,
|
||||
};
|
||||
unsigned long set41[] = {
|
||||
static const unsigned long set41[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140728157171712, 140737488351231,
|
||||
SNULL, 140728157175807, 140737488351231,
|
||||
@@ -31185,7 +31185,7 @@ STORE, 94376135090176, 94376135094271,
|
||||
STORE, 94376135094272, 94376135098367,
|
||||
SNULL, 94376135094272, 94377208836095,
|
||||
};
|
||||
unsigned long set42[] = {
|
||||
static const unsigned long set42[] = {
|
||||
STORE, 314572800, 1388314623,
|
||||
STORE, 1462157312, 1462169599,
|
||||
STORE, 1462169600, 1462185983,
|
||||
@@ -33862,7 +33862,7 @@ SNULL, 3798999040, 3799101439,
|
||||
*/
|
||||
};
|
||||
|
||||
unsigned long set43[] = {
|
||||
static const unsigned long set43[] = {
|
||||
STORE, 140737488347136, 140737488351231,
|
||||
STORE, 140734187720704, 140737488351231,
|
||||
SNULL, 140734187724800, 140737488351231,
|
||||
@@ -34513,7 +34513,7 @@ static void *rcu_reader_rev(void *ptr)
|
||||
if (mas.index != r_start) {
|
||||
alt = xa_mk_value(index + i * 2 + 1 +
|
||||
RCU_RANGE_COUNT);
|
||||
mt_dump(test->mt);
|
||||
mt_dump(test->mt, mt_dump_dec);
|
||||
printk("Error: %lu-%lu %p != %lu-%lu %p %p line %d i %d\n",
|
||||
mas.index, mas.last, entry,
|
||||
r_start, r_end, expected, alt,
|
||||
@@ -34996,7 +34996,7 @@ void run_check_rcu_slowread(struct maple_tree *mt, struct rcu_test_struct *vals)
|
||||
MT_BUG_ON(mt, !vals->seen_entry3);
|
||||
MT_BUG_ON(mt, !vals->seen_both);
|
||||
}
|
||||
static noinline void check_rcu_simulated(struct maple_tree *mt)
|
||||
static noinline void __init check_rcu_simulated(struct maple_tree *mt)
|
||||
{
|
||||
unsigned long i, nr_entries = 1000;
|
||||
unsigned long target = 4320;
|
||||
@@ -35157,7 +35157,7 @@ static noinline void check_rcu_simulated(struct maple_tree *mt)
|
||||
rcu_unregister_thread();
|
||||
}
|
||||
|
||||
static noinline void check_rcu_threaded(struct maple_tree *mt)
|
||||
static noinline void __init check_rcu_threaded(struct maple_tree *mt)
|
||||
{
|
||||
unsigned long i, nr_entries = 1000;
|
||||
struct rcu_test_struct vals;
|
||||
@@ -35259,6 +35259,7 @@ static void mas_dfs_preorder(struct ma_state *mas)
|
||||
|
||||
struct maple_enode *prev;
|
||||
unsigned char end, slot = 0;
|
||||
unsigned long *pivots;
|
||||
|
||||
if (mas->node == MAS_START) {
|
||||
mas_start(mas);
|
||||
@@ -35291,6 +35292,9 @@ walk_up:
|
||||
mas_ascend(mas);
|
||||
goto walk_up;
|
||||
}
|
||||
pivots = ma_pivots(mte_to_node(prev), mte_node_type(prev));
|
||||
mas->max = mas_safe_pivot(mas, pivots, slot, mte_node_type(prev));
|
||||
mas->min = mas_safe_min(mas, pivots, slot);
|
||||
|
||||
return;
|
||||
done:
|
||||
@@ -35366,7 +35370,7 @@ static void check_dfs_preorder(struct maple_tree *mt)
|
||||
/* End of depth first search tests */
|
||||
|
||||
/* Preallocation testing */
|
||||
static noinline void check_prealloc(struct maple_tree *mt)
|
||||
static noinline void __init check_prealloc(struct maple_tree *mt)
|
||||
{
|
||||
unsigned long i, max = 100;
|
||||
unsigned long allocated;
|
||||
@@ -35494,7 +35498,7 @@ static noinline void check_prealloc(struct maple_tree *mt)
|
||||
/* End of preallocation testing */
|
||||
|
||||
/* Spanning writes, writes that span nodes and layers of the tree */
|
||||
static noinline void check_spanning_write(struct maple_tree *mt)
|
||||
static noinline void __init check_spanning_write(struct maple_tree *mt)
|
||||
{
|
||||
unsigned long i, max = 5000;
|
||||
MA_STATE(mas, mt, 1200, 2380);
|
||||
@@ -35662,7 +35666,7 @@ static noinline void check_spanning_write(struct maple_tree *mt)
|
||||
/* End of spanning write testing */
|
||||
|
||||
/* Writes to a NULL area that are adjacent to other NULLs */
|
||||
static noinline void check_null_expand(struct maple_tree *mt)
|
||||
static noinline void __init check_null_expand(struct maple_tree *mt)
|
||||
{
|
||||
unsigned long i, max = 100;
|
||||
unsigned char data_end;
|
||||
@@ -35723,7 +35727,7 @@ static noinline void check_null_expand(struct maple_tree *mt)
|
||||
/* End of NULL area expansions */
|
||||
|
||||
/* Checking for no memory is best done outside the kernel */
|
||||
static noinline void check_nomem(struct maple_tree *mt)
|
||||
static noinline void __init check_nomem(struct maple_tree *mt)
|
||||
{
|
||||
MA_STATE(ms, mt, 1, 1);
|
||||
|
||||
@@ -35758,7 +35762,7 @@ static noinline void check_nomem(struct maple_tree *mt)
|
||||
mtree_destroy(mt);
|
||||
}
|
||||
|
||||
static noinline void check_locky(struct maple_tree *mt)
|
||||
static noinline void __init check_locky(struct maple_tree *mt)
|
||||
{
|
||||
MA_STATE(ms, mt, 2, 2);
|
||||
MA_STATE(reader, mt, 2, 2);
|
||||
@@ -35780,10 +35784,10 @@ void farmer_tests(void)
|
||||
struct maple_node *node;
|
||||
DEFINE_MTREE(tree);
|
||||
|
||||
mt_dump(&tree);
|
||||
mt_dump(&tree, mt_dump_dec);
|
||||
|
||||
tree.ma_root = xa_mk_value(0);
|
||||
mt_dump(&tree);
|
||||
mt_dump(&tree, mt_dump_dec);
|
||||
|
||||
node = mt_alloc_one(GFP_KERNEL);
|
||||
node->parent = (void *)((unsigned long)(&tree) | 1);
|
||||
@@ -35793,7 +35797,7 @@ void farmer_tests(void)
|
||||
node->mr64.pivot[1] = 1;
|
||||
node->mr64.pivot[2] = 0;
|
||||
tree.ma_root = mt_mk_node(node, maple_leaf_64);
|
||||
mt_dump(&tree);
|
||||
mt_dump(&tree, mt_dump_dec);
|
||||
|
||||
node->parent = ma_parent_ptr(node);
|
||||
ma_free_rcu(node);
|
||||
|
@@ -4,6 +4,7 @@ TARGETS += amd-pstate
|
||||
TARGETS += arm64
|
||||
TARGETS += bpf
|
||||
TARGETS += breakpoints
|
||||
TARGETS += cachestat
|
||||
TARGETS += capabilities
|
||||
TARGETS += cgroup
|
||||
TARGETS += clone3
|
||||
@@ -144,10 +145,12 @@ ifneq ($(KBUILD_OUTPUT),)
|
||||
abs_objtree := $(realpath $(abs_objtree))
|
||||
BUILD := $(abs_objtree)/kselftest
|
||||
KHDR_INCLUDES := -isystem ${abs_objtree}/usr/include
|
||||
KHDR_DIR := ${abs_objtree}/usr/include
|
||||
else
|
||||
BUILD := $(CURDIR)
|
||||
abs_srctree := $(shell cd $(top_srcdir) && pwd)
|
||||
KHDR_INCLUDES := -isystem ${abs_srctree}/usr/include
|
||||
KHDR_DIR := ${abs_srctree}/usr/include
|
||||
DEFAULT_INSTALL_HDR_PATH := 1
|
||||
endif
|
||||
|
||||
@@ -161,7 +164,7 @@ export KHDR_INCLUDES
|
||||
# all isn't the first target in the file.
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all:
|
||||
all: kernel_header_files
|
||||
@ret=1; \
|
||||
for TARGET in $(TARGETS); do \
|
||||
BUILD_TARGET=$$BUILD/$$TARGET; \
|
||||
@@ -172,6 +175,23 @@ all:
|
||||
ret=$$((ret * $$?)); \
|
||||
done; exit $$ret;
|
||||
|
||||
kernel_header_files:
|
||||
@ls $(KHDR_DIR)/linux/*.h >/dev/null 2>/dev/null; \
|
||||
if [ $$? -ne 0 ]; then \
|
||||
RED='\033[1;31m'; \
|
||||
NOCOLOR='\033[0m'; \
|
||||
echo; \
|
||||
echo -e "$${RED}error$${NOCOLOR}: missing kernel header files."; \
|
||||
echo "Please run this and try again:"; \
|
||||
echo; \
|
||||
echo " cd $(top_srcdir)"; \
|
||||
echo " make headers"; \
|
||||
echo; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: kernel_header_files
|
||||
|
||||
run_tests: all
|
||||
@for TARGET in $(TARGETS); do \
|
||||
BUILD_TARGET=$$BUILD/$$TARGET; \
|
||||
|
2
tools/testing/selftests/cachestat/.gitignore
vendored
Normal file
2
tools/testing/selftests/cachestat/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
test_cachestat
|
8
tools/testing/selftests/cachestat/Makefile
Normal file
8
tools/testing/selftests/cachestat/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
TEST_GEN_PROGS := test_cachestat
|
||||
|
||||
CFLAGS += $(KHDR_INCLUDES)
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -lrt
|
||||
|
||||
include ../lib.mk
|
269
tools/testing/selftests/cachestat/test_cachestat.c
Normal file
269
tools/testing/selftests/cachestat/test_cachestat.c
Normal file
@@ -0,0 +1,269 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mman.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../kselftest.h"
|
||||
|
||||
static const char * const dev_files[] = {
|
||||
"/dev/zero", "/dev/null", "/dev/urandom",
|
||||
"/proc/version", "/proc"
|
||||
};
|
||||
static const int cachestat_nr = 451;
|
||||
|
||||
void print_cachestat(struct cachestat *cs)
|
||||
{
|
||||
ksft_print_msg(
|
||||
"Using cachestat: Cached: %lu, Dirty: %lu, Writeback: %lu, Evicted: %lu, Recently Evicted: %lu\n",
|
||||
cs->nr_cache, cs->nr_dirty, cs->nr_writeback,
|
||||
cs->nr_evicted, cs->nr_recently_evicted);
|
||||
}
|
||||
|
||||
bool write_exactly(int fd, size_t filesize)
|
||||
{
|
||||
int random_fd = open("/dev/urandom", O_RDONLY);
|
||||
char *cursor, *data;
|
||||
int remained;
|
||||
bool ret;
|
||||
|
||||
if (random_fd < 0) {
|
||||
ksft_print_msg("Unable to access urandom.\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = malloc(filesize);
|
||||
if (!data) {
|
||||
ksft_print_msg("Unable to allocate data.\n");
|
||||
ret = false;
|
||||
goto close_random_fd;
|
||||
}
|
||||
|
||||
remained = filesize;
|
||||
cursor = data;
|
||||
|
||||
while (remained) {
|
||||
ssize_t read_len = read(random_fd, cursor, remained);
|
||||
|
||||
if (read_len <= 0) {
|
||||
ksft_print_msg("Unable to read from urandom.\n");
|
||||
ret = false;
|
||||
goto out_free_data;
|
||||
}
|
||||
|
||||
remained -= read_len;
|
||||
cursor += read_len;
|
||||
}
|
||||
|
||||
/* write random data to fd */
|
||||
remained = filesize;
|
||||
cursor = data;
|
||||
while (remained) {
|
||||
ssize_t write_len = write(fd, cursor, remained);
|
||||
|
||||
if (write_len <= 0) {
|
||||
ksft_print_msg("Unable write random data to file.\n");
|
||||
ret = false;
|
||||
goto out_free_data;
|
||||
}
|
||||
|
||||
remained -= write_len;
|
||||
cursor += write_len;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
out_free_data:
|
||||
free(data);
|
||||
close_random_fd:
|
||||
close(random_fd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open/create the file at filename, (optionally) write random data to it
|
||||
* (exactly num_pages), then test the cachestat syscall on this file.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
size_t PS = sysconf(_SC_PAGESIZE);
|
||||
int filesize = num_pages * PS;
|
||||
bool ret = true;
|
||||
long syscall_ret;
|
||||
struct cachestat cs;
|
||||
struct cachestat_range cs_range = { 0, filesize };
|
||||
|
||||
int fd = open(filename, open_flags, open_mode);
|
||||
|
||||
if (fd == -1) {
|
||||
ksft_print_msg("Unable to create/open file.\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
} else {
|
||||
ksft_print_msg("Create/open %s\n", filename);
|
||||
}
|
||||
|
||||
if (write_random) {
|
||||
if (!write_exactly(fd, filesize)) {
|
||||
ksft_print_msg("Unable to access urandom.\n");
|
||||
ret = false;
|
||||
goto out1;
|
||||
}
|
||||
}
|
||||
|
||||
syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0);
|
||||
|
||||
ksft_print_msg("Cachestat call returned %ld\n", syscall_ret);
|
||||
|
||||
if (syscall_ret) {
|
||||
ksft_print_msg("Cachestat returned non-zero.\n");
|
||||
ret = false;
|
||||
goto out1;
|
||||
|
||||
} else {
|
||||
print_cachestat(&cs);
|
||||
|
||||
if (write_random) {
|
||||
if (cs.nr_cache + cs.nr_evicted != num_pages) {
|
||||
ksft_print_msg(
|
||||
"Total number of cached and evicted pages is off.\n");
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (test_fsync) {
|
||||
if (fsync(fd)) {
|
||||
ksft_print_msg("fsync fails.\n");
|
||||
ret = false;
|
||||
} else {
|
||||
syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0);
|
||||
|
||||
ksft_print_msg("Cachestat call (after fsync) returned %ld\n",
|
||||
syscall_ret);
|
||||
|
||||
if (!syscall_ret) {
|
||||
print_cachestat(&cs);
|
||||
|
||||
if (cs.nr_dirty) {
|
||||
ret = false;
|
||||
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;
|
||||
goto out1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out1:
|
||||
close(fd);
|
||||
|
||||
if (create)
|
||||
remove(filename);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool test_cachestat_shmem(void)
|
||||
{
|
||||
size_t PS = sysconf(_SC_PAGESIZE);
|
||||
size_t filesize = PS * 512 * 2; /* 2 2MB huge pages */
|
||||
int syscall_ret;
|
||||
size_t compute_len = PS * 512;
|
||||
struct cachestat_range cs_range = { PS, compute_len };
|
||||
char *filename = "tmpshmcstat";
|
||||
struct cachestat cs;
|
||||
bool ret = true;
|
||||
unsigned long num_pages = compute_len / PS;
|
||||
int fd = shm_open(filename, O_CREAT | O_RDWR, 0600);
|
||||
|
||||
if (fd < 0) {
|
||||
ksft_print_msg("Unable to create shmem file.\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ftruncate(fd, filesize)) {
|
||||
ksft_print_msg("Unable to truncate shmem file.\n");
|
||||
ret = false;
|
||||
goto close_fd;
|
||||
}
|
||||
|
||||
if (!write_exactly(fd, filesize)) {
|
||||
ksft_print_msg("Unable to write to shmem file.\n");
|
||||
ret = false;
|
||||
goto close_fd;
|
||||
}
|
||||
|
||||
syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0);
|
||||
|
||||
if (syscall_ret) {
|
||||
ksft_print_msg("Cachestat returned non-zero.\n");
|
||||
ret = false;
|
||||
goto close_fd;
|
||||
} else {
|
||||
print_cachestat(&cs);
|
||||
if (cs.nr_cache + cs.nr_evicted != num_pages) {
|
||||
ksft_print_msg(
|
||||
"Total number of cached and evicted pages is off.\n");
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
close_fd:
|
||||
shm_unlink(filename);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
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))
|
||||
ksft_test_result_pass("cachestat works with %s\n", dev_filename);
|
||||
else {
|
||||
ksft_test_result_fail("cachestat fails with %s\n", dev_filename);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (test_cachestat("tmpfilecachestat", true, true,
|
||||
true, 4, O_CREAT | O_RDWR, 0400 | 0600))
|
||||
ksft_test_result_pass("cachestat works with a normal file\n");
|
||||
else {
|
||||
ksft_test_result_fail("cachestat fails with normal file\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (test_cachestat_shmem())
|
||||
ksft_test_result_pass("cachestat works with a shmem file\n");
|
||||
else {
|
||||
ksft_test_result_fail("cachestat fails with a shmem file\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
@@ -292,6 +292,7 @@ static int test_memcg_protection(const char *root, bool min)
|
||||
char *children[4] = {NULL};
|
||||
const char *attribute = min ? "memory.min" : "memory.low";
|
||||
long c[4];
|
||||
long current;
|
||||
int i, attempts;
|
||||
int fd;
|
||||
|
||||
@@ -400,7 +401,8 @@ static int test_memcg_protection(const char *root, bool min)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!values_close(cg_read_long(parent[1], "memory.current"), MB(50), 3))
|
||||
current = min ? MB(50) : MB(30);
|
||||
if (!values_close(cg_read_long(parent[1], "memory.current"), current, 3))
|
||||
goto cleanup;
|
||||
|
||||
if (!reclaim_until(children[0], MB(10)))
|
||||
@@ -987,7 +989,9 @@ static int tcp_client(const char *cgroup, unsigned short port)
|
||||
char servport[6];
|
||||
int retries = 0x10; /* nice round number */
|
||||
int sk, ret;
|
||||
long allocated;
|
||||
|
||||
allocated = cg_read_long(cgroup, "memory.current");
|
||||
snprintf(servport, sizeof(servport), "%hd", port);
|
||||
ret = getaddrinfo(server, servport, NULL, &ai);
|
||||
if (ret)
|
||||
@@ -1015,7 +1019,8 @@ static int tcp_client(const char *cgroup, unsigned short port)
|
||||
if (current < 0 || sock < 0)
|
||||
goto close_sk;
|
||||
|
||||
if (values_close(current, sock, 10)) {
|
||||
/* exclude the memory not related to socket connection */
|
||||
if (values_close(current - allocated, sock, 10)) {
|
||||
ret = KSFT_PASS;
|
||||
break;
|
||||
}
|
||||
|
7
tools/testing/selftests/damon/config
Normal file
7
tools/testing/selftests/damon/config
Normal file
@@ -0,0 +1,7 @@
|
||||
CONFIG_DAMON=y
|
||||
CONFIG_DAMON_SYSFS=y
|
||||
CONFIG_DAMON_DBGFS=y
|
||||
CONFIG_DAMON_PADDR=y
|
||||
CONFIG_DAMON_VADDR=y
|
||||
CONFIG_DAMON_RECLAIM=y
|
||||
CONFIG_DAMON_LRU_SORT=y
|
@@ -44,10 +44,26 @@ endif
|
||||
selfdir = $(realpath $(dir $(filter %/lib.mk,$(MAKEFILE_LIST))))
|
||||
top_srcdir = $(selfdir)/../../..
|
||||
|
||||
ifeq ($(KHDR_INCLUDES),)
|
||||
KHDR_INCLUDES := -isystem $(top_srcdir)/usr/include
|
||||
ifeq ("$(origin O)", "command line")
|
||||
KBUILD_OUTPUT := $(O)
|
||||
endif
|
||||
|
||||
ifneq ($(KBUILD_OUTPUT),)
|
||||
# Make's built-in functions such as $(abspath ...), $(realpath ...) cannot
|
||||
# expand a shell special character '~'. We use a somewhat tedious way here.
|
||||
abs_objtree := $(shell cd $(top_srcdir) && mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) && pwd)
|
||||
$(if $(abs_objtree),, \
|
||||
$(error failed to create output directory "$(KBUILD_OUTPUT)"))
|
||||
# $(realpath ...) resolves symlinks
|
||||
abs_objtree := $(realpath $(abs_objtree))
|
||||
KHDR_DIR := ${abs_objtree}/usr/include
|
||||
else
|
||||
abs_srctree := $(shell cd $(top_srcdir) && pwd)
|
||||
KHDR_DIR := ${abs_srctree}/usr/include
|
||||
endif
|
||||
|
||||
KHDR_INCLUDES := -isystem $(KHDR_DIR)
|
||||
|
||||
# The following are built by lib.mk common compile rules.
|
||||
# TEST_CUSTOM_PROGS should be used by tests that require
|
||||
# custom build rule and prevent common build rule use.
|
||||
@@ -58,7 +74,25 @@ TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS))
|
||||
TEST_GEN_PROGS_EXTENDED := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS_EXTENDED))
|
||||
TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES))
|
||||
|
||||
all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
|
||||
all: kernel_header_files $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) \
|
||||
$(TEST_GEN_FILES)
|
||||
|
||||
kernel_header_files:
|
||||
@ls $(KHDR_DIR)/linux/*.h >/dev/null 2>/dev/null; \
|
||||
if [ $$? -ne 0 ]; then \
|
||||
RED='\033[1;31m'; \
|
||||
NOCOLOR='\033[0m'; \
|
||||
echo; \
|
||||
echo -e "$${RED}error$${NOCOLOR}: missing kernel header files."; \
|
||||
echo "Please run this and try again:"; \
|
||||
echo; \
|
||||
echo " cd $(top_srcdir)"; \
|
||||
echo " make headers"; \
|
||||
echo; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: kernel_header_files
|
||||
|
||||
define RUN_TESTS
|
||||
BASE_DIR="$(selfdir)"; \
|
||||
|
3
tools/testing/selftests/mm/.gitignore
vendored
3
tools/testing/selftests/mm/.gitignore
vendored
@@ -39,3 +39,6 @@ local_config.h
|
||||
local_config.mk
|
||||
ksm_functional_tests
|
||||
mdwe_test
|
||||
gup_longterm
|
||||
mkdirty
|
||||
va_high_addr_switch
|
||||
|
@@ -32,11 +32,12 @@ endif
|
||||
# LDLIBS.
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
CFLAGS = -Wall -I $(top_srcdir) -I $(top_srcdir)/tools/include/uapi $(EXTRA_CFLAGS) $(KHDR_INCLUDES)
|
||||
CFLAGS = -Wall -I $(top_srcdir) $(EXTRA_CFLAGS) $(KHDR_INCLUDES)
|
||||
LDLIBS = -lrt -lpthread
|
||||
|
||||
TEST_GEN_PROGS = cow
|
||||
TEST_GEN_PROGS += compaction_test
|
||||
TEST_GEN_PROGS += gup_longterm
|
||||
TEST_GEN_PROGS += gup_test
|
||||
TEST_GEN_PROGS += hmm-tests
|
||||
TEST_GEN_PROGS += hugetlb-madvise
|
||||
@@ -167,6 +168,8 @@ endif
|
||||
# IOURING_EXTRA_LIBS may get set in local_config.mk, or it may be left empty.
|
||||
$(OUTPUT)/cow: LDLIBS += $(IOURING_EXTRA_LIBS)
|
||||
|
||||
$(OUTPUT)/gup_longterm: LDLIBS += $(IOURING_EXTRA_LIBS)
|
||||
|
||||
$(OUTPUT)/mlock-random-test $(OUTPUT)/memfd_secret: LDLIBS += -lcap
|
||||
|
||||
$(OUTPUT)/ksm_tests: LDLIBS += -lnuma
|
||||
|
@@ -14,8 +14,8 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <assert.h>
|
||||
#include <linux/mman.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -30,13 +30,6 @@
|
||||
#include "../kselftest.h"
|
||||
#include "vm_util.h"
|
||||
|
||||
#ifndef MADV_PAGEOUT
|
||||
#define MADV_PAGEOUT 21
|
||||
#endif
|
||||
#ifndef MADV_COLLAPSE
|
||||
#define MADV_COLLAPSE 25
|
||||
#endif
|
||||
|
||||
static size_t pagesize;
|
||||
static int pagemap_fd;
|
||||
static size_t thpsize;
|
||||
@@ -70,31 +63,6 @@ static void detect_huge_zeropage(void)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void detect_hugetlbsizes(void)
|
||||
{
|
||||
DIR *dir = opendir("/sys/kernel/mm/hugepages/");
|
||||
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
while (nr_hugetlbsizes < ARRAY_SIZE(hugetlbsizes)) {
|
||||
struct dirent *entry = readdir(dir);
|
||||
size_t kb;
|
||||
|
||||
if (!entry)
|
||||
break;
|
||||
if (entry->d_type != DT_DIR)
|
||||
continue;
|
||||
if (sscanf(entry->d_name, "hugepages-%zukB", &kb) != 1)
|
||||
continue;
|
||||
hugetlbsizes[nr_hugetlbsizes] = kb * 1024;
|
||||
nr_hugetlbsizes++;
|
||||
ksft_print_msg("[INFO] detected hugetlb size: %zu KiB\n",
|
||||
kb);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static bool range_is_swapped(void *addr, size_t size)
|
||||
{
|
||||
for (; size; addr += pagesize, size -= pagesize)
|
||||
@@ -1717,7 +1685,8 @@ int main(int argc, char **argv)
|
||||
if (thpsize)
|
||||
ksft_print_msg("[INFO] detected THP size: %zu KiB\n",
|
||||
thpsize / 1024);
|
||||
detect_hugetlbsizes();
|
||||
nr_hugetlbsizes = detect_hugetlb_page_sizes(hugetlbsizes,
|
||||
ARRAY_SIZE(hugetlbsizes));
|
||||
detect_huge_zeropage();
|
||||
|
||||
ksft_print_header();
|
||||
|
459
tools/testing/selftests/mm/gup_longterm.c
Normal file
459
tools/testing/selftests/mm/gup_longterm.c
Normal file
@@ -0,0 +1,459 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* GUP long-term page pinning tests.
|
||||
*
|
||||
* Copyright 2023, Red Hat, Inc.
|
||||
*
|
||||
* Author(s): David Hildenbrand <david@redhat.com>
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/memfd.h>
|
||||
|
||||
#include "local_config.h"
|
||||
#ifdef LOCAL_CONFIG_HAVE_LIBURING
|
||||
#include <liburing.h>
|
||||
#endif /* LOCAL_CONFIG_HAVE_LIBURING */
|
||||
|
||||
#include "../../../../mm/gup_test.h"
|
||||
#include "../kselftest.h"
|
||||
#include "vm_util.h"
|
||||
|
||||
static size_t pagesize;
|
||||
static int nr_hugetlbsizes;
|
||||
static size_t hugetlbsizes[10];
|
||||
static int gup_fd;
|
||||
|
||||
static __fsword_t get_fs_type(int fd)
|
||||
{
|
||||
struct statfs fs;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = fstatfs(fd, &fs);
|
||||
} while (ret && errno == EINTR);
|
||||
|
||||
return ret ? 0 : fs.f_type;
|
||||
}
|
||||
|
||||
static bool fs_is_unknown(__fsword_t fs_type)
|
||||
{
|
||||
/*
|
||||
* We only support some filesystems in our tests when dealing with
|
||||
* R/W long-term pinning. For these filesystems, we can be fairly sure
|
||||
* whether they support it or not.
|
||||
*/
|
||||
switch (fs_type) {
|
||||
case TMPFS_MAGIC:
|
||||
case HUGETLBFS_MAGIC:
|
||||
case BTRFS_SUPER_MAGIC:
|
||||
case EXT4_SUPER_MAGIC:
|
||||
case XFS_SUPER_MAGIC:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool fs_supports_writable_longterm_pinning(__fsword_t fs_type)
|
||||
{
|
||||
assert(!fs_is_unknown(fs_type));
|
||||
switch (fs_type) {
|
||||
case TMPFS_MAGIC:
|
||||
case HUGETLBFS_MAGIC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enum test_type {
|
||||
TEST_TYPE_RO,
|
||||
TEST_TYPE_RO_FAST,
|
||||
TEST_TYPE_RW,
|
||||
TEST_TYPE_RW_FAST,
|
||||
#ifdef LOCAL_CONFIG_HAVE_LIBURING
|
||||
TEST_TYPE_IOURING,
|
||||
#endif /* LOCAL_CONFIG_HAVE_LIBURING */
|
||||
};
|
||||
|
||||
static void do_test(int fd, size_t size, enum test_type type, bool shared)
|
||||
{
|
||||
__fsword_t fs_type = get_fs_type(fd);
|
||||
bool should_work;
|
||||
char *mem;
|
||||
int ret;
|
||||
|
||||
if (ftruncate(fd, size)) {
|
||||
ksft_test_result_fail("ftruncate() failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fallocate(fd, 0, 0, size)) {
|
||||
if (size == pagesize)
|
||||
ksft_test_result_fail("fallocate() failed\n");
|
||||
else
|
||||
ksft_test_result_skip("need more free huge pages\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mem = mmap(NULL, size, PROT_READ | PROT_WRITE,
|
||||
shared ? MAP_SHARED : MAP_PRIVATE, fd, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
if (size == pagesize || shared)
|
||||
ksft_test_result_fail("mmap() failed\n");
|
||||
else
|
||||
ksft_test_result_skip("need more free huge pages\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fault in the page writable such that GUP-fast can eventually pin
|
||||
* it immediately.
|
||||
*/
|
||||
memset(mem, 0, size);
|
||||
|
||||
switch (type) {
|
||||
case TEST_TYPE_RO:
|
||||
case TEST_TYPE_RO_FAST:
|
||||
case TEST_TYPE_RW:
|
||||
case TEST_TYPE_RW_FAST: {
|
||||
struct pin_longterm_test args;
|
||||
const bool fast = type == TEST_TYPE_RO_FAST ||
|
||||
type == TEST_TYPE_RW_FAST;
|
||||
const bool rw = type == TEST_TYPE_RW ||
|
||||
type == TEST_TYPE_RW_FAST;
|
||||
|
||||
if (gup_fd < 0) {
|
||||
ksft_test_result_skip("gup_test not available\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (rw && shared && fs_is_unknown(fs_type)) {
|
||||
ksft_test_result_skip("Unknown filesystem\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* R/O pinning or pinning in a private mapping is always
|
||||
* expected to work. Otherwise, we expect long-term R/W pinning
|
||||
* to only succeed for special fielesystems.
|
||||
*/
|
||||
should_work = !shared || !rw ||
|
||||
fs_supports_writable_longterm_pinning(fs_type);
|
||||
|
||||
args.addr = (__u64)(uintptr_t)mem;
|
||||
args.size = size;
|
||||
args.flags = fast ? PIN_LONGTERM_TEST_FLAG_USE_FAST : 0;
|
||||
args.flags |= rw ? PIN_LONGTERM_TEST_FLAG_USE_WRITE : 0;
|
||||
ret = ioctl(gup_fd, PIN_LONGTERM_TEST_START, &args);
|
||||
if (ret && errno == EINVAL) {
|
||||
ksft_test_result_skip("PIN_LONGTERM_TEST_START failed\n");
|
||||
break;
|
||||
} else if (ret && errno == EFAULT) {
|
||||
ksft_test_result(!should_work, "Should have failed\n");
|
||||
break;
|
||||
} else if (ret) {
|
||||
ksft_test_result_fail("PIN_LONGTERM_TEST_START failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (ioctl(gup_fd, PIN_LONGTERM_TEST_STOP))
|
||||
ksft_print_msg("[INFO] PIN_LONGTERM_TEST_STOP failed\n");
|
||||
|
||||
/*
|
||||
* TODO: if the kernel ever supports long-term R/W pinning on
|
||||
* some previously unsupported filesystems, we might want to
|
||||
* perform some additional tests for possible data corruptions.
|
||||
*/
|
||||
ksft_test_result(should_work, "Should have worked\n");
|
||||
break;
|
||||
}
|
||||
#ifdef LOCAL_CONFIG_HAVE_LIBURING
|
||||
case TEST_TYPE_IOURING: {
|
||||
struct io_uring ring;
|
||||
struct iovec iov;
|
||||
|
||||
/* io_uring always pins pages writable. */
|
||||
if (shared && fs_is_unknown(fs_type)) {
|
||||
ksft_test_result_skip("Unknown filesystem\n");
|
||||
return;
|
||||
}
|
||||
should_work = !shared ||
|
||||
fs_supports_writable_longterm_pinning(fs_type);
|
||||
|
||||
/* Skip on errors, as we might just lack kernel support. */
|
||||
ret = io_uring_queue_init(1, &ring, 0);
|
||||
if (ret < 0) {
|
||||
ksft_test_result_skip("io_uring_queue_init() failed\n");
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Register the range as a fixed buffer. This will FOLL_WRITE |
|
||||
* FOLL_PIN | FOLL_LONGTERM the range.
|
||||
*/
|
||||
iov.iov_base = mem;
|
||||
iov.iov_len = size;
|
||||
ret = io_uring_register_buffers(&ring, &iov, 1);
|
||||
/* Only new kernels return EFAULT. */
|
||||
if (ret && (errno == ENOSPC || errno == EOPNOTSUPP ||
|
||||
errno == EFAULT)) {
|
||||
ksft_test_result(!should_work, "Should have failed\n");
|
||||
} else if (ret) {
|
||||
/*
|
||||
* We might just lack support or have insufficient
|
||||
* MEMLOCK limits.
|
||||
*/
|
||||
ksft_test_result_skip("io_uring_register_buffers() failed\n");
|
||||
} else {
|
||||
ksft_test_result(should_work, "Should have worked\n");
|
||||
io_uring_unregister_buffers(&ring);
|
||||
}
|
||||
|
||||
io_uring_queue_exit(&ring);
|
||||
break;
|
||||
}
|
||||
#endif /* LOCAL_CONFIG_HAVE_LIBURING */
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
munmap(mem, size);
|
||||
}
|
||||
|
||||
typedef void (*test_fn)(int fd, size_t size);
|
||||
|
||||
static void run_with_memfd(test_fn fn, const char *desc)
|
||||
{
|
||||
int fd;
|
||||
|
||||
ksft_print_msg("[RUN] %s ... with memfd\n", desc);
|
||||
|
||||
fd = memfd_create("test", 0);
|
||||
if (fd < 0) {
|
||||
ksft_test_result_fail("memfd_create() failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fn(fd, pagesize);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void run_with_tmpfile(test_fn fn, const char *desc)
|
||||
{
|
||||
FILE *file;
|
||||
int fd;
|
||||
|
||||
ksft_print_msg("[RUN] %s ... with tmpfile\n", desc);
|
||||
|
||||
file = tmpfile();
|
||||
if (!file) {
|
||||
ksft_test_result_fail("tmpfile() failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fd = fileno(file);
|
||||
if (fd < 0) {
|
||||
ksft_test_result_fail("fileno() failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fn(fd, pagesize);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
static void run_with_local_tmpfile(test_fn fn, const char *desc)
|
||||
{
|
||||
char filename[] = __FILE__"_tmpfile_XXXXXX";
|
||||
int fd;
|
||||
|
||||
ksft_print_msg("[RUN] %s ... with local tmpfile\n", desc);
|
||||
|
||||
fd = mkstemp(filename);
|
||||
if (fd < 0) {
|
||||
ksft_test_result_fail("mkstemp() failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlink(filename)) {
|
||||
ksft_test_result_fail("unlink() failed\n");
|
||||
goto close;
|
||||
}
|
||||
|
||||
fn(fd, pagesize);
|
||||
close:
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void run_with_memfd_hugetlb(test_fn fn, const char *desc,
|
||||
size_t hugetlbsize)
|
||||
{
|
||||
int flags = MFD_HUGETLB;
|
||||
int fd;
|
||||
|
||||
ksft_print_msg("[RUN] %s ... with memfd hugetlb (%zu kB)\n", desc,
|
||||
hugetlbsize / 1024);
|
||||
|
||||
flags |= __builtin_ctzll(hugetlbsize) << MFD_HUGE_SHIFT;
|
||||
|
||||
fd = memfd_create("test", flags);
|
||||
if (fd < 0) {
|
||||
ksft_test_result_skip("memfd_create() failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fn(fd, hugetlbsize);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
struct test_case {
|
||||
const char *desc;
|
||||
test_fn fn;
|
||||
};
|
||||
|
||||
static void test_shared_rw_pin(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_RW, true);
|
||||
}
|
||||
|
||||
static void test_shared_rw_fast_pin(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_RW_FAST, true);
|
||||
}
|
||||
|
||||
static void test_shared_ro_pin(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_RO, true);
|
||||
}
|
||||
|
||||
static void test_shared_ro_fast_pin(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_RO_FAST, true);
|
||||
}
|
||||
|
||||
static void test_private_rw_pin(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_RW, false);
|
||||
}
|
||||
|
||||
static void test_private_rw_fast_pin(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_RW_FAST, false);
|
||||
}
|
||||
|
||||
static void test_private_ro_pin(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_RO, false);
|
||||
}
|
||||
|
||||
static void test_private_ro_fast_pin(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_RO_FAST, false);
|
||||
}
|
||||
|
||||
#ifdef LOCAL_CONFIG_HAVE_LIBURING
|
||||
static void test_shared_iouring(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_IOURING, true);
|
||||
}
|
||||
|
||||
static void test_private_iouring(int fd, size_t size)
|
||||
{
|
||||
do_test(fd, size, TEST_TYPE_IOURING, false);
|
||||
}
|
||||
#endif /* LOCAL_CONFIG_HAVE_LIBURING */
|
||||
|
||||
static const struct test_case test_cases[] = {
|
||||
{
|
||||
"R/W longterm GUP pin in MAP_SHARED file mapping",
|
||||
test_shared_rw_pin,
|
||||
},
|
||||
{
|
||||
"R/W longterm GUP-fast pin in MAP_SHARED file mapping",
|
||||
test_shared_rw_fast_pin,
|
||||
},
|
||||
{
|
||||
"R/O longterm GUP pin in MAP_SHARED file mapping",
|
||||
test_shared_ro_pin,
|
||||
},
|
||||
{
|
||||
"R/O longterm GUP-fast pin in MAP_SHARED file mapping",
|
||||
test_shared_ro_fast_pin,
|
||||
},
|
||||
{
|
||||
"R/W longterm GUP pin in MAP_PRIVATE file mapping",
|
||||
test_private_rw_pin,
|
||||
},
|
||||
{
|
||||
"R/W longterm GUP-fast pin in MAP_PRIVATE file mapping",
|
||||
test_private_rw_fast_pin,
|
||||
},
|
||||
{
|
||||
"R/O longterm GUP pin in MAP_PRIVATE file mapping",
|
||||
test_private_ro_pin,
|
||||
},
|
||||
{
|
||||
"R/O longterm GUP-fast pin in MAP_PRIVATE file mapping",
|
||||
test_private_ro_fast_pin,
|
||||
},
|
||||
#ifdef LOCAL_CONFIG_HAVE_LIBURING
|
||||
{
|
||||
"io_uring fixed buffer with MAP_SHARED file mapping",
|
||||
test_shared_iouring,
|
||||
},
|
||||
{
|
||||
"io_uring fixed buffer with MAP_PRIVATE file mapping",
|
||||
test_private_iouring,
|
||||
},
|
||||
#endif /* LOCAL_CONFIG_HAVE_LIBURING */
|
||||
};
|
||||
|
||||
static void run_test_case(struct test_case const *test_case)
|
||||
{
|
||||
int i;
|
||||
|
||||
run_with_memfd(test_case->fn, test_case->desc);
|
||||
run_with_tmpfile(test_case->fn, test_case->desc);
|
||||
run_with_local_tmpfile(test_case->fn, test_case->desc);
|
||||
for (i = 0; i < nr_hugetlbsizes; i++)
|
||||
run_with_memfd_hugetlb(test_case->fn, test_case->desc,
|
||||
hugetlbsizes[i]);
|
||||
}
|
||||
|
||||
static int tests_per_test_case(void)
|
||||
{
|
||||
return 3 + nr_hugetlbsizes;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
pagesize = getpagesize();
|
||||
nr_hugetlbsizes = detect_hugetlb_page_sizes(hugetlbsizes,
|
||||
ARRAY_SIZE(hugetlbsizes));
|
||||
|
||||
ksft_print_header();
|
||||
ksft_set_plan(ARRAY_SIZE(test_cases) * tests_per_test_case());
|
||||
|
||||
gup_fd = open("/sys/kernel/debug/gup_test", O_RDWR);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(test_cases); i++)
|
||||
run_test_case(&test_cases[i]);
|
||||
|
||||
err = ksft_get_fail_cnt();
|
||||
if (err)
|
||||
ksft_exit_fail_msg("%d out of %d tests failed\n",
|
||||
err, ksft_test_num());
|
||||
return ksft_exit_pass();
|
||||
}
|
@@ -35,10 +35,6 @@
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifndef SHM_HUGETLB
|
||||
#define SHM_HUGETLB 04000
|
||||
#endif
|
||||
|
||||
#define LENGTH (256UL*1024*1024)
|
||||
|
||||
#define dprintf(x) printf(x)
|
||||
|
@@ -13,10 +13,6 @@
|
||||
|
||||
#define MAP_LENGTH (2UL * 1024 * 1024)
|
||||
|
||||
#ifndef MAP_HUGETLB
|
||||
#define MAP_HUGETLB 0x40000 /* arch specific */
|
||||
#endif
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
#define PAGE_COMPOUND_HEAD (1UL << 15)
|
||||
|
@@ -65,11 +65,15 @@ void write_fault_pages(void *addr, unsigned long nr_pages)
|
||||
|
||||
void read_fault_pages(void *addr, unsigned long nr_pages)
|
||||
{
|
||||
unsigned long dummy = 0;
|
||||
volatile unsigned long dummy = 0;
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++)
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
dummy += *((unsigned long *)(addr + (i * huge_page_size)));
|
||||
|
||||
/* Prevent the compiler from optimizing out the entire loop: */
|
||||
asm volatile("" : "+r" (dummy));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/mman.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
@@ -22,16 +23,6 @@
|
||||
|
||||
#include "vm_util.h"
|
||||
|
||||
#ifndef MADV_PAGEOUT
|
||||
#define MADV_PAGEOUT 21
|
||||
#endif
|
||||
#ifndef MADV_POPULATE_READ
|
||||
#define MADV_POPULATE_READ 22
|
||||
#endif
|
||||
#ifndef MADV_COLLAPSE
|
||||
#define MADV_COLLAPSE 25
|
||||
#endif
|
||||
|
||||
#define BASE_ADDR ((void *)(1UL << 30))
|
||||
static unsigned long hpage_pmd_size;
|
||||
static unsigned long page_size;
|
||||
|
@@ -20,13 +20,6 @@
|
||||
#include "../kselftest.h"
|
||||
#include "vm_util.h"
|
||||
|
||||
#ifndef MADV_POPULATE_READ
|
||||
#define MADV_POPULATE_READ 22
|
||||
#endif /* MADV_POPULATE_READ */
|
||||
#ifndef MADV_POPULATE_WRITE
|
||||
#define MADV_POPULATE_WRITE 23
|
||||
#endif /* MADV_POPULATE_WRITE */
|
||||
|
||||
/*
|
||||
* For now, we're using 2 MiB of private anonymous memory for all tests.
|
||||
*/
|
||||
|
@@ -13,10 +13,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef MAP_FIXED_NOREPLACE
|
||||
#define MAP_FIXED_NOREPLACE 0x100000
|
||||
#endif
|
||||
|
||||
static void dump_maps(void)
|
||||
{
|
||||
char cmd[32];
|
||||
|
@@ -19,18 +19,6 @@
|
||||
#define LENGTH (256UL*1024*1024)
|
||||
#define PROTECTION (PROT_READ | PROT_WRITE)
|
||||
|
||||
#ifndef MAP_HUGETLB
|
||||
#define MAP_HUGETLB 0x40000 /* arch specific */
|
||||
#endif
|
||||
|
||||
#ifndef MAP_HUGE_SHIFT
|
||||
#define MAP_HUGE_SHIFT 26
|
||||
#endif
|
||||
|
||||
#ifndef MAP_HUGE_MASK
|
||||
#define MAP_HUGE_MASK 0x3f
|
||||
#endif
|
||||
|
||||
/* Only ia64 requires this */
|
||||
#ifdef __ia64__
|
||||
#define ADDR (void *)(0x8000000000000000UL)
|
||||
|
@@ -17,9 +17,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef MMAP_SZ
|
||||
#define MMAP_SZ 4096
|
||||
#endif
|
||||
|
||||
#define BUG_ON(condition, description) \
|
||||
do { \
|
||||
|
@@ -95,12 +95,15 @@ int migrate(uint64_t *ptr, int n1, int n2)
|
||||
|
||||
void *access_mem(void *ptr)
|
||||
{
|
||||
uint64_t y = 0;
|
||||
volatile uint64_t y = 0;
|
||||
volatile uint64_t *x = ptr;
|
||||
|
||||
while (1) {
|
||||
pthread_testcancel();
|
||||
y += *x;
|
||||
|
||||
/* Prevent the compiler from optimizing out the writes to y: */
|
||||
asm volatile("" : "+r" (y));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/ipc.h>
|
||||
|
@@ -50,7 +50,6 @@ static int get_vm_area(unsigned long addr, struct vm_boundaries *area)
|
||||
printf("cannot parse /proc/self/maps\n");
|
||||
goto out;
|
||||
}
|
||||
stop = '\0';
|
||||
|
||||
sscanf(line, "%lx", &start);
|
||||
sscanf(end_addr, "%lx", &end);
|
||||
|
@@ -4,14 +4,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef MLOCK_ONFAULT
|
||||
#define MLOCK_ONFAULT 1
|
||||
#endif
|
||||
|
||||
#ifndef MCL_ONFAULT
|
||||
#define MCL_ONFAULT (MCL_FUTURE << 1)
|
||||
#endif
|
||||
|
||||
static int mlock2_(void *start, size_t len, int flags)
|
||||
{
|
||||
#ifdef __NR_mlock2
|
||||
|
@@ -9,18 +9,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <asm-generic/unistd.h>
|
||||
#include "vm_util.h"
|
||||
|
||||
#include "../kselftest.h"
|
||||
|
||||
#ifndef __NR_pidfd_open
|
||||
#define __NR_pidfd_open -1
|
||||
#endif
|
||||
|
||||
#ifndef __NR_process_mrelease
|
||||
#define __NR_process_mrelease -1
|
||||
#endif
|
||||
|
||||
#define MB(x) (x << 20)
|
||||
#define MAX_SIZE_MB 1024
|
||||
|
||||
|
@@ -15,10 +15,6 @@
|
||||
|
||||
#include "../kselftest.h"
|
||||
|
||||
#ifndef MREMAP_DONTUNMAP
|
||||
#define MREMAP_DONTUNMAP 4
|
||||
#endif
|
||||
|
||||
unsigned long page_size;
|
||||
char *page_buffer;
|
||||
|
||||
|
@@ -6,10 +6,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifndef MCL_ONFAULT
|
||||
#define MCL_ONFAULT (MCL_FUTURE << 1)
|
||||
#endif
|
||||
|
||||
static int test_limit(void)
|
||||
{
|
||||
int ret = 1;
|
||||
|
@@ -3,9 +3,6 @@
|
||||
#ifndef _PKEYS_POWERPC_H
|
||||
#define _PKEYS_POWERPC_H
|
||||
|
||||
#ifndef SYS_mprotect_key
|
||||
# define SYS_mprotect_key 386
|
||||
#endif
|
||||
#ifndef SYS_pkey_alloc
|
||||
# define SYS_pkey_alloc 384
|
||||
# define SYS_pkey_free 385
|
||||
|
@@ -5,29 +5,11 @@
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#ifndef SYS_mprotect_key
|
||||
# define SYS_mprotect_key 380
|
||||
#endif
|
||||
|
||||
#ifndef SYS_pkey_alloc
|
||||
# define SYS_pkey_alloc 381
|
||||
# define SYS_pkey_free 382
|
||||
#endif
|
||||
|
||||
#define REG_IP_IDX REG_EIP
|
||||
#define si_pkey_offset 0x14
|
||||
|
||||
#else
|
||||
|
||||
#ifndef SYS_mprotect_key
|
||||
# define SYS_mprotect_key 329
|
||||
#endif
|
||||
|
||||
#ifndef SYS_pkey_alloc
|
||||
# define SYS_pkey_alloc 330
|
||||
# define SYS_pkey_free 331
|
||||
#endif
|
||||
|
||||
#define REG_IP_IDX REG_RIP
|
||||
#define si_pkey_offset 0x20
|
||||
|
||||
@@ -132,7 +114,7 @@ int pkey_reg_xstate_offset(void)
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
int xstate_offset;
|
||||
int xstate_size;
|
||||
int xstate_size = 0;
|
||||
unsigned long XSTATE_CPUID = 0xd;
|
||||
int leaf;
|
||||
|
||||
|
@@ -294,15 +294,6 @@ void pkey_access_deny(int pkey)
|
||||
pkey_disable_set(pkey, PKEY_DISABLE_ACCESS);
|
||||
}
|
||||
|
||||
/* Failed address bound checks: */
|
||||
#ifndef SEGV_BNDERR
|
||||
# define SEGV_BNDERR 3
|
||||
#endif
|
||||
|
||||
#ifndef SEGV_PKUERR
|
||||
# define SEGV_PKUERR 4
|
||||
#endif
|
||||
|
||||
static char *si_code_str(int si_code)
|
||||
{
|
||||
if (si_code == SEGV_MAPERR)
|
||||
@@ -476,7 +467,7 @@ int sys_mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
|
||||
ptr, size, orig_prot, pkey);
|
||||
|
||||
errno = 0;
|
||||
sret = syscall(SYS_mprotect_key, ptr, size, orig_prot, pkey);
|
||||
sret = syscall(__NR_pkey_mprotect, ptr, size, orig_prot, pkey);
|
||||
if (errno) {
|
||||
dprintf2("SYS_mprotect_key sret: %d\n", sret);
|
||||
dprintf2("SYS_mprotect_key prot: 0x%lx\n", orig_prot);
|
||||
@@ -1684,7 +1675,7 @@ void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey)
|
||||
return;
|
||||
}
|
||||
|
||||
sret = syscall(SYS_mprotect_key, ptr, size, PROT_READ, pkey);
|
||||
sret = syscall(__NR_pkey_mprotect, ptr, size, PROT_READ, pkey);
|
||||
pkey_assert(sret < 0);
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,7 @@ separated by spaces:
|
||||
- mmap
|
||||
tests for mmap(2)
|
||||
- gup_test
|
||||
tests for gup using gup_test interface
|
||||
tests for gup
|
||||
- userfaultfd
|
||||
tests for userfaultfd(2)
|
||||
- compaction
|
||||
@@ -196,6 +196,8 @@ CATEGORY="gup_test" run_test ./gup_test -a
|
||||
# Dump pages 0, 19, and 4096, using pin_user_pages:
|
||||
CATEGORY="gup_test" run_test ./gup_test -ct -F 0x1 0 19 0x1000
|
||||
|
||||
CATEGORY="gup_test" run_test ./gup_longterm
|
||||
|
||||
CATEGORY="userfaultfd" run_test ./uffd-unit-tests
|
||||
uffd_stress_bin=./uffd-stress
|
||||
CATEGORY="userfaultfd" run_test ${uffd_stress_bin} anon 20 16
|
||||
@@ -242,18 +244,18 @@ if [ $VADDR64 -ne 0 ]; then
|
||||
if [ "$ARCH" == "$ARCH_ARM64" ]; then
|
||||
echo 6 > /proc/sys/vm/nr_hugepages
|
||||
fi
|
||||
CATEGORY="hugevm" run_test ./va_high_addr_switch.sh
|
||||
CATEGORY="hugevm" run_test bash ./va_high_addr_switch.sh
|
||||
if [ "$ARCH" == "$ARCH_ARM64" ]; then
|
||||
echo $prev_nr_hugepages > /proc/sys/vm/nr_hugepages
|
||||
fi
|
||||
fi # VADDR64
|
||||
|
||||
# vmalloc stability smoke test
|
||||
CATEGORY="vmalloc" run_test ./test_vmalloc.sh smoke
|
||||
CATEGORY="vmalloc" run_test bash ./test_vmalloc.sh smoke
|
||||
|
||||
CATEGORY="mremap" run_test ./mremap_dontunmap
|
||||
|
||||
CATEGORY="hmm" run_test ./test_hmm.sh smoke
|
||||
CATEGORY="hmm" run_test bash ./test_hmm.sh smoke
|
||||
|
||||
# MADV_POPULATE_READ and MADV_POPULATE_WRITE tests
|
||||
CATEGORY="madv_populate" run_test ./madv_populate
|
||||
|
@@ -616,3 +616,62 @@ int copy_page(int ufd, unsigned long offset, bool wp)
|
||||
{
|
||||
return __copy_page(ufd, offset, false, wp);
|
||||
}
|
||||
|
||||
int uffd_open_dev(unsigned int flags)
|
||||
{
|
||||
int fd, uffd;
|
||||
|
||||
fd = open("/dev/userfaultfd", O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
uffd = ioctl(fd, USERFAULTFD_IOC_NEW, flags);
|
||||
close(fd);
|
||||
|
||||
return uffd;
|
||||
}
|
||||
|
||||
int uffd_open_sys(unsigned int flags)
|
||||
{
|
||||
#ifdef __NR_userfaultfd
|
||||
return syscall(__NR_userfaultfd, flags);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int uffd_open(unsigned int flags)
|
||||
{
|
||||
int uffd = uffd_open_sys(flags);
|
||||
|
||||
if (uffd < 0)
|
||||
uffd = uffd_open_dev(flags);
|
||||
|
||||
return uffd;
|
||||
}
|
||||
|
||||
int uffd_get_features(uint64_t *features)
|
||||
{
|
||||
struct uffdio_api uffdio_api = { .api = UFFD_API, .features = 0 };
|
||||
/*
|
||||
* This should by default work in most kernels; the feature list
|
||||
* will be the same no matter what we pass in here.
|
||||
*/
|
||||
int fd = uffd_open(UFFD_USER_MODE_ONLY);
|
||||
|
||||
if (fd < 0)
|
||||
/* Maybe the kernel is older than user-only mode? */
|
||||
fd = uffd_open(0);
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (ioctl(fd, UFFDIO_API, &uffdio_api)) {
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
*features = uffdio_api.features;
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -110,6 +110,11 @@ int __copy_page(int ufd, unsigned long offset, bool retry, bool wp);
|
||||
int copy_page(int ufd, unsigned long offset, bool wp);
|
||||
void *uffd_poll_thread(void *arg);
|
||||
|
||||
int uffd_open_dev(unsigned int flags);
|
||||
int uffd_open_sys(unsigned int flags);
|
||||
int uffd_open(unsigned int flags);
|
||||
int uffd_get_features(uint64_t *features);
|
||||
|
||||
#define TEST_ANON 1
|
||||
#define TEST_HUGETLB 2
|
||||
#define TEST_SHMEM 3
|
||||
|
@@ -88,16 +88,6 @@ static void uffd_stats_reset(struct uffd_args *args, unsigned long n_cpus)
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint64_t uffd_minor_feature(void)
|
||||
{
|
||||
if (test_type == TEST_HUGETLB && map_shared)
|
||||
return UFFD_FEATURE_MINOR_HUGETLBFS;
|
||||
else if (test_type == TEST_SHMEM)
|
||||
return UFFD_FEATURE_MINOR_SHMEM;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *locking_thread(void *arg)
|
||||
{
|
||||
unsigned long cpu = (unsigned long) arg;
|
||||
|
@@ -109,12 +109,11 @@ static void uffd_test_pass(void)
|
||||
ksft_inc_fail_cnt(); \
|
||||
} while (0)
|
||||
|
||||
#define uffd_test_skip(...) do { \
|
||||
printf("skipped [reason: "); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("]\n"); \
|
||||
ksft_inc_xskip_cnt(); \
|
||||
} while (0)
|
||||
static void uffd_test_skip(const char *message)
|
||||
{
|
||||
printf("skipped [reason: %s]\n", message);
|
||||
ksft_inc_xskip_cnt();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if specific userfaultfd supported, 0 otherwise. Note, we'll
|
||||
@@ -1149,7 +1148,6 @@ int main(int argc, char *argv[])
|
||||
uffd_test_case_t *test;
|
||||
mem_type_t *mem_type;
|
||||
uffd_test_args_t args;
|
||||
char test_name[128];
|
||||
const char *errmsg;
|
||||
int has_uffd, opt;
|
||||
int i, j;
|
||||
@@ -1192,10 +1190,8 @@ int main(int argc, char *argv[])
|
||||
mem_type = &mem_types[j];
|
||||
if (!(test->mem_targets & mem_type->mem_flag))
|
||||
continue;
|
||||
snprintf(test_name, sizeof(test_name),
|
||||
"%s on %s", test->name, mem_type->name);
|
||||
|
||||
uffd_test_start(test_name);
|
||||
uffd_test_start("%s on %s", test->name, mem_type->name);
|
||||
if (!uffd_feature_supported(test)) {
|
||||
uffd_test_skip("feature missing");
|
||||
continue;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/userfaultfd.h>
|
||||
#include <sys/syscall.h>
|
||||
@@ -198,6 +199,32 @@ unsigned long default_huge_page_size(void)
|
||||
return hps;
|
||||
}
|
||||
|
||||
int detect_hugetlb_page_sizes(size_t sizes[], int max)
|
||||
{
|
||||
DIR *dir = opendir("/sys/kernel/mm/hugepages/");
|
||||
int count = 0;
|
||||
|
||||
if (!dir)
|
||||
return 0;
|
||||
|
||||
while (count < max) {
|
||||
struct dirent *entry = readdir(dir);
|
||||
size_t kb;
|
||||
|
||||
if (!entry)
|
||||
break;
|
||||
if (entry->d_type != DT_DIR)
|
||||
continue;
|
||||
if (sscanf(entry->d_name, "hugepages-%zukB", &kb) != 1)
|
||||
continue;
|
||||
sizes[count++] = kb * 1024;
|
||||
ksft_print_msg("[INFO] detected hugetlb page size: %zu KiB\n",
|
||||
kb);
|
||||
}
|
||||
closedir(dir);
|
||||
return count;
|
||||
}
|
||||
|
||||
/* If `ioctls' non-NULL, the allowed ioctls will be returned into the var */
|
||||
int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len,
|
||||
bool miss, bool wp, bool minor, uint64_t *ioctls)
|
||||
@@ -242,62 +269,3 @@ int uffd_unregister(int uffd, void *addr, uint64_t len)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uffd_open_dev(unsigned int flags)
|
||||
{
|
||||
int fd, uffd;
|
||||
|
||||
fd = open("/dev/userfaultfd", O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
uffd = ioctl(fd, USERFAULTFD_IOC_NEW, flags);
|
||||
close(fd);
|
||||
|
||||
return uffd;
|
||||
}
|
||||
|
||||
int uffd_open_sys(unsigned int flags)
|
||||
{
|
||||
#ifdef __NR_userfaultfd
|
||||
return syscall(__NR_userfaultfd, flags);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int uffd_open(unsigned int flags)
|
||||
{
|
||||
int uffd = uffd_open_sys(flags);
|
||||
|
||||
if (uffd < 0)
|
||||
uffd = uffd_open_dev(flags);
|
||||
|
||||
return uffd;
|
||||
}
|
||||
|
||||
int uffd_get_features(uint64_t *features)
|
||||
{
|
||||
struct uffdio_api uffdio_api = { .api = UFFD_API, .features = 0 };
|
||||
/*
|
||||
* This should by default work in most kernels; the feature list
|
||||
* will be the same no matter what we pass in here.
|
||||
*/
|
||||
int fd = uffd_open(UFFD_USER_MODE_ONLY);
|
||||
|
||||
if (fd < 0)
|
||||
/* Maybe the kernel is older than user-only mode? */
|
||||
fd = uffd_open(0);
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (ioctl(fd, UFFDIO_API, &uffdio_api)) {
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
*features = uffdio_api.features;
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -44,14 +44,11 @@ bool check_huge_file(void *addr, int nr_hpages, uint64_t hpage_size);
|
||||
bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size);
|
||||
int64_t allocate_transhuge(void *ptr, int pagemap_fd);
|
||||
unsigned long default_huge_page_size(void);
|
||||
int detect_hugetlb_page_sizes(size_t sizes[], int max);
|
||||
|
||||
int uffd_register(int uffd, void *addr, uint64_t len,
|
||||
bool miss, bool wp, bool minor);
|
||||
int uffd_unregister(int uffd, void *addr, uint64_t len);
|
||||
int uffd_open_dev(unsigned int flags);
|
||||
int uffd_open_sys(unsigned int flags);
|
||||
int uffd_open(unsigned int flags);
|
||||
int uffd_get_features(uint64_t *features);
|
||||
int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len,
|
||||
bool miss, bool wp, bool minor, uint64_t *ioctls);
|
||||
|
||||
|
Reference in New Issue
Block a user