xref: /linux/drivers/md/dm-uevent.c (revision e46b272b6608783ed7aa7b0594871550ce20b849)
151e5b2bdSMike Anderson /*
251e5b2bdSMike Anderson  * Device Mapper Uevent Support (dm-uevent)
351e5b2bdSMike Anderson  *
451e5b2bdSMike Anderson  * This program is free software; you can redistribute it and/or modify it
551e5b2bdSMike Anderson  * under the terms of the GNU General Public License as published by the
651e5b2bdSMike Anderson  * Free Software Foundation; either version 2 of the License, or (at your
751e5b2bdSMike Anderson  * option) any later version.
851e5b2bdSMike Anderson  *
951e5b2bdSMike Anderson  * This program is distributed in the hope that it will be useful, but
1051e5b2bdSMike Anderson  * WITHOUT ANY WARRANTY; without even the implied warranty of
1151e5b2bdSMike Anderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1251e5b2bdSMike Anderson  * General Public License for more details.
1351e5b2bdSMike Anderson  *
1451e5b2bdSMike Anderson  * You should have received a copy of the GNU General Public License along
1551e5b2bdSMike Anderson  * with this program; if not, write to the Free Software Foundation, Inc.,
1651e5b2bdSMike Anderson  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1751e5b2bdSMike Anderson  *
1851e5b2bdSMike Anderson  * Copyright IBM Corporation, 2007
1951e5b2bdSMike Anderson  * 	Author: Mike Anderson <andmike@linux.vnet.ibm.com>
2051e5b2bdSMike Anderson  */
2151e5b2bdSMike Anderson #include <linux/list.h>
2251e5b2bdSMike Anderson #include <linux/slab.h>
2351e5b2bdSMike Anderson #include <linux/kobject.h>
247a8c3d3bSMike Anderson #include <linux/dm-ioctl.h>
2551e5b2bdSMike Anderson 
2651e5b2bdSMike Anderson #include "dm.h"
2751e5b2bdSMike Anderson #include "dm-uevent.h"
2851e5b2bdSMike Anderson 
2951e5b2bdSMike Anderson #define DM_MSG_PREFIX "uevent"
3051e5b2bdSMike Anderson 
317a8c3d3bSMike Anderson static const struct {
327a8c3d3bSMike Anderson 	enum dm_uevent_type type;
337a8c3d3bSMike Anderson 	enum kobject_action action;
347a8c3d3bSMike Anderson 	char *name;
357a8c3d3bSMike Anderson } _dm_uevent_type_names[] = {
367a8c3d3bSMike Anderson 	{DM_UEVENT_PATH_FAILED, KOBJ_CHANGE, "PATH_FAILED"},
377a8c3d3bSMike Anderson 	{DM_UEVENT_PATH_REINSTATED, KOBJ_CHANGE, "PATH_REINSTATED"},
387a8c3d3bSMike Anderson };
397a8c3d3bSMike Anderson 
4051e5b2bdSMike Anderson static struct kmem_cache *_dm_event_cache;
4151e5b2bdSMike Anderson 
4251e5b2bdSMike Anderson struct dm_uevent {
4351e5b2bdSMike Anderson 	struct mapped_device *md;
4451e5b2bdSMike Anderson 	enum kobject_action action;
4551e5b2bdSMike Anderson 	struct kobj_uevent_env ku_env;
4651e5b2bdSMike Anderson 	struct list_head elist;
477a8c3d3bSMike Anderson 	char name[DM_NAME_LEN];
487a8c3d3bSMike Anderson 	char uuid[DM_UUID_LEN];
4951e5b2bdSMike Anderson };
5051e5b2bdSMike Anderson 
5151e5b2bdSMike Anderson static void dm_uevent_free(struct dm_uevent *event)
5251e5b2bdSMike Anderson {
5351e5b2bdSMike Anderson 	kmem_cache_free(_dm_event_cache, event);
5451e5b2bdSMike Anderson }
5551e5b2bdSMike Anderson 
5651e5b2bdSMike Anderson static struct dm_uevent *dm_uevent_alloc(struct mapped_device *md)
5751e5b2bdSMike Anderson {
5851e5b2bdSMike Anderson 	struct dm_uevent *event;
5951e5b2bdSMike Anderson 
6051e5b2bdSMike Anderson 	event = kmem_cache_zalloc(_dm_event_cache, GFP_ATOMIC);
6151e5b2bdSMike Anderson 	if (!event)
6251e5b2bdSMike Anderson 		return NULL;
6351e5b2bdSMike Anderson 
6451e5b2bdSMike Anderson 	INIT_LIST_HEAD(&event->elist);
6551e5b2bdSMike Anderson 	event->md = md;
6651e5b2bdSMike Anderson 
6751e5b2bdSMike Anderson 	return event;
6851e5b2bdSMike Anderson }
6951e5b2bdSMike Anderson 
707a8c3d3bSMike Anderson static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md,
717a8c3d3bSMike Anderson 					      struct dm_target *ti,
727a8c3d3bSMike Anderson 					      enum kobject_action action,
737a8c3d3bSMike Anderson 					      const char *dm_action,
747a8c3d3bSMike Anderson 					      const char *path,
757a8c3d3bSMike Anderson 					      unsigned nr_valid_paths)
767a8c3d3bSMike Anderson {
777a8c3d3bSMike Anderson 	struct dm_uevent *event;
787a8c3d3bSMike Anderson 
797a8c3d3bSMike Anderson 	event = dm_uevent_alloc(md);
807a8c3d3bSMike Anderson 	if (!event) {
81*e46b272bSHarvey Harrison 		DMERR("%s: dm_uevent_alloc() failed", __func__);
827a8c3d3bSMike Anderson 		goto err_nomem;
837a8c3d3bSMike Anderson 	}
847a8c3d3bSMike Anderson 
857a8c3d3bSMike Anderson 	event->action = action;
867a8c3d3bSMike Anderson 
877a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_TARGET=%s", ti->type->name)) {
887a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_TARGET failed",
89*e46b272bSHarvey Harrison 		      __func__);
907a8c3d3bSMike Anderson 		goto err_add;
917a8c3d3bSMike Anderson 	}
927a8c3d3bSMike Anderson 
937a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_ACTION=%s", dm_action)) {
947a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_ACTION failed",
95*e46b272bSHarvey Harrison 		      __func__);
967a8c3d3bSMike Anderson 		goto err_add;
977a8c3d3bSMike Anderson 	}
987a8c3d3bSMike Anderson 
997a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_SEQNUM=%u",
1007a8c3d3bSMike Anderson 			   dm_next_uevent_seq(md))) {
1017a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_SEQNUM failed",
102*e46b272bSHarvey Harrison 		      __func__);
1037a8c3d3bSMike Anderson 		goto err_add;
1047a8c3d3bSMike Anderson 	}
1057a8c3d3bSMike Anderson 
1067a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_PATH=%s", path)) {
107*e46b272bSHarvey Harrison 		DMERR("%s: add_uevent_var() for DM_PATH failed", __func__);
1087a8c3d3bSMike Anderson 		goto err_add;
1097a8c3d3bSMike Anderson 	}
1107a8c3d3bSMike Anderson 
1117a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_NR_VALID_PATHS=%d",
1127a8c3d3bSMike Anderson 			   nr_valid_paths)) {
1137a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_NR_VALID_PATHS failed",
114*e46b272bSHarvey Harrison 		      __func__);
1157a8c3d3bSMike Anderson 		goto err_add;
1167a8c3d3bSMike Anderson 	}
1177a8c3d3bSMike Anderson 
1187a8c3d3bSMike Anderson 	return event;
1197a8c3d3bSMike Anderson 
1207a8c3d3bSMike Anderson err_add:
1217a8c3d3bSMike Anderson 	dm_uevent_free(event);
1227a8c3d3bSMike Anderson err_nomem:
1237a8c3d3bSMike Anderson 	return ERR_PTR(-ENOMEM);
1247a8c3d3bSMike Anderson }
1257a8c3d3bSMike Anderson 
1267a8c3d3bSMike Anderson /**
1277a8c3d3bSMike Anderson  * dm_send_uevents - send uevents for given list
1287a8c3d3bSMike Anderson  *
1297a8c3d3bSMike Anderson  * @events:	list of events to send
1307a8c3d3bSMike Anderson  * @kobj:	kobject generating event
1317a8c3d3bSMike Anderson  *
1327a8c3d3bSMike Anderson  */
1337a8c3d3bSMike Anderson void dm_send_uevents(struct list_head *events, struct kobject *kobj)
1347a8c3d3bSMike Anderson {
1357a8c3d3bSMike Anderson 	int r;
1367a8c3d3bSMike Anderson 	struct dm_uevent *event, *next;
1377a8c3d3bSMike Anderson 
1387a8c3d3bSMike Anderson 	list_for_each_entry_safe(event, next, events, elist) {
1397a8c3d3bSMike Anderson 		list_del_init(&event->elist);
1407a8c3d3bSMike Anderson 
1417a8c3d3bSMike Anderson 		/*
1427a8c3d3bSMike Anderson 		 * Need to call dm_copy_name_and_uuid from here for now.
1437a8c3d3bSMike Anderson 		 * Context of previous var adds and locking used for
1447a8c3d3bSMike Anderson 		 * hash_cell not compatable.
1457a8c3d3bSMike Anderson 		 */
1467a8c3d3bSMike Anderson 		if (dm_copy_name_and_uuid(event->md, event->name,
1477a8c3d3bSMike Anderson 					  event->uuid)) {
1487a8c3d3bSMike Anderson 			DMERR("%s: dm_copy_name_and_uuid() failed",
149*e46b272bSHarvey Harrison 			      __func__);
1507a8c3d3bSMike Anderson 			goto uevent_free;
1517a8c3d3bSMike Anderson 		}
1527a8c3d3bSMike Anderson 
1537a8c3d3bSMike Anderson 		if (add_uevent_var(&event->ku_env, "DM_NAME=%s", event->name)) {
1547a8c3d3bSMike Anderson 			DMERR("%s: add_uevent_var() for DM_NAME failed",
155*e46b272bSHarvey Harrison 			      __func__);
1567a8c3d3bSMike Anderson 			goto uevent_free;
1577a8c3d3bSMike Anderson 		}
1587a8c3d3bSMike Anderson 
1597a8c3d3bSMike Anderson 		if (add_uevent_var(&event->ku_env, "DM_UUID=%s", event->uuid)) {
1607a8c3d3bSMike Anderson 			DMERR("%s: add_uevent_var() for DM_UUID failed",
161*e46b272bSHarvey Harrison 			      __func__);
1627a8c3d3bSMike Anderson 			goto uevent_free;
1637a8c3d3bSMike Anderson 		}
1647a8c3d3bSMike Anderson 
1657a8c3d3bSMike Anderson 		r = kobject_uevent_env(kobj, event->action, event->ku_env.envp);
1667a8c3d3bSMike Anderson 		if (r)
167*e46b272bSHarvey Harrison 			DMERR("%s: kobject_uevent_env failed", __func__);
1687a8c3d3bSMike Anderson uevent_free:
1697a8c3d3bSMike Anderson 		dm_uevent_free(event);
1707a8c3d3bSMike Anderson 	}
1717a8c3d3bSMike Anderson }
1727a8c3d3bSMike Anderson EXPORT_SYMBOL_GPL(dm_send_uevents);
1737a8c3d3bSMike Anderson 
1747a8c3d3bSMike Anderson /**
1757a8c3d3bSMike Anderson  * dm_path_uevent - called to create a new path event and queue it
1767a8c3d3bSMike Anderson  *
1777a8c3d3bSMike Anderson  * @event_type:	path event type enum
1787a8c3d3bSMike Anderson  * @ti:			pointer to a dm_target
1797a8c3d3bSMike Anderson  * @path:		string containing pathname
1807a8c3d3bSMike Anderson  * @nr_valid_paths:	number of valid paths remaining
1817a8c3d3bSMike Anderson  *
1827a8c3d3bSMike Anderson  */
1837a8c3d3bSMike Anderson void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti,
1847a8c3d3bSMike Anderson 		   const char *path, unsigned nr_valid_paths)
1857a8c3d3bSMike Anderson {
1867a8c3d3bSMike Anderson 	struct mapped_device *md = dm_table_get_md(ti->table);
1877a8c3d3bSMike Anderson 	struct dm_uevent *event;
1887a8c3d3bSMike Anderson 
1897a8c3d3bSMike Anderson 	if (event_type >= ARRAY_SIZE(_dm_uevent_type_names)) {
190*e46b272bSHarvey Harrison 		DMERR("%s: Invalid event_type %d", __func__, event_type);
1917a8c3d3bSMike Anderson 		goto out;
1927a8c3d3bSMike Anderson 	}
1937a8c3d3bSMike Anderson 
1947a8c3d3bSMike Anderson 	event = dm_build_path_uevent(md, ti,
1957a8c3d3bSMike Anderson 				     _dm_uevent_type_names[event_type].action,
1967a8c3d3bSMike Anderson 				     _dm_uevent_type_names[event_type].name,
1977a8c3d3bSMike Anderson 				     path, nr_valid_paths);
1987a8c3d3bSMike Anderson 	if (IS_ERR(event))
1997a8c3d3bSMike Anderson 		goto out;
2007a8c3d3bSMike Anderson 
2017a8c3d3bSMike Anderson 	dm_uevent_add(md, &event->elist);
2027a8c3d3bSMike Anderson 
2037a8c3d3bSMike Anderson out:
2047a8c3d3bSMike Anderson 	dm_put(md);
2057a8c3d3bSMike Anderson }
2067a8c3d3bSMike Anderson EXPORT_SYMBOL_GPL(dm_path_uevent);
2077a8c3d3bSMike Anderson 
20851e5b2bdSMike Anderson int dm_uevent_init(void)
20951e5b2bdSMike Anderson {
21051e5b2bdSMike Anderson 	_dm_event_cache = KMEM_CACHE(dm_uevent, 0);
21151e5b2bdSMike Anderson 	if (!_dm_event_cache)
21251e5b2bdSMike Anderson 		return -ENOMEM;
21351e5b2bdSMike Anderson 
21451e5b2bdSMike Anderson 	DMINFO("version 1.0.3");
21551e5b2bdSMike Anderson 
21651e5b2bdSMike Anderson 	return 0;
21751e5b2bdSMike Anderson }
21851e5b2bdSMike Anderson 
21951e5b2bdSMike Anderson void dm_uevent_exit(void)
22051e5b2bdSMike Anderson {
22151e5b2bdSMike Anderson 	kmem_cache_destroy(_dm_event_cache);
22251e5b2bdSMike Anderson }
223