From patchwork Tue Dec 20 15:20:07 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amir Goldstein X-Patchwork-Id: 9481691 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4CBE260820 for ; Tue, 20 Dec 2016 15:20:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3F6D127F8C for ; Tue, 20 Dec 2016 15:20:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 34156284DD; Tue, 20 Dec 2016 15:20:56 +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=-6.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=unavailable 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 C3DC7283F0 for ; Tue, 20 Dec 2016 15:20:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758407AbcLTPUf (ORCPT ); Tue, 20 Dec 2016 10:20:35 -0500 Received: from mail-wm0-f68.google.com ([74.125.82.68]:35472 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758324AbcLTPUb (ORCPT ); Tue, 20 Dec 2016 10:20:31 -0500 Received: by mail-wm0-f68.google.com with SMTP id a20so25030745wme.2; Tue, 20 Dec 2016 07:20:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ht0EP2kijG2OFZYuwQ/PKC99Mcaqn9wbOdQiLxF23lg=; b=VOqya1CNxzEmwFC8AOwoot+lyDp0zlWCEZq2Q63LfK45AkAKheDxrKK0I06gdN2Roz uA+uPgFCTgx9ePIjX3FekBsB/+CBBUAdo7AbNrgfULWEaL7FFIjl6k/DynIZpexaNROR lK8dS6qWXWsEv1yDvAH8rsX4NfJ13Y5DujI0VDWTVdYxTtvJYqa0aabqR12w3uAhM22s pHUMRtzfhwTc1/JT/TdAFtp83crwyuJV7Lfx4+DPwwIRgaW6mRmdjHgiSqnUXEtsQ+3e KV7lGFnccYWXOQpCo3iRY2BZ+09bg++dwyuQy63C0Domt5MSsT5RynUkCT6iGDGZDgk5 GiKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ht0EP2kijG2OFZYuwQ/PKC99Mcaqn9wbOdQiLxF23lg=; b=O2xFVgF5s7PCcsKCbjSCpOp6GDjiIKfHYAiqAYN8986GdvWuOkqwqyWDvQmUgZWK4D MYY/fWbqlDxSQB2NDiO6dPH35t39CINB1u4o4BgoZSLJbtmFmM+io1DktWG0NLdMPITF XPRt0PfVsJgA9gEepd5NLk2++eCMorWCiGJb8PS5sRPEMUgZM0R5a4ehnTKNXLdn5wf8 pmBP6a8r2LNzZ96nUKmtBVJq82xVycHGZO/v1S4Empqf0oNFcvZsgK35hrPyND+qIZTT A3UpLyzwps73Zl9rbB8L3J95nbWKrNeqnvFgBk+bCzCCIDYLIxWFUv26uUjEJQ0up0X6 rKYw== X-Gm-Message-State: AIkVDXKQavaY/QIYL4icqnhKM4hguANfRT08vpKO86a1m03aMwUeXYJdAJJ2p0CBC0Y8Wg== X-Received: by 10.28.165.131 with SMTP id o125mr383885wme.9.1482247229679; Tue, 20 Dec 2016 07:20:29 -0800 (PST) Received: from amir-VirtualBox.ctera.local (bzq-82-81-193-202.cablep.bezeqint.net. [82.81.193.202]) by smtp.gmail.com with ESMTPSA id d64sm22537792wmh.3.2016.12.20.07.20.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 20 Dec 2016 07:20:29 -0800 (PST) From: Amir Goldstein To: Jan Kara Cc: Al Viro , Eric Paris , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC][PATCH 2/2] fsnotify: implement event reporting to super block's root inode Date: Tue, 20 Dec 2016 17:20:07 +0200 Message-Id: <1482247207-4424-3-git-send-email-amir73il@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1482247207-4424-1-git-send-email-amir73il@gmail.com> References: <1482247207-4424-1-git-send-email-amir73il@gmail.com> 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 When the flag FS_EVENT_ON_SB is set on a super block's root inode fsnotify mask, all events on inodes that are on the same super block are reported to the root inode. Events reported to root inode carry the flag FS_EVENT_ON_SB, to distinguish from events that happen to the root inode itself or to its direct children (FS_EVENT_ON_CHILD). The extra cost for vfs operations without any root inode watch is the test for fsnotify flag on root inode, i.e.: (dentry->d_sb->s_root->d_inode->i_fsnotify_mask & FS_EVENT_ON_SB) This could be further optimized by setting a flag on the super_block struct. Signed-off-by: Amir Goldstein --- fs/notify/fsnotify.c | 58 +++++++++++++++++++++++++++++++++++++--- include/linux/fsnotify_backend.h | 10 +++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 12d4479..c0a596c 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -183,12 +183,14 @@ static int send_to_group(struct inode *to_tell, /* * This is the main call to fsnotify. The VFS calls into hook specific functions - * in linux/fsnotify.h. Those functions then in turn call here. Here will call + * in linux/fsnotify.h. Those functions call the helpers fsnotify(), + * fsnotify_root(), fsnotify_parent() and they in turn call here. Here will call * out to all of the registered fsnotify_group. Those groups can then use the * notification event in whatever means they feel necessary. */ -int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, - const unsigned char *file_name, u32 cookie) +static int __fsnotify(struct inode *to_tell, __u32 mask, + void *data, int data_is, + const unsigned char *file_name, u32 cookie) { struct hlist_node *inode_node = NULL, *vfsmount_node = NULL; struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL; @@ -196,7 +198,7 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, struct mount *mnt; int idx, ret = 0; /* global tests shouldn't care about events on child only the specific event */ - __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); + __u32 test_mask = (mask & ~FS_EVENT_ON_DESCENDANT); if (data_is == FSNOTIFY_EVENT_PATH) mnt = real_mount(((struct path *)data)->mnt); @@ -291,6 +293,54 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, return ret; } + +/* Notify this dentry's sb root about descendant inode events. */ +static int fsnotify_root(struct dentry *dentry, __u32 mask, + void *data, int data_is, + const unsigned char *file_name, u32 cookie) +{ + struct inode *r_inode = d_inode(dentry->d_sb->s_root); + + if (likely(!fsnotify_inode_watches_sb(r_inode)) || + !(r_inode->i_fsnotify_mask & mask)) + return 0; + + /* we are notifying root so come up with the new mask which + * specifies these are events which came from sb. */ + mask |= FS_EVENT_ON_SB; + + return __fsnotify(r_inode, mask, data, data_is, file_name, cookie); +} + +/* Notify this inode and maybe the sb root inode. */ +int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, + const unsigned char *file_name, u32 cookie) +{ + struct dentry *dentry = NULL; + int ret = 0; + + BUG_ON(mask & FS_EVENT_ON_SB); + + if (data_is == FSNOTIFY_EVENT_PATH) + dentry = ((struct path *)data)->dentry; + else if (data_is == FSNOTIFY_EVENT_DENTRY) + dentry = data; + + if (dentry) { + /* First, notify root inode if it cares */ + ret = fsnotify_root(dentry, mask, data, data_is, + file_name, cookie); + if (ret) + return ret; + + /* Do not report to root sb watch an event twice */ + if (unlikely(fsnotify_inode_watches_sb(to_tell))) + return 0; + } + + /* Then, notify this inode */ + return __fsnotify(to_tell, mask, data, data_is, file_name, cookie); +} EXPORT_SYMBOL_GPL(fsnotify); static __init int fsnotify_init(void) diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index b7992da..224c4aa 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -266,6 +266,16 @@ extern void __fsnotify_inode_delete(struct inode *inode); extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); extern u32 fsnotify_get_cookie(void); +static inline int fsnotify_inode_watches_sb(struct inode *inode) +{ + /* FS_EVENT_ON_SB is set if the sb root inode may care */ + if (!(inode->i_fsnotify_mask & FS_EVENT_ON_SB)) + return 0; + /* this root inode might care about sb events, does it care about the + * specific set of events that can happen on a distant child? */ + return inode->i_fsnotify_mask & FS_EVENTS_POSS_ON_SB; +} + static inline int fsnotify_inode_watches_children(struct inode *inode) { /* FS_EVENT_ON_CHILD is set if the inode may care */