aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/kobject_uevent.c279
1 files changed, 95 insertions, 184 deletions
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 845bf67d94ca..dd061da3aba9 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -29,6 +29,7 @@
29char hotplug_path[HOTPLUG_PATH_LEN] = "/sbin/hotplug"; 29char hotplug_path[HOTPLUG_PATH_LEN] = "/sbin/hotplug";
30u64 hotplug_seqnum; 30u64 hotplug_seqnum;
31static DEFINE_SPINLOCK(sequence_lock); 31static DEFINE_SPINLOCK(sequence_lock);
32static struct sock *uevent_sock;
32 33
33static char *action_to_string(enum kobject_action action) 34static char *action_to_string(enum kobject_action action)
34{ 35{
@@ -48,123 +49,6 @@ static char *action_to_string(enum kobject_action action)
48 } 49 }
49} 50}
50 51
51static struct sock *uevent_sock;
52
53/**
54 * send_uevent - notify userspace by sending event through netlink socket
55 *
56 * @signal: signal name
57 * @obj: object path (kobject)
58 * @envp: possible hotplug environment to pass with the message
59 * @gfp_mask:
60 */
61static int send_uevent(const char *signal, const char *obj,
62 char **envp, gfp_t gfp_mask)
63{
64 struct sk_buff *skb;
65 char *pos;
66 int len;
67
68 if (!uevent_sock)
69 return -EIO;
70
71 len = strlen(signal) + 1;
72 len += strlen(obj) + 1;
73
74 /* allocate buffer with the maximum possible message size */
75 skb = alloc_skb(len + BUFFER_SIZE, gfp_mask);
76 if (!skb)
77 return -ENOMEM;
78
79 pos = skb_put(skb, len);
80 sprintf(pos, "%s@%s", signal, obj);
81
82 /* copy the environment key by key to our continuous buffer */
83 if (envp) {
84 int i;
85
86 for (i = 2; envp[i]; i++) {
87 len = strlen(envp[i]) + 1;
88 pos = skb_put(skb, len);
89 strcpy(pos, envp[i]);
90 }
91 }
92
93 NETLINK_CB(skb).dst_group = 1;
94 return netlink_broadcast(uevent_sock, skb, 0, 1, gfp_mask);
95}
96
97static int do_kobject_uevent(struct kobject *kobj, enum kobject_action action,
98 struct attribute *attr, gfp_t gfp_mask)
99{
100 char *path;
101 char *attrpath;
102 char *signal;
103 int len;
104 int rc = -ENOMEM;
105
106 path = kobject_get_path(kobj, gfp_mask);
107 if (!path)
108 return -ENOMEM;
109
110 signal = action_to_string(action);
111 if (!signal)
112 return -EINVAL;
113
114 if (attr) {
115 len = strlen(path);
116 len += strlen(attr->name) + 2;
117 attrpath = kmalloc(len, gfp_mask);
118 if (!attrpath)
119 goto exit;
120 sprintf(attrpath, "%s/%s", path, attr->name);
121 rc = send_uevent(signal, attrpath, NULL, gfp_mask);
122 kfree(attrpath);
123 } else
124 rc = send_uevent(signal, path, NULL, gfp_mask);
125
126exit:
127 kfree(path);
128 return rc;
129}
130
131/**
132 * kobject_uevent - notify userspace by sending event through netlink socket
133 *
134 * @signal: signal name
135 * @kobj: struct kobject that the event is happening to
136 * @attr: optional struct attribute the event belongs to
137 */
138int kobject_uevent(struct kobject *kobj, enum kobject_action action,
139 struct attribute *attr)
140{
141 return do_kobject_uevent(kobj, action, attr, GFP_KERNEL);
142}
143EXPORT_SYMBOL_GPL(kobject_uevent);
144
145int kobject_uevent_atomic(struct kobject *kobj, enum kobject_action action,
146 struct attribute *attr)
147{
148 return do_kobject_uevent(kobj, action, attr, GFP_ATOMIC);
149}
150EXPORT_SYMBOL_GPL(kobject_uevent_atomic);
151
152static int __init kobject_uevent_init(void)
153{
154 uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL,
155 THIS_MODULE);
156
157 if (!uevent_sock) {
158 printk(KERN_ERR
159 "kobject_uevent: unable to create netlink socket!\n");
160 return -ENODEV;
161 }
162
163 return 0;
164}
165
166postcore_initcall(kobject_uevent_init);
167
168/** 52/**
169 * kobject_hotplug - notify userspace by executing /sbin/hotplug 53 * kobject_hotplug - notify userspace by executing /sbin/hotplug
170 * 54 *
@@ -173,95 +57,84 @@ postcore_initcall(kobject_uevent_init);
173 */ 57 */
174void kobject_hotplug(struct kobject *kobj, enum kobject_action action) 58void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
175{ 59{
176 char *argv [3]; 60 char **envp;
177 char **envp = NULL; 61 char *buffer;
178 char *buffer = NULL;
179 char *seq_buff;
180 char *scratch; 62 char *scratch;
63 const char *action_string;
64 const char *devpath = NULL;
65 const char *subsystem;
66 struct kobject *top_kobj;
67 struct kset *kset;
68 struct kset_hotplug_ops *hotplug_ops;
69 u64 seq;
70 char *seq_buff;
181 int i = 0; 71 int i = 0;
182 int retval; 72 int retval;
183 char *kobj_path = NULL;
184 const char *name = NULL;
185 char *action_string;
186 u64 seq;
187 struct kobject *top_kobj = kobj;
188 struct kset *kset;
189 static struct kset_hotplug_ops null_hotplug_ops;
190 struct kset_hotplug_ops *hotplug_ops = &null_hotplug_ops;
191 73
192 /* If this kobj does not belong to a kset, 74 pr_debug("%s\n", __FUNCTION__);
193 try to find a parent that does. */ 75
76 action_string = action_to_string(action);
77 if (!action_string)
78 return;
79
80 /* search the kset we belong to */
81 top_kobj = kobj;
194 if (!top_kobj->kset && top_kobj->parent) { 82 if (!top_kobj->kset && top_kobj->parent) {
195 do { 83 do {
196 top_kobj = top_kobj->parent; 84 top_kobj = top_kobj->parent;
197 } while (!top_kobj->kset && top_kobj->parent); 85 } while (!top_kobj->kset && top_kobj->parent);
198 } 86 }
199 87 if (!top_kobj->kset)
200 if (top_kobj->kset)
201 kset = top_kobj->kset;
202 else
203 return; 88 return;
204 89
205 if (kset->hotplug_ops) 90 kset = top_kobj->kset;
206 hotplug_ops = kset->hotplug_ops; 91 hotplug_ops = kset->hotplug_ops;
207 92
208 /* If the kset has a filter operation, call it. 93 /* skip the event, if the filter returns zero. */
209 Skip the event, if the filter returns zero. */ 94 if (hotplug_ops && hotplug_ops->filter)
210 if (hotplug_ops->filter) {
211 if (!hotplug_ops->filter(kset, kobj)) 95 if (!hotplug_ops->filter(kset, kobj))
212 return; 96 return;
213 }
214
215 pr_debug ("%s\n", __FUNCTION__);
216
217 action_string = action_to_string(action);
218 if (!action_string)
219 return;
220 97
221 envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); 98 /* environment index */
99 envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
222 if (!envp) 100 if (!envp)
223 return; 101 return;
224 memset (envp, 0x00, NUM_ENVP * sizeof (char *));
225 102
103 /* environment values */
226 buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); 104 buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
227 if (!buffer) 105 if (!buffer)
228 goto exit; 106 goto exit;
229 107
230 if (hotplug_ops->name) 108 /* complete object path */
231 name = hotplug_ops->name(kset, kobj); 109 devpath = kobject_get_path(kobj, GFP_KERNEL);
232 if (name == NULL) 110 if (!devpath)
233 name = kobject_name(&kset->kobj); 111 goto exit;
234 112
235 argv [0] = hotplug_path; 113 /* originating subsystem */
236 argv [1] = (char *)name; /* won't be changed but 'const' has to go */ 114 if (hotplug_ops && hotplug_ops->name)
237 argv [2] = NULL; 115 subsystem = hotplug_ops->name(kset, kobj);
116 else
117 subsystem = kobject_name(&kset->kobj);
238 118
239 /* minimal command environment */ 119 /* event environemnt for helper process only */
240 envp [i++] = "HOME=/"; 120 envp[i++] = "HOME=/";
241 envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; 121 envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
242 122
123 /* default keys */
243 scratch = buffer; 124 scratch = buffer;
244
245 envp [i++] = scratch; 125 envp [i++] = scratch;
246 scratch += sprintf(scratch, "ACTION=%s", action_string) + 1; 126 scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
247
248 kobj_path = kobject_get_path(kobj, GFP_KERNEL);
249 if (!kobj_path)
250 goto exit;
251
252 envp [i++] = scratch; 127 envp [i++] = scratch;
253 scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1; 128 scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
254
255 envp [i++] = scratch; 129 envp [i++] = scratch;
256 scratch += sprintf(scratch, "SUBSYSTEM=%s", name) + 1; 130 scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
257 131
258 /* reserve space for the sequence, 132 /* just reserve the space, overwrite it after kset call has returned */
259 * put the real one in after the hotplug call */
260 envp[i++] = seq_buff = scratch; 133 envp[i++] = seq_buff = scratch;
261 scratch += strlen("SEQNUM=18446744073709551616") + 1; 134 scratch += strlen("SEQNUM=18446744073709551616") + 1;
262 135
263 if (hotplug_ops->hotplug) { 136 /* let the kset specific function add its stuff */
264 /* have the kset specific function add its stuff */ 137 if (hotplug_ops && hotplug_ops->hotplug) {
265 retval = hotplug_ops->hotplug (kset, kobj, 138 retval = hotplug_ops->hotplug (kset, kobj,
266 &envp[i], NUM_ENVP - i, scratch, 139 &envp[i], NUM_ENVP - i, scratch,
267 BUFFER_SIZE - (scratch - buffer)); 140 BUFFER_SIZE - (scratch - buffer));
@@ -272,27 +145,49 @@ void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
272 } 145 }
273 } 146 }
274 147
148 /* we will send an event, request a new sequence number */
275 spin_lock(&sequence_lock); 149 spin_lock(&sequence_lock);
276 seq = ++hotplug_seqnum; 150 seq = ++hotplug_seqnum;
277 spin_unlock(&sequence_lock); 151 spin_unlock(&sequence_lock);
278 sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq); 152 sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);
279 153
280 pr_debug ("%s: %s %s seq=%llu %s %s %s %s %s\n", 154 /* send netlink message */
281 __FUNCTION__, argv[0], argv[1], (unsigned long long)seq, 155 if (uevent_sock) {
282 envp[0], envp[1], envp[2], envp[3], envp[4]); 156 struct sk_buff *skb;
283 157 size_t len;
284 send_uevent(action_string, kobj_path, envp, GFP_KERNEL); 158
159 /* allocate message with the maximum possible size */
160 len = strlen(action_string) + strlen(devpath) + 2;
161 skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL);
162 if (skb) {
163 /* add header */
164 scratch = skb_put(skb, len);
165 sprintf(scratch, "%s@%s", action_string, devpath);
166
167 /* copy keys to our continuous event payload buffer */
168 for (i = 2; envp[i]; i++) {
169 len = strlen(envp[i]) + 1;
170 scratch = skb_put(skb, len);
171 strcpy(scratch, envp[i]);
172 }
173
174 NETLINK_CB(skb).dst_group = 1;
175 netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
176 }
177 }
285 178
286 if (!hotplug_path[0]) 179 /* call uevent_helper, usually only enabled during early boot */
287 goto exit; 180 if (hotplug_path[0]) {
181 char *argv [3];
288 182
289 retval = call_usermodehelper (argv[0], argv, envp, 0); 183 argv [0] = hotplug_path;
290 if (retval) 184 argv [1] = (char *)subsystem;
291 pr_debug ("%s - call_usermodehelper returned %d\n", 185 argv [2] = NULL;
292 __FUNCTION__, retval); 186 call_usermodehelper (argv[0], argv, envp, 0);
187 }
293 188
294exit: 189exit:
295 kfree(kobj_path); 190 kfree(devpath);
296 kfree(buffer); 191 kfree(buffer);
297 kfree(envp); 192 kfree(envp);
298 return; 193 return;
@@ -350,4 +245,20 @@ int add_hotplug_env_var(char **envp, int num_envp, int *cur_index,
350} 245}
351EXPORT_SYMBOL(add_hotplug_env_var); 246EXPORT_SYMBOL(add_hotplug_env_var);
352 247
248static int __init kobject_uevent_init(void)
249{
250 uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL,
251 THIS_MODULE);
252
253 if (!uevent_sock) {
254 printk(KERN_ERR
255 "kobject_uevent: unable to create netlink socket!\n");
256 return -ENODEV;
257 }
258
259 return 0;
260}
261
262postcore_initcall(kobject_uevent_init);
263
353#endif /* CONFIG_HOTPLUG */ 264#endif /* CONFIG_HOTPLUG */