From patchwork Mon May 25 05:47:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Kent X-Patchwork-Id: 11568075 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F2CA060D for ; Mon, 25 May 2020 05:47:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C7E1120849 for ; Mon, 25 May 2020 05:47:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=themaw.net header.i=@themaw.net header.b="Y/asayJu"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="bRS2EoAg" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729824AbgEYFrL (ORCPT ); Mon, 25 May 2020 01:47:11 -0400 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:41367 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725900AbgEYFrK (ORCPT ); Mon, 25 May 2020 01:47:10 -0400 Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailout.west.internal (Postfix) with ESMTP id BDC6EEBD; Mon, 25 May 2020 01:47:08 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Mon, 25 May 2020 01:47:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=themaw.net; h= subject:from:to:cc:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=fm3; bh= 0dsCYQ1K5CZ+uYcFvbEAk460nc8TAbKa5XDg2PC91c4=; b=Y/asayJujq9zuW5s WBel3kl2+wwW6+GivKpzpLzWa4ZgMLYLIGHpB1zqCqTL6IDX4+KILP1NXrlzOwDQ zXUz64mDnTI8a2WqwgI01DKWbz1VwMd2wpt8SUFOl5NfFjY0tamlpsAX7sPVIj5H mzMPw2Ccj/OV0TsIgPSl6Zm9CSCKd7ZhUeUux5PSoAXa9CSIFXMVRYeZmYVVvsZv tqis8s8ljD9n1o1nKp8uxKQdPndU4JEzasByyBR53owdtgEri/iXMg9vQpmc9DJ6 +z96fPjE++XL7aokt75WP2bJWsCUNkCeaswMFjCZuJvorbEDP/Xt/wLo/JrgQdB3 B3oUuw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm2; bh=0dsCYQ1K5CZ+uYcFvbEAk460nc8TAbKa5XDg2PC91 c4=; b=bRS2EoAgPjnJ1KOFMWAnRBPhzVJEK2bDr1Zxre6gJV4tmFnagwL/1cjuO ilyIwFzFIUiEc6dCK/urWUeGbXD43i6e4mrVnyw1+mLTLxDujT78qy0Z6Kl+/eFk aY4WDmaE/LOlsDn9q16e3Us0UQL7Eo7duFl+768I7iRy5Wj1g4ppAS4rlyNff0yn JYoh10YX+G8rO+YhPN4QtoZcI8TumrOcEfIaGvbT1dM53fTEZjhI3OJSYkcIn5Li RSDNf//GqYC2H0DuIPq813zeoQDlENqCrFALgMJsEVLgAhfgPM7VOUlJXjFdIfaG 5aMTf6XNw5HliP9lOOlc6rB/0idHg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrudduledgleejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepuffhvfffkfgjfhgfgggtgfesthejredttderjeenucfhrhhomhepkfgrnhcu mfgvnhhtuceorhgrvhgvnhesthhhvghmrgifrdhnvghtqeenucggtffrrghtthgvrhhnpe egveeuudffieeiffefieehvdetieeiteelheetueekledtledugeffheffieduieenucfk phepuddukedrvddtkedrudejkedrudeknecuvehluhhsthgvrhfuihiivgeptdenucfrrg hrrghmpehmrghilhhfrhhomheprhgrvhgvnhesthhhvghmrgifrdhnvght X-ME-Proxy: Received: from mickey.localdomain (unknown [118.208.178.18]) by mail.messagingengine.com (Postfix) with ESMTPA id 845E43280059; Mon, 25 May 2020 01:47:07 -0400 (EDT) Received: from mickey.themaw.net (localhost [127.0.0.1]) by mickey.localdomain (Postfix) with ESMTP id A33A5A01C8; Mon, 25 May 2020 13:47:04 +0800 (AWST) Subject: [PATCH 1/4] kernfs: switch kernfs to use an rwsem From: Ian Kent To: Andrew Morton Cc: Al Viro , Greg Kroah-Hartman , Tejun Heo , Rick Lindsley , Stephen Rothwell , David Howells , Miklos Szeredi , linux-fsdevel , Kernel Mailing List Date: Mon, 25 May 2020 13:47:04 +0800 Message-ID: <159038562460.276051.5267555021380171295.stgit@mickey.themaw.net> In-Reply-To: <159038508228.276051.14042452586133971255.stgit@mickey.themaw.net> References: <159038508228.276051.14042452586133971255.stgit@mickey.themaw.net> User-Agent: StGit/0.19 MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org The kernfs global lock restricts the ability to perform kernfs node lookup operations in parallel. Change the kernfs mutex to an rwsem so that, when oppertunity arises, node searches can be done in parallel. Signed-off-by: Ian Kent --- fs/kernfs/dir.c | 119 +++++++++++++++++++++++-------------------- fs/kernfs/file.c | 4 + fs/kernfs/inode.c | 16 +++--- fs/kernfs/kernfs-internal.h | 5 +- fs/kernfs/mount.c | 12 ++-- fs/kernfs/symlink.c | 4 + 6 files changed, 86 insertions(+), 74 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 9aec80b9d7c6..d8213fc65eba 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -17,7 +17,7 @@ #include "kernfs-internal.h" -DEFINE_MUTEX(kernfs_mutex); +DECLARE_RWSEM(kernfs_rwsem); static DEFINE_SPINLOCK(kernfs_rename_lock); /* kn->parent and ->name */ static char kernfs_pr_cont_buf[PATH_MAX]; /* protected by rename_lock */ static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */ @@ -26,10 +26,21 @@ static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */ static bool kernfs_active(struct kernfs_node *kn) { - lockdep_assert_held(&kernfs_mutex); return atomic_read(&kn->active) >= 0; } +static bool kernfs_active_write(struct kernfs_node *kn) +{ + lockdep_assert_held_write(&kernfs_rwsem); + return kernfs_active(kn); +} + +static bool kernfs_active_read(struct kernfs_node *kn) +{ + lockdep_assert_held_read(&kernfs_rwsem); + return kernfs_active(kn); +} + static bool kernfs_lockdep(struct kernfs_node *kn) { #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -340,7 +351,7 @@ static int kernfs_sd_compare(const struct kernfs_node *left, * @kn->parent->dir.children. * * Locking: - * mutex_lock(kernfs_mutex) + * kernfs_rwsem write lock * * RETURNS: * 0 on susccess -EEXIST on failure. @@ -385,7 +396,7 @@ static int kernfs_link_sibling(struct kernfs_node *kn) * removed, %false if @kn wasn't on the rbtree. * * Locking: - * mutex_lock(kernfs_mutex) + * kernfs_rwsem write lock */ static bool kernfs_unlink_sibling(struct kernfs_node *kn) { @@ -455,14 +466,14 @@ void kernfs_put_active(struct kernfs_node *kn) * return after draining is complete. */ static void kernfs_drain(struct kernfs_node *kn) - __releases(&kernfs_mutex) __acquires(&kernfs_mutex) + __releases(&kernfs_rwsem) __acquires(&kernfs_rwsem) { struct kernfs_root *root = kernfs_root(kn); - lockdep_assert_held(&kernfs_mutex); + lockdep_assert_held_write(&kernfs_rwsem); WARN_ON_ONCE(kernfs_active(kn)); - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); if (kernfs_lockdep(kn)) { rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); @@ -481,7 +492,7 @@ static void kernfs_drain(struct kernfs_node *kn) kernfs_drain_open_files(kn); - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); } /** @@ -560,10 +571,10 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) goto out_bad_unlocked; kn = kernfs_dentry_node(dentry); - mutex_lock(&kernfs_mutex); + down_read(&kernfs_rwsem); /* The kernfs node has been deactivated */ - if (!kernfs_active(kn)) + if (!kernfs_active_read(kn)) goto out_bad; /* The kernfs node has been moved? */ @@ -579,10 +590,10 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) kernfs_info(dentry->d_sb)->ns != kn->ns) goto out_bad; - mutex_unlock(&kernfs_mutex); + up_read(&kernfs_rwsem); return 1; out_bad: - mutex_unlock(&kernfs_mutex); + up_read(&kernfs_rwsem); out_bad_unlocked: return 0; } @@ -764,7 +775,7 @@ int kernfs_add_one(struct kernfs_node *kn) bool has_ns; int ret; - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); ret = -EINVAL; has_ns = kernfs_ns_enabled(parent); @@ -779,7 +790,7 @@ int kernfs_add_one(struct kernfs_node *kn) if (parent->flags & KERNFS_EMPTY_DIR) goto out_unlock; - if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent)) + if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active_write(parent)) goto out_unlock; kn->hash = kernfs_name_hash(kn->name, kn->ns); @@ -795,7 +806,7 @@ int kernfs_add_one(struct kernfs_node *kn) ps_iattr->ia_mtime = ps_iattr->ia_ctime; } - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); /* * Activate the new node unless CREATE_DEACTIVATED is requested. @@ -809,7 +820,7 @@ int kernfs_add_one(struct kernfs_node *kn) return 0; out_unlock: - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); return ret; } @@ -830,7 +841,7 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, bool has_ns = kernfs_ns_enabled(parent); unsigned int hash; - lockdep_assert_held(&kernfs_mutex); + lockdep_assert_held(&kernfs_rwsem); if (has_ns != (bool)ns) { WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", @@ -862,7 +873,7 @@ static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent, size_t len; char *p, *name; - lockdep_assert_held(&kernfs_mutex); + lockdep_assert_held_read(&kernfs_rwsem); /* grab kernfs_rename_lock to piggy back on kernfs_pr_cont_buf */ spin_lock_irq(&kernfs_rename_lock); @@ -902,10 +913,10 @@ struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, { struct kernfs_node *kn; - mutex_lock(&kernfs_mutex); + down_read(&kernfs_rwsem); kn = kernfs_find_ns(parent, name, ns); kernfs_get(kn); - mutex_unlock(&kernfs_mutex); + up_read(&kernfs_rwsem); return kn; } @@ -926,10 +937,10 @@ struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, { struct kernfs_node *kn; - mutex_lock(&kernfs_mutex); + down_read(&kernfs_rwsem); kn = kernfs_walk_ns(parent, path, ns); kernfs_get(kn); - mutex_unlock(&kernfs_mutex); + up_read(&kernfs_rwsem); return kn; } @@ -1084,7 +1095,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, struct inode *inode; const void *ns = NULL; - mutex_lock(&kernfs_mutex); + down_read(&kernfs_rwsem); if (kernfs_ns_enabled(parent)) ns = kernfs_info(dir->i_sb)->ns; @@ -1107,7 +1118,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, /* instantiate and hash dentry */ ret = d_splice_alias(inode, dentry); out_unlock: - mutex_unlock(&kernfs_mutex); + up_read(&kernfs_rwsem); return ret; } @@ -1226,7 +1237,7 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos, { struct rb_node *rbn; - lockdep_assert_held(&kernfs_mutex); + lockdep_assert_held_write(&kernfs_rwsem); /* if first iteration, visit leftmost descendant which may be root */ if (!pos) @@ -1262,7 +1273,7 @@ void kernfs_activate(struct kernfs_node *kn) { struct kernfs_node *pos; - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); pos = NULL; while ((pos = kernfs_next_descendant_post(pos, kn))) { @@ -1276,14 +1287,14 @@ void kernfs_activate(struct kernfs_node *kn) pos->flags |= KERNFS_ACTIVATED; } - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); } static void __kernfs_remove(struct kernfs_node *kn) { struct kernfs_node *pos; - lockdep_assert_held(&kernfs_mutex); + lockdep_assert_held_write(&kernfs_rwsem); /* * Short-circuit if non-root @kn has already finished removal. @@ -1298,7 +1309,7 @@ static void __kernfs_remove(struct kernfs_node *kn) /* prevent any new usage under @kn by deactivating all nodes */ pos = NULL; while ((pos = kernfs_next_descendant_post(pos, kn))) - if (kernfs_active(pos)) + if (kernfs_active_write(pos)) atomic_add(KN_DEACTIVATED_BIAS, &pos->active); /* deactivate and unlink the subtree node-by-node */ @@ -1306,7 +1317,7 @@ static void __kernfs_remove(struct kernfs_node *kn) pos = kernfs_leftmost_descendant(kn); /* - * kernfs_drain() drops kernfs_mutex temporarily and @pos's + * kernfs_drain() drops kernfs_rwsem temporarily and @pos's * base ref could have been put by someone else by the time * the function returns. Make sure it doesn't go away * underneath us. @@ -1353,9 +1364,9 @@ static void __kernfs_remove(struct kernfs_node *kn) */ void kernfs_remove(struct kernfs_node *kn) { - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); __kernfs_remove(kn); - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); } /** @@ -1442,17 +1453,17 @@ bool kernfs_remove_self(struct kernfs_node *kn) { bool ret; - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); kernfs_break_active_protection(kn); /* * SUICIDAL is used to arbitrate among competing invocations. Only * the first one will actually perform removal. When the removal * is complete, SUICIDED is set and the active ref is restored - * while holding kernfs_mutex. The ones which lost arbitration - * waits for SUICDED && drained which can happen only after the - * enclosing kernfs operation which executed the winning instance - * of kernfs_remove_self() finished. + * while holding kernfs_rwsem for write. The ones which lost + * arbitration waits for SUICIDED && drained which can happen only + * after the enclosing kernfs operation which executed the winning + * instance of kernfs_remove_self() finished. */ if (!(kn->flags & KERNFS_SUICIDAL)) { kn->flags |= KERNFS_SUICIDAL; @@ -1470,9 +1481,9 @@ bool kernfs_remove_self(struct kernfs_node *kn) atomic_read(&kn->active) == KN_DEACTIVATED_BIAS) break; - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); schedule(); - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); } finish_wait(waitq, &wait); WARN_ON_ONCE(!RB_EMPTY_NODE(&kn->rb)); @@ -1480,12 +1491,12 @@ bool kernfs_remove_self(struct kernfs_node *kn) } /* - * This must be done while holding kernfs_mutex; otherwise, waiting - * for SUICIDED && deactivated could finish prematurely. + * This must be done while holding kernfs_rwsem for write; otherwise, + * waiting for SUICIDED && deactivated could finish prematurely. */ kernfs_unbreak_active_protection(kn); - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); return ret; } @@ -1509,13 +1520,13 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, return -ENOENT; } - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); kn = kernfs_find_ns(parent, name, ns); if (kn) __kernfs_remove(kn); - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); if (kn) return 0; @@ -1541,10 +1552,10 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, if (!kn->parent) return -EINVAL; - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); error = -ENOENT; - if (!kernfs_active(kn) || !kernfs_active(new_parent) || + if (!kernfs_active_write(kn) || !kernfs_active_write(new_parent) || (new_parent->flags & KERNFS_EMPTY_DIR)) goto out; @@ -1595,7 +1606,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, error = 0; out: - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); return error; } @@ -1615,7 +1626,7 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns, struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) { if (pos) { - int valid = kernfs_active(pos) && + int valid = kernfs_active_read(pos) && pos->parent == parent && hash == pos->hash; kernfs_put(pos); if (!valid) @@ -1635,7 +1646,7 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns, } } /* Skip over entries which are dying/dead or in the wrong namespace */ - while (pos && (!kernfs_active(pos) || pos->ns != ns)) { + while (pos && (!kernfs_active_read(pos) || pos->ns != ns)) { struct rb_node *node = rb_next(&pos->rb); if (!node) pos = NULL; @@ -1656,7 +1667,7 @@ static struct kernfs_node *kernfs_dir_next_pos(const void *ns, pos = NULL; else pos = rb_to_kn(node); - } while (pos && (!kernfs_active(pos) || pos->ns != ns)); + } while (pos && (!kernfs_active_read(pos) || pos->ns != ns)); } return pos; } @@ -1670,7 +1681,7 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) if (!dir_emit_dots(file, ctx)) return 0; - mutex_lock(&kernfs_mutex); + down_read(&kernfs_rwsem); if (kernfs_ns_enabled(parent)) ns = kernfs_info(dentry->d_sb)->ns; @@ -1687,12 +1698,12 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) file->private_data = pos; kernfs_get(pos); - mutex_unlock(&kernfs_mutex); + up_read(&kernfs_rwsem); if (!dir_emit(ctx, name, len, ino, type)) return 0; - mutex_lock(&kernfs_mutex); + down_read(&kernfs_rwsem); } - mutex_unlock(&kernfs_mutex); + up_read(&kernfs_rwsem); file->private_data = NULL; ctx->pos = INT_MAX; return 0; diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 34366db3620d..455caea6ab0b 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -879,7 +879,7 @@ static void kernfs_notify_workfn(struct work_struct *work) spin_unlock_irq(&kernfs_notify_lock); /* kick fsnotify */ - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); list_for_each_entry(info, &kernfs_root(kn)->supers, node) { struct kernfs_node *parent; @@ -916,7 +916,7 @@ static void kernfs_notify_workfn(struct work_struct *work) iput(inode); } - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); kernfs_put(kn); goto repeat; } diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index fc2469a20fed..32e334e0d687 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -106,9 +106,9 @@ int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) { int ret; - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); ret = __kernfs_setattr(kn, iattr); - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); return ret; } @@ -121,7 +121,7 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr) if (!kn) return -EINVAL; - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); error = setattr_prepare(dentry, iattr); if (error) goto out; @@ -134,7 +134,7 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr) setattr_copy(inode, iattr); out: - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); return error; } @@ -189,9 +189,9 @@ int kernfs_iop_getattr(const struct path *path, struct kstat *stat, struct inode *inode = d_inode(path->dentry); struct kernfs_node *kn = inode->i_private; - mutex_lock(&kernfs_mutex); + down_read(&kernfs_rwsem); kernfs_refresh_inode(kn, inode); - mutex_unlock(&kernfs_mutex); + up_read(&kernfs_rwsem); generic_fillattr(inode, stat); return 0; @@ -281,9 +281,9 @@ int kernfs_iop_permission(struct inode *inode, int mask) kn = inode->i_private; - mutex_lock(&kernfs_mutex); + down_read(&kernfs_rwsem); kernfs_refresh_inode(kn, inode); - mutex_unlock(&kernfs_mutex); + up_read(&kernfs_rwsem); return generic_permission(inode, mask); } diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 7ee97ef59184..097c1a989aa4 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -69,7 +70,7 @@ struct kernfs_super_info { */ const void *ns; - /* anchored at kernfs_root->supers, protected by kernfs_mutex */ + /* anchored at kernfs_root->supers, protected by kernfs_rwsem */ struct list_head node; }; #define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info)) @@ -99,7 +100,7 @@ int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr); /* * dir.c */ -extern struct mutex kernfs_mutex; +extern struct rw_semaphore kernfs_rwsem; extern const struct dentry_operations kernfs_dops; extern const struct file_operations kernfs_dir_fops; extern const struct inode_operations kernfs_dir_iops; diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 9dc7e7a64e10..baa4155ba2ed 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -255,9 +255,9 @@ static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *k sb->s_shrink.seeks = 0; /* get root inode, initialize and unlock it */ - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); inode = kernfs_get_inode(sb, info->root->kn); - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); if (!inode) { pr_debug("kernfs: could not get root inode\n"); return -ENOMEM; @@ -344,9 +344,9 @@ int kernfs_get_tree(struct fs_context *fc) } sb->s_flags |= SB_ACTIVE; - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); list_add(&info->node, &info->root->supers); - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); } fc->root = dget(sb->s_root); @@ -372,9 +372,9 @@ void kernfs_kill_sb(struct super_block *sb) { struct kernfs_super_info *info = kernfs_info(sb); - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); list_del(&info->node); - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); /* * Remove the superblock from fs_supers/s_instances diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index 5432883d819f..7246b470de3c 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -116,9 +116,9 @@ static int kernfs_getlink(struct inode *inode, char *path) struct kernfs_node *target = kn->symlink.target_kn; int error; - mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); error = kernfs_get_target_path(parent, target, path); - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); return error; } From patchwork Mon May 25 05:47:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Kent X-Patchwork-Id: 11568077 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B40DD60D for ; Mon, 25 May 2020 05:47:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9649120825 for ; Mon, 25 May 2020 05:47:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=themaw.net header.i=@themaw.net header.b="u0qmfAHx"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="EJbduoMH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388519AbgEYFrP (ORCPT ); Mon, 25 May 2020 01:47:15 -0400 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:46009 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388508AbgEYFrO (ORCPT ); Mon, 25 May 2020 01:47:14 -0400 Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailout.west.internal (Postfix) with ESMTP id DE73AEC0; Mon, 25 May 2020 01:47:12 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Mon, 25 May 2020 01:47:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=themaw.net; h= subject:from:to:cc:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=fm3; bh= FtR+UgOOZLBiQrxLIVMV0q/xz8NJCgPfEh2OWV3jrgA=; b=u0qmfAHxIMHVRI0N ZTFLJ3BxnZMG0HEatOhEhb4Xg9/co4Y4hOoiZkW5qwF5YRDOJIpkmlbzdivWun2n RbteUJx4HHE0283zBlb6GkvNihLxTVI65D64O3KFAajbm9DaYBCgKDoB2s92O6am FOTATTr/fPChVcCoVqDfCYEpDD+6LGMArgfYnoo/UGZmCygZvfaBQAynSwVw1DOP v+DND6hrpCttdZW4doSIBpGC9+5+RVeFfVh/llNYJEK8mzAc4TMMwe+LsqDyKXSK 8E1BjYaSC1npJjGXFF/nbjlNW69Czxql8wXRrRdseCH2XObpT5xlVn4N88QIZlul saPhgg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm2; bh=FtR+UgOOZLBiQrxLIVMV0q/xz8NJCgPfEh2OWV3jr gA=; b=EJbduoMHGLUcTCmwBkosAXbtfWOJmbs4OauGGGo+rXXreutVzElhQr2d8 yBGvwl1mhadY6HEsUVJ+1vlwE/CTscrj3LlPHGJhccCFQVssZoA0AhDo26M/zyQD 4vvSDn3IS9Zu2dn2pucoX7MG9hWqwz/U0fKNVGd5USv4aqbBFv9xrFcq/dte9yYR Eugfn/g3aqxFrqrskD6HogUEaXXueeM6x97tAmiuVWsNioFoCzccc2Ry2Td4QsV2 T9r6eEtBWg86WCUi4qXFbkAkgkgwIYgD1Uay1Ct9nRsHzLbr388OIP7UCTG0P+Mw b0gUInD0XSpQ/RhfhG5u0fSaLgjnw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrudduledgleejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepuffhvfffkfgjfhgfgggtgfesthejredttderjeenucfhrhhomhepkfgrnhcu mfgvnhhtuceorhgrvhgvnhesthhhvghmrgifrdhnvghtqeenucggtffrrghtthgvrhhnpe egveeuudffieeiffefieehvdetieeiteelheetueekledtledugeffheffieduieenucfk phepuddukedrvddtkedrudejkedrudeknecuvehluhhsthgvrhfuihiivgeptdenucfrrg hrrghmpehmrghilhhfrhhomheprhgrvhgvnhesthhhvghmrgifrdhnvght X-ME-Proxy: Received: from mickey.localdomain (unknown [118.208.178.18]) by mail.messagingengine.com (Postfix) with ESMTPA id 266F6306654C; Mon, 25 May 2020 01:47:12 -0400 (EDT) Received: from mickey.themaw.net (localhost [127.0.0.1]) by mickey.localdomain (Postfix) with ESMTP id B01C0A01C8; Mon, 25 May 2020 13:47:09 +0800 (AWST) Subject: [PATCH 2/4] kernfs: move revalidate to be near lookup From: Ian Kent To: Andrew Morton Cc: Al Viro , Greg Kroah-Hartman , Tejun Heo , Rick Lindsley , Stephen Rothwell , David Howells , Miklos Szeredi , linux-fsdevel , Kernel Mailing List Date: Mon, 25 May 2020 13:47:09 +0800 Message-ID: <159038562968.276051.1536156625429513766.stgit@mickey.themaw.net> In-Reply-To: <159038508228.276051.14042452586133971255.stgit@mickey.themaw.net> References: <159038508228.276051.14042452586133971255.stgit@mickey.themaw.net> User-Agent: StGit/0.19 MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org While the dentry operation kernfs_dop_revalidate() is grouped with dentry'ish functions it also has a strong afinity to the inode operation ->lookup(). And when path walk improvements are applied it will need to call kernfs_find_ns() so move it to be near kernfs_iop_lookup() to avoid the need for a forward declaration. There's no functional change from this patch. Signed-off-by: Ian Kent --- fs/kernfs/dir.c | 86 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index d8213fc65eba..9b315f3b20ee 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -559,49 +559,6 @@ void kernfs_put(struct kernfs_node *kn) } EXPORT_SYMBOL_GPL(kernfs_put); -static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) -{ - struct kernfs_node *kn; - - if (flags & LOOKUP_RCU) - return -ECHILD; - - /* Always perform fresh lookup for negatives */ - if (d_really_is_negative(dentry)) - goto out_bad_unlocked; - - kn = kernfs_dentry_node(dentry); - down_read(&kernfs_rwsem); - - /* The kernfs node has been deactivated */ - if (!kernfs_active_read(kn)) - goto out_bad; - - /* The kernfs node has been moved? */ - if (kernfs_dentry_node(dentry->d_parent) != kn->parent) - goto out_bad; - - /* The kernfs node has been renamed */ - if (strcmp(dentry->d_name.name, kn->name) != 0) - goto out_bad; - - /* The kernfs node has been moved to a different namespace */ - if (kn->parent && kernfs_ns_enabled(kn->parent) && - kernfs_info(dentry->d_sb)->ns != kn->ns) - goto out_bad; - - up_read(&kernfs_rwsem); - return 1; -out_bad: - up_read(&kernfs_rwsem); -out_bad_unlocked: - return 0; -} - -const struct dentry_operations kernfs_dops = { - .d_revalidate = kernfs_dop_revalidate, -}; - /** * kernfs_node_from_dentry - determine kernfs_node associated with a dentry * @dentry: the dentry in question @@ -1085,6 +1042,49 @@ struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, return ERR_PTR(rc); } +static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) +{ + struct kernfs_node *kn; + + if (flags & LOOKUP_RCU) + return -ECHILD; + + /* Always perform fresh lookup for negatives */ + if (d_really_is_negative(dentry)) + goto out_bad_unlocked; + + kn = kernfs_dentry_node(dentry); + down_read(&kernfs_rwsem); + + /* The kernfs node has been deactivated */ + if (!kernfs_active_read(kn)) + goto out_bad; + + /* The kernfs node has been moved? */ + if (kernfs_dentry_node(dentry->d_parent) != kn->parent) + goto out_bad; + + /* The kernfs node has been renamed */ + if (strcmp(dentry->d_name.name, kn->name) != 0) + goto out_bad; + + /* The kernfs node has been moved to a different namespace */ + if (kn->parent && kernfs_ns_enabled(kn->parent) && + kernfs_info(dentry->d_sb)->ns != kn->ns) + goto out_bad; + + up_read(&kernfs_rwsem); + return 1; +out_bad: + up_read(&kernfs_rwsem); +out_bad_unlocked: + return 0; +} + +const struct dentry_operations kernfs_dops = { + .d_revalidate = kernfs_dop_revalidate, +}; + static struct dentry *kernfs_iop_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) From patchwork Mon May 25 05:47:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Kent X-Patchwork-Id: 11568079 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 71BAB1392 for ; Mon, 25 May 2020 05:47:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 556F12088E for ; Mon, 25 May 2020 05:47:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=themaw.net header.i=@themaw.net header.b="1BcISEUs"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="JT3Vn6sl" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388605AbgEYFrU (ORCPT ); Mon, 25 May 2020 01:47:20 -0400 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:48979 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388508AbgEYFrT (ORCPT ); Mon, 25 May 2020 01:47:19 -0400 Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailout.west.internal (Postfix) with ESMTP id 1E52EE95; Mon, 25 May 2020 01:47:18 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Mon, 25 May 2020 01:47:18 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=themaw.net; h= subject:from:to:cc:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=fm3; bh= /rAbDMt6FC3fG09UnQPczhNktJ9DSAXatCwomfNKw7A=; b=1BcISEUsmembfiAk uJgmNsmda1TxNncHvG+2lhjU4sMPNRvgLIsVRdPjTxbuY8RclLxaosNVQYT5HoKx RbpC0aNf7gm+IPSYhLYbZ97v72jwrrDtdteiIDA/7Nuj7gJrBL63M5OZxVfMNTqj JVNLhNq87RiX6fVyEXO7Bt/7bnl85QFY3qF6bbkC1EqjbRwijvbEHlaWoj6hm2jP ozSIJ/ZxabQYbMTBPf+tFqqB4OlLYxFnKoA8sJ2bZlDYQglOSVZVs5dA4ZsQZn+L ti3BJYA1lOkhbrDCaGQh0/BpyslDxkso0CqF8upJ3KU0Ld9nZ6YYDyXJwLKNO0MG 6KvHnA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm2; bh=/rAbDMt6FC3fG09UnQPczhNktJ9DSAXatCwomfNKw 7A=; b=JT3Vn6slGzHi27Xyf+LDuLF1anCpHRaUHJlicO7s6YOiIgy8wVnHkE9+P DNq+cliTGWoQxjlm7OohBuegvWAcVgrtnmMqCbvlku94BnOLYpQboeX+cxkPE0XT HcAdhqHNjxPxn7x9zSbS9hIKpARF8KtrrrQwM8Qy3+M+Aq+2Q/MI8X6RR0tdMyoO /aZdahWrv/xKO9g8/6ADK2J5EHmPGG7DtRaFG7XjwNWZjdmWo3dwSHD7eAu1rGnX l04FjBYPrqpI5IsDQPfobcsKi1zC7RUw1m1pBGvZZEZgocN8pnOkpYtECE2nreq1 129XErrk9v8VZE/z0uzVOHdREH0Ig== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrudduledgleejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepuffhvfffkfgjfhgfgggtgfesthejredttderjeenucfhrhhomhepkfgrnhcu mfgvnhhtuceorhgrvhgvnhesthhhvghmrgifrdhnvghtqeenucggtffrrghtthgvrhhnpe egveeuudffieeiffefieehvdetieeiteelheetueekledtledugeffheffieduieenucfk phepuddukedrvddtkedrudejkedrudeknecuvehluhhsthgvrhfuihiivgepvdenucfrrg hrrghmpehmrghilhhfrhhomheprhgrvhgvnhesthhhvghmrgifrdhnvght X-ME-Proxy: Received: from mickey.localdomain (unknown [118.208.178.18]) by mail.messagingengine.com (Postfix) with ESMTPA id 435083280059; Mon, 25 May 2020 01:47:17 -0400 (EDT) Received: from mickey.themaw.net (localhost [127.0.0.1]) by mickey.localdomain (Postfix) with ESMTP id BD48DA01C8; Mon, 25 May 2020 13:47:14 +0800 (AWST) Subject: [PATCH 3/4] kernfs: improve kernfs path resolution From: Ian Kent To: Andrew Morton Cc: Al Viro , Greg Kroah-Hartman , Tejun Heo , Rick Lindsley , Stephen Rothwell , David Howells , Miklos Szeredi , linux-fsdevel , Kernel Mailing List Date: Mon, 25 May 2020 13:47:14 +0800 Message-ID: <159038563473.276051.9549849659872866062.stgit@mickey.themaw.net> In-Reply-To: <159038508228.276051.14042452586133971255.stgit@mickey.themaw.net> References: <159038508228.276051.14042452586133971255.stgit@mickey.themaw.net> User-Agent: StGit/0.19 MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Now that an rwsem is used by kernfs, take advantage of it to reduce lookup overhead. If there are many lookups (possibly many negative ones) there can be a lot of overhead during path walks. To reduce lookup overhead avoid allocating a new dentry where possible. To do this stay in rcu-walk mode where possible and use the dentry cache handling of negative hashed dentries to avoid allocating (and freeing shortly after) new dentries on every negative lookup. Signed-off-by: Ian Kent --- fs/kernfs/dir.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 15 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 9b315f3b20ee..f4943329e578 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -1046,15 +1046,75 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) { struct kernfs_node *kn; - if (flags & LOOKUP_RCU) + if (flags & LOOKUP_RCU) { + kn = kernfs_dentry_node(dentry); + if (!kn) { + /* Negative hashed dentry, tell the VFS to switch to + * ref-walk mode and call us again so that node + * existence can be checked. + */ + if (!d_unhashed(dentry)) + return -ECHILD; + + /* Negative unhashed dentry, this shouldn't happen + * because this case occurs in rcu-walk mode after + * dentry allocation which is followed by a call + * to ->loopup(). But if it does happen the dentry + * is surely invalid. + */ + return 0; + } + + /* Since the dentry is positive (we got the kernfs node) a + * kernfs node reference was held at the time. Now if the + * dentry reference count is still greater than 0 it's still + * positive so take a reference to the node to perform an + * active check. + */ + if (d_count(dentry) <= 0 || !atomic_inc_not_zero(&kn->count)) + return -ECHILD; + + /* The kernfs node reference count was greater than 0, if + * it's active continue in rcu-walk mode. + */ + if (kernfs_active_read(kn)) { + kernfs_put(kn); + return 1; + } + + /* Otherwise, just tell the VFS to switch to ref-walk mode + * and call us again so the kernfs node can be validated. + */ + kernfs_put(kn); return -ECHILD; + } - /* Always perform fresh lookup for negatives */ - if (d_really_is_negative(dentry)) - goto out_bad_unlocked; + down_read(&kernfs_rwsem); kn = kernfs_dentry_node(dentry); - down_read(&kernfs_rwsem); + if (!kn) { + struct kernfs_node *parent; + + /* If the kernfs node can be found this is a stale negative + * hashed dentry so it must be discarded and the lookup redone. + */ + parent = kernfs_dentry_node(dentry->d_parent); + if (parent) { + const void *ns = NULL; + + if (kernfs_ns_enabled(parent)) + ns = kernfs_info(dentry->d_parent->d_sb)->ns; + kn = kernfs_find_ns(parent, dentry->d_name.name, ns); + if (kn) + goto out_bad; + } + + /* The kernfs node doesn't exist, leave the dentry negative + * and return success. + */ + goto out; + } + /* The kernfs node has been deactivated */ if (!kernfs_active_read(kn)) @@ -1072,12 +1132,11 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) if (kn->parent && kernfs_ns_enabled(kn->parent) && kernfs_info(dentry->d_sb)->ns != kn->ns) goto out_bad; - +out: up_read(&kernfs_rwsem); return 1; out_bad: up_read(&kernfs_rwsem); -out_bad_unlocked: return 0; } @@ -1092,7 +1151,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, struct dentry *ret; struct kernfs_node *parent = dir->i_private; struct kernfs_node *kn; - struct inode *inode; + struct inode *inode = NULL; const void *ns = NULL; down_read(&kernfs_rwsem); @@ -1102,11 +1161,9 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, kn = kernfs_find_ns(parent, dentry->d_name.name, ns); - /* no such entry */ - if (!kn || !kernfs_active(kn)) { - ret = NULL; - goto out_unlock; - } + /* no such entry, retain as negative hashed dentry */ + if (!kn || !kernfs_active(kn)) + goto out_negative; /* attach dentry and inode */ inode = kernfs_get_inode(dir->i_sb, kn); @@ -1114,10 +1171,10 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, ret = ERR_PTR(-ENOMEM); goto out_unlock; } - +out_negative: /* instantiate and hash dentry */ ret = d_splice_alias(inode, dentry); - out_unlock: +out_unlock: up_read(&kernfs_rwsem); return ret; } From patchwork Mon May 25 05:47:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Kent X-Patchwork-Id: 11568081 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1F38F60D for ; Mon, 25 May 2020 05:47:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F255C20849 for ; Mon, 25 May 2020 05:47:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=themaw.net header.i=@themaw.net header.b="WDSzJbSe"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="0IWE8Xn2" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388655AbgEYFrZ (ORCPT ); Mon, 25 May 2020 01:47:25 -0400 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:56777 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388508AbgEYFrY (ORCPT ); Mon, 25 May 2020 01:47:24 -0400 Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailout.west.internal (Postfix) with ESMTP id 315FFEAD; Mon, 25 May 2020 01:47:23 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Mon, 25 May 2020 01:47:23 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=themaw.net; h= subject:from:to:cc:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=fm3; bh= YP81i3I+Z4aS6pPC7VYSp+SNREBPRhMa7fFT8ZR5kf8=; b=WDSzJbSeRjxarBWv uv+FsTeoLHNBUCj55Tk1jNwyu+h4111LyEigBRNGAbPPV1ywpHAMX9VFScYCOcD4 5BPC+lAEJB68cOBM7YeYeOwlbZ7ut8hPFyTYu8EGUBLGkMbE15D3OdnN+E4dz7VS 138LOUGQ7Om0IJOevVRd5ipY7HI5LCDIbFBUgwC6OUWI4zPr6zEn8o6UZhlG8xKV WUcipVNcZ0Knn3soEXgIiyaedl0JULkM+JUjcVaAZp9vqYCQxoib4sxZCouqCc9T VUxeenSbrHPcFIfcgRMXP9VYlTCI8+QFW2DURMN1YkX+WbzRZyEwElRiHVjCCRl1 XUjx3Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm2; bh=YP81i3I+Z4aS6pPC7VYSp+SNREBPRhMa7fFT8ZR5k f8=; b=0IWE8Xn2u1YXzPUhw7aBa/tFsK6szhdkkcNKrofSzVr2KWuggjzBcIaej b8YjMvai3Acei9R8HjyT508uHyFnb5hbKPjzJDPsDPngF3jTMZxLkUim9KwrvubU nybuXdbs0Yt51xfZorKuBaxHD3k6sgt0fifVl7RP6YJ4gl/302SG8piLdSWzA2Ue YHnfu6rMic9QDJwI2E6y2JguL/lq/Br0sTyhRhT5vuYQyBtuIQFxNgP3r3TE1PgY gEgUG2mSHgL9Opnrz5EtaiwKY9XNKjM+PGy15j9cSGa0Gnjt+v6pQZJNVVv9zaoa YziGmE5PP15WDXK+ea7778AbFNNoQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrudduledgleejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepuffhvfffkfgjfhgfgggtgfesthejredttderjeenucfhrhhomhepkfgrnhcu mfgvnhhtuceorhgrvhgvnhesthhhvghmrgifrdhnvghtqeenucggtffrrghtthgvrhhnpe egveeuudffieeiffefieehvdetieeiteelheetueekledtledugeffheffieduieenucfk phepuddukedrvddtkedrudejkedrudeknecuvehluhhsthgvrhfuihiivgepfeenucfrrg hrrghmpehmrghilhhfrhhomheprhgrvhgvnhesthhhvghmrgifrdhnvght X-ME-Proxy: Received: from mickey.localdomain (unknown [118.208.178.18]) by mail.messagingengine.com (Postfix) with ESMTPA id 546803066549; Mon, 25 May 2020 01:47:22 -0400 (EDT) Received: from mickey.themaw.net (localhost [127.0.0.1]) by mickey.localdomain (Postfix) with ESMTP id CC18FA01C8; Mon, 25 May 2020 13:47:19 +0800 (AWST) Subject: [PATCH 4/4] kernfs: use revision to identify directory node changes From: Ian Kent To: Andrew Morton Cc: Al Viro , Greg Kroah-Hartman , Tejun Heo , Rick Lindsley , Stephen Rothwell , David Howells , Miklos Szeredi , linux-fsdevel , Kernel Mailing List Date: Mon, 25 May 2020 13:47:19 +0800 Message-ID: <159038563978.276051.367264947378071815.stgit@mickey.themaw.net> In-Reply-To: <159038508228.276051.14042452586133971255.stgit@mickey.themaw.net> References: <159038508228.276051.14042452586133971255.stgit@mickey.themaw.net> User-Agent: StGit/0.19 MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org If a kernfs directory node hasn't changed there's no need to search for an added (or removed) child dentry. Add a revision counter to kernfs directory nodes so it can be used to detect if a directory node has changed. Signed-off-by: Ian Kent --- fs/kernfs/dir.c | 17 +++++++++++++++-- fs/kernfs/kernfs-internal.h | 24 ++++++++++++++++++++++++ include/linux/kernfs.h | 5 +++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index f4943329e578..03f4f179bbc4 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -383,6 +383,7 @@ static int kernfs_link_sibling(struct kernfs_node *kn) /* successfully added, account subdir number */ if (kernfs_type(kn) == KERNFS_DIR) kn->parent->dir.subdirs++; + kernfs_inc_rev(kn->parent); return 0; } @@ -405,6 +406,7 @@ static bool kernfs_unlink_sibling(struct kernfs_node *kn) if (kernfs_type(kn) == KERNFS_DIR) kn->parent->dir.subdirs--; + kernfs_inc_rev(kn->parent); rb_erase(&kn->rb, &kn->parent->dir.children); RB_CLEAR_NODE(&kn->rb); @@ -1044,9 +1046,16 @@ struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) { + struct kernfs_node *parent; struct kernfs_node *kn; if (flags & LOOKUP_RCU) { + /* Directory node changed? */ + parent = kernfs_dentry_node(dentry->d_parent); + + if (!kernfs_dir_changed(parent, dentry)) + return 1; + kn = kernfs_dentry_node(dentry); if (!kn) { /* Negative hashed dentry, tell the VFS to switch to @@ -1093,8 +1102,6 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) kn = kernfs_dentry_node(dentry); if (!kn) { - struct kernfs_node *parent; - /* If the kernfs node can be found this is a stale negative * hashed dentry so it must be discarded and the lookup redone. */ @@ -1102,6 +1109,10 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) if (parent) { const void *ns = NULL; + /* Directory node changed? */ + if (kernfs_dir_changed(parent, dentry)) + goto out_bad; + if (kernfs_ns_enabled(parent)) ns = kernfs_info(dentry->d_parent->d_sb)->ns; kn = kernfs_find_ns(parent, dentry->d_name.name, ns); @@ -1156,6 +1167,8 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, down_read(&kernfs_rwsem); + kernfs_set_rev(dentry, parent); + if (kernfs_ns_enabled(parent)) ns = kernfs_info(dir->i_sb)->ns; diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 097c1a989aa4..a7b0e2074260 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -82,6 +82,30 @@ static inline struct kernfs_node *kernfs_dentry_node(struct dentry *dentry) return d_inode(dentry)->i_private; } +static inline void kernfs_set_rev(struct dentry *dentry, + struct kernfs_node *kn) +{ + dentry->d_time = kn->dir.rev; +} + +static inline void kernfs_inc_rev(struct kernfs_node *kn) +{ + if (kernfs_type(kn) == KERNFS_DIR) { + if (!++kn->dir.rev) + kn->dir.rev++; + } +} + +static inline bool kernfs_dir_changed(struct kernfs_node *kn, + struct dentry *dentry) +{ + if (kernfs_type(kn) == KERNFS_DIR) { + if (kn->dir.rev != dentry->d_time) + return true; + } + return false; +} + extern const struct super_operations kernfs_sops; extern struct kmem_cache *kernfs_node_cache, *kernfs_iattrs_cache; diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 89f6a4214a70..74727d98e380 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -98,6 +98,11 @@ struct kernfs_elem_dir { * better directly in kernfs_node but is here to save space. */ struct kernfs_root *root; + /* + * Monotonic revision counter, used to identify if a directory + * node has changed during revalidation. + */ + unsigned long rev; }; struct kernfs_elem_symlink {