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>
This commit is contained in:
Denys Vlasenko 2015-04-19 18:55:12 +02:00
parent bd77e9d609
commit ad795510d9

View File

@ -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. * Active mdev pokes us with SIGCHLD to check the new file.
*/ */
static int static int
wait_for_seqfile(const char *seq) wait_for_seqfile(unsigned expected_seq)
{ {
/* We time out after 2 sec */ /* We time out after 2 sec */
static const struct timespec ts = { 0, 32*1000*1000 }; static const struct timespec ts = { 0, 32*1000*1000 };
@ -962,12 +962,14 @@ wait_for_seqfile(const char *seq)
for (;;) { for (;;) {
int seqlen; int seqlen;
char seqbuf[sizeof(int)*3 + 2]; char seqbuf[sizeof(long)*3 + 2];
unsigned seqbufnum;
if (seq_fd < 0) { if (seq_fd < 0) {
seq_fd = open("mdev.seq", O_RDWR); seq_fd = open("mdev.seq", O_RDWR);
if (seq_fd < 0) if (seq_fd < 0)
break; break;
close_on_exec_on(seq_fd);
} }
seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0);
if (seqlen < 0) { if (seqlen < 0) {
@ -978,17 +980,25 @@ wait_for_seqfile(const char *seq)
seqbuf[seqlen] = '\0'; seqbuf[seqlen] = '\0';
if (seqbuf[0] == '\n' || seqbuf[0] == '\0') { if (seqbuf[0] == '\n' || seqbuf[0] == '\0') {
/* seed file: write out seq ASAP */ /* seed file: write out seq ASAP */
xwrite_str(seq_fd, seq); xwrite_str(seq_fd, utoa(expected_seq));
xlseek(seq_fd, 0, SEEK_SET); xlseek(seq_fd, 0, SEEK_SET);
dbg2("first seq written"); dbg2("first seq written");
break; break;
} }
if (strcmp(seq, seqbuf) == 0) { seqbufnum = atoll(seqbuf);
if (seqbufnum == expected_seq) {
/* correct idx */ /* correct idx */
break; 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) { 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; do_once = 0;
} }
if (sigtimedwait(&set_CHLD, NULL, &ts) >= 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_devname;
char *env_devpath; char *env_devpath;
unsigned my_pid; unsigned my_pid;
unsigned seqnum = seqnum; /* for compiler */
int seq_fd; int seq_fd;
smalluint op; smalluint op;
@ -1100,7 +1111,11 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
my_pid = getpid(); my_pid = getpid();
open_mdev_log(seq, my_pid); 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 " dbg1("%s "
"ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%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()); dbg1("%s exiting", curtime());
if (seq_fd >= 0) { if (seq_fd >= 0) {
xwrite_str(seq_fd, utoa(xatou(seq) + 1)); xwrite_str(seq_fd, utoa(seqnum + 1));
signal_mdevs(my_pid); signal_mdevs(my_pid);
} }
} }