From patchwork Wed Mar 23 13:36:06 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 8650111 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 57F48C0553 for ; Wed, 23 Mar 2016 13:35:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 353C6203B7 for ; Wed, 23 Mar 2016 13:35:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 91C1220254 for ; Wed, 23 Mar 2016 13:35:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755108AbcCWNfO (ORCPT ); Wed, 23 Mar 2016 09:35:14 -0400 Received: from mail-lf0-f45.google.com ([209.85.215.45]:33175 "EHLO mail-lf0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755041AbcCWNfN (ORCPT ); Wed, 23 Mar 2016 09:35:13 -0400 Received: by mail-lf0-f45.google.com with SMTP id o73so11603574lfe.0 for ; Wed, 23 Mar 2016 06:35:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=szeredi.hu; s=google; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :user-agent; bh=UKensJi2ww0SLbKH6xeb2aVZ2K+lc5/n1IoOO/LDDUQ=; b=WjY1DFJ6xeoS4YJ5ubqcT7ecYfZRrbe4F3E7yS7Uqon15KD1EFmE+qo0a7c8YKmeVt zWCykQNR2PYd7TX7dEXrWvbZhBjGFwg0BhLD3p/FK/aw+IF5kExmBNZDbc0JMOmdOqn/ bjsTyr9fzGml1BdUK3ngMZRoNZGFGL53yRkA0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:user-agent; bh=UKensJi2ww0SLbKH6xeb2aVZ2K+lc5/n1IoOO/LDDUQ=; b=O4t9KMm2uqGmX5595zDE05pRE1PRiFOSQwSAVbxH4uewFErfummFsaC4qRA+vKZwrK CC5ce/g6WNKcoDueRFEBd2fMsKlFh2YDD5KFzvRWe1xKJCcSKdvtGi19KFVApHSZeTVW qD2sGqYLbnUSqqq/DD2c3H4gC1YYKEu8ERQveVhu5nsV6wOdAt6Z4+VTUk/kVufKbidj 1yEt5CiTXg9CO+RadURxZU02pVt/Fv+wapffjaYZfBMA0mS/D7Eeli+NcB6UO8cZkQfd Z5MMoENEARqgYxj5L+4K+NLAu12AYw4OPrBeR3nhjqBESUKgd0HJ8KicpCkTW1WyZNIf tDyQ== X-Gm-Message-State: AD7BkJJL9tM89VgxAwVNp9pPjvtKPL9lGQ8xzw3HCvDh+h51jYXgEWONhf04Gq/D7MyGHA== X-Received: by 10.194.184.139 with SMTP id eu11mr3951614wjc.169.1458740087556; Wed, 23 Mar 2016 06:34:47 -0700 (PDT) Received: from tucsk (pool-dsl-2c-0018.externet.hu. [217.173.44.24]) by smtp.gmail.com with ESMTPSA id b1sm2675217wjy.0.2016.03.23.06.34.45 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 23 Mar 2016 06:34:46 -0700 (PDT) Date: Wed, 23 Mar 2016 14:36:06 +0100 From: Miklos Szeredi To: Al Viro Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, David Howells , Goldwyn Rodrigues , Trond Myklebust , Theodore Ts'o , Daniel Axtens , stable@vger.kernel.org Subject: [PATCH v2] fs: add file_dentry() Message-ID: <20160323133606.GF11906@tucsk> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID,T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This series fixes bugs in nfs and ext4 due to 4bacc9c9234c ("overlayfs: Make f_path always point to the overlay and f_inode to the underlay"). Regular files opened on overlayfs will result in the file being opened on the underlying filesystem, while f_path points to the overlayfs mount/dentry. This confuses filesystems which get the dentry from struct file and assume it's theirs. Add a new helper, file_dentry() [*], to get the filesystem's own dentry from the file. This checks file->f_path.dentry->d_flags against DCACHE_OP_REAL, and returns file->f_path.dentry if DCACHE_OP_REAL is not set (this is the common, non-overlayfs case). In the uncommon case it will call into overlayfs's ->d_real() to get the underlying dentry, matching file_inode(file). The reason we need to check against the inode is that if the file is copied up while being open, d_real() would return the upper dentry, while the open file comes from the lower dentry. [*] If possible, it's better simply to use file_inode() instead. Signed-off-by: Miklos Szeredi Tested-by: Goldwyn Rodrigues Reviewed-by: Trond Myklebust Cc: # v4.2 Cc: David Howells Cc: Al Viro Cc: Theodore Ts'o Cc: Daniel Axtens --- changes in v2: - rename method to d_op->d_real() - check d_flag instead of comparing inode for base dentry - ovl_d_real() now handles recursion - WARN instead of BUG and be more verbose - add d_real() helper too fs/dcache.c | 5 ++++- fs/overlayfs/super.c | 33 +++++++++++++++++++++++++++++++++ include/linux/dcache.h | 10 ++++++++++ include/linux/fs.h | 10 ++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1667,7 +1667,8 @@ void d_set_d_op(struct dentry *dentry, c DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_DELETE | - DCACHE_OP_SELECT_INODE)); + DCACHE_OP_SELECT_INODE | + DCACHE_OP_REAL)); dentry->d_op = op; if (!op) return; @@ -1685,6 +1686,8 @@ void d_set_d_op(struct dentry *dentry, c dentry->d_flags |= DCACHE_OP_PRUNE; if (op->d_select_inode) dentry->d_flags |= DCACHE_OP_SELECT_INODE; + if (op->d_real) + dentry->d_flags |= DCACHE_OP_REAL; } EXPORT_SYMBOL(d_set_d_op); --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -161,6 +161,7 @@ struct dentry_operations { struct vfsmount *(*d_automount)(struct path *); int (*d_manage)(struct dentry *, bool); struct inode *(*d_select_inode)(struct dentry *, unsigned); + struct dentry *(*d_real)(struct dentry *, struct inode *); } ____cacheline_aligned; /* @@ -229,6 +230,7 @@ struct dentry_operations { #define DCACHE_OP_SELECT_INODE 0x02000000 /* Unioned entry: dcache op selects inode */ #define DCACHE_ENCRYPTED_WITH_KEY 0x04000000 /* dir is encrypted with a valid key */ +#define DCACHE_OP_REAL 0x08000000 extern seqlock_t rename_lock; @@ -555,4 +557,12 @@ static inline struct dentry *d_backing_d return upper; } +static inline struct dentry *d_real(struct dentry *dentry) +{ + if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) + return dentry->d_op->d_real(dentry, NULL); + else + return dentry; +} + #endif /* __LINUX_DCACHE_H */ --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -295,6 +295,37 @@ static void ovl_dentry_release(struct de } } +static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode) +{ + struct dentry *real; + + if (d_is_dir(dentry)) { + if (!inode || inode == d_inode(dentry)) + return dentry; + goto bug; + } + + real = ovl_dentry_upper(dentry); + if (real && (!inode || inode == d_inode(real))) + return real; + + real = ovl_dentry_lower(dentry); + if (!real) + goto bug; + + if (!inode || inode == d_inode(real)) + return real; + + /* Handle recursion */ + if (real->d_flags & DCACHE_OP_REAL) + return real->d_op->d_real(real, inode); + +bug: + WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry, + inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0); + return dentry; +} + static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags) { struct ovl_entry *oe = dentry->d_fsdata; @@ -339,11 +370,13 @@ static int ovl_dentry_weak_revalidate(st static const struct dentry_operations ovl_dentry_operations = { .d_release = ovl_dentry_release, .d_select_inode = ovl_d_select_inode, + .d_real = ovl_d_real, }; static const struct dentry_operations ovl_reval_dentry_operations = { .d_release = ovl_dentry_release, .d_select_inode = ovl_d_select_inode, + .d_real = ovl_d_real, .d_revalidate = ovl_dentry_revalidate, .d_weak_revalidate = ovl_dentry_weak_revalidate, }; --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1241,6 +1241,16 @@ static inline struct inode *file_inode(c return f->f_inode; } +static inline struct dentry *file_dentry(const struct file *file) +{ + struct dentry *dentry = file->f_path.dentry; + + if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) + return dentry->d_op->d_real(dentry, file_inode(file)); + else + return dentry; +} + static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) { return locks_lock_inode_wait(file_inode(filp), fl);