From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D71ECC46CA3 for ; Mon, 4 Dec 2023 20:38:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1346331AbjLDUh6 (ORCPT ); Mon, 4 Dec 2023 15:37:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58300 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235571AbjLDUhZ (ORCPT ); Mon, 4 Dec 2023 15:37:25 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6427B18E for ; Mon, 4 Dec 2023 12:35:40 -0800 (PST) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 14263C433D9; Mon, 4 Dec 2023 20:35:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1701722140; bh=1aSSTz76/mulK0UxRDrGBoJkZ0tRJ/L82eiGvkMYXJ0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iHHkh8vfLgVkI4xN0UiPY4OMI9u8qL5y7Scl0cpk9UkyZpzE7L7b74ukyVRd3BvWb 3qGh+XZXubLvYvFSHohcBkxcEDaNhmOgz2gTCiu4H/NClWXLoIronQIFx3RxTZHqM8 yfLrxJo/gD2BAWRAcE5ZQjHsi2mg/gO8nCDECNO0YCKTB15aLaa7ceIeZ/7Qcj1b6v EXHVBwWnbWtJHFyHF6w+T43FawSa6SJCQyWz5VSk7FLTAhXwcE8rqpoGtVUKqoQNox qyKaxItvf4Vv+1+02ulex1vL7b1NzqEL89xNmo9GINpKP5nvpWb1slkBX3KFR8S+v0 2h4xwxdnjPZUQ== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Johannes Berg , Greg Kroah-Hartman , Sasha Levin Subject: [PATCH AUTOSEL 6.1 09/17] debugfs: annotate debugfs handlers vs. removal with lockdep Date: Mon, 4 Dec 2023 15:34:54 -0500 Message-ID: <20231204203514.2093855-9-sashal@kernel.org> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231204203514.2093855-1-sashal@kernel.org> References: <20231204203514.2093855-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore X-stable-base: Linux 6.1.65 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Johannes Berg [ Upstream commit f4acfcd4deb158b96595250cc332901b282d15b0 ] When you take a lock in a debugfs handler but also try to remove the debugfs file under that lock, things can deadlock since the removal has to wait for all users to finish. Add lockdep annotations in debugfs_file_get()/_put() to catch such issues. Acked-by: Greg Kroah-Hartman Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- fs/debugfs/file.c | 10 ++++++++++ fs/debugfs/inode.c | 12 ++++++++++++ fs/debugfs/internal.h | 6 ++++++ 3 files changed, 28 insertions(+) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index b38304b444764..375af381bf005 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -108,6 +108,12 @@ int debugfs_file_get(struct dentry *dentry) kfree(fsd); fsd = READ_ONCE(dentry->d_fsdata); } +#ifdef CONFIG_LOCKDEP + fsd->lock_name = kasprintf(GFP_KERNEL, "debugfs:%pd", dentry); + lockdep_register_key(&fsd->key); + lockdep_init_map(&fsd->lockdep_map, fsd->lock_name ?: "debugfs", + &fsd->key, 0); +#endif } /* @@ -124,6 +130,8 @@ int debugfs_file_get(struct dentry *dentry) if (!refcount_inc_not_zero(&fsd->active_users)) return -EIO; + lock_map_acquire_read(&fsd->lockdep_map); + return 0; } EXPORT_SYMBOL_GPL(debugfs_file_get); @@ -141,6 +149,8 @@ void debugfs_file_put(struct dentry *dentry) { struct debugfs_fsdata *fsd = READ_ONCE(dentry->d_fsdata); + lock_map_release(&fsd->lockdep_map); + if (refcount_dec_and_test(&fsd->active_users)) complete(&fsd->active_users_drained); } diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 08ef685167ec5..8fc470aa67823 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -242,6 +242,14 @@ static void debugfs_release_dentry(struct dentry *dentry) if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) return; + /* check it wasn't a dir (no fsdata) or automount (no real_fops) */ + if (fsd && fsd->real_fops) { +#ifdef CONFIG_LOCKDEP + lockdep_unregister_key(&fsd->key); + kfree(fsd->lock_name); +#endif + } + kfree(fsd); } @@ -745,6 +753,10 @@ static void __debugfs_file_removed(struct dentry *dentry) fsd = READ_ONCE(dentry->d_fsdata); if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) return; + + lock_map_acquire(&fsd->lockdep_map); + lock_map_release(&fsd->lockdep_map); + if (!refcount_dec_and_test(&fsd->active_users)) wait_for_completion(&fsd->active_users_drained); } diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index f7c489b5a368c..c7d61cfc97d26 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -7,6 +7,7 @@ #ifndef _DEBUGFS_INTERNAL_H_ #define _DEBUGFS_INTERNAL_H_ +#include struct file_operations; @@ -23,6 +24,11 @@ struct debugfs_fsdata { struct { refcount_t active_users; struct completion active_users_drained; +#ifdef CONFIG_LOCKDEP + struct lockdep_map lockdep_map; + struct lock_class_key key; + char *lock_name; +#endif }; }; }; -- 2.42.0