* [PATCH RFC 0/2] configfs: enable kernel-space item registration @ 2025-12-02 15:29 ` Breno Leitao 2025-12-02 15:29 ` [PATCH RFC 1/2] configfs: add kernel-space item registration API Breno Leitao ` (2 more replies) 0 siblings, 3 replies; 8+ messages in thread From: Breno Leitao @ 2025-12-02 15:29 UTC (permalink / raw) To: Andreas Hindborg, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni Cc: Breno Leitao, linux-kernel, hch, jlbec, linux-fsdevel, netdev, gustavold, asantostc, calvin, kernel-team This series introduces a new kernel-space item registration API for configfs to enable subsystems to programmatically create configfs items whose lifecycle is controlled by the kernel rather than userspace. Currently, configfs items can only be created via userspace mkdir operations, which limits their utility for kernel-driven configuration scenarios such as boot parameters or hardware auto-detection. This discussion about this feature started 2 years ago[1], when netconsole needed to have an configfs target that maps to what was passed by cmdline (something as netconsole=+6666@192.168.1.1....) The suggestion was to workaround configfs limitation by asking users to create some pre-defined configfs entries specially named (such as "cmdlineX", where X is the entry index in the list of targets), that would match entries coming from cmdline. That proved to be confusing in many ways, such as: 1) if cmdline is not properly passed or parsed, then cmdline0 becomes a new and unrelated target 2) If netconsole becomes a module, then cmdline0 is not populated, so, the creation of cmdline0 is something unrelated to what we have in cmdline. 3) The admin needs to create X items properly matching the iterms from cmdline, which is error prone. The solution proposed in this patchset is to manage the life cycle of an item by the kernel (if the cmdline entry exists, it will populate the cofingfs automatically), instead of by the user (mkdir-ing special names). The new configfs_register_item() and configfs_unregister_item() functions fill this gap by allowing kernel modules to register items that appear in configfs but are protected from userspace removal. These items are marked with the CONFIGFS_USET_DEFAULT flag, making them behave similarly to default groups that are automatically created but cannot be removed via rmdir. The primary motivation for this work is to support dynamic netconsole target registration from boot parameters. Currently, netconsole can be configured either statically at boot time (cmdline) or dynamically via userspace manipulation of configfs directories. However, there is no way to create netconsole targets from kernel command line parameters that persist in configfs for runtime inspection and modification. This series addresses that limitation by providing the necessary configfs infrastructure, making netconsole management easier, and simplifying the code. Link: https://lore.kernel.org/all/ZRWRal5bW93px4km@gmail.com/ [1] --- Breno Leitao (2): configfs: add kernel-space item registration API netconsole: Plug to dynamic configfs item drivers/net/netconsole.c | 63 +++++++++++++++----------------------------- fs/configfs/dir.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/configfs.h | 4 +++ 3 files changed, 159 insertions(+), 42 deletions(-) --- base-commit: e538109ac71d801d26776af5f3c54f548296c29c change-id: 20251128-configfs_netcon-f53ec4ca3363 Best regards, -- Breno Leitao <leitao@debian.org> ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH RFC 1/2] configfs: add kernel-space item registration API 2025-12-02 15:29 ` [PATCH RFC 0/2] configfs: enable kernel-space item registration Breno Leitao @ 2025-12-02 15:29 ` Breno Leitao 2025-12-03 19:44 ` Joel Becker 2025-12-02 15:29 ` [PATCH RFC 2/2] netconsole: Plug to dynamic configfs item Breno Leitao 2025-12-05 17:35 ` [PATCH RFC 0/2] configfs: enable kernel-space item registration Andreas Hindborg 2 siblings, 1 reply; 8+ messages in thread From: Breno Leitao @ 2025-12-02 15:29 UTC (permalink / raw) To: Andreas Hindborg, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni Cc: Breno Leitao, linux-kernel, hch, jlbec, linux-fsdevel, netdev, gustavold, asantostc, calvin, kernel-team Add configfs_register_item() and configfs_unregister_item() functions to allow kernel modules to register configfs items whose lifecycle is controlled by kernel space rather than userspace. This is useful for subsystems that need to expose configuration items that are created based on kernel events (like boot parameters) rather than explicit userspace mkdir operations. The items registered this way are marked as default items (CONFIGFS_USET_DEFAULT) and cannot be removed via rmdir. The API follows the same pattern as configfs_register_group() but for individual items: - configfs_register_item() links the item into the parent group's hierarchy and creates the filesystem representation - configfs_unregister_item() reverses the registration, removing the item from configfs Signed-off-by: Breno Leitao <leitao@debian.org> --- fs/configfs/dir.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/configfs.h | 4 +++ 2 files changed, 138 insertions(+) diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 81f4f06bc87e..f7224bc51826 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -1866,6 +1866,140 @@ void configfs_unregister_default_group(struct config_group *group) } EXPORT_SYMBOL(configfs_unregister_default_group); +/** + * configfs_register_item() - registers a kernel-created item with a parent group + * @parent_group: parent group for the new item + * @item: item to be registered + * + * This function allows kernel code to register configfs items whose lifecycle + * is controlled by kernel space rather than userspace (via mkdir/rmdir). + * The item must be already initialized with config_item_init_type_name(). + * + * Return: 0 on success, negative errno on failure + */ +int configfs_register_item(struct config_group *parent_group, + struct config_item *item) +{ + struct configfs_subsystem *subsys = parent_group->cg_subsys; + struct configfs_fragment *frag; + struct dentry *parent, *child; + struct configfs_dirent *sd; + int ret; + + if (!subsys || !item->ci_name) + return -EINVAL; + + frag = new_fragment(); + if (!frag) + return -ENOMEM; + + parent = parent_group->cg_item.ci_dentry; + /* Allocate dentry for the item */ + child = d_alloc_name(parent, item->ci_name); + if (!child) { + put_fragment(frag); + return -ENOMEM; + } + + mutex_lock(&subsys->su_mutex); + link_obj(&parent_group->cg_item, item); + mutex_unlock(&subsys->su_mutex); + + inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); + d_add(child, NULL); + + /* Attach the item to the filesystem */ + ret = configfs_attach_item(&parent_group->cg_item, item, child, frag); + if (ret) + goto err_out; + + /* + * CONFIGFS_USET_DEFAULT mark item as kernel-created (cannot be removed + * by userspace) + */ + sd = child->d_fsdata; + sd->s_type |= CONFIGFS_USET_DEFAULT; + + /* Mark directory as ready */ + spin_lock(&configfs_dirent_lock); + configfs_dir_set_ready(child->d_fsdata); + spin_unlock(&configfs_dirent_lock); + + inode_unlock(d_inode(parent)); + put_fragment(frag); + return 0; + +err_out: + d_drop(child); + dput(child); + inode_unlock(d_inode(parent)); + mutex_lock(&subsys->su_mutex); + unlink_obj(item); + mutex_unlock(&subsys->su_mutex); + put_fragment(frag); + return ret; +} +EXPORT_SYMBOL(configfs_register_item); + +/** + * configfs_unregister_item() - unregisters a kernel-created item + * @item: item to be unregistered + * + * This function reverses the effect of configfs_register_item(), removing + * the item from the configfs filesystem and releasing associated resources. + * The item must have been previously registered with configfs_register_item(). + */ +void configfs_unregister_item(struct config_item *item) +{ + struct config_group *group = item->ci_group; + struct dentry *dentry = item->ci_dentry; + struct configfs_subsystem *subsys; + struct configfs_fragment *frag; + struct configfs_dirent *sd; + struct dentry *parent; + + if (!group || !dentry) + return; + + subsys = group->cg_subsys; + if (!subsys) + return; + + parent = item->ci_parent->ci_dentry; + sd = dentry->d_fsdata; + frag = get_fragment(sd->s_frag); + + if (WARN_ON(!(sd->s_type & CONFIGFS_USET_DEFAULT))) { + put_fragment(frag); + return; + } + + /* Mark fragment as dead */ + down_write(&frag->frag_sem); + frag->frag_dead = true; + up_write(&frag->frag_sem); + + inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); + spin_lock(&configfs_dirent_lock); + configfs_detach_prep(dentry, NULL); + spin_unlock(&configfs_dirent_lock); + + configfs_detach_item(item); + d_inode(dentry)->i_flags |= S_DEAD; + dont_mount(dentry); + d_drop(dentry); + fsnotify_rmdir(d_inode(parent), dentry); + dput(dentry); + inode_unlock(d_inode(parent)); + + mutex_lock(&subsys->su_mutex); + unlink_obj(item); + mutex_unlock(&subsys->su_mutex); + + put_fragment(frag); +} +EXPORT_SYMBOL(configfs_unregister_item); + int configfs_register_subsystem(struct configfs_subsystem *subsys) { int err; diff --git a/include/linux/configfs.h b/include/linux/configfs.h index 698520b1bfdb..70f2d113b4b3 100644 --- a/include/linux/configfs.h +++ b/include/linux/configfs.h @@ -244,6 +244,10 @@ int configfs_register_group(struct config_group *parent_group, struct config_group *group); void configfs_unregister_group(struct config_group *group); +int configfs_register_item(struct config_group *parent_group, + struct config_item *item); +void configfs_unregister_item(struct config_item *item); + void configfs_remove_default_groups(struct config_group *group); struct config_group * -- 2.47.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH RFC 1/2] configfs: add kernel-space item registration API 2025-12-02 15:29 ` [PATCH RFC 1/2] configfs: add kernel-space item registration API Breno Leitao @ 2025-12-03 19:44 ` Joel Becker 2025-12-05 16:39 ` Breno Leitao 0 siblings, 1 reply; 8+ messages in thread From: Joel Becker @ 2025-12-03 19:44 UTC (permalink / raw) To: Breno Leitao Cc: Andreas Hindborg, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel, hch, linux-fsdevel, netdev, gustavold, asantostc, calvin, kernel-team On Tue, Dec 02, 2025 at 07:29:01AM -0800, Breno Leitao wrote: > Add configfs_register_item() and configfs_unregister_item() functions > to allow kernel modules to register configfs items whose lifecycle is > controlled by kernel space rather than userspace. > > This is useful for subsystems that need to expose configuration items > that are created based on kernel events (like boot parameters) rather > than explicit userspace mkdir operations. The items registered this > way are marked as default items (CONFIGFS_USET_DEFAULT) and cannot be > removed via rmdir. > > The API follows the same pattern as configfs_register_group() but for > individual items: > - configfs_register_item() links the item into the parent group's > hierarchy and creates the filesystem representation > - configfs_unregister_item() reverses the registration, removing the > item from configfs > > Signed-off-by: Breno Leitao <leitao@debian.org> > --- > fs/configfs/dir.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > include/linux/configfs.h | 4 +++ > 2 files changed, 138 insertions(+) > > diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c > index 81f4f06bc87e..f7224bc51826 100644 > --- a/fs/configfs/dir.c > +++ b/fs/configfs/dir.c > @@ -1866,6 +1866,140 @@ void configfs_unregister_default_group(struct config_group *group) > } > EXPORT_SYMBOL(configfs_unregister_default_group); > > +/** > + * configfs_register_item() - registers a kernel-created item with a parent group > + * @parent_group: parent group for the new item > + * @item: item to be registered > + * > + * This function allows kernel code to register configfs items whose lifecycle > + * is controlled by kernel space rather than userspace (via mkdir/rmdir). > + * The item must be already initialized with config_item_init_type_name(). > + * > + * Return: 0 on success, negative errno on failure > + */ > +int configfs_register_item(struct config_group *parent_group, > + struct config_item *item) > +{ > + struct configfs_subsystem *subsys = parent_group->cg_subsys; > + struct configfs_fragment *frag; > + struct dentry *parent, *child; > + struct configfs_dirent *sd; > + int ret; > + > + if (!subsys || !item->ci_name) > + return -EINVAL; > + > + frag = new_fragment(); > + if (!frag) > + return -ENOMEM; > + > + parent = parent_group->cg_item.ci_dentry; > + /* Allocate dentry for the item */ > + child = d_alloc_name(parent, item->ci_name); > + if (!child) { > + put_fragment(frag); > + return -ENOMEM; > + } > + > + mutex_lock(&subsys->su_mutex); > + link_obj(&parent_group->cg_item, item); > + mutex_unlock(&subsys->su_mutex); > + > + inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); > + d_add(child, NULL); > + > + /* Attach the item to the filesystem */ > + ret = configfs_attach_item(&parent_group->cg_item, item, child, frag); > + if (ret) > + goto err_out; The behavior here is significantly different than the flow in configfs_mkdir(). How do we a) ensure we're getting the right outcome b) make sure that commensurate changes in one are propagated to the other? For example, we take pains to get module pinning right in configfs_mkdir(), both for the parent_item and the child item. I see no pinning here. I see no handling of races with unregister (like the teardown races with rmdir). Some of these things are just different with kernel-registered items. I presume you are declaring the child item must be fully created, which is why this code doesn't call ->make_item(). But there is no documentation of that requirement. Thanks, Joel -- "Baby, even the losers Get luck sometimes. Even the losers Keep a little bit of pride." http://www.jlbec.org/ jlbec@evilplan.org ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC 1/2] configfs: add kernel-space item registration API 2025-12-03 19:44 ` Joel Becker @ 2025-12-05 16:39 ` Breno Leitao 0 siblings, 0 replies; 8+ messages in thread From: Breno Leitao @ 2025-12-05 16:39 UTC (permalink / raw) To: Andreas Hindborg, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel, hch, linux-fsdevel, netdev, gustavold, asantostc, calvin, kernel-team Hello Joel, First of all, thanks for thre review, On Wed, Dec 03, 2025 at 11:44:02AM -0800, Joel Becker wrote: > On Tue, Dec 02, 2025 at 07:29:01AM -0800, Breno Leitao wrote: > > Add configfs_register_item() and configfs_unregister_item() functions > > to allow kernel modules to register configfs items whose lifecycle is > > controlled by kernel space rather than userspace. > > > > This is useful for subsystems that need to expose configuration items > > that are created based on kernel events (like boot parameters) rather > > than explicit userspace mkdir operations. The items registered this > > way are marked as default items (CONFIGFS_USET_DEFAULT) and cannot be > > removed via rmdir. > > > > The API follows the same pattern as configfs_register_group() but for > > individual items: > > - configfs_register_item() links the item into the parent group's > > hierarchy and creates the filesystem representation > > - configfs_unregister_item() reverses the registration, removing the > > item from configfs > > > > Signed-off-by: Breno Leitao <leitao@debian.org> > > --- > > fs/configfs/dir.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > > include/linux/configfs.h | 4 +++ > > 2 files changed, 138 insertions(+) > > > > diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c > > index 81f4f06bc87e..f7224bc51826 100644 > > --- a/fs/configfs/dir.c > > +++ b/fs/configfs/dir.c > > @@ -1866,6 +1866,140 @@ void configfs_unregister_default_group(struct config_group *group) > > } > > EXPORT_SYMBOL(configfs_unregister_default_group); > > > > +/** > > + * configfs_register_item() - registers a kernel-created item with a parent group > > + * @parent_group: parent group for the new item > > + * @item: item to be registered > > + * > > + * This function allows kernel code to register configfs items whose lifecycle > > + * is controlled by kernel space rather than userspace (via mkdir/rmdir). > > + * The item must be already initialized with config_item_init_type_name(). > > + * > > + * Return: 0 on success, negative errno on failure > > + */ > > +int configfs_register_item(struct config_group *parent_group, > > + struct config_item *item) > > +{ > > + struct configfs_subsystem *subsys = parent_group->cg_subsys; > > + struct configfs_fragment *frag; > > + struct dentry *parent, *child; > > + struct configfs_dirent *sd; > > + int ret; > > + > > + if (!subsys || !item->ci_name) > > + return -EINVAL; > > + > > + frag = new_fragment(); > > + if (!frag) > > + return -ENOMEM; > > + > > + parent = parent_group->cg_item.ci_dentry; > > + /* Allocate dentry for the item */ > > + child = d_alloc_name(parent, item->ci_name); > > + if (!child) { > > + put_fragment(frag); > > + return -ENOMEM; > > + } > > + > > + mutex_lock(&subsys->su_mutex); > > + link_obj(&parent_group->cg_item, item); > > + mutex_unlock(&subsys->su_mutex); > > + > > + inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); > > + d_add(child, NULL); > > + > > + /* Attach the item to the filesystem */ > > + ret = configfs_attach_item(&parent_group->cg_item, item, child, frag); > > + if (ret) > > + goto err_out; > > The behavior here is significantly different than the flow in > configfs_mkdir(). How do we a) ensure we're getting the right outcome > b) make sure that commensurate changes in one are propagated to the > other? > > For example, we take pains to get module pinning right in > configfs_mkdir(), both for the parent_item and the child item. I see no > pinning here. You're absolutely right about the missing module pinning and race protection. On my example (netconsole), the items were added during module initialization and removed during device tear down, which is not an excuse, given the interface should be generic enough. I suppose I want to try_module_get(subsys_owner) and try_module_get(type->ct_owner) at the beginning of configfs_register_item(), and then put them back in configfs_unregister_item(). Would it be enough? int configfs_register_item(struct config_group *parent_group, struct config_item *item) ... /* * Pin the subsystem module first. The subsystem may belong to a * different module than the item being registered. We need to pin * both to prevent the subsystem from being unloaded while the item * exists. */ if (!subsys->su_group.cg_item.ci_type) { ret = -EINVAL; goto out; } subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; if (!try_module_get(subsys_owner)) { ret = -EINVAL; goto out; } /* * Pin the item's module. This prevents the module providing the * item's type (and its operations) from being unloaded. */ item_owner = type->ct_owner; if (!try_module_get(item_owner)) { ret = -EINVAL; goto out_subsys_put; } > I see no handling of races with unregister (like the > teardown races with rmdir). > Some of these things are just different with kernel-registered items. Would CONFIGFS_USET_IN_MKDIR be enought in this case? > I presume you are declaring the child item must be fully created, which is > why this code doesn't call ->make_item(). But there is no documentation > of that requirement. Right, do you think a kdoc would be enough in this case? This is the new functions I am coming up with, in case you want to read the full functions. Thanks for the review!! -- diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 81f4f06bc87e..73aa4e4a0966 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -1866,6 +1866,248 @@ void configfs_unregister_default_group(struct config_group *group) } EXPORT_SYMBOL(configfs_unregister_default_group); +/** + * configfs_register_item() - registers a kernel-created item with a parent group + * @parent_group: parent group for the new item + * @item: item to be registered + * + * This function allows kernel code to register configfs items whose lifecycle + * is controlled by kernel space rather than userspace (via mkdir/rmdir). + * + * Unlike configfs_mkdir(), which creates the item via ->make_item() callback, + * this function expects the item to be FULLY INITIALIZED by the caller before + * registration. This means: + * - The item must be initialized with config_item_init_type_name() + * - The item->ci_type must be set and valid + * - The item->ci_type->ct_owner (module) must be valid + * - Any item-specific initialization must be complete + * + * This function follows the same module pinning and locking semantics as + * configfs_mkdir() to ensure proper synchronization with rmdir and module + * unloading. + * + * Return: 0 on success, negative errno on failure + */ +int configfs_register_item(struct config_group *parent_group, + struct config_item *item) +{ + struct configfs_subsystem *subsys = parent_group->cg_subsys; + struct module *subsys_owner = NULL, *item_owner = NULL; + const struct config_item_type *type; + struct configfs_fragment *frag; + struct dentry *parent, *child; + struct configfs_dirent *sd; + int ret; + + if (!subsys || !item->ci_name) + return -EINVAL; + + /* + * Validate that the item is fully initialized. Unlike configfs_mkdir(), + * we don't call ->make_item(), so the caller must provide a complete + * item with a valid type. + */ + type = item->ci_type; + if (!type) { + ret = -EINVAL; + goto out; + } + + /* + * Pin the subsystem module first. The subsystem may belong to a + * different module than the item being registered. We need to pin + * both to prevent the subsystem from being unloaded while the item + * exists. + */ + if (!subsys->su_group.cg_item.ci_type) { + ret = -EINVAL; + goto out; + } + subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; + if (!try_module_get(subsys_owner)) { + ret = -EINVAL; + goto out; + } + + /* + * Pin the item's module. This prevents the module providing the + * item's type (and its operations) from being unloaded. + */ + item_owner = type->ct_owner; + if (!try_module_get(item_owner)) { + ret = -EINVAL; + goto out_subsys_put; + } + + frag = new_fragment(); + if (!frag) { + ret = -ENOMEM; + goto out_item_put; + } + + parent = parent_group->cg_item.ci_dentry; + /* Allocate dentry for the item */ + child = d_alloc_name(parent, item->ci_name); + if (!child) { + ret = -ENOMEM; + put_fragment(frag); + goto out_item_put; + } + + /* + * Link the item into the parent group's hierarchy under the subsystem + * mutex. This must be done before attaching to the filesystem. + */ + mutex_lock(&subsys->su_mutex); + link_obj(&parent_group->cg_item, item); + mutex_unlock(&subsys->su_mutex); + + /* + * From here on, errors must unlink the item since link_obj() has + * been called. + */ + inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); + + /* + * Protect against racing with configfs_unregister_item() or rmdir. + * The CONFIGFS_USET_IN_MKDIR flag will cause configfs_detach_prep() + * to fail, preventing concurrent teardown. + */ + sd = parent->d_fsdata; + spin_lock(&configfs_dirent_lock); + sd->s_type |= CONFIGFS_USET_IN_MKDIR; + spin_unlock(&configfs_dirent_lock); + + d_add(child, NULL); + + /* Attach the item to the filesystem */ + ret = configfs_attach_item(&parent_group->cg_item, item, child, frag); + /* if ret > 0, it will end up in err_unlink after unlocking everything */ + + spin_lock(&configfs_dirent_lock); + sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; + if (!ret) { + struct configfs_dirent *child_sd = child->d_fsdata; + /* + * Mark as CONFIGFS_USET_DEFAULT to indicate this is a + * kernel-created item that cannot be removed via rmdir. + */ + child_sd->s_type |= CONFIGFS_USET_DEFAULT; + configfs_dir_set_ready(child_sd); + } + spin_unlock(&configfs_dirent_lock); + inode_unlock(d_inode(parent)); + + /* in case configfs_attach_item() has failed */ + if (ret) + goto err_unlink; + + put_fragment(frag); + return 0; + +err_unlink: + /* Tear down everything we built up */ + d_drop(child); + dput(child); + mutex_lock(&subsys->su_mutex); + unlink_obj(item); + mutex_unlock(&subsys->su_mutex); + put_fragment(frag); + +out_item_put: + module_put(item_owner); +out_subsys_put: + module_put(subsys_owner); +out: + return ret; +} +EXPORT_SYMBOL(configfs_register_item); + +/** + * configfs_unregister_item() - unregisters a kernel-created item + * @item: item to be unregistered + * + * This function reverses the effect of configfs_register_item(), removing + * the item from the configfs filesystem and releasing associated resources. + * The item must have been previously registered with configfs_register_item(). + * + * This function releases the module references acquired during registration, + * following the same teardown semantics as configfs_rmdir(). + */ +void configfs_unregister_item(struct config_item *item) +{ + struct config_group *group = item->ci_group; + struct dentry *dentry = item->ci_dentry; + struct configfs_subsystem *subsys; + struct configfs_fragment *frag; + struct configfs_dirent *sd; + struct dentry *parent; + struct module *subsys_owner = NULL, *item_owner = NULL; + + if (!group || !dentry) + return; + + subsys = group->cg_subsys; + if (!subsys) + return; + + parent = item->ci_parent->ci_dentry; + sd = dentry->d_fsdata; + frag = get_fragment(sd->s_frag); + + if (WARN_ON(!(sd->s_type & CONFIGFS_USET_DEFAULT))) { + put_fragment(frag); + return; + } + + /* + * Retrieve module owners before detaching. These were pinned during + * configfs_register_item() and must be released. + */ + if (subsys->su_group.cg_item.ci_type) + subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; + if (item->ci_type) + item_owner = item->ci_type->ct_owner; + + /* Mark fragment as dead */ + down_write(&frag->frag_sem); + frag->frag_dead = true; + up_write(&frag->frag_sem); + + inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); + /* + * Take configfs_symlink_mutex to prevent racing with symlink + * creation/removal, matching the locking in configfs_rmdir(). + */ + mutex_lock(&configfs_symlink_mutex); + spin_lock(&configfs_dirent_lock); + configfs_detach_prep(dentry, NULL); + spin_unlock(&configfs_dirent_lock); + mutex_unlock(&configfs_symlink_mutex); + + configfs_detach_item(item); + d_inode(dentry)->i_flags |= S_DEAD; + dont_mount(dentry); + d_drop(dentry); + fsnotify_rmdir(d_inode(parent), dentry); + dput(dentry); + inode_unlock(d_inode(parent)); + + mutex_lock(&subsys->su_mutex); + unlink_obj(item); + mutex_unlock(&subsys->su_mutex); + + put_fragment(frag); + + /* + * Release module references that were acquired during registration. + * This mirrors the cleanup in configfs_rmdir(). + */ + module_put(item_owner); + module_put(subsys_owner); +} +EXPORT_SYMBOL(configfs_unregister_item); + int configfs_register_subsystem(struct configfs_subsystem *subsys) { int err; diff --git a/include/linux/configfs.h b/include/linux/configfs.h index 698520b1bfdb..70f2d113b4b3 100644 --- a/include/linux/configfs.h +++ b/include/linux/configfs.h @@ -244,6 +244,10 @@ int configfs_register_group(struct config_group *parent_group, struct config_group *group); void configfs_unregister_group(struct config_group *group); +int configfs_register_item(struct config_group *parent_group, + struct config_item *item); +void configfs_unregister_item(struct config_item *item); + void configfs_remove_default_groups(struct config_group *group); struct config_group * ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH RFC 2/2] netconsole: Plug to dynamic configfs item 2025-12-02 15:29 ` [PATCH RFC 0/2] configfs: enable kernel-space item registration Breno Leitao 2025-12-02 15:29 ` [PATCH RFC 1/2] configfs: add kernel-space item registration API Breno Leitao @ 2025-12-02 15:29 ` Breno Leitao 2025-12-05 17:35 ` [PATCH RFC 0/2] configfs: enable kernel-space item registration Andreas Hindborg 2 siblings, 0 replies; 8+ messages in thread From: Breno Leitao @ 2025-12-02 15:29 UTC (permalink / raw) To: Andreas Hindborg, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni Cc: Breno Leitao, linux-kernel, hch, jlbec, linux-fsdevel, netdev, gustavold, asantostc, calvin, kernel-team Convert netconsole to use the new configfs kernel-space item registration API for command-line configured targets. Previously, netconsole created boot-time targets by searching for them when userspace tried to create an item with the a special name. This approach was fragile and hard for users to deal with. This change refactors netconsole to: - Call configfs_register_item() directly from populate_configfs_item() to properly register boot/module parameter targets. - Remove the find_cmdline_target() logic and the special handling in make_netconsole_target() that intercepted userspace operations (aka the ugly workaround) This makes the management of netconsole easier, simplifies the code (removing ~40 lines) and properly separates kernel-created items from userspace-created items, making the code more maintainable and robust. Signed-off-by: Breno Leitao <leitao@debian.org> --- drivers/net/netconsole.c | 63 +++++++++++++++++++++------------------------------------------ 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index bb6e03a92956..d3c720a2f9ef 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -225,8 +225,8 @@ static void netconsole_target_put(struct netconsole_target *nt) { } -static void populate_configfs_item(struct netconsole_target *nt, - int cmdline_count) +static int populate_configfs_item(struct netconsole_target *nt, + int cmdline_count) { } #endif /* CONFIG_NETCONSOLE_DYNAMIC */ @@ -1256,23 +1256,6 @@ static void init_target_config_group(struct netconsole_target *nt, configfs_add_default_group(&nt->userdata_group, &nt->group); } -static struct netconsole_target *find_cmdline_target(const char *name) -{ - struct netconsole_target *nt, *ret = NULL; - unsigned long flags; - - spin_lock_irqsave(&target_list_lock, flags); - list_for_each_entry(nt, &target_list, list) { - if (!strcmp(nt->group.cg_item.ci_name, name)) { - ret = nt; - break; - } - } - spin_unlock_irqrestore(&target_list_lock, flags); - - return ret; -} - /* * Group operations and type for netconsole_subsys. */ @@ -1283,19 +1266,6 @@ static struct config_group *make_netconsole_target(struct config_group *group, struct netconsole_target *nt; unsigned long flags; - /* Checking if a target by this name was created at boot time. If so, - * attach a configfs entry to that target. This enables dynamic - * control. - */ - if (!strncmp(name, NETCONSOLE_PARAM_TARGET_PREFIX, - strlen(NETCONSOLE_PARAM_TARGET_PREFIX))) { - nt = find_cmdline_target(name); - if (nt) { - init_target_config_group(nt, name); - return &nt->group; - } - } - nt = alloc_and_init(); if (!nt) return ERR_PTR(-ENOMEM); @@ -1351,14 +1321,20 @@ static struct configfs_subsystem netconsole_subsys = { }, }; -static void populate_configfs_item(struct netconsole_target *nt, - int cmdline_count) +static int populate_configfs_item(struct netconsole_target *nt, + int cmdline_count) { char target_name[16]; + int ret; snprintf(target_name, sizeof(target_name), "%s%d", NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count); + init_target_config_group(nt, target_name); + + ret = configfs_register_item(&netconsole_subsys.su_group, + &nt->group.cg_item); + return ret; } static int sysdata_append_cpu_nr(struct netconsole_target *nt, int offset) @@ -1899,7 +1875,9 @@ static struct netconsole_target *alloc_param_target(char *target_config, } else { nt->enabled = true; } - populate_configfs_item(nt, cmdline_count); + err = populate_configfs_item(nt, cmdline_count); + if (err) + goto fail; return nt; @@ -1911,6 +1889,8 @@ static struct netconsole_target *alloc_param_target(char *target_config, /* Cleanup netpoll for given target (from boot/module param) and free it */ static void free_param_target(struct netconsole_target *nt) { + if (nt->group.cg_item.ci_dentry) + configfs_unregister_item(&nt->group.cg_item); netpoll_cleanup(&nt->np); kfree(nt); } @@ -1937,6 +1917,10 @@ static int __init init_netconsole(void) char *target_config; char *input = config; + err = dynamic_netconsole_init(); + if (err) + goto exit; + if (strnlen(input, MAX_PARAM_LENGTH)) { while ((target_config = strsep(&input, ";"))) { nt = alloc_param_target(target_config, count); @@ -1966,10 +1950,6 @@ static int __init init_netconsole(void) if (err) goto fail; - err = dynamic_netconsole_init(); - if (err) - goto undonotifier; - if (console_type_needed & CONS_EXTENDED) register_console(&netconsole_ext); if (console_type_needed & CONS_BASIC) @@ -1978,10 +1958,8 @@ static int __init init_netconsole(void) return err; -undonotifier: - unregister_netdevice_notifier(&netconsole_netdev_notifier); - fail: + dynamic_netconsole_exit(); pr_err("cleaning up\n"); /* @@ -1993,6 +1971,7 @@ static int __init init_netconsole(void) list_del(&nt->list); free_param_target(nt); } +exit: return err; } -- 2.47.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH RFC 0/2] configfs: enable kernel-space item registration 2025-12-02 15:29 ` [PATCH RFC 0/2] configfs: enable kernel-space item registration Breno Leitao 2025-12-02 15:29 ` [PATCH RFC 1/2] configfs: add kernel-space item registration API Breno Leitao 2025-12-02 15:29 ` [PATCH RFC 2/2] netconsole: Plug to dynamic configfs item Breno Leitao @ 2025-12-05 17:35 ` Andreas Hindborg 2025-12-05 18:03 ` Breno Leitao 2 siblings, 1 reply; 8+ messages in thread From: Andreas Hindborg @ 2025-12-05 17:35 UTC (permalink / raw) To: Breno Leitao, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni Cc: Breno Leitao, linux-kernel, hch, jlbec, linux-fsdevel, netdev, gustavold, asantostc, calvin, kernel-team "Breno Leitao" <leitao@debian.org> writes: > This series introduces a new kernel-space item registration API for configfs > to enable subsystems to programmatically create configfs items whose lifecycle > is controlled by the kernel rather than userspace. > > Currently, configfs items can only be created via userspace mkdir operations, > which limits their utility for kernel-driven configuration scenarios such as > boot parameters or hardware auto-detection. I thought sysfs would handle this kind of scenarios? Best regards, Andreas Hindborg ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC 0/2] configfs: enable kernel-space item registration 2025-12-05 17:35 ` [PATCH RFC 0/2] configfs: enable kernel-space item registration Andreas Hindborg @ 2025-12-05 18:03 ` Breno Leitao 2025-12-05 19:29 ` Andreas Hindborg 0 siblings, 1 reply; 8+ messages in thread From: Breno Leitao @ 2025-12-05 18:03 UTC (permalink / raw) To: Andreas Hindborg Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel, hch, jlbec, linux-fsdevel, netdev, gustavold, asantostc, calvin, kernel-team Hello Andreas, On Fri, Dec 05, 2025 at 06:35:12PM +0100, Andreas Hindborg wrote: > "Breno Leitao" <leitao@debian.org> writes: > > > This series introduces a new kernel-space item registration API for configfs > > to enable subsystems to programmatically create configfs items whose lifecycle > > is controlled by the kernel rather than userspace. > > > > Currently, configfs items can only be created via userspace mkdir operations, > > which limits their utility for kernel-driven configuration scenarios such as > > boot parameters or hardware auto-detection. > > I thought sysfs would handle this kind of scenarios? sysfs has gaps as well, to manage user-create items. Netconsole has two types of "targets". Those created dynamically (CONFIG_NETCONSOLE_DYNAMIC), where user can create and remove as many targets as it needs, and netconsole would send to it. This fits very well in configfs. mkdir /sys/kernel/config/netconsole/mytarget .. manage the target using configfs items/files rmdir /sys/kernel/config/netconsole/mytarget This is a perfect fit for configfs, and I don't see how it would work with sysfs. On top of that, there are netconsole targets that are coming from cmdline (basically to cover while userspace is not initialized). These are coming from cmdline and its life-cycle is managed by the kernel. I.e, the kernel knows about them, and wants to expose it to the user (which can even disable them later). This is the problem I this patch addresses (exposing them easily). It is kind of a mix of kernel and user-managed configuration items in coexisting. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC 0/2] configfs: enable kernel-space item registration 2025-12-05 18:03 ` Breno Leitao @ 2025-12-05 19:29 ` Andreas Hindborg 0 siblings, 0 replies; 8+ messages in thread From: Andreas Hindborg @ 2025-12-05 19:29 UTC (permalink / raw) To: Breno Leitao Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel, hch, jlbec, linux-fsdevel, netdev, gustavold, asantostc, calvin, kernel-team "Breno Leitao" <leitao@debian.org> writes: > Hello Andreas, > > On Fri, Dec 05, 2025 at 06:35:12PM +0100, Andreas Hindborg wrote: >> "Breno Leitao" <leitao@debian.org> writes: >> >> > This series introduces a new kernel-space item registration API for configfs >> > to enable subsystems to programmatically create configfs items whose lifecycle >> > is controlled by the kernel rather than userspace. >> > >> > Currently, configfs items can only be created via userspace mkdir operations, >> > which limits their utility for kernel-driven configuration scenarios such as >> > boot parameters or hardware auto-detection. >> >> I thought sysfs would handle this kind of scenarios? > > sysfs has gaps as well, to manage user-create items. > > Netconsole has two types of "targets". Those created dynamically > (CONFIG_NETCONSOLE_DYNAMIC), where user can create and remove as many > targets as it needs, and netconsole would send to it. This fits very > well in configfs. > > mkdir /sys/kernel/config/netconsole/mytarget > .. manage the target using configfs items/files > rmdir /sys/kernel/config/netconsole/mytarget > > This is a perfect fit for configfs, and I don't see how it would work > with sysfs. Right, these go in configfs, we are on the same page about that. > > On top of that, there are netconsole targets that are coming from > cmdline (basically to cover while userspace is not initialized). These > are coming from cmdline and its life-cycle is managed by the kernel. > I.e, the kernel knows about them, and wants to expose it to the user > (which can even disable them later). This is the problem I this patch > addresses (exposing them easily). I wonder if these entries could be exposed via sysfs? You could create the same directory structure as you have in configfs for the user created devices, so the only thing user space has to do is to point at a different directory. Best regards, Andreas Hindborg ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-12-05 19:29 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <fdieWSRrkaRJDRuUJYwp6EBe1NodHTz3PpVgkS662Ja0JcX3vfDbNo_bs1BM7zIkVsHmxHjeDi6jmq4sPKOCIw==@protonmail.internalid>
2025-12-02 15:29 ` [PATCH RFC 0/2] configfs: enable kernel-space item registration Breno Leitao
2025-12-02 15:29 ` [PATCH RFC 1/2] configfs: add kernel-space item registration API Breno Leitao
2025-12-03 19:44 ` Joel Becker
2025-12-05 16:39 ` Breno Leitao
2025-12-02 15:29 ` [PATCH RFC 2/2] netconsole: Plug to dynamic configfs item Breno Leitao
2025-12-05 17:35 ` [PATCH RFC 0/2] configfs: enable kernel-space item registration Andreas Hindborg
2025-12-05 18:03 ` Breno Leitao
2025-12-05 19:29 ` Andreas Hindborg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).