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