From patchwork Thu Jan 10 17:04:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amir Goldstein X-Patchwork-Id: 10756265 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 BEECE13B4 for ; Thu, 10 Jan 2019 17:04:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AB71D29AC2 for ; Thu, 10 Jan 2019 17:04:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9F8B129B55; Thu, 10 Jan 2019 17:04:58 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,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 16D7A29AC2 for ; Thu, 10 Jan 2019 17:04:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729001AbfAJRE5 (ORCPT ); Thu, 10 Jan 2019 12:04:57 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:32899 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728266AbfAJRE4 (ORCPT ); Thu, 10 Jan 2019 12:04:56 -0500 Received: by mail-wr1-f66.google.com with SMTP id c14so12298205wrr.0 for ; Thu, 10 Jan 2019 09:04:54 -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=e5A0OWSKfCDmuSlAF2SqifLaJPcgGpU1nwI2BDbCEnk=; b=ZMV8eA+sfn1foGB3OO9dlYlmYtFuDw6QaxeFUY68PlkC3DVBdkdXQKVJqGuszyeRH2 QWvodV757X0LC0LieAV4F/sVBNs9JwZfu3Tn2gyVV/B6pR4NMipngGZ7Q+PrkhcVMjnM mLY0m1TwrInhVy8lCKNruHVutJYdCEeg9KURVAyCAvqnbhtIdtGeMXgsNqtUX2b/NuIz Ck0jOkQFXUPayldmY5SxdBRa0iGCMEwQi2G+IFRAXeUseQemh61uVuhZ4gomywsVOHDh EQ8dYPdnwuoM1EyAeCoFbIXH4spmYQUKe8Gm6hfAPfvH5Uqlh8BM4dzuFK/ZHbYdUnAR ErTw== 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=e5A0OWSKfCDmuSlAF2SqifLaJPcgGpU1nwI2BDbCEnk=; b=R9whDd4MbRArM9o737gTHzhpBtIKMr8Iq01xmWO6Qp6Fy/SpIF7VwPn0hpDfN9bmRv CcsUzLrUmQn86mCDiswrb/5zVUurGqMBLJUoyjXdNuCcCXDntOSUOgTlBfcv1Kild8u4 3u12FN3P84KHZWiFJZDk1PzAUU3CQrFo+s1P24xEd7VHaSoLcyt/1saieyhL2T0/pxSP mBrScnUeP79NFTj1EKo86ifsafYfbiI0LTJ+mdXDGKmBq8j5MwahUHfs8T9+yj6r+A1g nJm9tuhjgpdJishP2d+NLJGGEw7Xi5b1sSH8Zg0ILAOeFSqSh2ppM09+vwbHqf53Ia5N s8yA== X-Gm-Message-State: AJcUukdzAnIXYpWWyDC6oGZNhKSMVeVcrfK7yxewZ52f0fBhDiPLyXqB GvhMegMtefw6QjEx1RVeSWg= X-Google-Smtp-Source: ALg8bN7w333ge/zIVq8KkeUMkeMO2oGUzIobMc5LamzIGAY/8BsererZD7qgSGWgFAyY+TMxOFedJA== X-Received: by 2002:a5d:4dc8:: with SMTP id f8mr10364897wru.45.1547139893460; Thu, 10 Jan 2019 09:04:53 -0800 (PST) Received: from amir-VirtualBox.ctera.local ([188.120.129.201]) by smtp.gmail.com with ESMTPSA id m4sm5725868wmi.3.2019.01.10.09.04.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 10 Jan 2019 09:04:52 -0800 (PST) From: Amir Goldstein To: Jan Kara Cc: Matthew Bobrowski , linux-fsdevel@vger.kernel.org Subject: [PATCH v5 01/17] fsnotify: annotate directory entry modification events Date: Thu, 10 Jan 2019 19:04:28 +0200 Message-Id: <20190110170444.30616-2-amir73il@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190110170444.30616-1-amir73il@gmail.com> References: <20190110170444.30616-1-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 "dirent" events are referring to events that modify directory entries, such as create,delete,rename. Those events should always be reported on a watched directory, regardless if FS_EVENT_ON_CHILD is set on the watch mask. fsnotify_nameremove() and fsnotify_move() were modified to no longer set the FS_EVENT_ON_CHILD event bit. This is a semantic change to align with the "dirent" event definition. It has no effect on any existing backend, because dnotify, inotify and audit always requets the child events and fanotify does not get the delete,rename events. The fsnotify_dirent() helper is used instead of fsnotify_parent() to report a dirent event to dentry->d_parent without FS_EVENT_ON_CHILD and regardless if parent has the FS_EVENT_ON_CHILD bit set. Unlike fsnotify_parent(), fsnotify_dirent() assumes that dentry->d_name and dentry->d_parent are stable. For fsnotify_create()/fsnotify_mkdir(), this assumption is abviously correct. For fsnotify_nameremove(), it is less trvial, so we use dget_parent() and take_dentry_name_snapshot() to grab stable references. Signed-off-by: Amir Goldstein --- include/linux/fsnotify.h | 68 ++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 2ccb08cb5d6a..116907928c7f 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -17,8 +17,22 @@ #include #include +/* + * Notify this @dir inode about a change in the directory entry @dentry. + * + * Unlike fsnotify_parent(), the event will be reported regardless of the + * FS_EVENT_ON_CHILD mask on the parent inode. + */ +static inline int fsnotify_dirent(struct inode *dir, struct dentry *dentry, + __u32 mask) +{ + return fsnotify(dir, mask, d_inode(dentry), FSNOTIFY_EVENT_INODE, + dentry->d_name.name, 0); +} + /* Notify this dentry's parent about a child's events. */ -static inline int fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask) +static inline int fsnotify_parent(const struct path *path, + struct dentry *dentry, __u32 mask) { if (!dentry) dentry = path->dentry; @@ -85,8 +99,8 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, { struct inode *source = moved->d_inode; u32 fs_cookie = fsnotify_get_cookie(); - __u32 old_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_FROM); - __u32 new_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_TO); + __u32 old_dir_mask = FS_MOVED_FROM; + __u32 new_dir_mask = FS_MOVED_TO; const unsigned char *new_name = moved->d_name.name; if (old_dir == new_dir) @@ -128,15 +142,54 @@ static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt) /* * fsnotify_nameremove - a filename was removed from a directory + * + * Called from d_delete() and nfs_complete_sillyrename(). + * The latter is called from nfs client ->unlink() ->rmdir() ->rename() + * under parent vfs inode lock. + * + * Most filesystems call d_delete() from ->unlink() ->rmdir() ->rename() + * ops under parent vfs inode lock. + * + * Some pseudo filesystems call d_delete() without parent inode lock. + * Those filesystems have no ->rename() op and they do not call + * d_move() directly, so d_parent and d_name are stable by definition. + * Examples: devpts, efivarfs, rpc_pipefs, functionfs. + * + * Some clustered filesystems call d_delete() on remote nodes, not under + * vfs parent inode lock, but they use cluster distributed locks on local + * and remote nodes. Those filesystems call d_delete() under their cluster + * lock. Examples: + * - in ceph_fill_trace() under CEPH_MDS_R_PARENT_LOCKED + * - in ocfs2_dentry_convert_worker() under ocfs2_dentry_lock + * But those filesystems also call d_move() under the same cluster lock + * (i.e. FS_RENAME_DOES_D_MOVE), so d_parent and d_name are also stable. + * + * However, to be on the safe side and be reselient to future callers + * and out of tree users of d_delete(), we do not assume that d_parent and + * d_name are stable and we use dget_parent() and take_dentry_name_snapshot() + * to grab stable references. */ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) { + struct dentry *parent; + struct name_snapshot name; __u32 mask = FS_DELETE; + /* d_delete() of pseudo inode? (e.g. __ns_get_path() playing tricks) */ + if (IS_ROOT(dentry)) + return; + if (isdir) mask |= FS_ISDIR; - fsnotify_parent(NULL, dentry, mask); + parent = dget_parent(dentry); + take_dentry_name_snapshot(&name, dentry); + + fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE, + name.name, 0); + + release_dentry_name_snapshot(&name); + dput(parent); } /* @@ -155,7 +208,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) { audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); - fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); + fsnotify_dirent(inode, dentry, FS_CREATE); } /* @@ -176,12 +229,9 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct */ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) { - __u32 mask = (FS_CREATE | FS_ISDIR); - struct inode *d_inode = dentry->d_inode; - audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); - fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); + fsnotify_dirent(inode, dentry, FS_CREATE | FS_ISDIR); } /*