Commit ecc2776f authored by Andrey Vagin's avatar Andrey Vagin Committed by Cyrill Gorcunov

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: 's avatarAndrey Vagin <avagin@openvz.org>
Acked-by: 's avatarPavel Emelianov <xemul@parallels.com>
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
parent c53972cd
...@@ -1059,7 +1059,6 @@ static int attach_pipe(int pid, struct pipe_entry *e, struct pipe_info *pi, int ...@@ -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: ...@@ -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) ...@@ -1179,26 +1190,58 @@ static int prepare_pipes(int pid)
return 1; return 1;
} }
buf = malloc(buf_size);
if (!buf) {
pr_perror("Can't allocate memory\n");
close(pipes_fd);
return 1;
}
while (1) { while (1) {
struct pipe_entry e;
int ret; int ret;
struct list_head *cur;
struct pipe_list_entry *cur_entry;
ret = read(pipes_fd, &e, sizeof(e)); le = &buf[nr];
if (ret == 0) {
close(pipes_fd); ret = read(pipes_fd, &le->e, sizeof(le->e));
if (ret == 0)
break; break;
}
if (ret != sizeof(e)) { if (ret != sizeof(le->e)) {
pr_perror("%d: Bad pipes entry\n", pid); pr_perror("%d: Bad pipes entry\n", pid);
return 1; goto err_free;
} }
if (open_pipe(pid, &e, &pipes_fd)) list_for_each(cur, &head) {
return 1; 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;
}
} }
return 0; 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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment