1*328970deSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 27063fbf2SJoel Becker /* -*- mode: c; c-basic-offset: 8; -*- 37063fbf2SJoel Becker * vim: noexpandtab sw=8 ts=8 sts=0: 47063fbf2SJoel Becker * 57063fbf2SJoel Becker * item.c - library routines for handling generic config items 67063fbf2SJoel Becker * 77063fbf2SJoel Becker * Based on kobject: 87063fbf2SJoel Becker * kobject is Copyright (c) 2002-2003 Patrick Mochel 97063fbf2SJoel Becker * 107063fbf2SJoel Becker * configfs Copyright (C) 2005 Oracle. All rights reserved. 117063fbf2SJoel Becker * 12395cf969SPaul Bolle * Please see the file Documentation/filesystems/configfs/configfs.txt for 137063fbf2SJoel Becker * critical information about using the config_item interface. 147063fbf2SJoel Becker */ 157063fbf2SJoel Becker 167063fbf2SJoel Becker #include <linux/string.h> 177063fbf2SJoel Becker #include <linux/module.h> 187063fbf2SJoel Becker #include <linux/stat.h> 197063fbf2SJoel Becker #include <linux/slab.h> 207063fbf2SJoel Becker 217063fbf2SJoel Becker #include <linux/configfs.h> 227063fbf2SJoel Becker 237063fbf2SJoel Becker 247063fbf2SJoel Becker static inline struct config_item *to_item(struct list_head *entry) 257063fbf2SJoel Becker { 267063fbf2SJoel Becker return container_of(entry, struct config_item, ci_entry); 277063fbf2SJoel Becker } 287063fbf2SJoel Becker 297063fbf2SJoel Becker /* Evil kernel */ 307063fbf2SJoel Becker static void config_item_release(struct kref *kref); 317063fbf2SJoel Becker 327063fbf2SJoel Becker /** 337063fbf2SJoel Becker * config_item_init - initialize item. 347063fbf2SJoel Becker * @item: item in question. 357063fbf2SJoel Becker */ 365286d20cSFabian Frederick static void config_item_init(struct config_item *item) 377063fbf2SJoel Becker { 387063fbf2SJoel Becker kref_init(&item->ci_kref); 397063fbf2SJoel Becker INIT_LIST_HEAD(&item->ci_entry); 407063fbf2SJoel Becker } 417063fbf2SJoel Becker 427063fbf2SJoel Becker /** 437063fbf2SJoel Becker * config_item_set_name - Set the name of an item 447063fbf2SJoel Becker * @item: item. 45f6b1fe7cSFabian Frederick * @fmt: The vsnprintf()'s format string. 467063fbf2SJoel Becker * 477063fbf2SJoel Becker * If strlen(name) >= CONFIGFS_ITEM_NAME_LEN, then use a 487063fbf2SJoel Becker * dynamically allocated string that @item->ci_name points to. 497063fbf2SJoel Becker * Otherwise, use the static @item->ci_namebuf array. 507063fbf2SJoel Becker */ 517063fbf2SJoel Becker int config_item_set_name(struct config_item *item, const char *fmt, ...) 527063fbf2SJoel Becker { 537063fbf2SJoel Becker int limit = CONFIGFS_ITEM_NAME_LEN; 547063fbf2SJoel Becker int need; 557063fbf2SJoel Becker va_list args; 567063fbf2SJoel Becker char *name; 577063fbf2SJoel Becker 587063fbf2SJoel Becker /* 597063fbf2SJoel Becker * First, try the static array 607063fbf2SJoel Becker */ 617063fbf2SJoel Becker va_start(args, fmt); 627063fbf2SJoel Becker need = vsnprintf(item->ci_namebuf, limit, fmt, args); 637063fbf2SJoel Becker va_end(args); 647063fbf2SJoel Becker if (need < limit) 657063fbf2SJoel Becker name = item->ci_namebuf; 667063fbf2SJoel Becker else { 677063fbf2SJoel Becker va_start(args, fmt); 68707c6235SBart Van Assche name = kvasprintf(GFP_KERNEL, fmt, args); 697063fbf2SJoel Becker va_end(args); 70707c6235SBart Van Assche if (!name) 71707c6235SBart Van Assche return -EFAULT; 727063fbf2SJoel Becker } 737063fbf2SJoel Becker 747063fbf2SJoel Becker /* Free the old name, if necessary. */ 757063fbf2SJoel Becker if (item->ci_name && item->ci_name != item->ci_namebuf) 767063fbf2SJoel Becker kfree(item->ci_name); 777063fbf2SJoel Becker 787063fbf2SJoel Becker /* Now, set the new name */ 797063fbf2SJoel Becker item->ci_name = name; 80707c6235SBart Van Assche return 0; 817063fbf2SJoel Becker } 827063fbf2SJoel Becker EXPORT_SYMBOL(config_item_set_name); 837063fbf2SJoel Becker 847063fbf2SJoel Becker void config_item_init_type_name(struct config_item *item, 857063fbf2SJoel Becker const char *name, 86aa293583SBhumika Goyal const struct config_item_type *type) 877063fbf2SJoel Becker { 883958b792SNicolas Iooss config_item_set_name(item, "%s", name); 897063fbf2SJoel Becker item->ci_type = type; 907063fbf2SJoel Becker config_item_init(item); 917063fbf2SJoel Becker } 927063fbf2SJoel Becker EXPORT_SYMBOL(config_item_init_type_name); 937063fbf2SJoel Becker 947063fbf2SJoel Becker void config_group_init_type_name(struct config_group *group, const char *name, 95aa293583SBhumika Goyal const struct config_item_type *type) 967063fbf2SJoel Becker { 973958b792SNicolas Iooss config_item_set_name(&group->cg_item, "%s", name); 987063fbf2SJoel Becker group->cg_item.ci_type = type; 997063fbf2SJoel Becker config_group_init(group); 1007063fbf2SJoel Becker } 1017063fbf2SJoel Becker EXPORT_SYMBOL(config_group_init_type_name); 1027063fbf2SJoel Becker 1037063fbf2SJoel Becker struct config_item *config_item_get(struct config_item *item) 1047063fbf2SJoel Becker { 1057063fbf2SJoel Becker if (item) 1067063fbf2SJoel Becker kref_get(&item->ci_kref); 1077063fbf2SJoel Becker return item; 1087063fbf2SJoel Becker } 109f6b1fe7cSFabian Frederick EXPORT_SYMBOL(config_item_get); 1107063fbf2SJoel Becker 11119e72d3aSBart Van Assche struct config_item *config_item_get_unless_zero(struct config_item *item) 11219e72d3aSBart Van Assche { 11319e72d3aSBart Van Assche if (item && kref_get_unless_zero(&item->ci_kref)) 11419e72d3aSBart Van Assche return item; 11519e72d3aSBart Van Assche return NULL; 11619e72d3aSBart Van Assche } 11719e72d3aSBart Van Assche EXPORT_SYMBOL(config_item_get_unless_zero); 11819e72d3aSBart Van Assche 1194c62b534SSatyam Sharma static void config_item_cleanup(struct config_item *item) 1207063fbf2SJoel Becker { 121aa293583SBhumika Goyal const struct config_item_type *t = item->ci_type; 1227063fbf2SJoel Becker struct config_group *s = item->ci_group; 1237063fbf2SJoel Becker struct config_item *parent = item->ci_parent; 1247063fbf2SJoel Becker 1257063fbf2SJoel Becker pr_debug("config_item %s: cleaning up\n", config_item_name(item)); 1267063fbf2SJoel Becker if (item->ci_name != item->ci_namebuf) 1277063fbf2SJoel Becker kfree(item->ci_name); 1287063fbf2SJoel Becker item->ci_name = NULL; 1297063fbf2SJoel Becker if (t && t->ct_item_ops && t->ct_item_ops->release) 1307063fbf2SJoel Becker t->ct_item_ops->release(item); 1317063fbf2SJoel Becker if (s) 1327063fbf2SJoel Becker config_group_put(s); 1337063fbf2SJoel Becker if (parent) 1347063fbf2SJoel Becker config_item_put(parent); 1357063fbf2SJoel Becker } 1367063fbf2SJoel Becker 1377063fbf2SJoel Becker static void config_item_release(struct kref *kref) 1387063fbf2SJoel Becker { 1397063fbf2SJoel Becker config_item_cleanup(container_of(kref, struct config_item, ci_kref)); 1407063fbf2SJoel Becker } 1417063fbf2SJoel Becker 1427063fbf2SJoel Becker /** 1437063fbf2SJoel Becker * config_item_put - decrement refcount for item. 1447063fbf2SJoel Becker * @item: item. 1457063fbf2SJoel Becker * 1467063fbf2SJoel Becker * Decrement the refcount, and if 0, call config_item_cleanup(). 1477063fbf2SJoel Becker */ 1487063fbf2SJoel Becker void config_item_put(struct config_item *item) 1497063fbf2SJoel Becker { 1507063fbf2SJoel Becker if (item) 1517063fbf2SJoel Becker kref_put(&item->ci_kref, config_item_release); 1527063fbf2SJoel Becker } 153f6b1fe7cSFabian Frederick EXPORT_SYMBOL(config_item_put); 1547063fbf2SJoel Becker 1557063fbf2SJoel Becker /** 1567063fbf2SJoel Becker * config_group_init - initialize a group for use 157f6b1fe7cSFabian Frederick * @group: config_group 1587063fbf2SJoel Becker */ 1597063fbf2SJoel Becker void config_group_init(struct config_group *group) 1607063fbf2SJoel Becker { 1617063fbf2SJoel Becker config_item_init(&group->cg_item); 1627063fbf2SJoel Becker INIT_LIST_HEAD(&group->cg_children); 1631ae1602dSChristoph Hellwig INIT_LIST_HEAD(&group->default_groups); 1647063fbf2SJoel Becker } 165f6b1fe7cSFabian Frederick EXPORT_SYMBOL(config_group_init); 1667063fbf2SJoel Becker 1677063fbf2SJoel Becker /** 1683fe6c5ceSSatyam Sharma * config_group_find_item - search for item in group. 1697063fbf2SJoel Becker * @group: group we're looking in. 1707063fbf2SJoel Becker * @name: item's name. 1717063fbf2SJoel Becker * 1723fe6c5ceSSatyam Sharma * Iterate over @group->cg_list, looking for a matching config_item. 1733fe6c5ceSSatyam Sharma * If matching item is found take a reference and return the item. 1743fe6c5ceSSatyam Sharma * Caller must have locked group via @group->cg_subsys->su_mtx. 1757063fbf2SJoel Becker */ 1763fe6c5ceSSatyam Sharma struct config_item *config_group_find_item(struct config_group *group, 1774c62b534SSatyam Sharma const char *name) 1787063fbf2SJoel Becker { 1797063fbf2SJoel Becker struct list_head *entry; 1807063fbf2SJoel Becker struct config_item *ret = NULL; 1817063fbf2SJoel Becker 1827063fbf2SJoel Becker list_for_each(entry, &group->cg_children) { 1837063fbf2SJoel Becker struct config_item *item = to_item(entry); 1847063fbf2SJoel Becker if (config_item_name(item) && 1857063fbf2SJoel Becker !strcmp(config_item_name(item), name)) { 1867063fbf2SJoel Becker ret = config_item_get(item); 1877063fbf2SJoel Becker break; 1887063fbf2SJoel Becker } 1897063fbf2SJoel Becker } 1907063fbf2SJoel Becker return ret; 1917063fbf2SJoel Becker } 1923fe6c5ceSSatyam Sharma EXPORT_SYMBOL(config_group_find_item); 193