2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-31 14:25:49 +00:00

pipe: fix deadlock

Probably all of you know about "lock inversion". There was a similar
problem on restoring pipes.

One process try to restore pipe1 and waits when another process attached
to it.  In this time another process restores pipe2 and waits too.

I know two solves.
1. Open all pipes -> attach to them -> close unnecessary ends.
This method has a problem, if only one end belongs to the process.  In
this cases another end occupies a descriptor, which may be needed to
another pipe.

2. Restore pipes in the same order. This patch does that.
A sorted list of pipe entries are constructed.

Signed-off-by: Andrey Vagin <avagin@openvz.org>
Acked-by: Pavel Emelianov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
This commit is contained in:
Andrey Vagin
2011-12-08 16:27:00 +04:00
committed by Cyrill Gorcunov
parent c53972cdc0
commit ecc2776fc9

View File

@@ -1059,7 +1059,6 @@ static int attach_pipe(int pid, struct pipe_entry *e, struct pipe_info *pi, int
tmp = reopen_fd_as(e->fd, fd); tmp = reopen_fd_as(e->fd, fd);
if (tmp < 0) if (tmp < 0)
return 1; return 1;
lseek(pipes_fd, e->bytes, SEEK_CUR);
pi->users--; pi->users--;
out: out:
@@ -1160,10 +1159,22 @@ err:
} }
struct pipe_list_entry {
struct pipe_entry e;
struct list_head list;
off_t offset;
};
static int prepare_pipes(int pid) static int prepare_pipes(int pid)
{ {
u32 type = 0, ret = 1;
int pipes_fd; int pipes_fd;
u32 type = 0;
struct pipe_list_entry *le, *buf;
int buf_size = PAGE_SIZE;
int nr = 0;
LIST_HEAD(head);
pr_info("%d: Opening pipes\n", pid); pr_info("%d: Opening pipes\n", pid);
@@ -1179,26 +1190,58 @@ static int prepare_pipes(int pid)
return 1; return 1;
} }
while (1) { buf = malloc(buf_size);
struct pipe_entry e; if (!buf) {
int ret; pr_perror("Can't allocate memory\n");
close(pipes_fd);
ret = read(pipes_fd, &e, sizeof(e)); return 1;
if (ret == 0) {
close(pipes_fd);
break;
}
if (ret != sizeof(e)) {
pr_perror("%d: Bad pipes entry\n", pid);
return 1;
}
if (open_pipe(pid, &e, &pipes_fd))
return 1;
} }
return 0; while (1) {
int ret;
struct list_head *cur;
struct pipe_list_entry *cur_entry;
le = &buf[nr];
ret = read(pipes_fd, &le->e, sizeof(le->e));
if (ret == 0)
break;
if (ret != sizeof(le->e)) {
pr_perror("%d: Bad pipes entry\n", pid);
goto err_free;
}
list_for_each(cur, &head) {
cur_entry = list_entry(cur, struct pipe_list_entry, list);
if (cur_entry->e.pipeid > le->e.pipeid)
break;
}
list_add_tail(&le->list, cur);
le->offset = lseek(pipes_fd, 0, SEEK_CUR);
lseek(pipes_fd, le->e.bytes, SEEK_CUR);
nr++;
if (nr > buf_size / sizeof(*le)) {
pr_err("OOM storing pipes");
goto err_free;
}
}
list_for_each_entry(le, &head, list) {
lseek(pipes_fd, le->offset, SEEK_SET);
if (open_pipe(pid, &le->e, &pipes_fd))
goto err_free;
}
ret = 0;
err_free:
free(buf);
close(pipes_fd);
return ret;
} }
static int restore_one_task(int pid) static int restore_one_task(int pid)