mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
shm: add memfd_create() syscall
memfd_create() is similar to mmap(MAP_ANON), but returns a file-descriptor that you can pass to mmap(). It can support sealing and avoids any connection to user-visible mount-points. Thus, it's not subject to quotas on mounted file-systems, but can be used like malloc()'ed memory, but with a file-descriptor to it. memfd_create() returns the raw shmem file, so calls like ftruncate() can be used to modify the underlying inode. Also calls like fstat() will return proper information and mark the file as regular file. If you want sealing, you can specify MFD_ALLOW_SEALING. Otherwise, sealing is not supported (like on all other regular files). Compared to O_TMPFILE, it does not require a tmpfs mount-point and is not subject to a filesystem size limit. It is still properly accounted to memcg limits, though, and to the same overcommit or no-overcommit accounting as all user memory. Signed-off-by: David Herrmann <[email protected]> Acked-by: Hugh Dickins <[email protected]> Cc: Michael Kerrisk <[email protected]> Cc: Ryan Lortie <[email protected]> Cc: Lennart Poettering <[email protected]> Cc: Daniel Mack <[email protected]> Cc: Andy Lutomirski <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
40e041a2c8
commit
9183df25fe
6 changed files with 85 additions and 0 deletions
73
mm/shmem.c
73
mm/shmem.c
|
|
@ -66,7 +66,9 @@ static struct vfsmount *shm_mnt;
|
|||
#include <linux/highmem.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <uapi/linux/memfd.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
|
@ -2732,6 +2734,77 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root)
|
|||
shmem_show_mpol(seq, sbinfo->mpol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MFD_NAME_PREFIX "memfd:"
|
||||
#define MFD_NAME_PREFIX_LEN (sizeof(MFD_NAME_PREFIX) - 1)
|
||||
#define MFD_NAME_MAX_LEN (NAME_MAX - MFD_NAME_PREFIX_LEN)
|
||||
|
||||
#define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING)
|
||||
|
||||
SYSCALL_DEFINE2(memfd_create,
|
||||
const char __user *, uname,
|
||||
unsigned int, flags)
|
||||
{
|
||||
struct shmem_inode_info *info;
|
||||
struct file *file;
|
||||
int fd, error;
|
||||
char *name;
|
||||
long len;
|
||||
|
||||
if (flags & ~(unsigned int)MFD_ALL_FLAGS)
|
||||
return -EINVAL;
|
||||
|
||||
/* length includes terminating zero */
|
||||
len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1);
|
||||
if (len <= 0)
|
||||
return -EFAULT;
|
||||
if (len > MFD_NAME_MAX_LEN + 1)
|
||||
return -EINVAL;
|
||||
|
||||
name = kmalloc(len + MFD_NAME_PREFIX_LEN, GFP_TEMPORARY);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy(name, MFD_NAME_PREFIX);
|
||||
if (copy_from_user(&name[MFD_NAME_PREFIX_LEN], uname, len)) {
|
||||
error = -EFAULT;
|
||||
goto err_name;
|
||||
}
|
||||
|
||||
/* terminating-zero may have changed after strnlen_user() returned */
|
||||
if (name[len + MFD_NAME_PREFIX_LEN - 1]) {
|
||||
error = -EFAULT;
|
||||
goto err_name;
|
||||
}
|
||||
|
||||
fd = get_unused_fd_flags((flags & MFD_CLOEXEC) ? O_CLOEXEC : 0);
|
||||
if (fd < 0) {
|
||||
error = fd;
|
||||
goto err_name;
|
||||
}
|
||||
|
||||
file = shmem_file_setup(name, 0, VM_NORESERVE);
|
||||
if (IS_ERR(file)) {
|
||||
error = PTR_ERR(file);
|
||||
goto err_fd;
|
||||
}
|
||||
info = SHMEM_I(file_inode(file));
|
||||
file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
|
||||
file->f_flags |= O_RDWR | O_LARGEFILE;
|
||||
if (flags & MFD_ALLOW_SEALING)
|
||||
info->seals &= ~F_SEAL_SEAL;
|
||||
|
||||
fd_install(fd, file);
|
||||
kfree(name);
|
||||
return fd;
|
||||
|
||||
err_fd:
|
||||
put_unused_fd(fd);
|
||||
err_name:
|
||||
kfree(name);
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TMPFS */
|
||||
|
||||
static void shmem_put_super(struct super_block *sb)
|
||||
|
|
|
|||
Loading…
Reference in a new issue