1328970deSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2*fa60ce2cSMasahiro Yamada /*
37063fbf2SJoel Becker * item.c - library routines for handling generic config items
47063fbf2SJoel Becker *
57063fbf2SJoel Becker * Based on kobject:
67063fbf2SJoel Becker * kobject is Copyright (c) 2002-2003 Patrick Mochel
77063fbf2SJoel Becker *
87063fbf2SJoel Becker * configfs Copyright (C) 2005 Oracle. All rights reserved.
97063fbf2SJoel Becker *
1098264991SMauro Carvalho Chehab * Please see the file Documentation/filesystems/configfs.rst for
117063fbf2SJoel Becker * critical information about using the config_item interface.
127063fbf2SJoel Becker */
137063fbf2SJoel Becker
147063fbf2SJoel Becker #include <linux/string.h>
157063fbf2SJoel Becker #include <linux/module.h>
167063fbf2SJoel Becker #include <linux/stat.h>
177063fbf2SJoel Becker #include <linux/slab.h>
187063fbf2SJoel Becker
197063fbf2SJoel Becker #include <linux/configfs.h>
207063fbf2SJoel Becker
217063fbf2SJoel Becker
to_item(struct list_head * entry)227063fbf2SJoel Becker static inline struct config_item *to_item(struct list_head *entry)
237063fbf2SJoel Becker {
247063fbf2SJoel Becker return container_of(entry, struct config_item, ci_entry);
257063fbf2SJoel Becker }
267063fbf2SJoel Becker
277063fbf2SJoel Becker /* Evil kernel */
287063fbf2SJoel Becker static void config_item_release(struct kref *kref);
297063fbf2SJoel Becker
307063fbf2SJoel Becker /**
317063fbf2SJoel Becker * config_item_init - initialize item.
327063fbf2SJoel Becker * @item: item in question.
337063fbf2SJoel Becker */
config_item_init(struct config_item * item)345286d20cSFabian Frederick static void config_item_init(struct config_item *item)
357063fbf2SJoel Becker {
367063fbf2SJoel Becker kref_init(&item->ci_kref);
377063fbf2SJoel Becker INIT_LIST_HEAD(&item->ci_entry);
387063fbf2SJoel Becker }
397063fbf2SJoel Becker
407063fbf2SJoel Becker /**
417063fbf2SJoel Becker * config_item_set_name - Set the name of an item
427063fbf2SJoel Becker * @item: item.
43f6b1fe7cSFabian Frederick * @fmt: The vsnprintf()'s format string.
447063fbf2SJoel Becker *
457063fbf2SJoel Becker * If strlen(name) >= CONFIGFS_ITEM_NAME_LEN, then use a
467063fbf2SJoel Becker * dynamically allocated string that @item->ci_name points to.
477063fbf2SJoel Becker * Otherwise, use the static @item->ci_namebuf array.
487063fbf2SJoel Becker */
config_item_set_name(struct config_item * item,const char * fmt,...)497063fbf2SJoel Becker int config_item_set_name(struct config_item *item, const char *fmt, ...)
507063fbf2SJoel Becker {
517063fbf2SJoel Becker int limit = CONFIGFS_ITEM_NAME_LEN;
527063fbf2SJoel Becker int need;
537063fbf2SJoel Becker va_list args;
547063fbf2SJoel Becker char *name;
557063fbf2SJoel Becker
567063fbf2SJoel Becker /*
577063fbf2SJoel Becker * First, try the static array
587063fbf2SJoel Becker */
597063fbf2SJoel Becker va_start(args, fmt);
607063fbf2SJoel Becker need = vsnprintf(item->ci_namebuf, limit, fmt, args);
617063fbf2SJoel Becker va_end(args);
627063fbf2SJoel Becker if (need < limit)
637063fbf2SJoel Becker name = item->ci_namebuf;
647063fbf2SJoel Becker else {
657063fbf2SJoel Becker va_start(args, fmt);
66707c6235SBart Van Assche name = kvasprintf(GFP_KERNEL, fmt, args);
677063fbf2SJoel Becker va_end(args);
68707c6235SBart Van Assche if (!name)
69707c6235SBart Van Assche return -EFAULT;
707063fbf2SJoel Becker }
717063fbf2SJoel Becker
727063fbf2SJoel Becker /* Free the old name, if necessary. */
737063fbf2SJoel Becker if (item->ci_name && item->ci_name != item->ci_namebuf)
747063fbf2SJoel Becker kfree(item->ci_name);
757063fbf2SJoel Becker
767063fbf2SJoel Becker /* Now, set the new name */
777063fbf2SJoel Becker item->ci_name = name;
78707c6235SBart Van Assche return 0;
797063fbf2SJoel Becker }
807063fbf2SJoel Becker EXPORT_SYMBOL(config_item_set_name);
817063fbf2SJoel Becker
config_item_init_type_name(struct config_item * item,const char * name,const struct config_item_type * type)827063fbf2SJoel Becker void config_item_init_type_name(struct config_item *item,
837063fbf2SJoel Becker const char *name,
84aa293583SBhumika Goyal const struct config_item_type *type)
857063fbf2SJoel Becker {
863958b792SNicolas Iooss config_item_set_name(item, "%s", name);
877063fbf2SJoel Becker item->ci_type = type;
887063fbf2SJoel Becker config_item_init(item);
897063fbf2SJoel Becker }
907063fbf2SJoel Becker EXPORT_SYMBOL(config_item_init_type_name);
917063fbf2SJoel Becker
config_group_init_type_name(struct config_group * group,const char * name,const struct config_item_type * type)927063fbf2SJoel Becker void config_group_init_type_name(struct config_group *group, const char *name,
93aa293583SBhumika Goyal const struct config_item_type *type)
947063fbf2SJoel Becker {
953958b792SNicolas Iooss config_item_set_name(&group->cg_item, "%s", name);
967063fbf2SJoel Becker group->cg_item.ci_type = type;
977063fbf2SJoel Becker config_group_init(group);
987063fbf2SJoel Becker }
997063fbf2SJoel Becker EXPORT_SYMBOL(config_group_init_type_name);
1007063fbf2SJoel Becker
config_item_get(struct config_item * item)1017063fbf2SJoel Becker struct config_item *config_item_get(struct config_item *item)
1027063fbf2SJoel Becker {
1037063fbf2SJoel Becker if (item)
1047063fbf2SJoel Becker kref_get(&item->ci_kref);
1057063fbf2SJoel Becker return item;
1067063fbf2SJoel Becker }
107f6b1fe7cSFabian Frederick EXPORT_SYMBOL(config_item_get);
1087063fbf2SJoel Becker
config_item_get_unless_zero(struct config_item * item)10919e72d3aSBart Van Assche struct config_item *config_item_get_unless_zero(struct config_item *item)
11019e72d3aSBart Van Assche {
11119e72d3aSBart Van Assche if (item && kref_get_unless_zero(&item->ci_kref))
11219e72d3aSBart Van Assche return item;
11319e72d3aSBart Van Assche return NULL;
11419e72d3aSBart Van Assche }
11519e72d3aSBart Van Assche EXPORT_SYMBOL(config_item_get_unless_zero);
11619e72d3aSBart Van Assche
config_item_cleanup(struct config_item * item)1174c62b534SSatyam Sharma static void config_item_cleanup(struct config_item *item)
1187063fbf2SJoel Becker {
119aa293583SBhumika Goyal const struct config_item_type *t = item->ci_type;
1207063fbf2SJoel Becker struct config_group *s = item->ci_group;
1217063fbf2SJoel Becker struct config_item *parent = item->ci_parent;
1227063fbf2SJoel Becker
1237063fbf2SJoel Becker pr_debug("config_item %s: cleaning up\n", config_item_name(item));
1247063fbf2SJoel Becker if (item->ci_name != item->ci_namebuf)
1257063fbf2SJoel Becker kfree(item->ci_name);
1267063fbf2SJoel Becker item->ci_name = NULL;
1277063fbf2SJoel Becker if (t && t->ct_item_ops && t->ct_item_ops->release)
1287063fbf2SJoel Becker t->ct_item_ops->release(item);
1297063fbf2SJoel Becker if (s)
1307063fbf2SJoel Becker config_group_put(s);
1317063fbf2SJoel Becker if (parent)
1327063fbf2SJoel Becker config_item_put(parent);
1337063fbf2SJoel Becker }
1347063fbf2SJoel Becker
config_item_release(struct kref * kref)1357063fbf2SJoel Becker static void config_item_release(struct kref *kref)
1367063fbf2SJoel Becker {
1377063fbf2SJoel Becker config_item_cleanup(container_of(kref, struct config_item, ci_kref));
1387063fbf2SJoel Becker }
1397063fbf2SJoel Becker
1407063fbf2SJoel Becker /**
1417063fbf2SJoel Becker * config_item_put - decrement refcount for item.
1427063fbf2SJoel Becker * @item: item.
1437063fbf2SJoel Becker *
1447063fbf2SJoel Becker * Decrement the refcount, and if 0, call config_item_cleanup().
1457063fbf2SJoel Becker */
config_item_put(struct config_item * item)1467063fbf2SJoel Becker void config_item_put(struct config_item *item)
1477063fbf2SJoel Becker {
1487063fbf2SJoel Becker if (item)
1497063fbf2SJoel Becker kref_put(&item->ci_kref, config_item_release);
1507063fbf2SJoel Becker }
151f6b1fe7cSFabian Frederick EXPORT_SYMBOL(config_item_put);
1527063fbf2SJoel Becker
1537063fbf2SJoel Becker /**
1547063fbf2SJoel Becker * config_group_init - initialize a group for use
155f6b1fe7cSFabian Frederick * @group: config_group
1567063fbf2SJoel Becker */
config_group_init(struct config_group * group)1577063fbf2SJoel Becker void config_group_init(struct config_group *group)
1587063fbf2SJoel Becker {
1597063fbf2SJoel Becker config_item_init(&group->cg_item);
1607063fbf2SJoel Becker INIT_LIST_HEAD(&group->cg_children);
1611ae1602dSChristoph Hellwig INIT_LIST_HEAD(&group->default_groups);
1627063fbf2SJoel Becker }
163f6b1fe7cSFabian Frederick EXPORT_SYMBOL(config_group_init);
1647063fbf2SJoel Becker
1657063fbf2SJoel Becker /**
1663fe6c5ceSSatyam Sharma * config_group_find_item - search for item in group.
1677063fbf2SJoel Becker * @group: group we're looking in.
1687063fbf2SJoel Becker * @name: item's name.
1697063fbf2SJoel Becker *
1703fe6c5ceSSatyam Sharma * Iterate over @group->cg_list, looking for a matching config_item.
1713fe6c5ceSSatyam Sharma * If matching item is found take a reference and return the item.
1723fe6c5ceSSatyam Sharma * Caller must have locked group via @group->cg_subsys->su_mtx.
1737063fbf2SJoel Becker */
config_group_find_item(struct config_group * group,const char * name)1743fe6c5ceSSatyam Sharma struct config_item *config_group_find_item(struct config_group *group,
1754c62b534SSatyam Sharma const char *name)
1767063fbf2SJoel Becker {
1777063fbf2SJoel Becker struct list_head *entry;
1787063fbf2SJoel Becker struct config_item *ret = NULL;
1797063fbf2SJoel Becker
1807063fbf2SJoel Becker list_for_each(entry, &group->cg_children) {
1817063fbf2SJoel Becker struct config_item *item = to_item(entry);
1827063fbf2SJoel Becker if (config_item_name(item) &&
1837063fbf2SJoel Becker !strcmp(config_item_name(item), name)) {
1847063fbf2SJoel Becker ret = config_item_get(item);
1857063fbf2SJoel Becker break;
1867063fbf2SJoel Becker }
1877063fbf2SJoel Becker }
1887063fbf2SJoel Becker return ret;
1897063fbf2SJoel Becker }
1903fe6c5ceSSatyam Sharma EXPORT_SYMBOL(config_group_find_item);
191