* [RFC PATCH v2 1/2] mm: restrictedmem: Allow userspace to specify mount for memfd_restricted
2023-03-21 20:15 [RFC PATCH v2 0/2] Providing mount in memfd_restricted() syscall Ackerley Tng
@ 2023-03-21 20:15 ` Ackerley Tng
2023-03-22 11:19 ` Christian Brauner
2023-03-21 20:15 ` [RFC PATCH v2 2/2] selftests: restrictedmem: Check hugepage-ness of shmem file backing restrictedmem fd Ackerley Tng
1 sibling, 1 reply; 5+ messages in thread
From: Ackerley Tng @ 2023-03-21 20:15 UTC (permalink / raw)
To: kvm, linux-api, linux-arch, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, qemu-devel
Cc: aarcange, ak, akpm, arnd, bfields, bp, chao.p.peng, corbet,
dave.hansen, david, ddutile, dhildenb, hpa, hughd, jlayton,
jmattson, joro, jun.nakajima, kirill.shutemov, linmiaohe, luto,
mail, mhocko, michael.roth, mingo, naoya.horiguchi, pbonzini,
qperret, rppt, seanjc, shuah, steven.price, tabba, tglx,
vannapurve, vbabka, vkuznets, wanpengli, wei.w.wang, x86,
yu.c.zhang, Ackerley Tng
By default, the backing shmem file for a restrictedmem fd is created
on shmem's kernel space mount.
With this patch, an optional tmpfs mount can be specified via an fd,
which will be used as the mountpoint for backing the shmem file
associated with a restrictedmem fd.
This change is modeled after how sys_open() can create an unnamed
temporary file in a given directory with O_TMPFILE.
This will help restrictedmem fds inherit the properties of the
provided tmpfs mounts, for example, hugepage allocation hints, NUMA
binding hints, etc.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
include/linux/syscalls.h | 2 +-
include/uapi/linux/restrictedmem.h | 8 ++++
mm/restrictedmem.c | 63 +++++++++++++++++++++++++++---
3 files changed, 66 insertions(+), 7 deletions(-)
create mode 100644 include/uapi/linux/restrictedmem.h
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index f9e9e0c820c5..a23c4c385cd3 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -1056,7 +1056,7 @@ asmlinkage long sys_memfd_secret(unsigned int flags);
asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long len,
unsigned long home_node,
unsigned long flags);
-asmlinkage long sys_memfd_restricted(unsigned int flags);
+asmlinkage long sys_memfd_restricted(unsigned int flags, int mount_fd);
/*
* Architecture-specific system calls
diff --git a/include/uapi/linux/restrictedmem.h b/include/uapi/linux/restrictedmem.h
new file mode 100644
index 000000000000..9f108dd1ac4c
--- /dev/null
+++ b/include/uapi/linux/restrictedmem.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_RESTRICTEDMEM_H
+#define _UAPI_LINUX_RESTRICTEDMEM_H
+
+/* flags for memfd_restricted */
+#define RMFD_TMPFILE 0x0001U
+
+#endif /* _UAPI_LINUX_RESTRICTEDMEM_H */
diff --git a/mm/restrictedmem.c b/mm/restrictedmem.c
index c5d869d8c2d8..4d83b949d84e 100644
--- a/mm/restrictedmem.c
+++ b/mm/restrictedmem.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
-#include "linux/sbitmap.h"
+#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/pseudo_fs.h>
#include <linux/shmem_fs.h>
#include <linux/syscalls.h>
#include <uapi/linux/falloc.h>
#include <uapi/linux/magic.h>
+#include <uapi/linux/restrictedmem.h>
#include <linux/restrictedmem.h>
struct restrictedmem {
@@ -189,19 +190,20 @@ static struct file *restrictedmem_file_create(struct file *memfd)
return file;
}
-SYSCALL_DEFINE1(memfd_restricted, unsigned int, flags)
+static int restrictedmem_create(struct vfsmount *mount)
{
struct file *file, *restricted_file;
int fd, err;
- if (flags)
- return -EINVAL;
-
fd = get_unused_fd_flags(0);
if (fd < 0)
return fd;
- file = shmem_file_setup("memfd:restrictedmem", 0, VM_NORESERVE);
+ if (mount)
+ file = shmem_file_setup_with_mnt(mount, "memfd:restrictedmem", 0, VM_NORESERVE);
+ else
+ file = shmem_file_setup("memfd:restrictedmem", 0, VM_NORESERVE);
+
if (IS_ERR(file)) {
err = PTR_ERR(file);
goto err_fd;
@@ -223,6 +225,55 @@ SYSCALL_DEFINE1(memfd_restricted, unsigned int, flags)
return err;
}
+static bool is_shmem_mount(struct vfsmount *mnt)
+{
+ return mnt && mnt->mnt_sb && mnt->mnt_sb->s_magic == TMPFS_MAGIC;
+}
+
+static int restrictedmem_create_from_file(int mount_fd)
+{
+ int ret;
+ struct fd f;
+ struct vfsmount *mnt;
+
+ f = fdget_raw(mount_fd);
+ if (!f.file)
+ return -EBADF;
+
+ mnt = f.file->f_path.mnt;
+ if (!is_shmem_mount(mnt)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = mnt_want_write(mnt);
+ if (unlikely(ret))
+ goto out;
+
+ ret = restrictedmem_create(mnt);
+
+ mnt_drop_write(mnt);
+out:
+ fdput(f);
+
+ return ret;
+}
+
+SYSCALL_DEFINE2(memfd_restricted, unsigned int, flags, int, mount_fd)
+{
+ if (flags & ~RMFD_TMPFILE)
+ return -EINVAL;
+
+ if (flags == RMFD_TMPFILE) {
+ if (mount_fd < 0)
+ return -EINVAL;
+
+ return restrictedmem_create_from_file(mount_fd);
+ } else {
+ return restrictedmem_create(NULL);
+ }
+}
+
int restrictedmem_bind(struct file *file, pgoff_t start, pgoff_t end,
struct restrictedmem_notifier *notifier, bool exclusive)
{
--
2.40.0.rc2.332.ga46443480c-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH v2 2/2] selftests: restrictedmem: Check hugepage-ness of shmem file backing restrictedmem fd
2023-03-21 20:15 [RFC PATCH v2 0/2] Providing mount in memfd_restricted() syscall Ackerley Tng
2023-03-21 20:15 ` [RFC PATCH v2 1/2] mm: restrictedmem: Allow userspace to specify mount for memfd_restricted Ackerley Tng
@ 2023-03-21 20:15 ` Ackerley Tng
1 sibling, 0 replies; 5+ messages in thread
From: Ackerley Tng @ 2023-03-21 20:15 UTC (permalink / raw)
To: kvm, linux-api, linux-arch, linux-doc, linux-fsdevel,
linux-kernel, linux-mm, qemu-devel
Cc: aarcange, ak, akpm, arnd, bfields, bp, chao.p.peng, corbet,
dave.hansen, david, ddutile, dhildenb, hpa, hughd, jlayton,
jmattson, joro, jun.nakajima, kirill.shutemov, linmiaohe, luto,
mail, mhocko, michael.roth, mingo, naoya.horiguchi, pbonzini,
qperret, rppt, seanjc, shuah, steven.price, tabba, tglx,
vannapurve, vbabka, vkuznets, wanpengli, wei.w.wang, x86,
yu.c.zhang, Ackerley Tng
For memfd_restricted() calls without a userspace mount, the backing
file should be the shmem mount in the kernel, and the size of backing
pages should be as defined by system-wide shmem configuration.
If a userspace mount is provided, the size of backing pages should be
as defined in the mount.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
tools/testing/selftests/Makefile | 1 +
.../selftests/restrictedmem/.gitignore | 3 +
.../testing/selftests/restrictedmem/Makefile | 15 +
.../testing/selftests/restrictedmem/common.c | 9 +
.../testing/selftests/restrictedmem/common.h | 8 +
.../restrictedmem_hugepage_test.c | 459 ++++++++++++++++++
6 files changed, 495 insertions(+)
create mode 100644 tools/testing/selftests/restrictedmem/.gitignore
create mode 100644 tools/testing/selftests/restrictedmem/Makefile
create mode 100644 tools/testing/selftests/restrictedmem/common.c
create mode 100644 tools/testing/selftests/restrictedmem/common.h
create mode 100644 tools/testing/selftests/restrictedmem/restrictedmem_hugepage_test.c
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index f07aef7c592c..44078eeefb79 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -60,6 +60,7 @@ TARGETS += pstore
TARGETS += ptrace
TARGETS += openat2
TARGETS += resctrl
+TARGETS += restrictedmem
TARGETS += rlimits
TARGETS += rseq
TARGETS += rtc
diff --git a/tools/testing/selftests/restrictedmem/.gitignore b/tools/testing/selftests/restrictedmem/.gitignore
new file mode 100644
index 000000000000..2581bcc8ff29
--- /dev/null
+++ b/tools/testing/selftests/restrictedmem/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+restrictedmem_hugepage_test
diff --git a/tools/testing/selftests/restrictedmem/Makefile b/tools/testing/selftests/restrictedmem/Makefile
new file mode 100644
index 000000000000..8e5378d20226
--- /dev/null
+++ b/tools/testing/selftests/restrictedmem/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+
+CFLAGS = $(KHDR_INCLUDES)
+CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -std=gnu99
+
+TEST_GEN_PROGS += restrictedmem_hugepage_test
+
+include ../lib.mk
+
+EXTRA_CLEAN = $(OUTPUT)/common.o
+
+$(OUTPUT)/common.o: common.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -ffreestanding $< -o $@
+
+$(TEST_GEN_PROGS): $(OUTPUT)/common.o
diff --git a/tools/testing/selftests/restrictedmem/common.c b/tools/testing/selftests/restrictedmem/common.c
new file mode 100644
index 000000000000..03dac843404f
--- /dev/null
+++ b/tools/testing/selftests/restrictedmem/common.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <sys/syscall.h>
+#include <unistd.h>
+
+int memfd_restricted(unsigned int flags, int mount_fd)
+{
+ return syscall(__NR_memfd_restricted, flags, mount_fd);
+}
diff --git a/tools/testing/selftests/restrictedmem/common.h b/tools/testing/selftests/restrictedmem/common.h
new file mode 100644
index 000000000000..06284ed86baf
--- /dev/null
+++ b/tools/testing/selftests/restrictedmem/common.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SELFTESTS_RESTRICTEDMEM_COMMON_H
+#define SELFTESTS_RESTRICTEDMEM_COMMON_H
+
+int memfd_restricted(unsigned int flags, int mount_fd);
+
+#endif // SELFTESTS_RESTRICTEDMEM_COMMON_H
diff --git a/tools/testing/selftests/restrictedmem/restrictedmem_hugepage_test.c b/tools/testing/selftests/restrictedmem/restrictedmem_hugepage_test.c
new file mode 100644
index 000000000000..ae37148342fe
--- /dev/null
+++ b/tools/testing/selftests/restrictedmem/restrictedmem_hugepage_test.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define _GNU_SOURCE /* for O_PATH */
+#define _POSIX_C_SOURCE /* for PATH_MAX */
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "linux/restrictedmem.h"
+
+#include "common.h"
+#include "../kselftest_harness.h"
+
+/*
+ * Expect policy to be one of always, within_size, advise, never,
+ * deny, force
+ */
+#define POLICY_BUF_SIZE 12
+
+static int get_hpage_pmd_size(void)
+{
+ FILE *fp;
+ char buf[100];
+ char *ret;
+ int size;
+
+ fp = fopen("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", "r");
+ if (!fp)
+ return -1;
+
+ ret = fgets(buf, 100, fp);
+ if (ret != buf) {
+ size = -1;
+ goto out;
+ }
+
+ if (sscanf(buf, "%d\n", &size) != 1)
+ size = -1;
+
+out:
+ fclose(fp);
+
+ return size;
+}
+
+static bool is_valid_shmem_thp_policy(char *policy)
+{
+ if (strcmp(policy, "always") == 0)
+ return true;
+ if (strcmp(policy, "within_size") == 0)
+ return true;
+ if (strcmp(policy, "advise") == 0)
+ return true;
+ if (strcmp(policy, "never") == 0)
+ return true;
+ if (strcmp(policy, "deny") == 0)
+ return true;
+ if (strcmp(policy, "force") == 0)
+ return true;
+
+ return false;
+}
+
+static int get_shmem_thp_policy(char *policy)
+{
+ FILE *fp;
+ char buf[100];
+ char *left = NULL;
+ char *right = NULL;
+ int ret = -1;
+
+ fp = fopen("/sys/kernel/mm/transparent_hugepage/shmem_enabled", "r");
+ if (!fp)
+ return -1;
+
+ if (fgets(buf, 100, fp) != buf)
+ goto out;
+
+ /*
+ * Expect shmem_enabled to be of format like "always within_size advise
+ * [never] deny force"
+ */
+ left = memchr(buf, '[', 100);
+ if (!left)
+ goto out;
+
+ right = memchr(buf, ']', 100);
+ if (!right)
+ goto out;
+
+ memcpy(policy, left + 1, right - left - 1);
+
+ ret = !is_valid_shmem_thp_policy(policy);
+
+out:
+ fclose(fp);
+ return ret;
+}
+
+static int write_string_to_file(const char *path, const char *string)
+{
+ FILE *fp;
+ size_t len = strlen(string);
+ int ret = -1;
+
+ fp = fopen(path, "w");
+ if (!fp)
+ return ret;
+
+ if (fwrite(string, 1, len, fp) != len)
+ goto out;
+
+ ret = 0;
+
+out:
+ fclose(fp);
+ return ret;
+}
+
+static int set_shmem_thp_policy(char *policy)
+{
+ int ret = -1;
+ /* +1 for newline */
+ char to_write[POLICY_BUF_SIZE + 1] = { 0 };
+
+ if (!is_valid_shmem_thp_policy(policy))
+ return ret;
+
+ ret = snprintf(to_write, POLICY_BUF_SIZE + 1, "%s\n", policy);
+ if (ret != strlen(policy) + 1)
+ return -1;
+
+ ret = write_string_to_file(
+ "/sys/kernel/mm/transparent_hugepage/shmem_enabled", to_write);
+
+ return ret;
+}
+
+FIXTURE(reset_shmem_enabled)
+{
+ char shmem_enabled[POLICY_BUF_SIZE];
+};
+
+FIXTURE_SETUP(reset_shmem_enabled)
+{
+ memset(self->shmem_enabled, 0, POLICY_BUF_SIZE);
+ ASSERT_EQ(0, get_shmem_thp_policy(self->shmem_enabled));
+}
+
+FIXTURE_TEARDOWN(reset_shmem_enabled)
+{
+ ASSERT_EQ(0, set_shmem_thp_policy(self->shmem_enabled));
+}
+
+TEST_F(reset_shmem_enabled, restrictedmem_fstat_shmem_enabled_never)
+{
+ int fd = -1;
+ struct stat stat;
+
+ ASSERT_EQ(0, set_shmem_thp_policy("never"));
+
+ fd = memfd_restricted(0, -1);
+ ASSERT_NE(-1, fd);
+
+ ASSERT_EQ(0, fstat(fd, &stat));
+
+ /*
+ * st_blksize is set based on the superblock's s_blocksize_bits. For
+ * shmem, this is set to PAGE_SHIFT
+ */
+ ASSERT_EQ(stat.st_blksize, getpagesize());
+
+ close(fd);
+}
+
+TEST_F(reset_shmem_enabled, restrictedmem_fstat_shmem_enabled_always)
+{
+ int fd = -1;
+ struct stat stat;
+
+ ASSERT_EQ(0, set_shmem_thp_policy("always"));
+
+ fd = memfd_restricted(0, -1);
+ ASSERT_NE(-1, fd);
+
+ ASSERT_EQ(0, fstat(fd, &stat));
+
+ ASSERT_EQ(stat.st_blksize, get_hpage_pmd_size());
+
+ close(fd);
+}
+
+TEST(restrictedmem_tmpfile_invalid_fd)
+{
+ int fd = memfd_restricted(RMFD_TMPFILE, -2);
+
+ ASSERT_EQ(-1, fd);
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(restrictedmem_tmpfile_fd_not_a_mount)
+{
+ int fd = memfd_restricted(RMFD_TMPFILE, STDOUT_FILENO);
+
+ ASSERT_EQ(-1, fd);
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(restrictedmem_tmpfile_not_tmpfs_mount)
+{
+ int fd = -1;
+ int mfd = -1;
+
+ mfd = open("/proc", O_PATH);
+ ASSERT_NE(-1, mfd);
+
+ fd = memfd_restricted(RMFD_TMPFILE, mfd);
+
+ ASSERT_EQ(-1, fd);
+ ASSERT_EQ(EINVAL, errno);
+}
+
+FIXTURE(tmpfs_hugepage_sfd)
+{
+ int sfd;
+};
+
+FIXTURE_SETUP(tmpfs_hugepage_sfd)
+{
+ self->sfd = fsopen("tmpfs", 0);
+ ASSERT_NE(-1, self->sfd);
+}
+
+FIXTURE_TEARDOWN(tmpfs_hugepage_sfd)
+{
+ close(self->sfd);
+}
+
+TEST_F(tmpfs_hugepage_sfd, restrictedmem_fstat_tmpfs_huge_always)
+{
+ int ret = -1;
+ int fd = -1;
+ int mfd = -1;
+ struct stat stat;
+
+ fsconfig(self->sfd, FSCONFIG_SET_STRING, "huge", "always", 0);
+ fsconfig(self->sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
+
+ mfd = fsmount(self->sfd, 0, 0);
+ ASSERT_NE(-1, mfd);
+
+ fd = memfd_restricted(RMFD_TMPFILE, mfd);
+ ASSERT_NE(-1, fd);
+
+ /* User can close reference to mount */
+ ret = close(mfd);
+ ASSERT_EQ(0, ret);
+
+ ret = fstat(fd, &stat);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(stat.st_blksize, get_hpage_pmd_size());
+
+ close(fd);
+}
+
+TEST_F(tmpfs_hugepage_sfd, restrictedmem_fstat_tmpfs_huge_never)
+{
+ int ret = -1;
+ int fd = -1;
+ int mfd = -1;
+ struct stat stat;
+
+ fsconfig(self->sfd, FSCONFIG_SET_STRING, "huge", "never", 0);
+ fsconfig(self->sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
+
+ mfd = fsmount(self->sfd, 0, 0);
+ ASSERT_NE(-1, mfd);
+
+ fd = memfd_restricted(RMFD_TMPFILE, mfd);
+ ASSERT_NE(-1, fd);
+
+ /* User can close reference to mount */
+ ret = close(mfd);
+ ASSERT_EQ(0, ret);
+
+ ret = fstat(fd, &stat);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(stat.st_blksize, getpagesize());
+
+ close(fd);
+}
+
+static bool directory_exists(const char *path)
+{
+ struct stat sb;
+
+ return stat(path, &sb) == 0 && S_ISDIR(sb.st_mode);
+}
+
+FIXTURE(tmpfs_hugepage_mount_path)
+{
+ char *mount_path;
+};
+
+FIXTURE_SETUP(tmpfs_hugepage_mount_path)
+{
+ int ret = -1;
+
+ /* /tmp is an FHS-mandated world-writable directory */
+ self->mount_path = "/tmp/restrictedmem-selftest-mnt";
+
+ if (!directory_exists(self->mount_path)) {
+ ret = mkdir(self->mount_path, 0777);
+ ASSERT_EQ(0, ret);
+ }
+}
+
+FIXTURE_TEARDOWN(tmpfs_hugepage_mount_path)
+{
+ int ret = -1;
+
+ if (!directory_exists(self->mount_path))
+ return;
+
+ ret = umount2(self->mount_path, MNT_FORCE);
+ EXPECT_EQ(0, ret);
+ if (ret == -1 && errno == EINVAL)
+ fprintf(stderr, "%s was not mounted\n", self->mount_path);
+
+ ret = rmdir(self->mount_path);
+ EXPECT_EQ(0, ret);
+ if (ret == -1)
+ fprintf(stderr, "rmdir(%s) failed\n", self->mount_path);
+}
+
+/*
+ * When the restrictedmem's fd is open, a user should not be able to unmount or
+ * remove the mounted directory
+ */
+TEST_F(tmpfs_hugepage_mount_path, restrictedmem_umount_rmdir_while_file_open)
+{
+ int ret = -1;
+ int fd = -1;
+ int mfd = -1;
+ struct stat stat;
+
+ ret = mount("name", self->mount_path, "tmpfs", 0, "huge=always");
+ ASSERT_EQ(0, ret);
+
+ mfd = open(self->mount_path, O_PATH);
+ ASSERT_NE(-1, mfd);
+
+ fd = memfd_restricted(RMFD_TMPFILE, mfd);
+ ASSERT_NE(-1, fd);
+
+ /* We don't need this reference to the mount anymore */
+ ret = close(mfd);
+ ASSERT_EQ(0, ret);
+
+ /* restrictedmem's fd should still be usable */
+ ret = fstat(fd, &stat);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(stat.st_blksize, get_hpage_pmd_size());
+
+ /* User should not be able to unmount directory */
+ ret = umount2(self->mount_path, MNT_FORCE);
+ ASSERT_EQ(-1, ret);
+ ASSERT_EQ(EBUSY, errno);
+
+ ret = rmdir(self->mount_path);
+ ASSERT_EQ(-1, ret);
+ ASSERT_EQ(EBUSY, errno);
+
+ close(fd);
+}
+
+/* The fd of a file on the mount can be provided as mount_fd */
+TEST_F(tmpfs_hugepage_mount_path, restrictedmem_provide_fd_of_file)
+{
+ int ret = -1;
+ int fd = -1;
+ int ffd = -1;
+ char tmp_file_path[PATH_MAX] = { 0 };
+ struct stat stat;
+
+ ret = mount("name", self->mount_path, "tmpfs", 0, "huge=always");
+ ASSERT_EQ(0, ret);
+
+ snprintf(tmp_file_path, PATH_MAX, "%s/tmp-file", self->mount_path);
+ ret = write_string_to_file(tmp_file_path, "filler\n");
+ ASSERT_EQ(0, ret);
+
+ ffd = open(tmp_file_path, O_RDWR);
+ ASSERT_NE(-1, ffd);
+
+ fd = memfd_restricted(RMFD_TMPFILE, ffd);
+ ASSERT_NE(-1, fd);
+
+ /* We don't need this reference anymore */
+ ret = close(ffd);
+ ASSERT_EQ(0, ret);
+
+ ret = fstat(fd, &stat);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(stat.st_blksize, get_hpage_pmd_size());
+
+ close(fd);
+ remove(tmp_file_path);
+}
+
+/*
+ * The fd of any file on the mount (including subdirectories) can be provided as
+ * mount_fd
+ */
+TEST_F(tmpfs_hugepage_mount_path, restrictedmem_provide_fd_of_file_in_subdir)
+{
+ int ret = -1;
+ int fd = -1;
+ int ffd = -1;
+ char tmp_dir_path[PATH_MAX] = { 0 };
+ char tmp_file_path[PATH_MAX] = { 0 };
+ struct stat stat;
+
+ ret = mount("name", self->mount_path, "tmpfs", 0, "huge=always");
+ ASSERT_EQ(0, ret);
+
+ snprintf(tmp_dir_path, PATH_MAX, "%s/tmp-subdir", self->mount_path);
+ ret = mkdir(tmp_dir_path, 0777);
+ ASSERT_EQ(0, ret);
+
+ snprintf(tmp_file_path, PATH_MAX, "%s/tmp-subdir/tmp-file",
+ self->mount_path);
+ ret = write_string_to_file(tmp_file_path, "filler\n");
+ ASSERT_EQ(0, ret);
+
+ ffd = open(tmp_file_path, O_RDWR);
+ ASSERT_NE(-1, ffd);
+
+ fd = memfd_restricted(RMFD_TMPFILE, ffd);
+ ASSERT_NE(-1, fd);
+
+ /* We don't need this reference anymore */
+ ret = close(ffd);
+ ASSERT_EQ(0, ret);
+
+ ret = fstat(fd, &stat);
+ ASSERT_EQ(0, ret);
+ ASSERT_EQ(stat.st_blksize, get_hpage_pmd_size());
+
+ close(fd);
+ remove(tmp_file_path);
+ rmdir(tmp_dir_path);
+}
+
+TEST_HARNESS_MAIN
--
2.40.0.rc2.332.ga46443480c-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread