diff --git a/fs/exec.c b/fs/exec.c index 371f96c3d5b8651283ec178e348221eb71094362..17e11c9bfa3054431b70db80b8fdac6322fc15a5 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1685,10 +1685,24 @@ static int bprm_creds_from_file(struct linux_binprm *bprm) */ static int prepare_binprm(struct linux_binprm *bprm) { + unsigned int flags = 0; loff_t pos = 0; + int ret; + + /* + * Update task flag with PF_MCS to enable mcs support during + * reading binrpm + */ + if (IS_ENABLED(CONFIG_ARM64) && IS_ENABLED(CONFIG_ARCH_HAS_COPY_MC) && + !(current->flags & PF_MCS)) + flags = PF_MCS; + current->flags |= flags; memset(bprm->buf, 0, BINPRM_BUF_SIZE); - return kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, &pos); + ret = kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, &pos); + current->flags &= ~flags; + + return ret; } /* diff --git a/include/linux/uio.h b/include/linux/uio.h index cedb68e49e4f9830173dbb983f16c0f6bd3ca4a9..1bf0a426ef02429a4260dd13f6f836b0ff552519 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -141,6 +141,8 @@ size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i); bool _copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i); size_t _copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i); bool _copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i); +size_t copy_mc_page_to_kvec_iter(struct page *page, size_t offset, size_t bytes, + struct iov_iter *i); static __always_inline __must_check size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) diff --git a/lib/iov_iter.c b/lib/iov_iter.c index ce8c225237f56e9e160fe2524f44c9fcd7371401..15b373f2e5084258da366a47aa739161fc63af59 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -908,6 +908,24 @@ static inline bool page_copy_sane(struct page *page, size_t offset, size_t n) return false; } +size_t copy_mc_page_to_kvec_iter(struct page *page, size_t offset, size_t bytes, + struct iov_iter *i) +{ + size_t wanted; + void *kaddr; + + if (unlikely(!page_copy_sane(page, offset, bytes))) + return 0; + + if (!(i->type & ITER_KVEC)) + return 0; + + kaddr = kmap_atomic(page); + wanted = copy_mc_to_iter(kaddr + offset, bytes, i); + kunmap_atomic(kaddr); + return wanted; +} + size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, struct iov_iter *i) { diff --git a/mm/shmem.c b/mm/shmem.c index 9cb612d1153bf2e5438e9f14f6d1c9b1d7bfa817..a5e7ed01943b63b50236c05feeadfdaf2c6252b7 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2601,10 +2601,15 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to) int error = 0; ssize_t retval = 0; loff_t *ppos = &iocb->ki_pos; + bool use_copy_mc = false; index = *ppos >> PAGE_SHIFT; offset = *ppos & ~PAGE_MASK; + if (IS_ENABLED(CONFIG_ARM64) && IS_ENABLED(CONFIG_ARCH_HAS_COPY_MC) && + (current->flags & PF_MCS) && iov_iter_is_kvec(to)) + use_copy_mc = true; + for (;;) { struct page *page = NULL; pgoff_t end_index; @@ -2664,7 +2669,10 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to) * Ok, we have the page, and it's up-to-date, so * now we can copy it to user space... */ - ret = copy_page_to_iter(page, offset, nr, to); + if (use_copy_mc) + ret = copy_mc_page_to_kvec_iter(page, offset, nr, to); + else + ret = copy_page_to_iter(page, offset, nr, to); put_page(page); } else if (iter_is_iovec(to)) {