summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/mempolicy.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux/mempolicy.cc')
-rw-r--r--test/syscalls/linux/mempolicy.cc289
1 files changed, 0 insertions, 289 deletions
diff --git a/test/syscalls/linux/mempolicy.cc b/test/syscalls/linux/mempolicy.cc
deleted file mode 100644
index 9d5f47651..000000000
--- a/test/syscalls/linux/mempolicy.cc
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2018 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <sys/syscall.h>
-
-#include "gtest/gtest.h"
-#include "absl/memory/memory.h"
-#include "test/util/cleanup.h"
-#include "test/util/memory_util.h"
-#include "test/util/test_util.h"
-#include "test/util/thread_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-#define BITS_PER_BYTE 8
-
-#define MPOL_F_STATIC_NODES (1 << 15)
-#define MPOL_F_RELATIVE_NODES (1 << 14)
-#define MPOL_DEFAULT 0
-#define MPOL_PREFERRED 1
-#define MPOL_BIND 2
-#define MPOL_INTERLEAVE 3
-#define MPOL_LOCAL 4
-#define MPOL_F_NODE (1 << 0)
-#define MPOL_F_ADDR (1 << 1)
-#define MPOL_F_MEMS_ALLOWED (1 << 2)
-#define MPOL_MF_STRICT (1 << 0)
-#define MPOL_MF_MOVE (1 << 1)
-#define MPOL_MF_MOVE_ALL (1 << 2)
-
-int get_mempolicy(int *policy, uint64_t *nmask, uint64_t maxnode, void *addr,
- int flags) {
- return syscall(SYS_get_mempolicy, policy, nmask, maxnode, addr, flags);
-}
-
-int set_mempolicy(int mode, uint64_t *nmask, uint64_t maxnode) {
- return syscall(SYS_set_mempolicy, mode, nmask, maxnode);
-}
-
-int mbind(void *addr, unsigned long len, int mode,
- const unsigned long *nodemask, unsigned long maxnode,
- unsigned flags) {
- return syscall(SYS_mbind, addr, len, mode, nodemask, maxnode, flags);
-}
-
-// Creates a cleanup object that resets the calling thread's mempolicy to the
-// system default when the calling scope ends.
-Cleanup ScopedMempolicy() {
- return Cleanup([] {
- EXPECT_THAT(set_mempolicy(MPOL_DEFAULT, nullptr, 0), SyscallSucceeds());
- });
-}
-
-// Temporarily change the memory policy for the calling thread within the
-// caller's scope.
-PosixErrorOr<Cleanup> ScopedSetMempolicy(int mode, uint64_t *nmask,
- uint64_t maxnode) {
- if (set_mempolicy(mode, nmask, maxnode)) {
- return PosixError(errno, "set_mempolicy");
- }
- return ScopedMempolicy();
-}
-
-TEST(MempolicyTest, CheckDefaultPolicy) {
- int mode = 0;
- uint64_t nodemask = 0;
- ASSERT_THAT(get_mempolicy(&mode, &nodemask, sizeof(nodemask) * BITS_PER_BYTE,
- nullptr, 0),
- SyscallSucceeds());
-
- EXPECT_EQ(MPOL_DEFAULT, mode);
- EXPECT_EQ(0x0, nodemask);
-}
-
-TEST(MempolicyTest, PolicyPreservedAfterSetMempolicy) {
- uint64_t nodemask = 0x1;
- auto cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSetMempolicy(
- MPOL_BIND, &nodemask, sizeof(nodemask) * BITS_PER_BYTE));
-
- int mode = 0;
- uint64_t nodemask_after = 0x0;
- ASSERT_THAT(get_mempolicy(&mode, &nodemask_after,
- sizeof(nodemask_after) * BITS_PER_BYTE, nullptr, 0),
- SyscallSucceeds());
- EXPECT_EQ(MPOL_BIND, mode);
- EXPECT_EQ(0x1, nodemask_after);
-
- // Try throw in some mode flags.
- for (auto mode_flag : {MPOL_F_STATIC_NODES, MPOL_F_RELATIVE_NODES}) {
- auto cleanup2 = ASSERT_NO_ERRNO_AND_VALUE(
- ScopedSetMempolicy(MPOL_INTERLEAVE | mode_flag, &nodemask,
- sizeof(nodemask) * BITS_PER_BYTE));
- mode = 0;
- nodemask_after = 0x0;
- ASSERT_THAT(
- get_mempolicy(&mode, &nodemask_after,
- sizeof(nodemask_after) * BITS_PER_BYTE, nullptr, 0),
- SyscallSucceeds());
- EXPECT_EQ(MPOL_INTERLEAVE | mode_flag, mode);
- EXPECT_EQ(0x1, nodemask_after);
- }
-}
-
-TEST(MempolicyTest, SetMempolicyRejectsInvalidInputs) {
- auto cleanup = ScopedMempolicy();
- uint64_t nodemask;
-
- if (IsRunningOnGvisor()) {
- // Invalid nodemask, we only support a single node on gvisor.
- nodemask = 0x4;
- ASSERT_THAT(set_mempolicy(MPOL_DEFAULT, &nodemask,
- sizeof(nodemask) * BITS_PER_BYTE),
- SyscallFailsWithErrno(EINVAL));
- }
-
- nodemask = 0x1;
-
- // Invalid mode.
- ASSERT_THAT(set_mempolicy(7439, &nodemask, sizeof(nodemask) * BITS_PER_BYTE),
- SyscallFailsWithErrno(EINVAL));
-
- // Invalid nodemask size.
- ASSERT_THAT(set_mempolicy(MPOL_DEFAULT, &nodemask, 0),
- SyscallFailsWithErrno(EINVAL));
-
- // Invalid mode flag.
- ASSERT_THAT(
- set_mempolicy(MPOL_DEFAULT | MPOL_F_STATIC_NODES | MPOL_F_RELATIVE_NODES,
- &nodemask, sizeof(nodemask) * BITS_PER_BYTE),
- SyscallFailsWithErrno(EINVAL));
-
- // MPOL_INTERLEAVE with empty nodemask.
- nodemask = 0x0;
- ASSERT_THAT(set_mempolicy(MPOL_INTERLEAVE, &nodemask,
- sizeof(nodemask) * BITS_PER_BYTE),
- SyscallFailsWithErrno(EINVAL));
-}
-
-// The manpages specify that the nodemask provided to set_mempolicy are
-// considered empty if the nodemask pointer is null, or if the nodemask size is
-// 0. We use a policy which accepts both empty and non-empty nodemasks
-// (MPOL_PREFERRED), a policy which requires a non-empty nodemask (MPOL_BIND),
-// and a policy which completely ignores the nodemask (MPOL_DEFAULT) to verify
-// argument checking around nodemasks.
-TEST(MempolicyTest, EmptyNodemaskOnSet) {
- auto cleanup = ScopedMempolicy();
-
- EXPECT_THAT(set_mempolicy(MPOL_DEFAULT, nullptr, 1), SyscallSucceeds());
- EXPECT_THAT(set_mempolicy(MPOL_BIND, nullptr, 1),
- SyscallFailsWithErrno(EINVAL));
- EXPECT_THAT(set_mempolicy(MPOL_PREFERRED, nullptr, 1), SyscallSucceeds());
-
- uint64_t nodemask = 0x1;
- EXPECT_THAT(set_mempolicy(MPOL_DEFAULT, &nodemask, 0),
- SyscallFailsWithErrno(EINVAL));
- EXPECT_THAT(set_mempolicy(MPOL_BIND, &nodemask, 0),
- SyscallFailsWithErrno(EINVAL));
- EXPECT_THAT(set_mempolicy(MPOL_PREFERRED, &nodemask, 0),
- SyscallFailsWithErrno(EINVAL));
-}
-
-TEST(MempolicyTest, QueryAvailableNodes) {
- uint64_t nodemask = 0;
- ASSERT_THAT(
- get_mempolicy(nullptr, &nodemask, sizeof(nodemask) * BITS_PER_BYTE,
- nullptr, MPOL_F_MEMS_ALLOWED),
- SyscallSucceeds());
- // We can only be sure there is a single node if running on gvisor.
- if (IsRunningOnGvisor()) {
- EXPECT_EQ(0x1, nodemask);
- }
-
- // MPOL_F_ADDR and MPOL_F_NODE flags may not be combined with
- // MPOL_F_MEMS_ALLLOWED.
- for (auto flags :
- {MPOL_F_MEMS_ALLOWED | MPOL_F_ADDR, MPOL_F_MEMS_ALLOWED | MPOL_F_NODE,
- MPOL_F_MEMS_ALLOWED | MPOL_F_ADDR | MPOL_F_NODE}) {
- ASSERT_THAT(get_mempolicy(nullptr, &nodemask,
- sizeof(nodemask) * BITS_PER_BYTE, nullptr, flags),
- SyscallFailsWithErrno(EINVAL));
- }
-}
-
-TEST(MempolicyTest, GetMempolicyQueryNodeForAddress) {
- uint64_t dummy_stack_address;
- auto dummy_heap_address = absl::make_unique<uint64_t>();
- int mode;
-
- for (auto ptr : {&dummy_stack_address, dummy_heap_address.get()}) {
- mode = -1;
- ASSERT_THAT(
- get_mempolicy(&mode, nullptr, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE),
- SyscallSucceeds());
- // If we're not running on gvisor, the address may be allocated on a
- // different numa node.
- if (IsRunningOnGvisor()) {
- EXPECT_EQ(0, mode);
- }
- }
-
- void* invalid_address = reinterpret_cast<void*>(-1);
-
- // Invalid address.
- ASSERT_THAT(get_mempolicy(&mode, nullptr, 0, invalid_address,
- MPOL_F_ADDR | MPOL_F_NODE),
- SyscallFailsWithErrno(EFAULT));
-
- // Invalid mode pointer.
- ASSERT_THAT(get_mempolicy(reinterpret_cast<int*>(invalid_address), nullptr, 0,
- &dummy_stack_address, MPOL_F_ADDR | MPOL_F_NODE),
- SyscallFailsWithErrno(EFAULT));
-}
-
-TEST(MempolicyTest, GetMempolicyCanOmitPointers) {
- int mode;
- uint64_t nodemask;
-
- // Omit nodemask pointer.
- ASSERT_THAT(get_mempolicy(&mode, nullptr, 0, nullptr, 0), SyscallSucceeds());
- // Omit mode pointer.
- ASSERT_THAT(get_mempolicy(nullptr, &nodemask,
- sizeof(nodemask) * BITS_PER_BYTE, nullptr, 0),
- SyscallSucceeds());
- // Omit both pointers.
- ASSERT_THAT(get_mempolicy(nullptr, nullptr, 0, nullptr, 0),
- SyscallSucceeds());
-}
-
-TEST(MempolicyTest, GetMempolicyNextInterleaveNode) {
- int mode;
- // Policy for thread not yet set to MPOL_INTERLEAVE, can't query for
- // the next node which will be used for allocation.
- ASSERT_THAT(get_mempolicy(&mode, nullptr, 0, nullptr, MPOL_F_NODE),
- SyscallFailsWithErrno(EINVAL));
-
- // Set default policy for thread to MPOL_INTERLEAVE.
- uint64_t nodemask = 0x1;
- auto cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSetMempolicy(
- MPOL_INTERLEAVE, &nodemask, sizeof(nodemask) * BITS_PER_BYTE));
-
- mode = -1;
- ASSERT_THAT(get_mempolicy(&mode, nullptr, 0, nullptr, MPOL_F_NODE),
- SyscallSucceeds());
- EXPECT_EQ(0, mode);
-}
-
-TEST(MempolicyTest, Mbind) {
- // Temporarily set the thread policy to MPOL_PREFERRED.
- const auto cleanup_thread_policy =
- ASSERT_NO_ERRNO_AND_VALUE(ScopedSetMempolicy(MPOL_PREFERRED, nullptr, 0));
-
- const auto mapping = ASSERT_NO_ERRNO_AND_VALUE(
- MmapAnon(kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS));
-
- // vmas default to MPOL_DEFAULT irrespective of the thread policy (currently
- // MPOL_PREFERRED).
- int mode;
- ASSERT_THAT(get_mempolicy(&mode, nullptr, 0, mapping.ptr(), MPOL_F_ADDR),
- SyscallSucceeds());
- EXPECT_EQ(mode, MPOL_DEFAULT);
-
- // Set MPOL_PREFERRED for the vma and read it back.
- ASSERT_THAT(
- mbind(mapping.ptr(), mapping.len(), MPOL_PREFERRED, nullptr, 0, 0),
- SyscallSucceeds());
- ASSERT_THAT(get_mempolicy(&mode, nullptr, 0, mapping.ptr(), MPOL_F_ADDR),
- SyscallSucceeds());
- EXPECT_EQ(mode, MPOL_PREFERRED);
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor