xref: /openbmc/linux/drivers/md/dm-uevent.c (revision 8ca817c4)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
251e5b2bdSMike Anderson /*
351e5b2bdSMike Anderson  * Device Mapper Uevent Support (dm-uevent)
451e5b2bdSMike Anderson  *
551e5b2bdSMike Anderson  * Copyright IBM Corporation, 2007
651e5b2bdSMike Anderson  *	Author: Mike Anderson <andmike@linux.vnet.ibm.com>
751e5b2bdSMike Anderson  */
851e5b2bdSMike Anderson #include <linux/list.h>
951e5b2bdSMike Anderson #include <linux/slab.h>
1051e5b2bdSMike Anderson #include <linux/kobject.h>
117a8c3d3bSMike Anderson #include <linux/dm-ioctl.h>
12daaa5f7cSPaul Gortmaker #include <linux/export.h>
1351e5b2bdSMike Anderson 
1451e5b2bdSMike Anderson #include "dm.h"
1551e5b2bdSMike Anderson #include "dm-uevent.h"
1651e5b2bdSMike Anderson 
1751e5b2bdSMike Anderson #define DM_MSG_PREFIX "uevent"
1851e5b2bdSMike Anderson 
197a8c3d3bSMike Anderson static const struct {
207a8c3d3bSMike Anderson 	enum dm_uevent_type type;
217a8c3d3bSMike Anderson 	enum kobject_action action;
227a8c3d3bSMike Anderson 	char *name;
237a8c3d3bSMike Anderson } _dm_uevent_type_names[] = {
247a8c3d3bSMike Anderson 	{DM_UEVENT_PATH_FAILED, KOBJ_CHANGE, "PATH_FAILED"},
257a8c3d3bSMike Anderson 	{DM_UEVENT_PATH_REINSTATED, KOBJ_CHANGE, "PATH_REINSTATED"},
267a8c3d3bSMike Anderson };
277a8c3d3bSMike Anderson 
2851e5b2bdSMike Anderson static struct kmem_cache *_dm_event_cache;
2951e5b2bdSMike Anderson 
3051e5b2bdSMike Anderson struct dm_uevent {
3151e5b2bdSMike Anderson 	struct mapped_device *md;
3251e5b2bdSMike Anderson 	enum kobject_action action;
3351e5b2bdSMike Anderson 	struct kobj_uevent_env ku_env;
3451e5b2bdSMike Anderson 	struct list_head elist;
357a8c3d3bSMike Anderson 	char name[DM_NAME_LEN];
367a8c3d3bSMike Anderson 	char uuid[DM_UUID_LEN];
3751e5b2bdSMike Anderson };
3851e5b2bdSMike Anderson 
dm_uevent_free(struct dm_uevent * event)3951e5b2bdSMike Anderson static void dm_uevent_free(struct dm_uevent *event)
4051e5b2bdSMike Anderson {
4151e5b2bdSMike Anderson 	kmem_cache_free(_dm_event_cache, event);
4251e5b2bdSMike Anderson }
4351e5b2bdSMike Anderson 
dm_uevent_alloc(struct mapped_device * md)4451e5b2bdSMike Anderson static struct dm_uevent *dm_uevent_alloc(struct mapped_device *md)
4551e5b2bdSMike Anderson {
4651e5b2bdSMike Anderson 	struct dm_uevent *event;
4751e5b2bdSMike Anderson 
4851e5b2bdSMike Anderson 	event = kmem_cache_zalloc(_dm_event_cache, GFP_ATOMIC);
4951e5b2bdSMike Anderson 	if (!event)
5051e5b2bdSMike Anderson 		return NULL;
5151e5b2bdSMike Anderson 
5251e5b2bdSMike Anderson 	INIT_LIST_HEAD(&event->elist);
5351e5b2bdSMike Anderson 	event->md = md;
5451e5b2bdSMike Anderson 
5551e5b2bdSMike Anderson 	return event;
5651e5b2bdSMike Anderson }
5751e5b2bdSMike Anderson 
dm_build_path_uevent(struct mapped_device * md,struct dm_target * ti,enum kobject_action action,const char * dm_action,const char * path,unsigned int nr_valid_paths)587a8c3d3bSMike Anderson static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md,
597a8c3d3bSMike Anderson 					      struct dm_target *ti,
607a8c3d3bSMike Anderson 					      enum kobject_action action,
617a8c3d3bSMike Anderson 					      const char *dm_action,
627a8c3d3bSMike Anderson 					      const char *path,
63*86a3238cSHeinz Mauelshagen 					      unsigned int nr_valid_paths)
647a8c3d3bSMike Anderson {
657a8c3d3bSMike Anderson 	struct dm_uevent *event;
667a8c3d3bSMike Anderson 
677a8c3d3bSMike Anderson 	event = dm_uevent_alloc(md);
687a8c3d3bSMike Anderson 	if (!event) {
69e46b272bSHarvey Harrison 		DMERR("%s: dm_uevent_alloc() failed", __func__);
707a8c3d3bSMike Anderson 		goto err_nomem;
717a8c3d3bSMike Anderson 	}
727a8c3d3bSMike Anderson 
737a8c3d3bSMike Anderson 	event->action = action;
747a8c3d3bSMike Anderson 
757a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_TARGET=%s", ti->type->name)) {
767a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_TARGET failed",
77e46b272bSHarvey Harrison 		      __func__);
787a8c3d3bSMike Anderson 		goto err_add;
797a8c3d3bSMike Anderson 	}
807a8c3d3bSMike Anderson 
817a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_ACTION=%s", dm_action)) {
827a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_ACTION failed",
83e46b272bSHarvey Harrison 		      __func__);
847a8c3d3bSMike Anderson 		goto err_add;
857a8c3d3bSMike Anderson 	}
867a8c3d3bSMike Anderson 
877a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_SEQNUM=%u",
887a8c3d3bSMike Anderson 			   dm_next_uevent_seq(md))) {
897a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_SEQNUM failed",
90e46b272bSHarvey Harrison 		      __func__);
917a8c3d3bSMike Anderson 		goto err_add;
927a8c3d3bSMike Anderson 	}
937a8c3d3bSMike Anderson 
947a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_PATH=%s", path)) {
95e46b272bSHarvey Harrison 		DMERR("%s: add_uevent_var() for DM_PATH failed", __func__);
967a8c3d3bSMike Anderson 		goto err_add;
977a8c3d3bSMike Anderson 	}
987a8c3d3bSMike Anderson 
997a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_NR_VALID_PATHS=%d",
1007a8c3d3bSMike Anderson 			   nr_valid_paths)) {
1017a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_NR_VALID_PATHS failed",
102e46b272bSHarvey Harrison 		      __func__);
1037a8c3d3bSMike Anderson 		goto err_add;
1047a8c3d3bSMike Anderson 	}
1057a8c3d3bSMike Anderson 
1067a8c3d3bSMike Anderson 	return event;
1077a8c3d3bSMike Anderson 
1087a8c3d3bSMike Anderson err_add:
1097a8c3d3bSMike Anderson 	dm_uevent_free(event);
1107a8c3d3bSMike Anderson err_nomem:
1117a8c3d3bSMike Anderson 	return ERR_PTR(-ENOMEM);
1127a8c3d3bSMike Anderson }
1137a8c3d3bSMike Anderson 
1147a8c3d3bSMike Anderson /**
1157a8c3d3bSMike Anderson  * dm_send_uevents - send uevents for given list
1167a8c3d3bSMike Anderson  *
1177a8c3d3bSMike Anderson  * @events:	list of events to send
1187a8c3d3bSMike Anderson  * @kobj:	kobject generating event
1197a8c3d3bSMike Anderson  *
1207a8c3d3bSMike Anderson  */
dm_send_uevents(struct list_head * events,struct kobject * kobj)1217a8c3d3bSMike Anderson void dm_send_uevents(struct list_head *events, struct kobject *kobj)
1227a8c3d3bSMike Anderson {
1237a8c3d3bSMike Anderson 	int r;
1247a8c3d3bSMike Anderson 	struct dm_uevent *event, *next;
1257a8c3d3bSMike Anderson 
1267a8c3d3bSMike Anderson 	list_for_each_entry_safe(event, next, events, elist) {
1277a8c3d3bSMike Anderson 		list_del_init(&event->elist);
1287a8c3d3bSMike Anderson 
1297a8c3d3bSMike Anderson 		/*
1306076905bSMikulas Patocka 		 * When a device is being removed this copy fails and we
1316076905bSMikulas Patocka 		 * discard these unsent events.
1327a8c3d3bSMike Anderson 		 */
1337a8c3d3bSMike Anderson 		if (dm_copy_name_and_uuid(event->md, event->name,
1347a8c3d3bSMike Anderson 					  event->uuid)) {
1356076905bSMikulas Patocka 			DMINFO("%s: skipping sending uevent for lost device",
136e46b272bSHarvey Harrison 			       __func__);
1377a8c3d3bSMike Anderson 			goto uevent_free;
1387a8c3d3bSMike Anderson 		}
1397a8c3d3bSMike Anderson 
1407a8c3d3bSMike Anderson 		if (add_uevent_var(&event->ku_env, "DM_NAME=%s", event->name)) {
1417a8c3d3bSMike Anderson 			DMERR("%s: add_uevent_var() for DM_NAME failed",
142e46b272bSHarvey Harrison 			      __func__);
1437a8c3d3bSMike Anderson 			goto uevent_free;
1447a8c3d3bSMike Anderson 		}
1457a8c3d3bSMike Anderson 
1467a8c3d3bSMike Anderson 		if (add_uevent_var(&event->ku_env, "DM_UUID=%s", event->uuid)) {
1477a8c3d3bSMike Anderson 			DMERR("%s: add_uevent_var() for DM_UUID failed",
148e46b272bSHarvey Harrison 			      __func__);
1497a8c3d3bSMike Anderson 			goto uevent_free;
1507a8c3d3bSMike Anderson 		}
1517a8c3d3bSMike Anderson 
1527a8c3d3bSMike Anderson 		r = kobject_uevent_env(kobj, event->action, event->ku_env.envp);
1537a8c3d3bSMike Anderson 		if (r)
154e46b272bSHarvey Harrison 			DMERR("%s: kobject_uevent_env failed", __func__);
1557a8c3d3bSMike Anderson uevent_free:
1567a8c3d3bSMike Anderson 		dm_uevent_free(event);
1577a8c3d3bSMike Anderson 	}
1587a8c3d3bSMike Anderson }
1597a8c3d3bSMike Anderson EXPORT_SYMBOL_GPL(dm_send_uevents);
1607a8c3d3bSMike Anderson 
1617a8c3d3bSMike Anderson /**
1627a8c3d3bSMike Anderson  * dm_path_uevent - called to create a new path event and queue it
1637a8c3d3bSMike Anderson  *
1647a8c3d3bSMike Anderson  * @event_type:	path event type enum
1657a8c3d3bSMike Anderson  * @ti:			pointer to a dm_target
1667a8c3d3bSMike Anderson  * @path:		string containing pathname
1677a8c3d3bSMike Anderson  * @nr_valid_paths:	number of valid paths remaining
1687a8c3d3bSMike Anderson  *
1697a8c3d3bSMike Anderson  */
dm_path_uevent(enum dm_uevent_type event_type,struct dm_target * ti,const char * path,unsigned int nr_valid_paths)1707a8c3d3bSMike Anderson void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti,
171*86a3238cSHeinz Mauelshagen 		   const char *path, unsigned int nr_valid_paths)
1727a8c3d3bSMike Anderson {
1737a8c3d3bSMike Anderson 	struct mapped_device *md = dm_table_get_md(ti->table);
1747a8c3d3bSMike Anderson 	struct dm_uevent *event;
1757a8c3d3bSMike Anderson 
1767a8c3d3bSMike Anderson 	if (event_type >= ARRAY_SIZE(_dm_uevent_type_names)) {
177e46b272bSHarvey Harrison 		DMERR("%s: Invalid event_type %d", __func__, event_type);
178ecdb2e25SKiyoshi Ueda 		return;
1797a8c3d3bSMike Anderson 	}
1807a8c3d3bSMike Anderson 
1817a8c3d3bSMike Anderson 	event = dm_build_path_uevent(md, ti,
1827a8c3d3bSMike Anderson 				     _dm_uevent_type_names[event_type].action,
1837a8c3d3bSMike Anderson 				     _dm_uevent_type_names[event_type].name,
1847a8c3d3bSMike Anderson 				     path, nr_valid_paths);
1857a8c3d3bSMike Anderson 	if (IS_ERR(event))
186ecdb2e25SKiyoshi Ueda 		return;
1877a8c3d3bSMike Anderson 
1887a8c3d3bSMike Anderson 	dm_uevent_add(md, &event->elist);
1897a8c3d3bSMike Anderson }
1907a8c3d3bSMike Anderson EXPORT_SYMBOL_GPL(dm_path_uevent);
1917a8c3d3bSMike Anderson 
dm_uevent_init(void)19251e5b2bdSMike Anderson int dm_uevent_init(void)
19351e5b2bdSMike Anderson {
19451e5b2bdSMike Anderson 	_dm_event_cache = KMEM_CACHE(dm_uevent, 0);
19551e5b2bdSMike Anderson 	if (!_dm_event_cache)
19651e5b2bdSMike Anderson 		return -ENOMEM;
19751e5b2bdSMike Anderson 
19851e5b2bdSMike Anderson 	DMINFO("version 1.0.3");
19951e5b2bdSMike Anderson 
20051e5b2bdSMike Anderson 	return 0;
20151e5b2bdSMike Anderson }
20251e5b2bdSMike Anderson 
dm_uevent_exit(void)20351e5b2bdSMike Anderson void dm_uevent_exit(void)
20451e5b2bdSMike Anderson {
20551e5b2bdSMike Anderson 	kmem_cache_destroy(_dm_event_cache);
20651e5b2bdSMike Anderson }
207