Received: by 10.223.148.5 with SMTP id 5csp6278420wrq; Wed, 17 Jan 2018 11:38:48 -0800 (PST) X-Google-Smtp-Source: ACJfBouhn4jGBWX0vjNd/+ppo8jtePqkVGt0YekJmuGL4yCFd7EKCRgpCP8xq3DcXXukSnS6i0oT X-Received: by 10.98.51.130 with SMTP id z124mr38519136pfz.21.1516217928259; Wed, 17 Jan 2018 11:38:48 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516217928; cv=none; d=google.com; s=arc-20160816; b=fq6cuWDFvlj7k3S48UmRnJhI7roWWz3pw2NkpabLIlAAvXRtmNUdvZw0hildOtK3yw w0cVOkTlXh3ZTYeLxFdcVAof2PU+W9wcd2I49X3+6oghATPP4jjtwJPgc96Ykw/C3Vvp QnO6vOreCq0ONehaR0LLSR5q4XwjIwEa/ojH0Htioj7WlxBXF1ncuLM6H1htxNImfC0o WWgF4Ie/DCWrvjusJ8am8/gM6r2FSc88tmPOH6ywd+fn3tKEo2d0/x5hS6B4YUPelijR cN7dom5xE1v+xdqvzA0O1tBltBvo8XBo5Xv/Rd3+bBuz279/ZjZNXrJPINpGDu/DiXB9 ZVjg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=dyZ9XpMl9dpYYtMZyNFHam9MRQVQsWQixLW6gmwoanQ=; b=pa/Fv7CvUSJjQ6RbqAI4TM8IZcO7dA3OfFeO8WnG75DhXkk4PWO1EdbHehZx4IeZ2m 4VE/V7IOuHztCl+cxbVe9oX3NrxO8djeTF4cEKbDHrdm8Eo6lf/7dk+Aez0wnxOQUe9j Gxl8PJ6Q1ibKW6ghpV6FPLoMXLTB206vSrvhboNNwyMzraLxui+hv6ab6/f/030X/jC+ Zs6WjfgQCbLbeSy2MHG3GjJANANmAyAQtKSNxqACk0y+sABM39XS/L79FsmGTobNDTs4 l8yCok9Go7O6bl6gHMfG4O/L4RePqaywbmZm3I3cZQflh/BDn3+keRuZdErGZhh/wttF P29A== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@infradead.org header.s=bombadil.20170209 header.b=PFUU4vdK; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v10si2353973ply.79.2018.01.17.11.38.33; Wed, 17 Jan 2018 11:38:48 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@infradead.org header.s=bombadil.20170209 header.b=PFUU4vdK; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753600AbeAQT2g (ORCPT + 99 others); Wed, 17 Jan 2018 14:28:36 -0500 Received: from bombadil.infradead.org ([65.50.211.133]:38887 "EHLO bombadil.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753545AbeAQT2b (ORCPT ); Wed, 17 Jan 2018 14:28:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20170209; h=References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=dyZ9XpMl9dpYYtMZyNFHam9MRQVQsWQixLW6gmwoanQ=; b=PFUU4vdKESLQRNJ7sNQ3aH69e tV4SV4MtaHBMk/Rdn45cwz1U9qg5RVwdXnUyAWI5pZ9DoyYB6NjXCigwWH1nITtRynPqtJ4Ct37el eSXPYyM6PNAo6Z1B8rcjiPJO+Ulb3WtcVcz4yAnWeZ0FtP88L7IrfV5gkGkA0FaGrl0hq6TD2WVPT Vj4bZtKI2fZzavEdELXg+3uQV9dqGGvVnBqcRLy9Q3cbHpSbfU42VsrrXlhjlXOelIvxD8OCMAbDz TAsLlvkt1n6eyZHq47lqXfoPlnwNQ4ZBK60NqhvFzUHgVdwhX7kQsO4bWwOpQHrz9VNQvXyf7WLTJ NoAvA5f/w==; Received: from 77.117.185.35.wireless.dyn.drei.com ([77.117.185.35] helo=localhost) by bombadil.infradead.org with esmtpsa (Exim 4.89 #1 (Red Hat Linux)) id 1ebtNt-00033x-R7; Wed, 17 Jan 2018 19:28:30 +0000 From: Christoph Hellwig To: viro@zeniv.linux.org.uk Cc: Avi Kivity , linux-aio@kvack.org, linux-fsdevel@vger.kernel.org, netdev@vger.kernel.org, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 13/36] fs: introduce new ->get_poll_head and ->poll_mask methods Date: Wed, 17 Jan 2018 20:27:19 +0100 Message-Id: <20180117192742.710-14-hch@lst.de> X-Mailer: git-send-email 2.14.2 In-Reply-To: <20180117192742.710-1-hch@lst.de> References: <20180117192742.710-1-hch@lst.de> X-SRS-Rewrite: SMTP reverse-path rewritten from by bombadil.infradead.org. See http://www.infradead.org/rpr.html Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org ->get_poll_head returns the waitqueue that the poll operation is going to sleep on. Note that this means we can only use a single waitqueue for the poll, unlike some current drivers that use two waitqueues for different events. But now that we have keyed wakeups and heavily use those for poll there aren't that many good reason left to keep the multiple waitqueues, and if there are any ->poll is still around, the driver just won't support aio poll. ->poll_mask is called before going to sleep to check for already pending events, and after the wakeup to return the actual mask of events reported by poll. It can be called with the waitqueue lock held to gurantee race free checking for events and to be called from the waitqueue wake callback, but the legacy callers don't hold it yet. Signed-off-by: Christoph Hellwig --- Documentation/filesystems/Locking | 7 ++++++- Documentation/filesystems/vfs.txt | 11 +++++++++++ fs/select.c | 29 +++++++++++++++++++++++++++++ include/linux/fs.h | 2 ++ include/linux/poll.h | 19 +++++++++++++++---- 5 files changed, 63 insertions(+), 5 deletions(-) diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 220bba28f72b..6d227f9d7bd9 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -440,6 +440,8 @@ prototypes: ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); __poll_t (*poll) (struct file *, struct poll_table_struct *); + struct wait_queue_head * (*get_poll_head)(struct file *, __poll_t); + __poll_t (*poll_mask) (struct file *, __poll_t); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); @@ -470,7 +472,7 @@ prototypes: }; locking rules: - All may block. + All except for ->poll_mask may block. ->llseek() locking has moved from llseek to the individual llseek implementations. If your fs is not using generic_file_llseek, you @@ -498,6 +500,9 @@ in sys_read() and friends. the lease within the individual filesystem to record the result of the operation +->poll_mask can be called with or without the waitqueue lock for the waitqueue +returned from ->get_poll_head. + --------------------------- dquot_operations ------------------------------- prototypes: int (*write_dquot) (struct dquot *); diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index f608180ad59d..17e0355be7d1 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -857,6 +857,8 @@ struct file_operations { ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); __poll_t (*poll) (struct file *, struct poll_table_struct *); + struct wait_queue_head * (*get_poll_head)(struct file *, __poll_t); + __poll_t (*poll_mask) (struct file *, __poll_t); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); @@ -901,6 +903,15 @@ otherwise noted. activity on this file and (optionally) go to sleep until there is activity. Called by the select(2) and poll(2) system calls + get_poll_head: Returns the struct wait_queue_head that poll, select, + epoll or aio poll should wait on in case this instance only has single + waitqueue. Can return NULL to indicate polling is not supported. + + poll_mask: return the mask of POLL* values describing the file descriptor + state. Called before going to sleep on the waitqueue returned by + get_poll_head, and after it has been woken. If ->get_poll_head and + ->poll_mask are implemented ->poll does not need to be implement. + unlocked_ioctl: called by the ioctl(2) system call. compat_ioctl: called by the ioctl(2) system call when 32 bit system calls diff --git a/fs/select.c b/fs/select.c index e96f1342c2f6..707abe79536b 100644 --- a/fs/select.c +++ b/fs/select.c @@ -34,6 +34,35 @@ #include +__poll_t vfs_poll(struct file *file, struct poll_table_struct *pt) +{ + unsigned int events = poll_requested_events(pt), mask; + struct wait_queue_head *head; + + if (unlikely(!file_can_poll(file))) + return DEFAULT_POLLMASK; + + if (file->f_op->poll) + return file->f_op->poll(file, pt); + + /* + * Only get the poll head and do the first mask check if we are actually + * going to sleep on this file: + */ + if (pt && pt->_qproc) { + head = vfs_get_poll_head(file, events); + if (!head) + return DEFAULT_POLLMASK; + mask = file->f_op->poll_mask(file, events); + if (mask) + return mask; + + pt->_qproc(file, head, pt); + } + + return file->f_op->poll_mask(file, events); +} +EXPORT_SYMBOL_GPL(vfs_poll); /* * Estimate expected accuracy in ns from a timeval. diff --git a/include/linux/fs.h b/include/linux/fs.h index 34c0434511c7..f7dd8eb1eb85 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1699,6 +1699,8 @@ struct file_operations { int (*iterate) (struct file *, struct dir_context *); int (*iterate_shared) (struct file *, struct dir_context *); __poll_t (*poll) (struct file *, struct poll_table_struct *); + struct wait_queue_head * (*get_poll_head)(struct file *, __poll_t); + __poll_t (*poll_mask) (struct file *, __poll_t); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); diff --git a/include/linux/poll.h b/include/linux/poll.h index 7afd259c570f..7ce8b7f902cd 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h @@ -75,16 +75,27 @@ static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc) static inline bool file_can_poll(struct file *file) { - return file->f_op->poll; + return file->f_op->poll || + (file->f_op->get_poll_head && file->f_op->poll_mask); } -static inline __poll_t vfs_poll(struct file *file, struct poll_table_struct *pt) +static inline struct wait_queue_head *vfs_get_poll_head(struct file *file, + __poll_t events) { - if (unlikely(!file->f_op->poll)) + if (unlikely(!file->f_op->get_poll_head || !file->f_op->poll_mask)) + return NULL; + return file->f_op->get_poll_head(file, events); +} + +static inline __poll_t vfs_poll_mask(struct file *file, __poll_t events) +{ + if (unlikely(!file->f_op->poll_mask)) return DEFAULT_POLLMASK; - return file->f_op->poll(file, pt); + return file->f_op->poll_mask(file, events) & events; } +__poll_t vfs_poll(struct file *file, struct poll_table_struct *pt); + struct poll_table_entry { struct file *filp; __poll_t key; -- 2.14.2