diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c index 732385ce..45f5ccfe 100644 --- a/arch/arm64/kernel/syscall.c +++ b/arch/arm64/kernel/syscall.c @@ -15,6 +15,7 @@ #include #include #include +#include #include void terminate_mcexec(int, int); @@ -1958,6 +1959,12 @@ SYSCALL_DECLARE(mmap) goto out; } pgsize = (size_t)1 << ((flags >> MAP_HUGE_SHIFT) & 0x3F); + + if (rusage_check_overmap(len0, + (flags >> MAP_HUGE_SHIFT) & 0x3F)) { + error = -ENOMEM; + goto out; + } } #define VALID_DUMMY_ADDR ((region->user_start + PTL3_SIZE - 1) & ~(PTL3_SIZE - 1)) diff --git a/arch/x86_64/kernel/syscall.c b/arch/x86_64/kernel/syscall.c index 231f5d51..8beafd4e 100644 --- a/arch/x86_64/kernel/syscall.c +++ b/arch/x86_64/kernel/syscall.c @@ -31,6 +31,7 @@ #include #include #include +#include #include void terminate_mcexec(int, int); @@ -1701,6 +1702,12 @@ SYSCALL_DECLARE(mmap) } pgsize = (size_t)1 << ((flags >> MAP_HUGE_SHIFT) & 0x3F); + + if (rusage_check_overmap(len0, + (flags >> MAP_HUGE_SHIFT) & 0x3F)) { + error = -ENOMEM; + goto out; + } } #define VALID_DUMMY_ADDR ((region->user_start + PTL3_SIZE - 1) & ~(PTL3_SIZE - 1)) diff --git a/kernel/include/rusage_private.h b/kernel/include/rusage_private.h index 6cc97914..df8b6daa 100644 --- a/kernel/include/rusage_private.h +++ b/kernel/include/rusage_private.h @@ -301,6 +301,23 @@ rusage_check_oom(int numa_id, unsigned long pages, int is_user) return 0; } +static inline int +rusage_check_overmap(size_t len, int pgshift) +{ + int npages = 0, remain_pages = 0; + + npages = (len + (1UL << pgshift) - 1) >> pgshift; + remain_pages = (rusage.total_memory - rusage.total_memory_usage) + >> pgshift; + + if (npages > remain_pages) { + /* overmap */ + return 1; + } + + return 0; +} + static inline void rusage_page_add(int numa_id, unsigned long pages, int is_user) { diff --git a/test/issues/1183/C1183.sh b/test/issues/1183/C1183.sh new file mode 100755 index 00000000..d8adf9b5 --- /dev/null +++ b/test/issues/1183/C1183.sh @@ -0,0 +1,142 @@ +#!/bin/sh + +USELTP=1 +USEOSTEST=0 + +arch=`uname -p` +if [ -f "./${arch}_config" ]; then + . ./${arch}_config +else + echo "$1 is unexpected arch" + exit 1 +fi + +. ../../common.sh + +issue=1183 +tid=01 +ng=0 +echo "*** C${issue}T${tid} start *******************************" +echo "** over-mapping with MAP_HUGETLB (expect mmap FAIL)" +for pgshift in ${PGSHIFT_LIST[@]} +do + echo pageshift: ${pgshift} + ${MCEXEC} ./hugemap ${OVERSIZE} ${OVERSIZE} ${pgshift} + + if [ $? -ne 0 ]; then + echo "** [OK]" + else + echo "** [NG]" + ng=1 + fi +done +if [ ${ng} -eq 0 ]; then + echo "*** C${issue}T${tid}: PASSED" +else + echo "*** C${issue}T${tid}: FAILED" +fi +echo "" + +tid=02 +ng=0 +echo "*** C${issue}T${tid} start *******************************" +echo "** within-mapping with MAP_HUGETLB (expect mmap SUCCESS)" +for pgshift in ${PGSHIFT_LIST[@]} +do + echo pageshift: ${pgshift} + ${MCEXEC} ./hugemap ${INSIZE} ${INSIZE} ${pgshift} + + if [ $? -eq 0 ]; then + echo "** [OK]" + else + echo "** [NG]" + ng=1 + fi +done +if [ ${ng} -eq 0 ]; then + echo "*** C${issue}T${tid}: PASSED" +else + echo "*** C${issue}T${tid}: FAILED" +fi +echo "" + +tid=03 +ng=0 +idx=0 +echo "*** C${issue}T${tid} start *******************************" +echo "** multi within-mapping with MAP_HUGETLB" +for pgshift in ${PGSHIFT_LIST[@]} +do + echo pageshift: ${pgshift} + ${MCEXEC} ./hugemap `expr ${MEMALL} \* 4` ${INSIZE} ${pgshift} + + if [ $? -eq ${MULTI_MAP_RESULT[${idx}]} ]; then + echo "** [OK]" + else + echo "** [NG]" + ng=1 + fi + let idx++ +done +if [ ${ng} -eq 0 ]; then + echo "*** C${issue}T${tid}: PASSED" +else + echo "*** C${issue}T${tid}: FAILED" +fi +echo "" + +tid=04 +ng=0 +echo "*** C${issue}T${tid} start *******************************" +echo "** over-mapping without MAP_HUGETLB (expect mmap SUCCESS)" +${MCEXEC} ./hugemap ${OVERSIZE} ${OVERSIZE} -1 + +if [ $? -eq 0 ]; then + echo "** [OK]" +else + echo "** [NG]" + ng=1 +fi +if [ ${ng} -eq 0 ]; then + echo "*** C${issue}T${tid}: PASSED" +else + echo "*** C${issue}T${tid}: FAILED" +fi +echo "" + +tid=05 +ng=0 +echo "*** C${issue}T${tid} start *******************************" +echo "** within-mapping without MAP_HUGETLB (expect mmap SUCCESS)" +${MCEXEC} ./hugemap ${INSIZE} ${INSIZE} -1 + +if [ $? -eq 0 ]; then + echo "** [OK]" +else + echo "** [NG]" + ng=1 +fi +if [ ${ng} -eq 0 ]; then + echo "*** C${issue}T${tid}: PASSED" +else + echo "*** C${issue}T${tid}: FAILED" +fi +echo "" + +tid=06 +ng=0 +echo "*** C${issue}T${tid} start *******************************" +echo "** multi within-mapping with MAP_HUGETLB (expect mmap SUCCESS)" +${MCEXEC} ./hugemap `expr ${MEMALL} \* 4` ${INSIZE} -1 + +if [ $? -eq 0 ]; then + echo "** [OK]" +else + echo "** [NG]" + ng=1 +fi +if [ ${ng} -eq 0 ]; then + echo "*** C${issue}T${tid}: PASSED" +else + echo "*** C${issue}T${tid}: FAILED" +fi diff --git a/test/issues/1183/Makefile b/test/issues/1183/Makefile new file mode 100644 index 00000000..ce4d2800 --- /dev/null +++ b/test/issues/1183/Makefile @@ -0,0 +1,17 @@ +CC = gcc +TARGET=hugemap + +CPPFLAGS = +LDFLAGS = + +all: $(TARGET) + +hugemap: hugemap.c + $(CC) -o $@ $^ $(LDFLAGS) + +test: all + @sh ./C1183.sh + +clean: + rm -f $(TARGET) *.o + diff --git a/test/issues/1183/README b/test/issues/1183/README new file mode 100644 index 00000000..b158f340 --- /dev/null +++ b/test/issues/1183/README @@ -0,0 +1,49 @@ +【Issue#1183 動作確認】 +□ テスト内容 +テストで扱うメモリサイズについて、以下のように定義する + メモリ総容量:McKernelに割り当てられたメモリ量。本テストでは10GB とする + 利用可能サイズ:メモリ総容量から、マップ済ページの合計サイズを引いたもの + 利用可能サイズを超えるサイズ:本テストではメモリ総容量 + 1GB とする + 利用可能サイズを超えないサイズ: 本テストではメモリ総容量 / 2 とする + +1. MAP_HUGETLB指定時のmmapの動作確認 +C1183T01: + 一回のmmapでの要求サイズが、利用可能サイズを超える場合、 + 利用可能なそれぞれのHugePageSizeでmmapが失敗することを確認する + +C1183T02: + 一回のmmapでの要求サイズが、利用可能サイズを超えない場合、 + 利用可能なそれぞれのHugePageSize でmmapが成功することを確認する + +C1183T03: + 複数回のmmapにおいて、各回のmmapでの要求サイズが利用可能サイズを超えない場合に成功し、 + 超えた場合に失敗することを確認する + なお、anonymous mmapは連続した物理メモリが確保出来た場合はプリマップをするため、 + アーキテクチャごとに下記のような動作となる + - x86_64 : 2MBページ要求時は利用可能サイズが減少していくが、1GBページ要求時は減少しない + - aarch64 : 64KB, 2MBページ要求時は利用可能サイズが減少していくが、32MB, 1GBページ要求時は減少しない + +1. MAP_HUGETLB未指定時のmmapの動作確認 +C1183T04: + 一回のmmapでの要求サイズが、利用可能サイズを超える場合、mmapが成功することを確認する + +C1183T05 + 一回のmmapでの要求サイズが、利用可能サイズを超えない場合、mmapが成功することを確認する + +C1183T06: + 複数回のmmapにおいて、各回のmmapでの要求サイズが利用可能サイズを超えない場合に成功し、 + 超えた場合に失敗することを確認する + なお、MAP_HUGETLB未指定時にはプリマップは行われないため、複数回のmmapによっても + 利用可能サイズは減少せず、累積のmmap要求サイズがメモリ総容量を超過してもmmapは成功する + +□ 実行手順 +$ make test + +McKernelのインストール先や、OSTEST, LTPの配置場所は、 +$HOME/.mck_test_config を参照している +.mck_test_config は、McKernelをビルドした際に生成されるmck_test_config.sample ファイルを +$HOMEにコピーし、適宜編集する + +□ 実行結果 +x86_64_result.log, aarch64_result.log 参照。 +すべての項目をPASSしていることを確認。 diff --git a/test/issues/1183/aarch64_config b/test/issues/1183/aarch64_config new file mode 100644 index 00000000..b36249ee --- /dev/null +++ b/test/issues/1183/aarch64_config @@ -0,0 +1,6 @@ +MEMALL=10 +BOOTPARAM="-c 1-7,9-15 -m ${MEMALL}G@0 -r 1-7:0+9-15:8 -O" +OVERSIZE=`expr ${MEMALL} + 1` +INSIZE=`expr ${MEMALL} / 2` +PGSHIFT_LIST=(0 16 21 25 30) +MULTI_MAP_RESULT=(1 1 1 0 0) diff --git a/test/issues/1183/aarch64_result.log b/test/issues/1183/aarch64_result.log new file mode 100644 index 00000000..bbea13d4 --- /dev/null +++ b/test/issues/1183/aarch64_result.log @@ -0,0 +1,126 @@ +*** C1183T01 start ******************************* +** over-mapping with MAP_HUGETLB (expect mmap FAIL) +pageshift: 0 +*** total_mapsize: 11 GB, mapsize: 11 pgshift: 0 +** mmap 11 GB: failed +** [OK] +pageshift: 16 +*** total_mapsize: 11 GB, mapsize: 11 pgshift: 16 +** mmap 11 GB: failed +** [OK] +pageshift: 21 +*** total_mapsize: 11 GB, mapsize: 11 pgshift: 21 +** mmap 11 GB: failed +** [OK] +pageshift: 25 +*** total_mapsize: 11 GB, mapsize: 11 pgshift: 25 +** mmap 11 GB: failed +** [OK] +pageshift: 30 +*** total_mapsize: 11 GB, mapsize: 11 pgshift: 30 +** mmap 11 GB: failed +** [OK] +*** C1183T01: PASSED + +*** C1183T02 start ******************************* +** within-mapping with MAP_HUGETLB (expect mmap SUCCESS) +pageshift: 0 +*** total_mapsize: 5 GB, mapsize: 5 pgshift: 0 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +pageshift: 16 +*** total_mapsize: 5 GB, mapsize: 5 pgshift: 16 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +pageshift: 21 +*** total_mapsize: 5 GB, mapsize: 5 pgshift: 21 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +pageshift: 25 +*** total_mapsize: 5 GB, mapsize: 5 pgshift: 25 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +pageshift: 30 +*** total_mapsize: 5 GB, mapsize: 5 pgshift: 30 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T02: PASSED + +*** C1183T03 start ******************************* +** multi within-mapping with MAP_HUGETLB +pageshift: 0 +*** total_mapsize: 40 GB, mapsize: 5 pgshift: 0 +** mmap 5 GB: succeed +** mmap 5 GB: failed +** [OK] +pageshift: 16 +*** total_mapsize: 40 GB, mapsize: 5 pgshift: 16 +** mmap 5 GB: succeed +** mmap 5 GB: failed +** [OK] +pageshift: 21 +*** total_mapsize: 40 GB, mapsize: 5 pgshift: 21 +** mmap 5 GB: succeed +** mmap 5 GB: failed +** [OK] +pageshift: 25 +*** total_mapsize: 40 GB, mapsize: 5 pgshift: 25 +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +pageshift: 30 +*** total_mapsize: 40 GB, mapsize: 5 pgshift: 30 +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T03: PASSED + +*** C1183T04 start ******************************* +** over-mapping without MAP_HUGETLB (expect mmap SUCCESS) +*** total_mapsize: 11 GB, mapsize: 11 pgshift: -1 +** mmap 11 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T04: PASSED + +*** C1183T05 start ******************************* +** within-mapping without MAP_HUGETLB (expect mmap SUCCESS) +*** total_mapsize: 5 GB, mapsize: 5 pgshift: -1 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T05: PASSED + +*** C1183T06 start ******************************* +** multi within-mapping with MAP_HUGETLB (expect mmap SUCCESS) +*** total_mapsize: 40 GB, mapsize: 5 pgshift: -1 +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T06: PASSED diff --git a/test/issues/1183/hugemap.c b/test/issues/1183/hugemap.c new file mode 100644 index 00000000..949c7f67 --- /dev/null +++ b/test/issues/1183/hugemap.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +#define MAP_HUGE_SHIFT 26 + +void print_usage(void) +{ + printf("usage: hugemap \n"); +} + +int mmap_flag(size_t mapsize, int page_shift) +{ + char *addr_mmap; + int flags = MAP_ANONYMOUS | MAP_PRIVATE; + + if (page_shift >= 0) { + /* mean use MAP_HUGETLB */ + flags |= MAP_HUGETLB | (page_shift << MAP_HUGE_SHIFT); + } + + addr_mmap = mmap(0, mapsize, + PROT_READ | PROT_WRITE, + flags, -1, 0); + + if (addr_mmap == MAP_FAILED) { + return 1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + int ret; + int i; + unsigned long maptotal; + size_t mapsize; + int pgshift; + + void *addr = NULL; + + if (argc < 4) { + print_usage(); + return 1; + } + + maptotal = atol(argv[1]) << 30; + mapsize = atol(argv[2]) << 30; + pgshift = atoi(argv[3]); + + printf("*** total_mapsize: %ld GB, mapsize: %ld pgshift: %d\n", + maptotal >> 30, mapsize >> 30, pgshift); + + for (i = 0; i < maptotal / mapsize; i++) { + printf("** mmap %ld GB: ", mapsize >> 30); + + ret = mmap_flag(mapsize, pgshift); + + if (ret != 0) { + printf("failed\n"); + goto out; + } + else { + printf("succeed\n"); + } + } + printf("** all mmaps succeeded\n"); +out: + return ret; +} diff --git a/test/issues/1183/x86_64_config b/test/issues/1183/x86_64_config new file mode 100644 index 00000000..8d33e8bf --- /dev/null +++ b/test/issues/1183/x86_64_config @@ -0,0 +1,7 @@ +MEMALL=10 +BOOTPARAM="-c 1-7,9-15,17-23,25-31 -m ${MEMALL}G@0 -r 1-7:0+9-15:8+17-23:16+25-31:24 -O" +OVERSIZE=`expr ${MEMALL} + 1` +INSIZE=`expr ${MEMALL} / 2` +PGSHIFT_LIST=(0 21 30) +MULTI_MAP_RESULT=(1 1 0) + diff --git a/test/issues/1183/x86_64_result.log b/test/issues/1183/x86_64_result.log new file mode 100644 index 00000000..c3deaf1a --- /dev/null +++ b/test/issues/1183/x86_64_result.log @@ -0,0 +1,91 @@ +*** C1183T01 start ******************************* +** over-mapping with MAP_HUGETLB (expect mmap FAIL) +pageshift: 0 +*** total_mapsize: 11 GB, mapsize: 11 pgshift: 0 +** mmap 11 GB: failed +** [OK] +pageshift: 21 +*** total_mapsize: 11 GB, mapsize: 11 pgshift: 21 +** mmap 11 GB: failed +** [OK] +pageshift: 30 +*** total_mapsize: 11 GB, mapsize: 11 pgshift: 30 +** mmap 11 GB: failed +** [OK] +*** C1183T01: PASSED + +*** C1183T02 start ******************************* +** within-mapping with MAP_HUGETLB (expect mmap SUCCESS) +pageshift: 0 +*** total_mapsize: 5 GB, mapsize: 5 pgshift: 0 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +pageshift: 21 +*** total_mapsize: 5 GB, mapsize: 5 pgshift: 21 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +pageshift: 30 +*** total_mapsize: 5 GB, mapsize: 5 pgshift: 30 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T02: PASSED + +*** C1183T03 start ******************************* +** multi within-mapping with MAP_HUGETLB +pageshift: 0 +*** total_mapsize: 40 GB, mapsize: 5 pgshift: 0 +** mmap 5 GB: succeed +** mmap 5 GB: failed +** [OK] +pageshift: 21 +*** total_mapsize: 40 GB, mapsize: 5 pgshift: 21 +** mmap 5 GB: succeed +** mmap 5 GB: failed +** [OK] +pageshift: 30 +*** total_mapsize: 40 GB, mapsize: 5 pgshift: 30 +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T03: PASSED + +*** C1183T04 start ******************************* +** over-mapping without MAP_HUGETLB (expect mmap SUCCESS) +*** total_mapsize: 11 GB, mapsize: 11 pgshift: -1 +** mmap 11 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T04: PASSED + +*** C1183T05 start ******************************* +** within-mapping without MAP_HUGETLB (expect mmap SUCCESS) +*** total_mapsize: 5 GB, mapsize: 5 pgshift: -1 +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T05: PASSED + +*** C1183T06 start ******************************* +** multi within-mapping with MAP_HUGETLB (expect mmap SUCCESS) +*** total_mapsize: 40 GB, mapsize: 5 pgshift: -1 +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** mmap 5 GB: succeed +** all mmaps succeeded +** [OK] +*** C1183T06: PASSED