Add an ioctl for mapping objects within an mshare region. The arguments are the same as mmap(). Only shared anonymous memory mapped with MAP_FIXED is supported initially. Signed-off-by: Anthony Yznaga <anthony.yznaga@xxxxxxxxxx> --- include/uapi/linux/msharefs.h | 9 +++++ mm/mshare.c | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/include/uapi/linux/msharefs.h b/include/uapi/linux/msharefs.h index c7b509c7e093..fea0afdf000d 100644 --- a/include/uapi/linux/msharefs.h +++ b/include/uapi/linux/msharefs.h @@ -20,10 +20,19 @@ */ #define MSHAREFS_GET_SIZE _IOR('x', 0, struct mshare_info) #define MSHAREFS_SET_SIZE _IOW('x', 1, struct mshare_info) +#define MSHAREFS_CREATE_MAPPING _IOW('x', 2, struct mshare_create) struct mshare_info { __u64 start; __u64 size; }; +struct mshare_create { + __u64 addr; + __u64 size; + __u64 offset; + __u32 prot; + __u32 flags; + __u32 fd; +}; #endif diff --git a/mm/mshare.c b/mm/mshare.c index 9ada1544aeb1..d70f10210b46 100644 --- a/mm/mshare.c +++ b/mm/mshare.c @@ -194,12 +194,60 @@ msharefs_set_size(struct mm_struct *host_mm, struct mshare_data *m_data, return 0; } +static long +msharefs_create_mapping(struct mm_struct *host_mm, struct mshare_data *m_data, + struct mshare_create *mcreate) +{ + unsigned long mshare_start, mshare_end; + unsigned long mapped_addr; + unsigned long populate = 0; + unsigned long addr = mcreate->addr; + unsigned long size = mcreate->size; + unsigned int fd = mcreate->fd; + int prot = mcreate->prot; + int flags = mcreate->flags; + vm_flags_t vm_flags; + int err = -EINVAL; + + mshare_start = m_data->minfo.start; + mshare_end = mshare_start + m_data->minfo.size; + + if ((addr < mshare_start) || (addr >= mshare_end) || + (addr + size > mshare_end)) + goto out; + + /* + * Only anonymous shared memory at fixed addresses is allowed for now. + */ + if ((flags & (MAP_SHARED | MAP_FIXED)) != (MAP_SHARED | MAP_FIXED)) + goto out; + if (fd != -1) + goto out; + + if (mmap_write_lock_killable(host_mm)) { + err = -EINTR; + goto out; + } + + err = 0; + mapped_addr = __do_mmap(NULL, addr, size, prot, flags, vm_flags, + 0, &populate, NULL, host_mm); + + if (IS_ERR_VALUE(mapped_addr)) + err = (long)mapped_addr; + + mmap_write_unlock(host_mm); +out: + return err; +} + static long msharefs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct mshare_data *m_data = filp->private_data; struct mm_struct *host_mm = m_data->mm; struct mshare_info minfo; + struct mshare_create mcreate; switch (cmd) { case MSHAREFS_GET_SIZE: @@ -228,6 +276,23 @@ msharefs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return msharefs_set_size(host_mm, m_data, &minfo); + case MSHAREFS_CREATE_MAPPING: + if (copy_from_user(&mcreate, (struct mshare_create __user *)arg, + sizeof(mcreate))) + return -EFAULT; + + /* + * validate mshare region + */ + spin_lock(&m_data->m_lock); + if (m_data->minfo.size == 0) { + spin_unlock(&m_data->m_lock); + return -EINVAL; + } + spin_unlock(&m_data->m_lock); + + return msharefs_create_mapping(host_mm, m_data, &mcreate); + default: return -ENOTTY; } -- 2.43.5