From 27600805e62f800bacf990354632eae4e487d34c Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Thu, 3 Sep 2026 10:43:25 -0500 Subject: x86/amd_node: Fix PCI device reference counting in amd_smn_init() The local "root" pointer is a temporary variable used during the device search. Therefore, refcount related to the search iterators should be cleaned up after the search is complete. Use the __free() cleanup macro to ensure the refcount is decremented when the temporary pointer goes out of scope. Additionally, increment the refcount when caching a root pointer. This ensures the in-use refcount is separate from the temporary search refcounting. Finally, drop the redundant "root = NULL" before the second search loop. The pci_get_class() iterator always decrements the refcount of its "from" argument, so the first loop can only fall through with "root" already NULL. Fixes: 0a4b61d9c2e4 ("x86/amd_node: Fix AMD root device caching") Closes: https://sashiko.dev/#/patchset/20260806160159.230453-1-jason.andryuk%40amd.com Reported-by: Sashiko Assisted-by: LLM Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Mario Limonciello (AMD) Cc: Link: https://patch.msgid.link/20260903154325.74343-1-yazen.ghannam@amd.com --- fs/configfs/mount.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 fs/configfs/mount.c (limited to 'fs/configfs/mount.c') diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c new file mode 100644 index 000000000..4929f3431 --- /dev/null +++ b/fs/configfs/mount.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * mount.c - operations for initializing and mounting configfs. + * + * Based on sysfs: + * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel + * + * configfs Copyright (C) 2005 Oracle. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "configfs_internal.h" + +/* Random magic number */ +#define CONFIGFS_MAGIC 0x62656570 + +static struct vfsmount *configfs_mount = NULL; +struct kmem_cache *configfs_dir_cachep; +static int configfs_mnt_count = 0; + + +static void configfs_free_inode(struct inode *inode) +{ + if (S_ISLNK(inode->i_mode)) + kfree(inode->i_link); + free_inode_nonrcu(inode); +} + +static const struct super_operations configfs_ops = { + .statfs = simple_statfs, + .drop_inode = inode_just_drop, + .free_inode = configfs_free_inode, +}; + +static struct config_group configfs_root_group = { + .cg_item = { + .ci_namebuf = "root", + .ci_name = configfs_root_group.cg_item.ci_namebuf, + }, +}; + +int configfs_is_root(struct config_item *item) +{ + return item == &configfs_root_group.cg_item; +} + +static struct configfs_dirent configfs_root = { + .s_sibling = LIST_HEAD_INIT(configfs_root.s_sibling), + .s_children = LIST_HEAD_INIT(configfs_root.s_children), + .s_element = &configfs_root_group.cg_item, + .s_type = CONFIGFS_ROOT, + .s_iattr = NULL, +}; + +static int configfs_fill_super(struct super_block *sb, struct fs_context *fc) +{ + struct inode *inode; + struct dentry *root; + + sb->s_blocksize = PAGE_SIZE; + sb->s_blocksize_bits = PAGE_SHIFT; + sb->s_magic = CONFIGFS_MAGIC; + sb->s_op = &configfs_ops; + sb->s_time_gran = 1; + + inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, + &configfs_root, sb); + if (inode) { + inode->i_op = &configfs_root_inode_operations; + inode->i_fop = &configfs_dir_operations; + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inc_nlink(inode); + } else { + pr_debug("could not get root inode\n"); + return -ENOMEM; + } + + root = d_make_root(inode); + if (!root) { + pr_debug("%s: could not get root dentry!\n",__func__); + return -ENOMEM; + } + config_group_init(&configfs_root_group); + configfs_root_group.cg_item.ci_dentry = root; + root->d_fsdata = &configfs_root; + sb->s_root = root; + set_default_d_op(sb, &configfs_dentry_ops); /* the rest get that */ + sb->s_d_flags |= DCACHE_DONTCACHE; + return 0; +} + +static int configfs_get_tree(struct fs_context *fc) +{ + return get_tree_single(fc, configfs_fill_super); +} + +static const struct fs_context_operations configfs_context_ops = { + .get_tree = configfs_get_tree, +}; + +static int configfs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &configfs_context_ops; + return 0; +} + +static struct file_system_type configfs_fs_type = { + .owner = THIS_MODULE, + .name = "configfs", + .init_fs_context = configfs_init_fs_context, + .kill_sb = kill_anon_super, +}; +MODULE_ALIAS_FS("configfs"); + +struct dentry *configfs_pin_fs(void) +{ + int err = simple_pin_fs(&configfs_fs_type, &configfs_mount, + &configfs_mnt_count); + return err ? ERR_PTR(err) : configfs_mount->mnt_root; +} + +void configfs_release_fs(void) +{ + simple_release_fs(&configfs_mount, &configfs_mnt_count); +} + + +static int __init configfs_init(void) +{ + int err = -ENOMEM; + + configfs_dir_cachep = kmem_cache_create("configfs_dir_cache", + sizeof(struct configfs_dirent), + 0, 0, NULL); + if (!configfs_dir_cachep) + goto out; + + err = sysfs_create_mount_point(kernel_kobj, "config"); + if (err) + goto out2; + + err = register_filesystem(&configfs_fs_type); + if (err) + goto out3; + + return 0; +out3: + pr_err("Unable to register filesystem!\n"); + sysfs_remove_mount_point(kernel_kobj, "config"); +out2: + kmem_cache_destroy(configfs_dir_cachep); + configfs_dir_cachep = NULL; +out: + return err; +} + +static void __exit configfs_exit(void) +{ + unregister_filesystem(&configfs_fs_type); + sysfs_remove_mount_point(kernel_kobj, "config"); + kmem_cache_destroy(configfs_dir_cachep); + configfs_dir_cachep = NULL; +} + +MODULE_AUTHOR("Oracle"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.2"); +MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration."); + +core_initcall(configfs_init); +module_exit(configfs_exit); -- cgit v1.3.1