diff options
| -rw-r--r-- | docs/mdev.txt | 23 | ||||
| -rw-r--r-- | util-linux/mdev.c | 31 |
2 files changed, 51 insertions, 3 deletions
diff --git a/docs/mdev.txt b/docs/mdev.txt index 1a97be4ce..555c2bf61 100644 --- a/docs/mdev.txt +++ b/docs/mdev.txt | |||
| @@ -95,3 +95,26 @@ properly initialize a device. Place all such firmware files into the | |||
| 95 | filename of the firmware which mdev will load out of /lib/firmware/ and into | 95 | filename of the firmware which mdev will load out of /lib/firmware/ and into |
| 96 | the kernel via the sysfs interface. The exact filename is hardcoded in the | 96 | the kernel via the sysfs interface. The exact filename is hardcoded in the |
| 97 | kernel, so look there if you need to know how to name the file in userspace. | 97 | kernel, so look there if you need to know how to name the file in userspace. |
| 98 | |||
| 99 | ------------ | ||
| 100 | SEQUENCING | ||
| 101 | ------------ | ||
| 102 | |||
| 103 | Kernel does not serialize hotplug events. It increments SEQNUM environmental | ||
| 104 | variable for each successive hotplug invocation. Normally, mdev doesn't care. | ||
| 105 | This may reorder hotplug and hot-unplug events, with typical symptoms of | ||
| 106 | device nodes sometimes not created as expected. | ||
| 107 | |||
| 108 | However, if /dev/mdev.seq file is found, mdev will compare its | ||
| 109 | contents with SEQNUM. It will retry up to two seconds, waiting for them | ||
| 110 | to match. If they match exactly (not even trailing '\n' is allowed), | ||
| 111 | or if two seconds pass, mdev runs as usual, then it rewrites /dev/mdev.seq | ||
| 112 | with SEQNUM+1. | ||
| 113 | |||
| 114 | IOW: this will serialize concurrent mdev invocations. | ||
| 115 | |||
| 116 | If you want to activate this feature, execute "echo >/dev/mdev.seq" prior to | ||
| 117 | setting mdev to be the hotplug handler. This writes single '\n' to the file. | ||
| 118 | NB: mdev recognizes /dev/mdev.seq consisting of single '\n' characher | ||
| 119 | as a special case. IOW: this will not make your first hotplug event | ||
| 120 | to stall for two seconds. | ||
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index c61521cbb..8968e45f8 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
| @@ -374,8 +374,6 @@ static void load_firmware(const char *const firmware, const char *const sysfs_pa | |||
| 374 | int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 374 | int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| 375 | int mdev_main(int argc UNUSED_PARAM, char **argv) | 375 | int mdev_main(int argc UNUSED_PARAM, char **argv) |
| 376 | { | 376 | { |
| 377 | char *action; | ||
| 378 | char *env_path; | ||
| 379 | RESERVE_CONFIG_BUFFER(temp, PATH_MAX + SCRATCH_SIZE); | 377 | RESERVE_CONFIG_BUFFER(temp, PATH_MAX + SCRATCH_SIZE); |
| 380 | 378 | ||
| 381 | /* We can be called as hotplug helper */ | 379 | /* We can be called as hotplug helper */ |
| @@ -417,8 +415,14 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
| 417 | ACTION_RECURSE | ACTION_FOLLOWLINKS, | 415 | ACTION_RECURSE | ACTION_FOLLOWLINKS, |
| 418 | fileAction, dirAction, temp, 0); | 416 | fileAction, dirAction, temp, 0); |
| 419 | } else { | 417 | } else { |
| 418 | char *seq; | ||
| 419 | char *action; | ||
| 420 | char *env_path; | ||
| 421 | char seqbuf[sizeof(int)*3 + 2]; | ||
| 422 | int seqlen = seqlen; /* for compiler */ | ||
| 423 | |||
| 420 | /* Hotplug: | 424 | /* Hotplug: |
| 421 | * env ACTION=... DEVPATH=... mdev | 425 | * env ACTION=... DEVPATH=... [SEQNUM=...] mdev |
| 422 | * ACTION can be "add" or "remove" | 426 | * ACTION can be "add" or "remove" |
| 423 | * DEVPATH is like "/block/sda" or "/class/input/mice" | 427 | * DEVPATH is like "/block/sda" or "/class/input/mice" |
| 424 | */ | 428 | */ |
| @@ -427,6 +431,23 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
| 427 | if (!action || !env_path) | 431 | if (!action || !env_path) |
| 428 | bb_show_usage(); | 432 | bb_show_usage(); |
| 429 | 433 | ||
| 434 | seq = getenv("SEQNUM"); | ||
| 435 | if (seq) { | ||
| 436 | int timeout = 2000 / 32; | ||
| 437 | do { | ||
| 438 | seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf-1)); | ||
| 439 | if (seqlen < 0) | ||
| 440 | break; | ||
| 441 | seqbuf[seqlen] = '\0'; | ||
| 442 | if (seqbuf[0] == '\n' /* seed file? */ | ||
| 443 | || strcmp(seq, seqbuf) == 0 /* correct idx? */ | ||
| 444 | ) { | ||
| 445 | break; | ||
| 446 | } | ||
| 447 | usleep(32*1000); | ||
| 448 | } while (--timeout); | ||
| 449 | } | ||
| 450 | |||
| 430 | snprintf(temp, PATH_MAX, "/sys%s", env_path); | 451 | snprintf(temp, PATH_MAX, "/sys%s", env_path); |
| 431 | if (!strcmp(action, "remove")) | 452 | if (!strcmp(action, "remove")) |
| 432 | make_device(temp, 1); | 453 | make_device(temp, 1); |
| @@ -439,6 +460,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
| 439 | load_firmware(fw, temp); | 460 | load_firmware(fw, temp); |
| 440 | } | 461 | } |
| 441 | } | 462 | } |
| 463 | |||
| 464 | if (seq && seqlen >= 0) { | ||
| 465 | xopen_xwrite_close("mdev.seq", utoa(xatou(seq) + 1)); | ||
| 466 | } | ||
| 442 | } | 467 | } |
| 443 | 468 | ||
| 444 | if (ENABLE_FEATURE_CLEAN_UP) | 469 | if (ENABLE_FEATURE_CLEAN_UP) |
