From patchwork Tue May 31 09:04:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ashish Sangwan X-Patchwork-Id: 9143877 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 C984F60757 for ; Tue, 31 May 2016 09:04:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BDD5D27BF1 for ; Tue, 31 May 2016 09:04:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B2BED28185; Tue, 31 May 2016 09:04:42 +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.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID 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 E24D127BF1 for ; Tue, 31 May 2016 09:04:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756637AbcEaJEk (ORCPT ); Tue, 31 May 2016 05:04:40 -0400 Received: from mail-pa0-f65.google.com ([209.85.220.65]:34329 "EHLO mail-pa0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755920AbcEaJEh (ORCPT ); Tue, 31 May 2016 05:04:37 -0400 Received: by mail-pa0-f65.google.com with SMTP id x1so7811403pav.1 for ; Tue, 31 May 2016 02:04:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=X6bvZTAAST3WQoC6Ngje1S6w1TXlsjN9zV8LQVUb9LY=; b=r8pmuIuGZ6ouc6eNwlQl92rMMWBgJlejNJ+jxOT0fYuW0GpQgLNrYgpyFfXnLIwejC ZBcw/ckMvT+IYkbLyVWe8DUOu2UnBfs7tFrHa3vuitEHtKXA87pJCDv/IOh2D48y2eZy HaHlwNdFEC9eUFVk+16IbbQvmru5jNjVIsrFxMoEsjlzCADuzGXWG0bLW0gzGzsIsD4D VOWtKPsHUPm/NbwmF9SQbl3xXS43MbRjvI5ZJYCaTjE6MHjwVH6dZ+W3wawBChrMEUhH 4l4u8IZNAOe90bo2jXwuGHATffuSiFtZomhg9rls/XL6D+kRMWoRqIU6q7NjLPRSXlbf Shzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=X6bvZTAAST3WQoC6Ngje1S6w1TXlsjN9zV8LQVUb9LY=; b=VkBcmnYIgUpP8c8IwHLrfgqMHGKHJoUu0JobUZ8+oUuMym+40NVsAYZdBDP9ID4Zzk f4R26sU3G3g7ydobnwGF32EqjP1I+H6LTZBxLliTKxe1W4rvgDEUJHljZ7k7qighi03K 3u3U8kfO+MeeD/kosIGMk/Whkb/m5g32lR/jdhGOYFMGyIYWY0xLV/iUQFOq3ex1/2yO qRmFde0P3RNReLJclKebB1aN2Ah1+Z5dbpE/eOwxWmiFqleZhc97NL7B/KOK+zyyzDdY Sl54/6EW1p3A4cMqBayk1r1Kgiut5s2KKI5N7F5SV2qxH8wl31M4cxdZ2ahR0PkPBKer 3GUA== X-Gm-Message-State: ALyK8tKNqAT28TodA9nyu2b5yqI8Pwc2MIotm+nSmqvVXgGqt9EsnjcrMQBpz6bw6YPEJA== X-Received: by 10.66.47.196 with SMTP id f4mr52303906pan.126.1464685476576; Tue, 31 May 2016 02:04:36 -0700 (PDT) Received: from ashish-pc.corp.maprtech.com ([14.142.27.186]) by smtp.gmail.com with ESMTPSA id 83sm38529080pfl.12.2016.05.31.02.04.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 31 May 2016 02:04:35 -0700 (PDT) From: Ashish Sangwan To: Miklos Szeredi , Nikolaus Rath Cc: fuse-devel@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, Ashish Sangwan Subject: [PATCH] fuse: callback for invalidating cached children dentries for a directory Date: Tue, 31 May 2016 14:34:14 +0530 Message-Id: <1464685454-19650-1-git-send-email-ashishsangwan2@gmail.com> X-Mailer: git-send-email 1.9.1 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 This patch solves a long standing bug. "([bug #15](https://github.com/libfuse/libfuse/issues/15)): if the `default_permissions` mount option is not used, the results of the first permission check performed by the file system for a directory entry will be re-used for subsequent accesses as long as the inode of the accessed entry is present in the kernel cache - even if the permissions have since changed, and even if the subsequent access is made by a different user. This bug needs to be fixed in the Linux kernel and has been known since 2006 but unfortunately no fix has been applied yet. If you depend on correct permission handling for FUSE file systems, the only workaround is to use `default_permissions` (which does not currently support ACLs), or to completely disable caching of directory entry attributes. Alternatively, the severity of the bug can be somewhat reduced by not using the `allow_other` mount option." This patch introduce a callback which the user space implementation can use to invalidate the cached entries of a parent directory, for example when the execute permissions are revoked and force real lookup. Signed-off-by: Ashish Sangwan --- fs/fuse/dev.c | 28 ++++++++++++++++++++++++++++ fs/fuse/dir.c | 32 ++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 3 +++ include/uapi/linux/fuse.h | 5 +++++ 4 files changed, 68 insertions(+) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index cbece12..56ce470 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1490,6 +1490,31 @@ err: return err; } +static int +fuse_notify_inval_dircache_entries(struct fuse_conn *fc, unsigned int size, + struct fuse_copy_state *cs) +{ + struct fuse_notify_inval_dircache_entries_out outarg; + int err = -EINVAL; + + if (size < sizeof(outarg)) + goto err; + err = fuse_copy_one(cs, &outarg, sizeof(outarg)); + if (err) + goto err; + fuse_copy_finish(cs); + down_read(&fc->killsb); + err = -ENOENT; + if (fc->sb) + err = fuse_reverse_inval_dircache_entries(fc->sb, + outarg.parent); + up_read(&fc->killsb); + return err; +err: + fuse_copy_finish(cs); + return err; +} + static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, struct fuse_copy_state *cs) { @@ -1815,6 +1840,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, case FUSE_NOTIFY_DELETE: return fuse_notify_delete(fc, size, cs); + case FUSE_NOTIFY_INVAL_DIRCACHE_ENTRIES: + return fuse_notify_inval_dircache_entries(fc, size, cs); + default: fuse_copy_finish(cs); return -EINVAL; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index ccd4971..8bc5f32 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -932,6 +932,38 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat, return err; } +int fuse_reverse_inval_dircache_entries(struct super_block *sb, + u64 parent_nodeid) +{ + int err = -ENOTDIR; + struct inode *parent; + struct dentry *dir; + struct dentry *child; + + parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid); + if (!parent) + return -ENOENT; + + inode_lock(parent); + if (!S_ISDIR(parent->i_mode)) + goto unlock; + + err = -ENOENT; + dir = d_find_alias(parent); + if (!dir) + goto unlock; + err = 0; + spin_lock(&dir->d_lock); + list_for_each_entry(child, &dir->d_subdirs, d_child) + fuse_invalidate_entry_cache(child); + spin_unlock(&dir->d_lock); + dput(dir); + unlock: + inode_unlock(parent); + iput(parent); + return err; +} + int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, u64 child_nodeid, struct qstr *name) { diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index eddbe02..7cf0a3f 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -924,6 +924,9 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid, int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, u64 child_nodeid, struct qstr *name); +int fuse_reverse_inval_dircache_entries(struct super_block *sb, + u64 parent_nodeid); + int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, bool isdir); diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 5974fae..c74fc3c 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -374,6 +374,7 @@ enum fuse_notify_code { FUSE_NOTIFY_STORE = 4, FUSE_NOTIFY_RETRIEVE = 5, FUSE_NOTIFY_DELETE = 6, + FUSE_NOTIFY_INVAL_DIRCACHE_ENTRIES = 7, FUSE_NOTIFY_CODE_MAX, }; @@ -715,6 +716,10 @@ struct fuse_direntplus { #define FUSE_DIRENTPLUS_SIZE(d) \ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen) +struct fuse_notify_inval_dircache_entries_out { + uint64_t parent; +}; + struct fuse_notify_inval_inode_out { uint64_t ino; int64_t off;