diff options
author | Denys Vlasenko | 2015-04-19 18:55:12 +0200 |
---|---|---|
committer | Denys Vlasenko | 2015-04-19 18:55:12 +0200 |
commit | ad795510d9fd6f4290be170c84c0d30eb1af7245 (patch) | |
tree | d9fdc1a48404e9d26b016adbfe3e58e7a0e279e9 | |
parent | bd77e9d6093dc8632788a3c3efffd53ac8ba3233 (diff) | |
download | busybox-ad795510d9fd6f4290be170c84c0d30eb1af7245.zip busybox-ad795510d9fd6f4290be170c84c0d30eb1af7245.tar.gz |
mdev: if a "future" mdev.seq is seen, do not overwrite it with ours
This was seen to happen if two mdevs are run in parallel,
mdev.seq is empty, and the "newer" one manages to write it first.
function old new delta
mdev_main 1366 1388 +22
atoll - 20 +20
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | util-linux/mdev.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 884e5de..ca4b915 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -947,7 +947,7 @@ static void open_mdev_log(const char *seq, unsigned my_pid) * Active mdev pokes us with SIGCHLD to check the new file. */ static int -wait_for_seqfile(const char *seq) +wait_for_seqfile(unsigned expected_seq) { /* We time out after 2 sec */ static const struct timespec ts = { 0, 32*1000*1000 }; @@ -962,12 +962,14 @@ wait_for_seqfile(const char *seq) for (;;) { int seqlen; - char seqbuf[sizeof(int)*3 + 2]; + char seqbuf[sizeof(long)*3 + 2]; + unsigned seqbufnum; if (seq_fd < 0) { seq_fd = open("mdev.seq", O_RDWR); if (seq_fd < 0) break; + close_on_exec_on(seq_fd); } seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); if (seqlen < 0) { @@ -978,17 +980,25 @@ wait_for_seqfile(const char *seq) seqbuf[seqlen] = '\0'; if (seqbuf[0] == '\n' || seqbuf[0] == '\0') { /* seed file: write out seq ASAP */ - xwrite_str(seq_fd, seq); + xwrite_str(seq_fd, utoa(expected_seq)); xlseek(seq_fd, 0, SEEK_SET); dbg2("first seq written"); break; } - if (strcmp(seq, seqbuf) == 0) { + seqbufnum = atoll(seqbuf); + if (seqbufnum == expected_seq) { /* correct idx */ break; } + if (seqbufnum > expected_seq) { + /* a later mdev runs already (this was seen by users to happen) */ + /* do not overwrite seqfile on exit */ + close(seq_fd); + seq_fd = -1; + break; + } if (do_once) { - dbg2("%s mdev.seq='%s', need '%s'", curtime(), seqbuf, seq); + dbg2("%s mdev.seq='%s', need '%u'", curtime(), seqbuf, expected_seq); do_once = 0; } if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { @@ -1079,6 +1089,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) char *env_devname; char *env_devpath; unsigned my_pid; + unsigned seqnum = seqnum; /* for compiler */ int seq_fd; smalluint op; @@ -1100,7 +1111,11 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) my_pid = getpid(); open_mdev_log(seq, my_pid); - seq_fd = seq ? wait_for_seqfile(seq) : -1; + seq_fd = -1; + if (seq) { + seqnum = atoll(seq); + seq_fd = wait_for_seqfile(seqnum); + } dbg1("%s " "ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%s" @@ -1128,7 +1143,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) dbg1("%s exiting", curtime()); if (seq_fd >= 0) { - xwrite_str(seq_fd, utoa(xatou(seq) + 1)); + xwrite_str(seq_fd, utoa(seqnum + 1)); signal_mdevs(my_pid); } } |