Commit 53a11dfc authored by Kirill Tkhai's avatar Kirill Tkhai Committed by Andrei Vagin

forking: Use last_pid_mutex for synchronization during clone()

Before this patch we used flock to order task creation,
but this way is not good. It took 5 syscalls to synchronize
a creation of a single child:

1)open()
2)flock(LOCK_EX)
3)flock(LOCK_UN)
4)close() in parent
5)close() in child

The patch introduces more effective way for synchronization,
which executes 2 syscalls only. We use last_pid_mutex,
and the syscalls number sounds definitely better.

v2: Don't use flock() at all
Signed-off-by: 's avatarKirill Tkhai <ktkhai@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 9a64e003
......@@ -1243,7 +1243,6 @@ static int restore_one_task(int pid, CoreEntry *core)
struct cr_clone_arg {
struct pstree_item *item;
unsigned long clone_flags;
int fd;
CoreEntry *core;
};
......@@ -1346,24 +1345,22 @@ static inline int fork_with_pid(struct pstree_item *item)
if (!(ca.clone_flags & CLONE_NEWPID)) {
char buf[32];
int len;
int fd;
ca.fd = open_proc_rw(PROC_GEN, LAST_PID_PATH);
if (ca.fd < 0)
fd = open_proc_rw(PROC_GEN, LAST_PID_PATH);
if (fd < 0)
goto err;
if (flock(ca.fd, LOCK_EX)) {
close(ca.fd);
pr_perror("%d: Can't lock %s", pid, LAST_PID_PATH);
goto err;
}
lock_last_pid();
len = snprintf(buf, sizeof(buf), "%d", pid - 1);
if (write(ca.fd, buf, len) != len) {
if (write(fd, buf, len) != len) {
pr_perror("%d: Write %s to %s", pid, buf, LAST_PID_PATH);
close(fd);
goto err_unlock;
}
close(fd);
} else {
ca.fd = -1;
BUG_ON(pid != INIT_PID);
}
......@@ -1395,12 +1392,8 @@ static inline int fork_with_pid(struct pstree_item *item)
}
err_unlock:
if (ca.fd >= 0) {
if (flock(ca.fd, LOCK_UN))
pr_perror("%d: Can't unlock %s", pid, LAST_PID_PATH);
close(ca.fd);
}
if (!(ca.clone_flags & CLONE_NEWPID))
unlock_last_pid();
err:
if (ca.core)
core_entry__free_unpacked(ca.core, NULL);
......@@ -1664,9 +1657,6 @@ static int restore_task_with_children(void *_arg)
current->pid->real, vpid(current));
}
if ( !(ca->clone_flags & CLONE_FILES))
close_safe(&ca->fd);
pid = getpid();
if (vpid(current) != pid) {
pr_err("Pid %d do not match expected %d\n", pid, vpid(current));
......
......@@ -1551,20 +1551,16 @@ long __export_restore_task(struct task_restore_args *args)
CLONE_THREAD | CLONE_SYSVSEM | CLONE_FS;
long last_pid_len;
long parent_tid;
int i, fd;
int i, fd = -1;
/* One level pid ns hierarhy */
fd = sys_openat(args->proc_fd, LAST_PID_PATH, O_RDWR, 0);
if (fd < 0) {
pr_err("can't open last pid fd %d\n", fd);
goto core_restore_end;
}
ret = sys_flock(fd, LOCK_EX);
if (ret) {
pr_err("Can't lock last_pid %d\n", fd);
sys_close(fd);
goto core_restore_end;
}
mutex_lock(&task_entries_local->last_pid_mutex);
for (i = 0; i < args->nr_threads; i++) {
char last_pid_buf[16], *s;
......@@ -1580,6 +1576,7 @@ long __export_restore_task(struct task_restore_args *args)
if (ret < 0) {
pr_err("Can't set last_pid %ld/%s\n", ret, last_pid_buf);
sys_close(fd);
mutex_unlock(&task_entries_local->last_pid_mutex);
goto core_restore_end;
}
......@@ -1593,18 +1590,14 @@ long __export_restore_task(struct task_restore_args *args)
RUN_CLONE_RESTORE_FN(ret, clone_flags, new_sp, parent_tid, thread_args, args->clone_restore_fn);
if (ret != thread_args[i].pid) {
pr_err("Unable to create a thread: %ld\n", ret);
mutex_unlock(&task_entries_local->last_pid_mutex);
goto core_restore_end;
}
}
ret = sys_flock(fd, LOCK_UN);
if (ret) {
pr_err("Can't unlock last_pid %ld\n", ret);
mutex_unlock(&task_entries_local->last_pid_mutex);
if (fd >= 0)
sys_close(fd);
goto core_restore_end;
}
sys_close(fd);
}
restore_rlims(args);
......
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