xref: /openbmc/linux/fs/configfs/item.c (revision fa60ce2c)
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