18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Device Mapper Uevent Support (dm-uevent) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright IBM Corporation, 2007 68c2ecf20Sopenharmony_ci * Author: Mike Anderson <andmike@linux.vnet.ibm.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/list.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/kobject.h> 118c2ecf20Sopenharmony_ci#include <linux/dm-ioctl.h> 128c2ecf20Sopenharmony_ci#include <linux/export.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "dm.h" 158c2ecf20Sopenharmony_ci#include "dm-uevent.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "uevent" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic const struct { 208c2ecf20Sopenharmony_ci enum dm_uevent_type type; 218c2ecf20Sopenharmony_ci enum kobject_action action; 228c2ecf20Sopenharmony_ci char *name; 238c2ecf20Sopenharmony_ci} _dm_uevent_type_names[] = { 248c2ecf20Sopenharmony_ci {DM_UEVENT_PATH_FAILED, KOBJ_CHANGE, "PATH_FAILED"}, 258c2ecf20Sopenharmony_ci {DM_UEVENT_PATH_REINSTATED, KOBJ_CHANGE, "PATH_REINSTATED"}, 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic struct kmem_cache *_dm_event_cache; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct dm_uevent { 318c2ecf20Sopenharmony_ci struct mapped_device *md; 328c2ecf20Sopenharmony_ci enum kobject_action action; 338c2ecf20Sopenharmony_ci struct kobj_uevent_env ku_env; 348c2ecf20Sopenharmony_ci struct list_head elist; 358c2ecf20Sopenharmony_ci char name[DM_NAME_LEN]; 368c2ecf20Sopenharmony_ci char uuid[DM_UUID_LEN]; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void dm_uevent_free(struct dm_uevent *event) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci kmem_cache_free(_dm_event_cache, event); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic struct dm_uevent *dm_uevent_alloc(struct mapped_device *md) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct dm_uevent *event; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci event = kmem_cache_zalloc(_dm_event_cache, GFP_ATOMIC); 498c2ecf20Sopenharmony_ci if (!event) 508c2ecf20Sopenharmony_ci return NULL; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&event->elist); 538c2ecf20Sopenharmony_ci event->md = md; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return event; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic struct dm_uevent *dm_build_path_uevent(struct mapped_device *md, 598c2ecf20Sopenharmony_ci struct dm_target *ti, 608c2ecf20Sopenharmony_ci enum kobject_action action, 618c2ecf20Sopenharmony_ci const char *dm_action, 628c2ecf20Sopenharmony_ci const char *path, 638c2ecf20Sopenharmony_ci unsigned nr_valid_paths) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct dm_uevent *event; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci event = dm_uevent_alloc(md); 688c2ecf20Sopenharmony_ci if (!event) { 698c2ecf20Sopenharmony_ci DMERR("%s: dm_uevent_alloc() failed", __func__); 708c2ecf20Sopenharmony_ci goto err_nomem; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci event->action = action; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (add_uevent_var(&event->ku_env, "DM_TARGET=%s", ti->type->name)) { 768c2ecf20Sopenharmony_ci DMERR("%s: add_uevent_var() for DM_TARGET failed", 778c2ecf20Sopenharmony_ci __func__); 788c2ecf20Sopenharmony_ci goto err_add; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (add_uevent_var(&event->ku_env, "DM_ACTION=%s", dm_action)) { 828c2ecf20Sopenharmony_ci DMERR("%s: add_uevent_var() for DM_ACTION failed", 838c2ecf20Sopenharmony_ci __func__); 848c2ecf20Sopenharmony_ci goto err_add; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (add_uevent_var(&event->ku_env, "DM_SEQNUM=%u", 888c2ecf20Sopenharmony_ci dm_next_uevent_seq(md))) { 898c2ecf20Sopenharmony_ci DMERR("%s: add_uevent_var() for DM_SEQNUM failed", 908c2ecf20Sopenharmony_ci __func__); 918c2ecf20Sopenharmony_ci goto err_add; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (add_uevent_var(&event->ku_env, "DM_PATH=%s", path)) { 958c2ecf20Sopenharmony_ci DMERR("%s: add_uevent_var() for DM_PATH failed", __func__); 968c2ecf20Sopenharmony_ci goto err_add; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (add_uevent_var(&event->ku_env, "DM_NR_VALID_PATHS=%d", 1008c2ecf20Sopenharmony_ci nr_valid_paths)) { 1018c2ecf20Sopenharmony_ci DMERR("%s: add_uevent_var() for DM_NR_VALID_PATHS failed", 1028c2ecf20Sopenharmony_ci __func__); 1038c2ecf20Sopenharmony_ci goto err_add; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return event; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cierr_add: 1098c2ecf20Sopenharmony_ci dm_uevent_free(event); 1108c2ecf20Sopenharmony_cierr_nomem: 1118c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/** 1158c2ecf20Sopenharmony_ci * dm_send_uevents - send uevents for given list 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * @events: list of events to send 1188c2ecf20Sopenharmony_ci * @kobj: kobject generating event 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_civoid dm_send_uevents(struct list_head *events, struct kobject *kobj) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int r; 1248c2ecf20Sopenharmony_ci struct dm_uevent *event, *next; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci list_for_each_entry_safe(event, next, events, elist) { 1278c2ecf20Sopenharmony_ci list_del_init(&event->elist); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * When a device is being removed this copy fails and we 1318c2ecf20Sopenharmony_ci * discard these unsent events. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci if (dm_copy_name_and_uuid(event->md, event->name, 1348c2ecf20Sopenharmony_ci event->uuid)) { 1358c2ecf20Sopenharmony_ci DMINFO("%s: skipping sending uevent for lost device", 1368c2ecf20Sopenharmony_ci __func__); 1378c2ecf20Sopenharmony_ci goto uevent_free; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (add_uevent_var(&event->ku_env, "DM_NAME=%s", event->name)) { 1418c2ecf20Sopenharmony_ci DMERR("%s: add_uevent_var() for DM_NAME failed", 1428c2ecf20Sopenharmony_ci __func__); 1438c2ecf20Sopenharmony_ci goto uevent_free; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (add_uevent_var(&event->ku_env, "DM_UUID=%s", event->uuid)) { 1478c2ecf20Sopenharmony_ci DMERR("%s: add_uevent_var() for DM_UUID failed", 1488c2ecf20Sopenharmony_ci __func__); 1498c2ecf20Sopenharmony_ci goto uevent_free; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci r = kobject_uevent_env(kobj, event->action, event->ku_env.envp); 1538c2ecf20Sopenharmony_ci if (r) 1548c2ecf20Sopenharmony_ci DMERR("%s: kobject_uevent_env failed", __func__); 1558c2ecf20Sopenharmony_ciuevent_free: 1568c2ecf20Sopenharmony_ci dm_uevent_free(event); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_send_uevents); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/** 1628c2ecf20Sopenharmony_ci * dm_path_uevent - called to create a new path event and queue it 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * @event_type: path event type enum 1658c2ecf20Sopenharmony_ci * @ti: pointer to a dm_target 1668c2ecf20Sopenharmony_ci * @path: string containing pathname 1678c2ecf20Sopenharmony_ci * @nr_valid_paths: number of valid paths remaining 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_civoid dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti, 1718c2ecf20Sopenharmony_ci const char *path, unsigned nr_valid_paths) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct mapped_device *md = dm_table_get_md(ti->table); 1748c2ecf20Sopenharmony_ci struct dm_uevent *event; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (event_type >= ARRAY_SIZE(_dm_uevent_type_names)) { 1778c2ecf20Sopenharmony_ci DMERR("%s: Invalid event_type %d", __func__, event_type); 1788c2ecf20Sopenharmony_ci return; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci event = dm_build_path_uevent(md, ti, 1828c2ecf20Sopenharmony_ci _dm_uevent_type_names[event_type].action, 1838c2ecf20Sopenharmony_ci _dm_uevent_type_names[event_type].name, 1848c2ecf20Sopenharmony_ci path, nr_valid_paths); 1858c2ecf20Sopenharmony_ci if (IS_ERR(event)) 1868c2ecf20Sopenharmony_ci return; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci dm_uevent_add(md, &event->elist); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_path_uevent); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ciint dm_uevent_init(void) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci _dm_event_cache = KMEM_CACHE(dm_uevent, 0); 1958c2ecf20Sopenharmony_ci if (!_dm_event_cache) 1968c2ecf20Sopenharmony_ci return -ENOMEM; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci DMINFO("version 1.0.3"); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_civoid dm_uevent_exit(void) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci kmem_cache_destroy(_dm_event_cache); 2068c2ecf20Sopenharmony_ci} 207