qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH 5/6] mm: restrictedmem: Add memfd_restricted_bind() syscall


From: Ackerley Tng
Subject: [RFC PATCH 5/6] mm: restrictedmem: Add memfd_restricted_bind() syscall
Date: Fri, 14 Apr 2023 00:11:54 +0000

memfd_restricted_bind() sets the NUMA memory policy, which consists of
a policy mode and zero or more nodes, for an offset within a
restrictedmem file with file descriptor fd and continuing for len
bytes.

This is intended to be like mbind() but specially for restrictedmem
files, which cannot be mmap()ed into userspace and hence has no memory
addresses that can be used with mbind().

Unlike mbind(), memfd_restricted_bind() will override any existing
memory policy if a new memory policy is defined for the same ranges.

For now, memfd_restricted_bind() does not perform migrations and no
flags are supported.

This syscall is specialised just for restrictedmem files because this
functionality is not required by other files.

Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
 arch/x86/entry/syscalls/syscall_32.tbl |  1 +
 arch/x86/entry/syscalls/syscall_64.tbl |  1 +
 include/linux/mempolicy.h              |  2 +-
 include/linux/syscalls.h               |  5 ++
 include/uapi/asm-generic/unistd.h      |  5 +-
 include/uapi/linux/mempolicy.h         |  7 ++-
 kernel/sys_ni.c                        |  1 +
 mm/restrictedmem.c                     | 75 ++++++++++++++++++++++++++
 scripts/checksyscalls.sh               |  1 +
 9 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/arch/x86/entry/syscalls/syscall_32.tbl 
b/arch/x86/entry/syscalls/syscall_32.tbl
index dc70ba90247e..c94e9ce46cc3 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -456,3 +456,4 @@
 449    i386    futex_waitv             sys_futex_waitv
 450    i386    set_mempolicy_home_node         sys_set_mempolicy_home_node
 451    i386    memfd_restricted        sys_memfd_restricted
+452    i386    memfd_restricted_bind   sys_memfd_restricted_bind
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl 
b/arch/x86/entry/syscalls/syscall_64.tbl
index 06516abc8318..6bd86b45d63a 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -373,6 +373,7 @@
 449    common  futex_waitv             sys_futex_waitv
 450    common  set_mempolicy_home_node sys_set_mempolicy_home_node
 451    common  memfd_restricted        sys_memfd_restricted
+452    common  memfd_restricted_bind   sys_memfd_restricted_bind
 
 #
 # Due to a historical design error, certain syscalls are numbered differently
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index 15facd9de087..af62233df0c0 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -126,7 +126,7 @@ struct shared_policy {
 
 int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst);
 struct mempolicy *mpol_create(
-       unsigned long mode, const unsigned long __user *nmask, unsigned long 
maxnode)
+       unsigned long mode, const unsigned long __user *nmask, unsigned long 
maxnode);
 void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol);
 int __mpol_set_shared_policy(struct shared_policy *info, struct mempolicy 
*mpol,
                             unsigned long pgoff_start, unsigned long npages);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 660be0bf89d5..852b202d3837 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -1059,6 +1059,11 @@ asmlinkage long sys_set_mempolicy_home_node(unsigned 
long start, unsigned long l
                                            unsigned long home_node,
                                            unsigned long flags);
 asmlinkage long sys_memfd_restricted(unsigned int flags);
+asmlinkage long sys_memfd_restricted_bind(int fd, struct file_range __user 
*range,
+                                         unsigned long mode,
+                                         const unsigned long __user *nmask,
+                                         unsigned long maxnode,
+                                         unsigned int flags);
 
 /*
  * Architecture-specific system calls
diff --git a/include/uapi/asm-generic/unistd.h 
b/include/uapi/asm-generic/unistd.h
index e2ea7cd964f8..b5a1385bb4a7 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -889,10 +889,13 @@ __SYSCALL(__NR_set_mempolicy_home_node, 
sys_set_mempolicy_home_node)
 #ifdef __ARCH_WANT_MEMFD_RESTRICTED
 #define __NR_memfd_restricted 451
 __SYSCALL(__NR_memfd_restricted, sys_memfd_restricted)
+
+#define __NR_memfd_restricted_bind 452
+__SYSCALL(__NR_memfd_restricted_bind, sys_memfd_restricted_bind)
 #endif
 
 #undef __NR_syscalls
-#define __NR_syscalls 452
+#define __NR_syscalls 453
 
 /*
  * 32 bit systems traditionally used different
diff --git a/include/uapi/linux/mempolicy.h b/include/uapi/linux/mempolicy.h
index 046d0ccba4cd..979499abd253 100644
--- a/include/uapi/linux/mempolicy.h
+++ b/include/uapi/linux/mempolicy.h
@@ -6,9 +6,9 @@
 #ifndef _UAPI_LINUX_MEMPOLICY_H
 #define _UAPI_LINUX_MEMPOLICY_H
 
+#include <asm-generic/posix_types.h>
 #include <linux/errno.h>
 
-
 /*
  * Both the MPOL_* mempolicy mode and the MPOL_F_* optional mode flags are
  * passed by the user to either set_mempolicy() or mbind() in an 'int' actual.
@@ -72,4 +72,9 @@ enum {
 #define RECLAIM_WRITE  (1<<1)  /* Writeout pages during reclaim */
 #define RECLAIM_UNMAP  (1<<2)  /* Unmap pages during reclaim */
 
+struct file_range {
+       __kernel_loff_t offset;
+       __kernel_size_t len;
+};
+
 #endif /* _UAPI_LINUX_MEMPOLICY_H */
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 7c4a32cbd2e7..db24d3fe6dc5 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -362,6 +362,7 @@ COND_SYSCALL(memfd_secret);
 
 /* memfd_restricted */
 COND_SYSCALL(memfd_restricted);
+COND_SYSCALL(memfd_restricted_bind);
 
 /*
  * Architecture specific weak syscall entries.
diff --git a/mm/restrictedmem.c b/mm/restrictedmem.c
index 55e99e6c09a1..9c249722c61b 100644
--- a/mm/restrictedmem.c
+++ b/mm/restrictedmem.c
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/mempolicy.h>
 #include "linux/sbitmap.h"
 #include <linux/pagemap.h>
 #include <linux/pseudo_fs.h>
@@ -359,3 +360,77 @@ int restrictedmem_get_page(struct file *file, pgoff_t 
offset,
        return 0;
 }
 EXPORT_SYMBOL_GPL(restrictedmem_get_page);
+
+static int restrictedmem_set_shared_policy(
+       struct file *file, loff_t start, size_t len, struct mempolicy *mpol)
+{
+       struct restrictedmem *rm;
+       unsigned long end;
+
+       if (!PAGE_ALIGNED(start))
+               return -EINVAL;
+
+       len = PAGE_ALIGN(len);
+       end = start + len;
+
+       if (end < start)
+               return -EINVAL;
+       if (end == start)
+               return 0;
+
+       rm = file->f_mapping->private_data;
+       return __mpol_set_shared_policy(shmem_shared_policy(rm->memfd), mpol,
+                                       start >> PAGE_SHIFT, len >> PAGE_SHIFT);
+}
+
+static long do_memfd_restricted_bind(
+       int fd, loff_t offset, size_t len,
+       unsigned long mode, const unsigned long __user *nmask,
+       unsigned long maxnode, unsigned int flags)
+{
+       long ret;
+       struct fd f;
+       struct mempolicy *mpol;
+
+       /* None of the flags are supported */
+       if (flags)
+               return -EINVAL;
+
+       f = fdget_raw(fd);
+       if (!f.file)
+               return -EBADF;
+
+       if (!file_is_restrictedmem(f.file))
+               return -EINVAL;
+
+       mpol = mpol_create(mode, nmask, maxnode);
+       if (IS_ERR(mpol)) {
+               ret = PTR_ERR(mpol);
+               goto out;
+       }
+
+       ret = restrictedmem_set_shared_policy(f.file, offset, len, mpol);
+
+       mpol_put(mpol);
+
+out:
+       fdput(f);
+
+       return ret;
+}
+
+SYSCALL_DEFINE6(memfd_restricted_bind, int, fd, struct file_range __user *, 
range,
+               unsigned long, mode, const unsigned long __user *, nmask,
+               unsigned long, maxnode, unsigned int, flags)
+{
+       loff_t offset;
+       size_t len;
+
+       if (unlikely(get_user(offset, &range->offset)))
+               return -EFAULT;
+       if (unlikely(get_user(len, &range->len)))
+               return -EFAULT;
+
+       return do_memfd_restricted_bind(fd, offset, len, mode, nmask,
+                                           maxnode, flags);
+}
diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh
index 3c4d2508226a..e253529cf1ec 100755
--- a/scripts/checksyscalls.sh
+++ b/scripts/checksyscalls.sh
@@ -46,6 +46,7 @@ cat << EOF
 
 #ifndef __ARCH_WANT_MEMFD_RESTRICTED
 #define __IGNORE_memfd_restricted
+#define __IGNORE_memfd_restricted_bind
 #endif
 
 /* Missing flags argument */
-- 
2.40.0.634.g4ca3ef3211-goog




reply via email to

[Prev in Thread] Current Thread [Next in Thread]