From patchwork Wed Jan 9 16:40:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Penyaev X-Patchwork-Id: 10754501 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2BBD513BF for ; Wed, 9 Jan 2019 16:40:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1C5BE29418 for ; Wed, 9 Jan 2019 16:40:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1AAD429439; Wed, 9 Jan 2019 16:40:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ED57D29460 for ; Wed, 9 Jan 2019 16:40:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726663AbfAIQkp (ORCPT ); Wed, 9 Jan 2019 11:40:45 -0500 Received: from mx2.suse.de ([195.135.220.15]:57778 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726642AbfAIQko (ORCPT ); Wed, 9 Jan 2019 11:40:44 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id B39C1B01C; Wed, 9 Jan 2019 16:40:42 +0000 (UTC) From: Roman Penyaev Cc: Roman Penyaev , Andrew Morton , Davidlohr Bueso , Jason Baron , Al Viro , "Paul E. McKenney" , Linus Torvalds , Andrea Parri , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 15/15] epoll: support mapping for epfd when polled from userspace Date: Wed, 9 Jan 2019 17:40:25 +0100 Message-Id: <20190109164025.24554-16-rpenyaev@suse.de> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20190109164025.24554-1-rpenyaev@suse.de> References: <20190109164025.24554-1-rpenyaev@suse.de> MIME-Version: 1.0 To: unlisted-recipients:; (no To-header on input) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP User has to mmap user_header and user_index vmalloce'd pointers in order to consume events from userspace. Support mapping with possibility to mremap() in the future, i.e. vma does not have VM_DONTEXPAND flag set. User mmaps two pointers: header and index in order to expand both calling mremap(). Expanding is made with support of the fault callback, where page is mmaped with all appropriate size checks. Signed-off-by: Roman Penyaev Cc: Andrew Morton Cc: Davidlohr Bueso Cc: Jason Baron Cc: Al Viro Cc: "Paul E. McKenney" Cc: Linus Torvalds Cc: Andrea Parri Cc: linux-fsdevel@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- fs/eventpoll.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 5de640fcf28b..2849b238f80b 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1388,11 +1388,96 @@ static void ep_show_fdinfo(struct seq_file *m, struct file *f) } #endif +static vm_fault_t ep_eventpoll_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct eventpoll *ep = vma->vm_file->private_data; + size_t off = vmf->address - vma->vm_start; + vm_fault_t ret; + int rc; + + mutex_lock(&ep->mtx); + ret = VM_FAULT_SIGBUS; + if (!vma->vm_pgoff) { + if (ep->header_length < (off + PAGE_SIZE)) + goto unlock_and_out; + + rc = remap_vmalloc_range_partial(vma, vmf->address, + ep->user_header + off, + PAGE_SIZE); + } else { + if (ep->index_length < (off + PAGE_SIZE)) + goto unlock_and_out; + + rc = remap_vmalloc_range_partial(vma, vmf->address, + ep->user_index + off, + PAGE_SIZE); + } + if (likely(!rc)) { + /* Success path */ + vma->vm_flags &= ~VM_DONTEXPAND; + ret = VM_FAULT_NOPAGE; + } +unlock_and_out: + mutex_unlock(&ep->mtx); + + return ret; +} + +static const struct vm_operations_struct eventpoll_vm_ops = { + .fault = ep_eventpoll_fault, +}; + +static int ep_eventpoll_mmap(struct file *filep, struct vm_area_struct *vma) +{ + struct eventpoll *ep = vma->vm_file->private_data; + size_t size; + int rc; + + if (!ep_polled_by_user(ep)) + return -ENOTSUPP; + + mutex_lock(&ep->mtx); + rc = -ENXIO; + size = vma->vm_end - vma->vm_start; + if (!vma->vm_pgoff && size > ep->header_length) + goto unlock_and_out; + if (vma->vm_pgoff && ep->header_length != (vma->vm_pgoff << PAGE_SHIFT)) + /* + * Index ring starts exactly after header. In future vm_pgoff + * is not used, only as indication what kernel ptr is mapped. + */ + goto unlock_and_out; + if (vma->vm_pgoff && size > ep->index_length) + goto unlock_and_out; + + /* + * vm_pgoff is used *only* for indication, what is mapped: user header + * or user index ring. + */ + if (!vma->vm_pgoff) + rc = remap_vmalloc_range_partial(vma, vma->vm_start, + ep->user_header, size); + else + rc = remap_vmalloc_range_partial(vma, vma->vm_start, + ep->user_index, size); + + if (likely(!rc)) { + vma->vm_flags &= ~VM_DONTEXPAND; + vma->vm_ops = &eventpoll_vm_ops; + } +unlock_and_out: + mutex_unlock(&ep->mtx); + + return rc; +} + /* File callbacks that implement the eventpoll file behaviour */ static const struct file_operations eventpoll_fops = { #ifdef CONFIG_PROC_FS .show_fdinfo = ep_show_fdinfo, #endif + .mmap = ep_eventpoll_mmap, .release = ep_eventpoll_release, .poll = ep_eventpoll_poll, .llseek = noop_llseek,