1.概述
UML中的分区暂时无法挂载。
2. 挂载流程
函数调用流程:
InitRequiredDevices()--->uevent_callback()--->UeventCallback()
在init/first_stage_mount.cpp中
415 ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
416 // Ignores everything that is not a block device.
417 if (uevent.subsystem != "block") {
418 return ListenerAction::kContinue;
419 }
420
421 if (!uevent.partition_name.empty()) {
422 if ( (uevent.partition_name == "super") || (uevent.partition_name == "vbmeta")) {
423 LOG(INFO) << "tom action=" << uevent.action<<" path="<<uevent.path<<" subsystem="<<uevent.subsystem;
424 LOG(INFO) << "tom firmware=" << uevent.firmware<<" p_name="<<uevent.partition_name;
425 LOG(INFO) << "tom device_name=" << uevent.device_name<<" modifies="<<uevent.modalias;
426 LOG(INFO) << "tom partition_num=" << uevent.partition_num<<" major="<<uevent.major<<" minor="<<uevent.minor;
427 }
428 return HandleBlockDevice(uevent.partition_name, uevent);
429 } else {
430 size_t base_idx = uevent.path.rfind('/');
431 if (base_idx != std::string::npos) {
432 return HandleBlockDevice(uevent.path.substr(base_idx + 1), uevent);
433 }
434 }
435 // Not found a partition or find an unneeded partition, continue to find others.
436 return ListenerAction::kContinue;
437 }
打印信息:
[ 1.370375] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda2 subsystem=block
[ 1.372134] init: tom firmware= p_name=super
[ 1.372457] init: tom device_name=vda2 modifies=
[ 1.372838] init: tom partition_num=2 major=253 minor=2
[ 1.373596] tom F=kobject_uevent_env subsystem=block
[ 1.373597] tom F=kobject_uevent_env devpath=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1
[ 1.374069] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1 subsystem=block
[ 1.375689] init: tom firmware= p_name=vbmeta
[ 1.376047] init: tom device_name=vda1 modifies=
[ 1.376420] init: tom partition_num=1 major=253 minor=1
分析,在uevent事件中,接受到partion_name的super和vbmeta时候,就加载system分区。
启动信息如下:
[ 0.000000] Command line: qemu=1 no_timer_check androidboot.hardware=ranchu androidboot.serialno=EMULATOR29X0X1X0 clocksource=pit no-kvmclock console=ttyS0,38400 android.qemud=1 android.checkjni=1 qemu.gles=1 qemu.settings.system.screen_off_timeout=2147483647 qemu.encrypt=1 qemu.opengles.version=196609 qemu.uirenderer=skiagl cma=262M@0-4G qemu.wifi=1 mac80211_hwsim.channels=2 loop.max_part=7 androidboot.vbmeta.size=4352 androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.digest=de63a9b7482880698b68084b079c251fb974d1c7f06d588865f1ddd5a866008c androidboot.boot_devices=pci0000:00/0000:00:03.0 ramoops.mem_address=0xff018000 ramoops.mem_size=0x10000 memmap=0x10000$0xff018000 qemu.dalvik.vm.heapsize=192m mac80211_hwsim.mac_prefix=5554
可以看出b
3. 问题
1)这个uevent消息是谁发出的?
2)init进程接受的uevent消息中partition_name是kernel的uevent发送?
3) kernel的uevent根据什么发送?
4. uevent的partition_name
在uevent_listener.cpp中,通过ReadUevent函数,给msg赋值,调用 ParseEvent(msg, uevent)。
98 bool UeventListener::ReadUevent(Uevent* uevent) const {
99 char msg[UEVENT_MSG_LEN + 2];
100 int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN);
101 if (n <= 0) {
102 if (errno != EAGAIN && errno != EWOULDBLOCK) {
103 LOG(ERROR) << "Error reading from Uevent Fd";
104 }
105 return false;
106 }
107 if (n >= UEVENT_MSG_LEN) {
108 LOG(ERROR) << "Uevent overflowed buffer, discarding";
109 // Return true here even if we discard as we may have more uevents pending and we
110 // want to keep processing them.
111 return true;
112 }
113
114 msg[n] = '\0';
115 msg[n + 1] = '\0';
116
117 ParseEvent(msg, uevent);
118
119 return true;
120 }
函数uevent_kernel_multicast_recv中,调用uevent_kernel_multicast_uid_recv,主要看buffer的赋值。
35 ssize_t uevent_kernel_multicast_recv(int socket, void* buffer, size_t length) {
36 uid_t uid = -1;
37 return uevent_kernel_multicast_uid_recv(socket, buffer, length, &uid);
38 }
uevent_kernel_multicast_uid_recv函数:
49 ssize_t uevent_kernel_multicast_uid_recv(int socket, void* buffer, size_t length, uid_t* uid) {
50 return uevent_kernel_recv(socket, buffer, length, true, uid);
51 }
函数uevent_kernel_recv的定义如下:
53 ssize_t uevent_kernel_recv(int socket, void* buffer, size_t length, bool require_group, uid_t* uid) {
54 struct iovec iov = {buffer, length};
55 struct sockaddr_nl addr;
56 char control[CMSG_SPACE(sizeof(struct ucred))];
57 struct msghdr hdr = {
58 &addr, sizeof(addr), &iov, 1, control, sizeof(control), 0,
59 };
60 struct ucred* cred;
61
62 *uid = -1;
63 ssize_t n = recvmsg(socket, &hdr, 0);
64 if (n <= 0) {
65 return n;
66 }
67
68 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
69 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
70 /* ignoring netlink message with no sender credentials */
71 goto out;
72 }
73
74 cred = (struct ucred*)CMSG_DATA(cmsg);
75 *uid = cred->uid;
76
77 if (addr.nl_pid != 0) {
78 /* ignore non-kernel */
79 goto out;
80 }
81 if (require_group && addr.nl_groups == 0) {
82 /* ignore unicast messages when requested */
83 goto out;
84 }
85
86 return n;
87
88 out:
89 /* clear residual potentially malicious data */
90 bzero(buffer, length);
91 errno = EIO;
92 return -1;
93 }
在uevent_listener.cpp中:
在文件lib/kobject_uevent.c的kobject_uevent_env的函数中:
481 list_for_each_entry(ue_sk, &uevent_sock_list, list) {
482 struct sock *uevent_sock = ue_sk->sk;
483 struct sk_buff *skb;
484 size_t len;
485
486 if (!netlink_has_listeners(uevent_sock, 1))
487 continue;
488
489 /* allocate message with the maximum possible size */
490 len = strlen(action_string) + strlen(devpath) + 2;
491 skb = alloc_skb(len + env->buflen, GFP_KERNEL);
492 if (skb) {
493 char *scratch;
494
495 /* add header */
496 scratch = skb_put(skb, len);
497 sprintf(scratch, "%s@%s", action_string, devpath);
498
499 /* copy keys to our continuous event payload buffer */
500 for (i = 0; i < env->envp_idx; i++) {
501 len = strlen(env->envp[i]) + 1;
502 scratch = skb_put(skb, len);
503 strcpy(scratch, env->envp[i]);
504 if(!strncmp(subsystem,"block",5)) {
505 printk(KERN_ERR "tom F=%s env1->envp[%d]=%s",__FUNCTION__,i,env->envp[i]);
506 }
507 }
508
509 NETLINK_CB(skb).dst_group = 1;
510 retval = netlink_broadcast_filtered(uevent_sock, skb,
511 0, 1, GFP_KERNEL,
512 kobj_bcast_filter,
513 kobj);
514 /* ENOBUFS should be handled in userspace */
515 if (retval == -ENOBUFS || retval == -ESRCH)
516 retval = 0;
517 } else
518 retval = -ENOMEM;
519 }
调试记录:
[ 1.391153] tom F=kobject_uevent_env env1->envp[0]=ACTION=add
[ 1.391630] tom F=kobject_uevent_env env1->envp[1]=DEVPATH=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda2
[ 1.392211] tom F=kobject_uevent_env env1->envp[2]=SUBSYSTEM=block
[ 1.393073] tom F=kobject_uevent_env env1->envp[3]=SYNTH_UUID=0
[ 1.393574] tom F=kobject_uevent_env env1->envp[4]=MAJOR=253
[ 1.394135] tom F=kobject_uevent_env env1->envp[5]=MINOR=2
[ 1.394748] tom F=kobject_uevent_env env1->envp[6]=DEVNAME=vda2
[ 1.395193] tom F=kobject_uevent_env env1->envp[7]=DEVTYPE=partition
[ 1.395670] tom F=kobject_uevent_env env1->envp[8]=PARTN=2
[ 1.396199] tom F=kobject_uevent_env env1->envp[9]=PARTNAME=super
[ 1.396732] tom F=kobject_uevent_env env1->envp[10]=SEQNUM=1035
[ 1.397385] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda2 subsystem=block
[ 1.398695] init: tom firmware= p_name=super
[ 1.399152] init: tom device_name=vda2 modifies=
[ 1.399540] init: tom partition_num=2 major=253 minor=2
[ 1.400378] tom F=kobject_uevent_env subsystem=block
[ 1.400379] tom F=kobject_uevent_env devpath=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1
[ 1.400864] tom F=kobject_uevent_env envp=SYNTH_UUID=0
[ 1.401666] tom F=kobject_uevent_env env1->envp[0]=ACTION=add
[ 1.402088] tom F=kobject_uevent_env env1->envp[1]=DEVPATH=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1
[ 1.402559] tom F=kobject_uevent_env env1->envp[2]=SUBSYSTEM=block
[ 1.403382] tom F=kobject_uevent_env env1->envp[3]=SYNTH_UUID=0
[ 1.403995] tom F=kobject_uevent_env env1->envp[4]=MAJOR=253
[ 1.404501] tom F=kobject_uevent_env env1->envp[5]=MINOR=1
[ 1.404957] tom F=kobject_uevent_env env1->envp[6]=DEVNAME=vda1
[ 1.405399] tom F=kobject_uevent_env env1->envp[7]=DEVTYPE=partition
[ 1.405878] tom F=kobject_uevent_env env1->envp[8]=PARTN=1
[ 1.406393] tom F=kobject_uevent_env env1->envp[9]=PARTNAME=vbmeta
[ 1.406838] tom F=kobject_uevent_env env1->envp[10]=SEQNUM=1036
[ 1.407369] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1 subsystem=block
[ 1.408748] init: tom firmware= p_name=vbmeta
[ 1.409110] init: tom device_name=vda1 modifies=
[ 1.409495] init: tom partition_num=1 major=253 minor=1
调试纪录:
可以看出,在kernel中传递了PARTNAME、DEVPATH和DEVTYPE等变量.
在core/init/uevent_listener.cpp的ParseEvent函数中:
32 static void ParseEvent(const char* msg, Uevent* uevent) {
33 uevent->partition_num = -1;
34 uevent->major = -1;
35 uevent->minor = -1;
36 uevent->action.clear();
37 uevent->path.clear();
38 uevent->subsystem.clear();
39 uevent->firmware.clear();
40 uevent->partition_name.clear();
41 uevent->device_name.clear();
42 uevent->modalias.clear();
43 // currently ignoring SEQNUM
44 while (*msg) {
45 if (!strncmp(msg, "ACTION=", 7)) {
46 msg += 7;
47 uevent->action = msg;
48 } else if (!strncmp(msg, "DEVPATH=", 8)) {
49 msg += 8;
50 uevent->path = msg;
51 } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
52 msg += 10;
53 uevent->subsystem = msg;
54 } else if (!strncmp(msg, "FIRMWARE=", 9)) {
55 msg += 9;
56 uevent->firmware = msg;
57 } else if (!strncmp(msg, "MAJOR=", 6)) {
58 msg += 6;
59 uevent->major = atoi(msg);
60 } else if (!strncmp(msg, "MINOR=", 6)) {
61 msg += 6;
62 uevent->minor = atoi(msg);
63 } else if (!strncmp(msg, "PARTN=", 6)) {
64 msg += 6;
65 uevent->partition_num = atoi(msg);
66 } else if (!strncmp(msg, "PARTNAME=", 9)) {
67 msg += 9;
68 uevent->partition_name = msg;
69 } else if (!strncmp(msg, "DEVNAME=", 8)) {
70 msg += 8;
71 uevent->device_name = msg;
72 } else if (!strncmp(msg, "MODALIAS=", 9)) {
73 msg += 9;
74 uevent->modalias = msg;
75 }
76
77 // advance to after the next \0
78 while (*msg++)
79 ;
80 }
结论是: init进程接收的partname是由kernel中传递的。
日志的LOG如下:
210 [ 1.226856] tom virtio_blk_init
211 [ 1.227226] random: crng init done
212 [ 1.229048] tom F=set_disk_ro_uevent L=1464
213 [ 1.230329] vda: vda1 vda2
214 [ 1.239918] tom F=set_disk_ro_uevent L=1464
322 [ 1.386757] init: [libfs_mgr]ReadFstabFromDt(): failed to read fstab from dt
323 [ 1.387494] init: [libfs_mgr]ReadDefaultFstab L=749 default_fstab_path=/fstab.ranchu
324 [ 1.388292] init: [libfs_mgr]tom L=476 line=# Android fstab file for ramdisk tom -3
325 [ 1.389028] init:
326 [ 1.389212] init: [libfs_mgr]tom L=476 line=#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags>
327 [ 1.389993] init:
328 [ 1.390272] init: [libfs_mgr]tom L=476 line=system /system ext4 ro,barrier=1 wait,logical,avb=vbmeta,first_stage_mount
329 [ 1.391230] init:
330 [ 1.391430] init: [libfs_mgr]tom L=476 line=vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount
215 [ 1.242200] vde: vde1
375 [ 1.421904] tom F=kobject_uevent_env env1->envp[1]=DEVPATH=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda
376 [ 1.422365] tom F=kobject_uevent_env env1->envp[2]=SUBSYSTEM=block
377 [ 1.423161] tom F=kobject_uevent_env env1->envp[3]=SYNTH_UUID=0
378 [ 1.423652] tom F=kobject_uevent_env env1->envp[4]=MAJOR=253
379 [ 1.424122] tom F=kobject_uevent_env env1->envp[5]=MINOR=0
380 [ 1.424568] tom F=kobject_uevent_env env1->envp[6]=DEVNAME=vda
381 [ 1.425009] tom F=kobject_uevent_env env1->envp[7]=DEVTYPE=disk
382 [ 1.425468] tom F=kobject_uevent_env env1->envp[8]=SEQNUM=1034
383 [ 1.426090] tom F=kobject_uevent_env subsystem=block
384 [ 1.426592] tom F=kobject_uevent_env devpath=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda2
385 [ 1.427128] tom F=kobject_uevent_env envp=SYNTH_UUID=0
386 [ 1.427899] tom F=kobject_uevent_env env1->envp[0]=ACTION=add
387 [ 1.428308] tom F=kobject_uevent_env env1->envp[1]=DEVPATH=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda2
388 [ 1.428760] tom F=kobject_uevent_env env1->envp[2]=SUBSYSTEM=block
389 [ 1.429575] tom F=kobject_uevent_env env1->envp[3]=SYNTH_UUID=0
390 [ 1.430091] tom F=kobject_uevent_env env1->envp[4]=MAJOR=253
391 [ 1.430557] tom F=kobject_uevent_env env1->envp[5]=MINOR=2
392 [ 1.431003] tom F=kobject_uevent_env env1->envp[6]=DEVNAME=vda2
393 [ 1.431438] tom F=kobject_uevent_env env1->envp[7]=DEVTYPE=partition
394 [ 1.431903] tom F=kobject_uevent_env env1->envp[8]=PARTN=2
395 [ 1.432401] tom F=kobject_uevent_env env1->envp[9]=PARTNAME=super
396 [ 1.432837] tom F=kobject_uevent_env env1->envp[10]=SEQNUM=1035
397 [ 1.433422] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda2 subsystem=block
398 [ 1.434670] init: tom firmware= p_name=super
399 [ 1.435018] init: tom device_name=vda2 modifies=
400 [ 1.435408] init: tom partition_num=2 major=253 minor=2
401 [ 1.436173] tom F=kobject_uevent_env subsystem=block
402 [ 1.436174] tom F=kobject_uevent_env devpath=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1
403 [ 1.436565] tom F=kobject_uevent_env envp=SYNTH_UUID=0
404 [ 1.437265] tom F=kobject_uevent_env env1->envp[0]=ACTION=add
405 [ 1.437662] tom F=kobject_uevent_env env1->envp[1]=DEVPATH=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1
406 [ 1.438103] tom F=kobject_uevent_env env1->envp[2]=SUBSYSTEM=block
407 [ 1.438881] tom F=kobject_uevent_env env1->envp[3]=SYNTH_UUID=0
408 [ 1.439347] tom F=kobject_uevent_env env1->envp[4]=MAJOR=253
409 [ 1.439805] tom F=kobject_uevent_env env1->envp[5]=MINOR=1
410 [ 1.440362] tom F=kobject_uevent_env env1->envp[6]=DEVNAME=vda1
411 [ 1.440793] tom F=kobject_uevent_env env1->envp[7]=DEVTYPE=partition
412 [ 1.441329] tom F=kobject_uevent_env env1->envp[8]=PARTN=1
413 [ 1.441874] tom F=kobject_uevent_env env1->envp[9]=PARTNAME=vbmeta
414 [ 1.442316] tom F=kobject_uevent_env env1->envp[10]=SEQNUM=1036
415 [ 1.442835] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1 subsystem=block
416 [ 1.444161] init: tom firmware= p_name=vbmeta
417 [ 1.444510] init: tom device_name=vda1 modifies=
418 [ 1.444898] init: tom partition_num=1 major=253 minor=1
函数 定义如下:
327 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
328 char *envp_ext[])
329 {
330 struct kobj_uevent_env *env;
331 const char *action_string = kobject_actions[action];
332 const char *devpath = NULL;
333 const char *subsystem;
334 struct kobject *top_kobj;
335 struct kset *kset;
336 const struct kset_uevent_ops *uevent_ops;
337 int i = 0;
338 int retval = 0;
339 #ifdef CONFIG_NET
340 struct uevent_sock *ue_sk;
341 u32 dst_nl_group = 0;
342 #endif
343
344 /*
345 * Mark "remove" event done regardless of result, for some subsystems
346 * do not want to re-trigger "remove" event via automatic cleanup.
347 */
348 if (action == KOBJ_REMOVE)
349 kobj->state_remove_uevent_sent = 1;
350
351 pr_debug("kobject: '%s' (%p): %s\n",
352 kobject_name(kobj), kobj, __func__);
353
354 /* search the kset we belong to */
355 top_kobj = kobj;
356 while (!top_kobj->kset && top_kobj->parent)
357 top_kobj = top_kobj->parent;
358
359 if (!top_kobj->kset) {
360 pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
361 "without kset!\n", kobject_name(kobj), kobj,
362 __func__);
363 return -EINVAL;
364 }
365
366 kset = top_kobj->kset;
367 uevent_ops = kset->uevent_ops;
368
369 /* skip the event, if uevent_suppress is set*/
370 if (kobj->uevent_suppress) {
371 pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
372 "caused the event to drop!\n",
373 kobject_name(kobj), kobj, __func__);
374 return 0;
375 }
376 /* skip the event, if the filter returns zero. */
377 if (uevent_ops && uevent_ops->filter)
378 if (!uevent_ops->filter(kset, kobj)) {
379 pr_debug("kobject: '%s' (%p): %s: filter function "
380 "caused the event to drop!\n",
381 kobject_name(kobj), kobj, __func__);
382 return 0;
383 }
384
385 /* originating subsystem */
386 if (uevent_ops && uevent_ops->name)
387 subsystem = uevent_ops->name(kset, kobj);
388 else
389 subsystem = kobject_name(&kset->kobj);
390 if (!subsystem) {
391 pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
392 "event to drop!\n", kobject_name(kobj), kobj,
393 __func__);
394 return 0;
395 }
396
397
398 /* environment buffer */
399 env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
400 if (!env)
401 return -ENOMEM;
402
403 /* complete object path */
404 devpath = kobject_get_path(kobj, GFP_KERNEL);
405 if (!devpath) {
406 retval = -ENOENT;
407 goto exit;
408 }
409
410 /* default keys */
411 retval = add_uevent_var(env, "ACTION=%s", action_string);
412 if (retval)
413 goto exit;
414 retval = add_uevent_var(env, "DEVPATH=%s", devpath);
415 if (retval)
416 goto exit;
417 retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
418 if (retval)
419 goto exit;
420
421 if(!strncmp(subsystem,"block",5))
422 printk(KERN_ERR "tom F=%s L=%d env->envp_idx=%d",__FUNCTION__,__LINE__,env->envp_idx);
423
424 /* keys passed in from the caller */
425 if (envp_ext) {
426 for (i = 0; envp_ext[i]; i++) {
427 retval = add_uevent_var(env, "%s", envp_ext[i]);
428
429
430 if (retval)
431 goto exit;
432 }
433 }
434
435 if(!strncmp(subsystem,"block",5))
436 printk(KERN_ERR "tom F=%s L=%d env->envp_idx=%d",__FUNCTION__,__LINE__,env->envp_idx);
437
438 /* let the kset specific function add its stuff */
439 if (uevent_ops && uevent_ops->uevent) {
440 retval = uevent_ops->uevent(kset, kobj, env);
441
442 if(!strncmp(subsystem,"block",5))
443 printk(KERN_ERR "tom F=%s L=%d env->envp_idx=%d",__FUNCTION__,__LINE__,env->envp_idx);
444
445 if (retval) {
446 pr_debug("kobject: '%s' (%p): %s: uevent() returned "
447 "%d\n", kobject_name(kobj), kobj,
448 __func__, retval);
449 goto exit;
450 }
451 }
452
453 if(!strncmp(subsystem,"block",5))
454 printk(KERN_ERR "tom F=%s L=%d env->envp_idx=%d",__FUNCTION__,__LINE__,env->envp_idx);
455
456 switch (action) {
457 case KOBJ_ADD:
458 /*
459 * Mark "add" event so we can make sure we deliver "remove"
460 * event to userspace during automatic cleanup. If
461 * the object did send an "add" event, "remove" will
462 * automatically generated by the core, if not already done
463 * by the caller.
464 */
465 kobj->state_add_uevent_sent = 1;
466 break;
467
468 case KOBJ_UNBIND:
469 zap_modalias_env(env);
470 break;
471
472 default:
473 break;
474 }
475
476 if(!strncmp(subsystem,"block",5))
477 printk(KERN_ERR "tom F=%s L=%d env->envp_idx=%d",__FUNCTION__,__LINE__,env->envp_idx);
478 mutex_lock(&uevent_sock_mutex);
479 /* we will send an event, so request a new sequence number */
480 retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
481 if (retval) {
482 mutex_unlock(&uevent_sock_mutex);
483 goto exit;
484 }
485
486
487 /* for (i = 0; i < env->envp_idx; i++) {*/
488 /*if(!strncmp(subsystem,"block",5))*/
489 /*printk(KERN_ERR "tom-111 F=%s env1->envp[%d]=%s",__FUNCTION__,i,env->envp[i]);*/
490 /*}*/
491
492 if(!strncmp(subsystem,"block",5))
493 printk(KERN_ERR "tom F=%s L=%d env->envp_idx=%d",__FUNCTION__,__LINE__,env->envp_idx);
494
495 #if defined(CONFIG_NET)
496 dst_nl_group =
497 (strcmp(subsystem, "power_supply") == 0) ? (1u << 16) : 0;
498
499 /* send netlink message */
500 list_for_each_entry(ue_sk, &uevent_sock_list, list) {
501 struct sock *uevent_sock = ue_sk->sk;
502 struct sk_buff *skb;
503 size_t len;
504
505 if (!netlink_has_listeners(uevent_sock, 1))
506 continue;
507
508 /* allocate message with the maximum possible size */
509 len = strlen(action_string) + strlen(devpath) + 2;
510 skb = alloc_skb(len + env->buflen, GFP_KERNEL);
511 if (skb) {
512 char *scratch;
513
514 /* add header */
515 scratch = skb_put(skb, len);
516 sprintf(scratch, "%s@%s", action_string, devpath);
517
518 /* copy keys to our continuous event payload buffer */
519 for (i = 0; i < env->envp_idx; i++) {
520 len = strlen(env->envp[i]) + 1;
521 scratch = skb_put(skb, len);
522 strcpy(scratch, env->envp[i]);
523 if(!strncmp(subsystem,"block",5)) {
524 printk(KERN_ERR "tom F=%s env1->envp[%d]=%s",__FUNCTION__,i,env->envp[i]);
525 }
526 }
527
528 NETLINK_CB(skb).dst_group = 1;
529 retval = netlink_broadcast_filtered(uevent_sock, skb,
530 0, 1, GFP_KERNEL,
531 kobj_bcast_filter,
532 kobj);
533 /* ENOBUFS should be handled in userspace */
534 if (retval == -ENOBUFS || retval == -ESRCH)
535 retval = 0;
536 } else
537 retval = -ENOMEM;
538 }
539 if(!strncmp(subsystem,"block",5))
540 printk(KERN_ERR "tom F=%s L=%d env->envp_idx=%d",__FUNCTION__,__LINE__,env->envp_idx);
541
542 if (dst_nl_group) {
543 /* send netlink message */
544 list_for_each_entry(ue_sk, &uevent_sock_list, list) {
545 struct sock *uevent_sock = ue_sk->sk;
546 struct sk_buff *skb;
547 size_t len;
548
549 if (!netlink_has_listeners(uevent_sock, dst_nl_group))
550 continue;
551
552 /* allocate message with the maximum possible size */
553 len = strlen(action_string) + strlen(devpath) + 2;
554 skb = alloc_skb(len + env->buflen, GFP_KERNEL);
555 if (skb) {
556 char *scratch;
557
558 /* add header */
559 scratch = skb_put(skb, len);
560 sprintf(scratch, "%s@%s", action_string,
561 devpath);
562
563 /* copy keys to our continuous event payload
564 * buffer
565 */
566 for (i = 0; i < env->envp_idx; i++) {
567 len = strlen(env->envp[i]) + 1;
568 scratch = skb_put(skb, len);
569 strcpy(scratch, env->envp[i]);
570 if(!strncmp(subsystem,"block",5)) {
571 printk(KERN_ERR "tom F=%s env2->envp[%d]=%s",__FUNCTION__,i,env->envp[i]);
572 }
573 }
574
575
576 if(!strncmp(subsystem,"block",5)) {
577 printk(KERN_ERR "tom F=%s subsystem=%s",__FUNCTION__,subsystem);
578 printk(KERN_ERR "tom F=%s devpath=%s",__FUNCTION__,devpath);
579 printk(KERN_ERR "tom F=%s envp=%s",__FUNCTION__,envp_ext[i]);
580 }
581
582
583 NETLINK_CB(skb).dst_group = dst_nl_group;
584 retval = netlink_broadcast_filtered(
585 uevent_sock, skb,
586 0, dst_nl_group, GFP_KERNEL,
587 kobj_bcast_filter,
588 kobj);
589 /* ENOBUFS should be handled in userspace */
590 if (retval == -ENOBUFS || retval == -ESRCH)
591 retval = 0;
592 } else
593 retval = -ENOMEM;
594 }
595 }
596 #endif
597 mutex_unlock(&uevent_sock_mutex);
598
599 #ifdef CONFIG_UEVENT_HELPER
600 /* call uevent_helper, usually only enabled during early boot */
601 if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
602 struct subprocess_info *info;
603
604 retval = add_uevent_var(env, "HOME=/");
605 if (retval)
606 goto exit;
607 retval = add_uevent_var(env,
608 "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
609 if (retval)
610 goto exit;
611 retval = init_uevent_argv(env, subsystem);
612 if (retval)
613 goto exit;
614
615 retval = -ENOMEM;
616 info = call_usermodehelper_setup(env->argv[0], env->argv,
617 env->envp, GFP_KERNEL,
618 NULL, cleanup_uevent_env, env);
619 if (info) {
620 retval = call_usermodehelper_exec(info, UMH_NO_WAIT);
621 env = NULL; /* freed by cleanup_uevent_env */
622 }
623 }
624 #endif
625
626 exit:
627 kfree(devpath);
628 kfree(env);
629 return retval;
630 }