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