xref: /openbmc/linux/fs/configfs/item.c (revision 3fe6c5ce)
17063fbf2SJoel Becker /* -*- mode: c; c-basic-offset: 8; -*-
27063fbf2SJoel Becker  * vim: noexpandtab sw=8 ts=8 sts=0:
37063fbf2SJoel Becker  *
47063fbf2SJoel Becker  * item.c - library routines for handling generic config items
57063fbf2SJoel Becker  *
67063fbf2SJoel Becker  * This program is free software; you can redistribute it and/or
77063fbf2SJoel Becker  * modify it under the terms of the GNU General Public
87063fbf2SJoel Becker  * License as published by the Free Software Foundation; either
97063fbf2SJoel Becker  * version 2 of the License, or (at your option) any later version.
107063fbf2SJoel Becker  *
117063fbf2SJoel Becker  * This program is distributed in the hope that it will be useful,
127063fbf2SJoel Becker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
137063fbf2SJoel Becker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147063fbf2SJoel Becker  * General Public License for more details.
157063fbf2SJoel Becker  *
167063fbf2SJoel Becker  * You should have received a copy of the GNU General Public
177063fbf2SJoel Becker  * License along with this program; if not, write to the
187063fbf2SJoel Becker  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
197063fbf2SJoel Becker  * Boston, MA 021110-1307, USA.
207063fbf2SJoel Becker  *
217063fbf2SJoel Becker  * Based on kobject:
227063fbf2SJoel Becker  * 	kobject is Copyright (c) 2002-2003 Patrick Mochel
237063fbf2SJoel Becker  *
247063fbf2SJoel Becker  * configfs Copyright (C) 2005 Oracle.  All rights reserved.
257063fbf2SJoel Becker  *
267063fbf2SJoel Becker  * Please see the file Documentation/filesystems/configfs.txt for
277063fbf2SJoel Becker  * critical information about using the config_item interface.
287063fbf2SJoel Becker  */
297063fbf2SJoel Becker 
307063fbf2SJoel Becker #include <linux/string.h>
317063fbf2SJoel Becker #include <linux/module.h>
327063fbf2SJoel Becker #include <linux/stat.h>
337063fbf2SJoel Becker #include <linux/slab.h>
347063fbf2SJoel Becker 
357063fbf2SJoel Becker #include <linux/configfs.h>
367063fbf2SJoel Becker 
377063fbf2SJoel Becker 
387063fbf2SJoel Becker static inline struct config_item * to_item(struct list_head * entry)
397063fbf2SJoel Becker {
407063fbf2SJoel Becker 	return container_of(entry,struct config_item,ci_entry);
417063fbf2SJoel Becker }
427063fbf2SJoel Becker 
437063fbf2SJoel Becker /* Evil kernel */
447063fbf2SJoel Becker static void config_item_release(struct kref *kref);
457063fbf2SJoel Becker 
467063fbf2SJoel Becker /**
477063fbf2SJoel Becker  *	config_item_init - initialize item.
487063fbf2SJoel Becker  *	@item:	item in question.
497063fbf2SJoel Becker  */
507063fbf2SJoel Becker void config_item_init(struct config_item * item)
517063fbf2SJoel Becker {
527063fbf2SJoel Becker 	kref_init(&item->ci_kref);
537063fbf2SJoel Becker 	INIT_LIST_HEAD(&item->ci_entry);
547063fbf2SJoel Becker }
557063fbf2SJoel Becker 
567063fbf2SJoel Becker /**
577063fbf2SJoel Becker  *	config_item_set_name - Set the name of an item
587063fbf2SJoel Becker  *	@item:	item.
597063fbf2SJoel Becker  *	@name:	name.
607063fbf2SJoel Becker  *
617063fbf2SJoel Becker  *	If strlen(name) >= CONFIGFS_ITEM_NAME_LEN, then use a
627063fbf2SJoel Becker  *	dynamically allocated string that @item->ci_name points to.
637063fbf2SJoel Becker  *	Otherwise, use the static @item->ci_namebuf array.
647063fbf2SJoel Becker  */
657063fbf2SJoel Becker int config_item_set_name(struct config_item * item, const char * fmt, ...)
667063fbf2SJoel Becker {
677063fbf2SJoel Becker 	int error = 0;
687063fbf2SJoel Becker 	int limit = CONFIGFS_ITEM_NAME_LEN;
697063fbf2SJoel Becker 	int need;
707063fbf2SJoel Becker 	va_list args;
717063fbf2SJoel Becker 	char * name;
727063fbf2SJoel Becker 
737063fbf2SJoel Becker 	/*
747063fbf2SJoel Becker 	 * First, try the static array
757063fbf2SJoel Becker 	 */
767063fbf2SJoel Becker 	va_start(args,fmt);
777063fbf2SJoel Becker 	need = vsnprintf(item->ci_namebuf,limit,fmt,args);
787063fbf2SJoel Becker 	va_end(args);
797063fbf2SJoel Becker 	if (need < limit)
807063fbf2SJoel Becker 		name = item->ci_namebuf;
817063fbf2SJoel Becker 	else {
827063fbf2SJoel Becker 		/*
837063fbf2SJoel Becker 		 * Need more space? Allocate it and try again
847063fbf2SJoel Becker 		 */
857063fbf2SJoel Becker 		limit = need + 1;
867063fbf2SJoel Becker 		name = kmalloc(limit,GFP_KERNEL);
877063fbf2SJoel Becker 		if (!name) {
887063fbf2SJoel Becker 			error = -ENOMEM;
897063fbf2SJoel Becker 			goto Done;
907063fbf2SJoel Becker 		}
917063fbf2SJoel Becker 		va_start(args,fmt);
927063fbf2SJoel Becker 		need = vsnprintf(name,limit,fmt,args);
937063fbf2SJoel Becker 		va_end(args);
947063fbf2SJoel Becker 
957063fbf2SJoel Becker 		/* Still? Give up. */
967063fbf2SJoel Becker 		if (need >= limit) {
977063fbf2SJoel Becker 			kfree(name);
987063fbf2SJoel Becker 			error = -EFAULT;
997063fbf2SJoel Becker 			goto Done;
1007063fbf2SJoel Becker 		}
1017063fbf2SJoel Becker 	}
1027063fbf2SJoel Becker 
1037063fbf2SJoel Becker 	/* Free the old name, if necessary. */
1047063fbf2SJoel Becker 	if (item->ci_name && item->ci_name != item->ci_namebuf)
1057063fbf2SJoel Becker 		kfree(item->ci_name);
1067063fbf2SJoel Becker 
1077063fbf2SJoel Becker 	/* Now, set the new name */
1087063fbf2SJoel Becker 	item->ci_name = name;
1097063fbf2SJoel Becker  Done:
1107063fbf2SJoel Becker 	return error;
1117063fbf2SJoel Becker }
1127063fbf2SJoel Becker 
1137063fbf2SJoel Becker EXPORT_SYMBOL(config_item_set_name);
1147063fbf2SJoel Becker 
1157063fbf2SJoel Becker void config_item_init_type_name(struct config_item *item,
1167063fbf2SJoel Becker 				const char *name,
1177063fbf2SJoel Becker 				struct config_item_type *type)
1187063fbf2SJoel Becker {
1197063fbf2SJoel Becker 	config_item_set_name(item, name);
1207063fbf2SJoel Becker 	item->ci_type = type;
1217063fbf2SJoel Becker 	config_item_init(item);
1227063fbf2SJoel Becker }
1237063fbf2SJoel Becker EXPORT_SYMBOL(config_item_init_type_name);
1247063fbf2SJoel Becker 
1257063fbf2SJoel Becker void config_group_init_type_name(struct config_group *group, const char *name,
1267063fbf2SJoel Becker 			 struct config_item_type *type)
1277063fbf2SJoel Becker {
1287063fbf2SJoel Becker 	config_item_set_name(&group->cg_item, name);
1297063fbf2SJoel Becker 	group->cg_item.ci_type = type;
1307063fbf2SJoel Becker 	config_group_init(group);
1317063fbf2SJoel Becker }
1327063fbf2SJoel Becker EXPORT_SYMBOL(config_group_init_type_name);
1337063fbf2SJoel Becker 
1347063fbf2SJoel Becker struct config_item * config_item_get(struct config_item * item)
1357063fbf2SJoel Becker {
1367063fbf2SJoel Becker 	if (item)
1377063fbf2SJoel Becker 		kref_get(&item->ci_kref);
1387063fbf2SJoel Becker 	return item;
1397063fbf2SJoel Becker }
1407063fbf2SJoel Becker 
1414c62b534SSatyam Sharma static void config_item_cleanup(struct config_item * item)
1427063fbf2SJoel Becker {
1437063fbf2SJoel Becker 	struct config_item_type * t = item->ci_type;
1447063fbf2SJoel Becker 	struct config_group * s = item->ci_group;
1457063fbf2SJoel Becker 	struct config_item * parent = item->ci_parent;
1467063fbf2SJoel Becker 
1477063fbf2SJoel Becker 	pr_debug("config_item %s: cleaning up\n",config_item_name(item));
1487063fbf2SJoel Becker 	if (item->ci_name != item->ci_namebuf)
1497063fbf2SJoel Becker 		kfree(item->ci_name);
1507063fbf2SJoel Becker 	item->ci_name = NULL;
1517063fbf2SJoel Becker 	if (t && t->ct_item_ops && t->ct_item_ops->release)
1527063fbf2SJoel Becker 		t->ct_item_ops->release(item);
1537063fbf2SJoel Becker 	if (s)
1547063fbf2SJoel Becker 		config_group_put(s);
1557063fbf2SJoel Becker 	if (parent)
1567063fbf2SJoel Becker 		config_item_put(parent);
1577063fbf2SJoel Becker }
1587063fbf2SJoel Becker 
1597063fbf2SJoel Becker static void config_item_release(struct kref *kref)
1607063fbf2SJoel Becker {
1617063fbf2SJoel Becker 	config_item_cleanup(container_of(kref, struct config_item, ci_kref));
1627063fbf2SJoel Becker }
1637063fbf2SJoel Becker 
1647063fbf2SJoel Becker /**
1657063fbf2SJoel Becker  *	config_item_put - decrement refcount for item.
1667063fbf2SJoel Becker  *	@item:	item.
1677063fbf2SJoel Becker  *
1687063fbf2SJoel Becker  *	Decrement the refcount, and if 0, call config_item_cleanup().
1697063fbf2SJoel Becker  */
1707063fbf2SJoel Becker void config_item_put(struct config_item * item)
1717063fbf2SJoel Becker {
1727063fbf2SJoel Becker 	if (item)
1737063fbf2SJoel Becker 		kref_put(&item->ci_kref, config_item_release);
1747063fbf2SJoel Becker }
1757063fbf2SJoel Becker 
1767063fbf2SJoel Becker /**
1777063fbf2SJoel Becker  *	config_group_init - initialize a group for use
1787063fbf2SJoel Becker  *	@k:	group
1797063fbf2SJoel Becker  */
1807063fbf2SJoel Becker void config_group_init(struct config_group *group)
1817063fbf2SJoel Becker {
1827063fbf2SJoel Becker 	config_item_init(&group->cg_item);
1837063fbf2SJoel Becker 	INIT_LIST_HEAD(&group->cg_children);
1847063fbf2SJoel Becker }
1857063fbf2SJoel Becker 
1867063fbf2SJoel Becker /**
1873fe6c5ceSSatyam Sharma  *	config_group_find_item - search for item in group.
1887063fbf2SJoel Becker  *	@group:	group we're looking in.
1897063fbf2SJoel Becker  *	@name:	item's name.
1907063fbf2SJoel Becker  *
1913fe6c5ceSSatyam Sharma  *	Iterate over @group->cg_list, looking for a matching config_item.
1923fe6c5ceSSatyam Sharma  *	If matching item is found take a reference and return the item.
1933fe6c5ceSSatyam Sharma  *	Caller must have locked group via @group->cg_subsys->su_mtx.
1947063fbf2SJoel Becker  */
1953fe6c5ceSSatyam Sharma struct config_item *config_group_find_item(struct config_group *group,
1964c62b534SSatyam Sharma 					   const char *name)
1977063fbf2SJoel Becker {
1987063fbf2SJoel Becker 	struct list_head * entry;
1997063fbf2SJoel Becker 	struct config_item * ret = NULL;
2007063fbf2SJoel Becker 
2017063fbf2SJoel Becker 	list_for_each(entry,&group->cg_children) {
2027063fbf2SJoel Becker 		struct config_item * item = to_item(entry);
2037063fbf2SJoel Becker 		if (config_item_name(item) &&
2047063fbf2SJoel Becker 		    !strcmp(config_item_name(item), name)) {
2057063fbf2SJoel Becker 			ret = config_item_get(item);
2067063fbf2SJoel Becker 			break;
2077063fbf2SJoel Becker 		}
2087063fbf2SJoel Becker 	}
2097063fbf2SJoel Becker 	return ret;
2107063fbf2SJoel Becker }
2117063fbf2SJoel Becker 
2127063fbf2SJoel Becker EXPORT_SYMBOL(config_item_init);
2137063fbf2SJoel Becker EXPORT_SYMBOL(config_group_init);
2147063fbf2SJoel Becker EXPORT_SYMBOL(config_item_get);
2157063fbf2SJoel Becker EXPORT_SYMBOL(config_item_put);
2163fe6c5ceSSatyam Sharma EXPORT_SYMBOL(config_group_find_item);
217