mdev: support for serializing hotplug
No binary (build failed)
—
(log yok)
| @@ -95,3 +95,26 @@ properly initialize a device. Place all such firmware files into the | |
| filename of the firmware which mdev will load out of /lib/firmware/ and into | |
| the kernel via the sysfs interface. The exact filename is hardcoded in the | |
| kernel, so look there if you need to know how to name the file in userspace. | |
| + | |
| + | ------------ |
| + | SEQUENCING |
| + | ------------ |
| + | |
| + | Kernel does not serialize hotplug events. It increments SEQNUM environmental |
| + | variable for each successive hotplug invocation. Normally, mdev doesn't care. |
| + | This may reorder hotplug and hot-unplug events, with typical symptoms of |
| + | device nodes sometimes not created as expected. |
| + | |
| + | However, if /dev/mdev.seq file is found, mdev will compare its |
| + | contents with SEQNUM. It will retry up to two seconds, waiting for them |
| + | to match. If they match exactly (not even trailing '\n' is allowed), |
| + | or if two seconds pass, mdev runs as usual, then it rewrites /dev/mdev.seq |
| + | with SEQNUM+1. |
| + | |
| + | IOW: this will serialize concurrent mdev invocations. |
| + | |
| + | If you want to activate this feature, execute "echo >/dev/mdev.seq" prior to |
| + | setting mdev to be the hotplug handler. This writes single '\n' to the file. |
| + | NB: mdev recognizes /dev/mdev.seq consisting of single '\n' characher |
| + | as a special case. IOW: this will not make your first hotplug event |
| + | to stall for two seconds. |
| @@ -374,8 +374,6 @@ static void load_firmware(const char *const firmware, const char *const sysfs_pa | |
| int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int mdev_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| - | char *action; |
| - | char *env_path; |
| RESERVE_CONFIG_BUFFER(temp, PATH_MAX + SCRATCH_SIZE); | |
| /* We can be called as hotplug helper */ | |
| @@ -417,8 +415,14 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |
| ACTION_RECURSE | ACTION_FOLLOWLINKS, | |
| fileAction, dirAction, temp, 0); | |
| } else { | |
| + | char *seq; |
| + | char *action; |
| + | char *env_path; |
| + | char seqbuf[sizeof(int)*3 + 2]; |
| + | int seqlen = seqlen; /* for compiler */ |
| + | |
| /* Hotplug: | |
| - | * env ACTION=... DEVPATH=... mdev |
| + | * env ACTION=... DEVPATH=... [SEQNUM=...] mdev |
| * ACTION can be "add" or "remove" | |
| * DEVPATH is like "/block/sda" or "/class/input/mice" | |
| */ | |
| @@ -427,6 +431,23 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |
| if (!action || !env_path) | |
| bb_show_usage(); | |
| + | seq = getenv("SEQNUM"); |
| + | if (seq) { |
| + | int timeout = 2000 / 32; |
| + | do { |
| + | seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf-1)); |
| + | if (seqlen < 0) |
| + | break; |
| + | seqbuf[seqlen] = '\0'; |
| + | if (seqbuf[0] == '\n' /* seed file? */ |
| + | || strcmp(seq, seqbuf) == 0 /* correct idx? */ |
| + | ) { |
| + | break; |
| + | } |
| + | usleep(32*1000); |
| + | } while (--timeout); |
| + | } |
| + | |
| snprintf(temp, PATH_MAX, "/sys%s", env_path); | |
| if (!strcmp(action, "remove")) | |
| make_device(temp, 1); | |
| @@ -439,6 +460,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |
| load_firmware(fw, temp); | |
| } | |
| } | |
| + | |
| + | if (seq && seqlen >= 0) { |
| + | xopen_xwrite_close("mdev.seq", utoa(xatou(seq) + 1)); |
| + | } |
| } | |
| if (ENABLE_FEATURE_CLEAN_UP) | |