From patchwork Mon Nov 7 10:51:58 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 9414717 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 3BE886022E for ; Mon, 7 Nov 2016 10:52:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2C7D52873E for ; Mon, 7 Nov 2016 10:52:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2143628CF5; Mon, 7 Nov 2016 10:52:18 +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.9 required=2.0 tests=BAYES_00,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 54D2628C5F for ; Mon, 7 Nov 2016 10:52:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751296AbcKGKwK (ORCPT ); Mon, 7 Nov 2016 05:52:10 -0500 Received: from mail-wm0-f53.google.com ([74.125.82.53]:38245 "EHLO mail-wm0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752421AbcKGKwG (ORCPT ); Mon, 7 Nov 2016 05:52:06 -0500 Received: by mail-wm0-f53.google.com with SMTP id f82so110148603wmf.1 for ; Mon, 07 Nov 2016 02:52:05 -0800 (PST) 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:in-reply-to :references; bh=393ouuL/0XfOkZX4xaRUuLZAUKz4miPxl/5LOZzzipc=; b=Yh06NsPeHaVbHK+IcFE/PKwMDxtSINZJSy+Y9PTSaLMqfU9iwrw4xU1i6XhH1GRozN EdA2udPYwfSjEXBjxF8bGAqVZyYBVxhafLlHpUSaChA5zSiwIFU/G6AtLD78ja0qstga 1wSPVgLx3Eqs1l17gaOSKK9wchLsOPtl+LUDd5+0zZyoZd4GyrssWOaNk5qyI3ihchyH Xm6RJr0LaqwwNftlm94HOb07a2102pZ0XI6/BM/+HZNHlY5dTA0oFMmk8pTiISfjyYoX qwJgzH/awaOVNJ7LPYBrmxaGuQzkjAp3DajLqLGLv7yeex+rGPp2Y3AQD2a4yPWyQp+7 4q6g== X-Gm-Message-State: ABUngvf79I/UYE6y5bMXJNOVz1GTuPM3eVOgfUpJcIqCN5Ggou5nUoqbtAl1L/BnpUPtdigd X-Received: by 10.28.184.74 with SMTP id i71mr5847107wmf.49.1478515924679; Mon, 07 Nov 2016 02:52:04 -0800 (PST) Received: from veci.piliscsaba.szeredi.hu (pool-dsl-2c-0018.externet.hu. [217.173.44.24]) by smtp.gmail.com with ESMTPSA id 1sm12749496wmk.22.2016.11.07.02.52.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 07 Nov 2016 02:52:03 -0800 (PST) From: Miklos Szeredi To: Al Viro Cc: Trond Myklebust , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/3] nfs: don't use ->d_time Date: Mon, 7 Nov 2016 11:51:58 +0100 Message-Id: <1478515920-20458-2-git-send-email-mszeredi@redhat.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1478515920-20458-1-git-send-email-mszeredi@redhat.com> References: <1478515920-20458-1-git-send-email-mszeredi@redhat.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 NFS is the most complicated of the lot. It uses ->d_fsdata to 1) store devname in the root dentry, and 2) store nfs_unlinkdata for sillyrenames. In addition it stores a verifier in ->d_time. Introduce nfs_dentry structure that to store all of the above and make d_fsdata point to it. Need to use rcu freeing since ->verf is accessed from dentry revalidation. And not only read, but changed as well, so rcu_head must not overlay verf. Signed-off-by: Miklos Szeredi Cc: Trond Myklebust --- fs/nfs/dir.c | 18 ++++++++++++++---- fs/nfs/getroot.c | 4 ++-- fs/nfs/namespace.c | 2 +- fs/nfs/unlink.c | 16 ++++++++-------- include/linux/nfs_fs.h | 19 ++++++++++++++++++- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 5f1af4cd1a33..5a3f02c4c28a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1041,7 +1041,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry, return 1; if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) return 0; - if (!nfs_verify_change_attribute(dir, dentry->d_time)) + if (!nfs_verify_change_attribute(dir, NFS_D(dentry)->verf)) return 0; /* Revalidate nfsi->cache_change_attribute before we declare a match */ if (rcu_walk) @@ -1050,7 +1050,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry, ret = nfs_revalidate_inode(NFS_SERVER(dir), dir); if (ret < 0) return 0; - if (!nfs_verify_change_attribute(dir, dentry->d_time)) + if (!nfs_verify_change_attribute(dir, NFS_D(dentry)->verf)) return 0; return 1; } @@ -1358,15 +1358,23 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) iput(inode); } +static int nfs_d_init(struct dentry *dentry) +{ + dentry->d_fsdata = kzalloc(sizeof(struct nfs_dentry), GFP_KERNEL); + + return dentry->d_fsdata ? 0 : -ENOMEM; +} + static void nfs_d_release(struct dentry *dentry) { /* free cached devname value, if it survived that far */ - if (unlikely(dentry->d_fsdata)) { + if (unlikely(NFS_D(dentry)->devname)) { if (dentry->d_flags & DCACHE_NFSFS_RENAMED) WARN_ON(1); else - kfree(dentry->d_fsdata); + kfree(NFS_D(dentry)->devname); } + kfree_rcu(NFS_D(dentry), rcu); } const struct dentry_operations nfs_dentry_operations = { @@ -1375,6 +1383,7 @@ const struct dentry_operations nfs_dentry_operations = { .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, .d_automount = nfs_d_automount, + .d_init = nfs_d_init, .d_release = nfs_d_release, }; EXPORT_SYMBOL_GPL(nfs_dentry_operations); @@ -1453,6 +1462,7 @@ const struct dentry_operations nfs4_dentry_operations = { .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, .d_automount = nfs_d_automount, + .d_init = nfs_d_init, .d_release = nfs_d_release, }; EXPORT_SYMBOL_GPL(nfs4_dentry_operations); diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index a608ffd28acc..84482c656e05 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -120,9 +120,9 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, security_d_instantiate(ret, inode); spin_lock(&ret->d_lock); - if (IS_ROOT(ret) && !ret->d_fsdata && + if (IS_ROOT(ret) && !NFS_D(ret)->devname && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { - ret->d_fsdata = name; + NFS_D(ret)->devname = name; name = NULL; } spin_unlock(&ret->d_lock); diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index c8162c660c44..0060806d047b 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -90,7 +90,7 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen, *--end = '/'; } *p = end; - base = dentry->d_fsdata; + base = NFS_D(dentry)->devname; if (!base) { spin_unlock(&dentry->d_lock); rcu_read_unlock(); diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 191aa577dd1f..74e708fbd945 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -134,8 +134,8 @@ static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data) spin_lock(&alias->d_lock); if (d_really_is_positive(alias) && !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { - devname_garbage = alias->d_fsdata; - alias->d_fsdata = data; + devname_garbage = NFS_D(alias)->devname; + NFS_D(alias)->data = data; alias->d_flags |= DCACHE_NFSFS_RENAMED; ret = 1; } else @@ -189,8 +189,8 @@ nfs_async_unlink(struct dentry *dentry, const struct qstr *name) if (dentry->d_flags & DCACHE_NFSFS_RENAMED) goto out_unlock; dentry->d_flags |= DCACHE_NFSFS_RENAMED; - devname_garbage = dentry->d_fsdata; - dentry->d_fsdata = data; + devname_garbage = NFS_D(dentry)->devname; + NFS_D(dentry)->data = data; spin_unlock(&dentry->d_lock); /* * If we'd displaced old cached devname, free it. At that @@ -226,8 +226,8 @@ nfs_complete_unlink(struct dentry *dentry, struct inode *inode) spin_lock(&dentry->d_lock); dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; - data = dentry->d_fsdata; - dentry->d_fsdata = NULL; + data = NFS_D(dentry)->data; + NFS_D(dentry)->data = NULL; spin_unlock(&dentry->d_lock); if (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)) @@ -240,10 +240,10 @@ nfs_cancel_async_unlink(struct dentry *dentry) { spin_lock(&dentry->d_lock); if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { - struct nfs_unlinkdata *data = dentry->d_fsdata; + struct nfs_unlinkdata *data = NFS_D(dentry)->data; dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; - dentry->d_fsdata = NULL; + NFS_D(dentry)->data = NULL; spin_unlock(&dentry->d_lock); nfs_free_unlinkdata(data); return; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 810124b33327..20a07688a392 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -187,6 +187,18 @@ struct nfs_inode { }; /* + * NFS specific dentry data + */ +struct nfs_dentry { + union { + char *devname; + struct nfs_unlinkdata *data; + struct rcu_head rcu; + }; + unsigned long verf; +}; + +/* * Cache validity bit flags */ #define NFS_INO_INVALID_ATTR 0x0001 /* cached attrs are invalid */ @@ -217,6 +229,11 @@ static inline struct nfs_inode *NFS_I(const struct inode *inode) return container_of(inode, struct nfs_inode, vfs_inode); } +static inline struct nfs_dentry *NFS_D(struct dentry *dentry) +{ + return (struct nfs_dentry *) dentry->d_fsdata; +} + static inline struct nfs_server *NFS_SB(const struct super_block *s) { return (struct nfs_server *)(s->s_fs_info); @@ -299,7 +316,7 @@ static inline int nfs_server_capable(struct inode *inode, int cap) static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) { - dentry->d_time = verf; + NFS_D(dentry)->verf = verf; } /**