Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/um/os-Linux/helper.c
10817 views
1
/*
2
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3
* Licensed under the GPL
4
*/
5
6
#include <stdlib.h>
7
#include <unistd.h>
8
#include <errno.h>
9
#include <sched.h>
10
#include <linux/limits.h>
11
#include <sys/socket.h>
12
#include <sys/wait.h>
13
#include "kern_constants.h"
14
#include "kern_util.h"
15
#include "os.h"
16
#include "um_malloc.h"
17
#include "user.h"
18
19
struct helper_data {
20
void (*pre_exec)(void*);
21
void *pre_data;
22
char **argv;
23
int fd;
24
char *buf;
25
};
26
27
static int helper_child(void *arg)
28
{
29
struct helper_data *data = arg;
30
char **argv = data->argv;
31
int err;
32
33
if (data->pre_exec != NULL)
34
(*data->pre_exec)(data->pre_data);
35
err = execvp_noalloc(data->buf, argv[0], argv);
36
37
/* If the exec succeeds, we don't get here */
38
write(data->fd, &err, sizeof(err));
39
40
return 0;
41
}
42
43
/* Returns either the pid of the child process we run or -E* on failure. */
44
int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
45
{
46
struct helper_data data;
47
unsigned long stack, sp;
48
int pid, fds[2], ret, n;
49
50
stack = alloc_stack(0, __cant_sleep());
51
if (stack == 0)
52
return -ENOMEM;
53
54
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
55
if (ret < 0) {
56
ret = -errno;
57
printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n",
58
errno);
59
goto out_free;
60
}
61
62
ret = os_set_exec_close(fds[1]);
63
if (ret < 0) {
64
printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, "
65
"ret = %d\n", -ret);
66
goto out_close;
67
}
68
69
sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *);
70
data.pre_exec = pre_exec;
71
data.pre_data = pre_data;
72
data.argv = argv;
73
data.fd = fds[1];
74
data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
75
uml_kmalloc(PATH_MAX, UM_GFP_KERNEL);
76
pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
77
if (pid < 0) {
78
ret = -errno;
79
printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n",
80
errno);
81
goto out_free2;
82
}
83
84
close(fds[1]);
85
fds[1] = -1;
86
87
/*
88
* Read the errno value from the child, if the exec failed, or get 0 if
89
* the exec succeeded because the pipe fd was set as close-on-exec.
90
*/
91
n = read(fds[0], &ret, sizeof(ret));
92
if (n == 0) {
93
ret = pid;
94
} else {
95
if (n < 0) {
96
n = -errno;
97
printk(UM_KERN_ERR "run_helper : read on pipe failed, "
98
"ret = %d\n", -n);
99
ret = n;
100
}
101
CATCH_EINTR(waitpid(pid, NULL, __WCLONE));
102
}
103
104
out_free2:
105
kfree(data.buf);
106
out_close:
107
if (fds[1] != -1)
108
close(fds[1]);
109
close(fds[0]);
110
out_free:
111
free_stack(stack, 0);
112
return ret;
113
}
114
115
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
116
unsigned long *stack_out)
117
{
118
unsigned long stack, sp;
119
int pid, status, err;
120
121
stack = alloc_stack(0, __cant_sleep());
122
if (stack == 0)
123
return -ENOMEM;
124
125
sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *);
126
pid = clone(proc, (void *) sp, flags, arg);
127
if (pid < 0) {
128
err = -errno;
129
printk(UM_KERN_ERR "run_helper_thread : clone failed, "
130
"errno = %d\n", errno);
131
return err;
132
}
133
if (stack_out == NULL) {
134
CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE));
135
if (pid < 0) {
136
err = -errno;
137
printk(UM_KERN_ERR "run_helper_thread - wait failed, "
138
"errno = %d\n", errno);
139
pid = err;
140
}
141
if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
142
printk(UM_KERN_ERR "run_helper_thread - thread "
143
"returned status 0x%x\n", status);
144
free_stack(stack, 0);
145
} else
146
*stack_out = stack;
147
return pid;
148
}
149
150
int helper_wait(int pid)
151
{
152
int ret, status;
153
int wflags = __WCLONE;
154
155
CATCH_EINTR(ret = waitpid(pid, &status, wflags));
156
if (ret < 0) {
157
printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, "
158
"errno = %d\n", pid, errno);
159
return -errno;
160
} else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
161
printk(UM_KERN_ERR "helper_wait : process %d exited with "
162
"status 0x%x\n", pid, status);
163
return -ECHILD;
164
} else
165
return 0;
166
}
167
168