xref: /linux/drivers/md/dm-uevent.c (revision 7a8c3d3b92883798e4ead21dd48c16db0ec0ff6f)
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>
24*7a8c3d3bSMike 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 
31*7a8c3d3bSMike Anderson static const struct {
32*7a8c3d3bSMike Anderson 	enum dm_uevent_type type;
33*7a8c3d3bSMike Anderson 	enum kobject_action action;
34*7a8c3d3bSMike Anderson 	char *name;
35*7a8c3d3bSMike Anderson } _dm_uevent_type_names[] = {
36*7a8c3d3bSMike Anderson 	{DM_UEVENT_PATH_FAILED, KOBJ_CHANGE, "PATH_FAILED"},
37*7a8c3d3bSMike Anderson 	{DM_UEVENT_PATH_REINSTATED, KOBJ_CHANGE, "PATH_REINSTATED"},
38*7a8c3d3bSMike Anderson };
39*7a8c3d3bSMike 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;
47*7a8c3d3bSMike Anderson 	char name[DM_NAME_LEN];
48*7a8c3d3bSMike 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 
70*7a8c3d3bSMike Anderson static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md,
71*7a8c3d3bSMike Anderson 					      struct dm_target *ti,
72*7a8c3d3bSMike Anderson 					      enum kobject_action action,
73*7a8c3d3bSMike Anderson 					      const char *dm_action,
74*7a8c3d3bSMike Anderson 					      const char *path,
75*7a8c3d3bSMike Anderson 					      unsigned nr_valid_paths)
76*7a8c3d3bSMike Anderson {
77*7a8c3d3bSMike Anderson 	struct dm_uevent *event;
78*7a8c3d3bSMike Anderson 
79*7a8c3d3bSMike Anderson 	event = dm_uevent_alloc(md);
80*7a8c3d3bSMike Anderson 	if (!event) {
81*7a8c3d3bSMike Anderson 		DMERR("%s: dm_uevent_alloc() failed", __FUNCTION__);
82*7a8c3d3bSMike Anderson 		goto err_nomem;
83*7a8c3d3bSMike Anderson 	}
84*7a8c3d3bSMike Anderson 
85*7a8c3d3bSMike Anderson 	event->action = action;
86*7a8c3d3bSMike Anderson 
87*7a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_TARGET=%s", ti->type->name)) {
88*7a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_TARGET failed",
89*7a8c3d3bSMike Anderson 		      __FUNCTION__);
90*7a8c3d3bSMike Anderson 		goto err_add;
91*7a8c3d3bSMike Anderson 	}
92*7a8c3d3bSMike Anderson 
93*7a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_ACTION=%s", dm_action)) {
94*7a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_ACTION failed",
95*7a8c3d3bSMike Anderson 		      __FUNCTION__);
96*7a8c3d3bSMike Anderson 		goto err_add;
97*7a8c3d3bSMike Anderson 	}
98*7a8c3d3bSMike Anderson 
99*7a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_SEQNUM=%u",
100*7a8c3d3bSMike Anderson 			   dm_next_uevent_seq(md))) {
101*7a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_SEQNUM failed",
102*7a8c3d3bSMike Anderson 		      __FUNCTION__);
103*7a8c3d3bSMike Anderson 		goto err_add;
104*7a8c3d3bSMike Anderson 	}
105*7a8c3d3bSMike Anderson 
106*7a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_PATH=%s", path)) {
107*7a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_PATH failed", __FUNCTION__);
108*7a8c3d3bSMike Anderson 		goto err_add;
109*7a8c3d3bSMike Anderson 	}
110*7a8c3d3bSMike Anderson 
111*7a8c3d3bSMike Anderson 	if (add_uevent_var(&event->ku_env, "DM_NR_VALID_PATHS=%d",
112*7a8c3d3bSMike Anderson 			   nr_valid_paths)) {
113*7a8c3d3bSMike Anderson 		DMERR("%s: add_uevent_var() for DM_NR_VALID_PATHS failed",
114*7a8c3d3bSMike Anderson 		      __FUNCTION__);
115*7a8c3d3bSMike Anderson 		goto err_add;
116*7a8c3d3bSMike Anderson 	}
117*7a8c3d3bSMike Anderson 
118*7a8c3d3bSMike Anderson 	return event;
119*7a8c3d3bSMike Anderson 
120*7a8c3d3bSMike Anderson err_add:
121*7a8c3d3bSMike Anderson 	dm_uevent_free(event);
122*7a8c3d3bSMike Anderson err_nomem:
123*7a8c3d3bSMike Anderson 	return ERR_PTR(-ENOMEM);
124*7a8c3d3bSMike Anderson }
125*7a8c3d3bSMike Anderson 
126*7a8c3d3bSMike Anderson /**
127*7a8c3d3bSMike Anderson  * dm_send_uevents - send uevents for given list
128*7a8c3d3bSMike Anderson  *
129*7a8c3d3bSMike Anderson  * @events:	list of events to send
130*7a8c3d3bSMike Anderson  * @kobj:	kobject generating event
131*7a8c3d3bSMike Anderson  *
132*7a8c3d3bSMike Anderson  */
133*7a8c3d3bSMike Anderson void dm_send_uevents(struct list_head *events, struct kobject *kobj)
134*7a8c3d3bSMike Anderson {
135*7a8c3d3bSMike Anderson 	int r;
136*7a8c3d3bSMike Anderson 	struct dm_uevent *event, *next;
137*7a8c3d3bSMike Anderson 
138*7a8c3d3bSMike Anderson 	list_for_each_entry_safe(event, next, events, elist) {
139*7a8c3d3bSMike Anderson 		list_del_init(&event->elist);
140*7a8c3d3bSMike Anderson 
141*7a8c3d3bSMike Anderson 		/*
142*7a8c3d3bSMike Anderson 		 * Need to call dm_copy_name_and_uuid from here for now.
143*7a8c3d3bSMike Anderson 		 * Context of previous var adds and locking used for
144*7a8c3d3bSMike Anderson 		 * hash_cell not compatable.
145*7a8c3d3bSMike Anderson 		 */
146*7a8c3d3bSMike Anderson 		if (dm_copy_name_and_uuid(event->md, event->name,
147*7a8c3d3bSMike Anderson 					  event->uuid)) {
148*7a8c3d3bSMike Anderson 			DMERR("%s: dm_copy_name_and_uuid() failed",
149*7a8c3d3bSMike Anderson 			      __FUNCTION__);
150*7a8c3d3bSMike Anderson 			goto uevent_free;
151*7a8c3d3bSMike Anderson 		}
152*7a8c3d3bSMike Anderson 
153*7a8c3d3bSMike Anderson 		if (add_uevent_var(&event->ku_env, "DM_NAME=%s", event->name)) {
154*7a8c3d3bSMike Anderson 			DMERR("%s: add_uevent_var() for DM_NAME failed",
155*7a8c3d3bSMike Anderson 			      __FUNCTION__);
156*7a8c3d3bSMike Anderson 			goto uevent_free;
157*7a8c3d3bSMike Anderson 		}
158*7a8c3d3bSMike Anderson 
159*7a8c3d3bSMike Anderson 		if (add_uevent_var(&event->ku_env, "DM_UUID=%s", event->uuid)) {
160*7a8c3d3bSMike Anderson 			DMERR("%s: add_uevent_var() for DM_UUID failed",
161*7a8c3d3bSMike Anderson 			      __FUNCTION__);
162*7a8c3d3bSMike Anderson 			goto uevent_free;
163*7a8c3d3bSMike Anderson 		}
164*7a8c3d3bSMike Anderson 
165*7a8c3d3bSMike Anderson 		r = kobject_uevent_env(kobj, event->action, event->ku_env.envp);
166*7a8c3d3bSMike Anderson 		if (r)
167*7a8c3d3bSMike Anderson 			DMERR("%s: kobject_uevent_env failed", __FUNCTION__);
168*7a8c3d3bSMike Anderson uevent_free:
169*7a8c3d3bSMike Anderson 		dm_uevent_free(event);
170*7a8c3d3bSMike Anderson 	}
171*7a8c3d3bSMike Anderson }
172*7a8c3d3bSMike Anderson EXPORT_SYMBOL_GPL(dm_send_uevents);
173*7a8c3d3bSMike Anderson 
174*7a8c3d3bSMike Anderson /**
175*7a8c3d3bSMike Anderson  * dm_path_uevent - called to create a new path event and queue it
176*7a8c3d3bSMike Anderson  *
177*7a8c3d3bSMike Anderson  * @event_type:	path event type enum
178*7a8c3d3bSMike Anderson  * @ti:			pointer to a dm_target
179*7a8c3d3bSMike Anderson  * @path:		string containing pathname
180*7a8c3d3bSMike Anderson  * @nr_valid_paths:	number of valid paths remaining
181*7a8c3d3bSMike Anderson  *
182*7a8c3d3bSMike Anderson  */
183*7a8c3d3bSMike Anderson void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti,
184*7a8c3d3bSMike Anderson 		   const char *path, unsigned nr_valid_paths)
185*7a8c3d3bSMike Anderson {
186*7a8c3d3bSMike Anderson 	struct mapped_device *md = dm_table_get_md(ti->table);
187*7a8c3d3bSMike Anderson 	struct dm_uevent *event;
188*7a8c3d3bSMike Anderson 
189*7a8c3d3bSMike Anderson 	if (event_type >= ARRAY_SIZE(_dm_uevent_type_names)) {
190*7a8c3d3bSMike Anderson 		DMERR("%s: Invalid event_type %d", __FUNCTION__, event_type);
191*7a8c3d3bSMike Anderson 		goto out;
192*7a8c3d3bSMike Anderson 	}
193*7a8c3d3bSMike Anderson 
194*7a8c3d3bSMike Anderson 	event = dm_build_path_uevent(md, ti,
195*7a8c3d3bSMike Anderson 				     _dm_uevent_type_names[event_type].action,
196*7a8c3d3bSMike Anderson 				     _dm_uevent_type_names[event_type].name,
197*7a8c3d3bSMike Anderson 				     path, nr_valid_paths);
198*7a8c3d3bSMike Anderson 	if (IS_ERR(event))
199*7a8c3d3bSMike Anderson 		goto out;
200*7a8c3d3bSMike Anderson 
201*7a8c3d3bSMike Anderson 	dm_uevent_add(md, &event->elist);
202*7a8c3d3bSMike Anderson 
203*7a8c3d3bSMike Anderson out:
204*7a8c3d3bSMike Anderson 	dm_put(md);
205*7a8c3d3bSMike Anderson }
206*7a8c3d3bSMike Anderson EXPORT_SYMBOL_GPL(dm_path_uevent);
207*7a8c3d3bSMike 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