root / hw / 9pfs / virtio-9p-proxy.c @ 1a9978a5
History | View | Annotate | Download (34.1 kB)
1 |
/*
|
---|---|
2 |
* Virtio 9p Proxy callback
|
3 |
*
|
4 |
* Copyright IBM, Corp. 2011
|
5 |
*
|
6 |
* Authors:
|
7 |
* M. Mohan Kumar <mohan@in.ibm.com>
|
8 |
*
|
9 |
* This work is licensed under the terms of the GNU GPL, version 2. See
|
10 |
* the COPYING file in the top-level directory.
|
11 |
*/
|
12 |
#include <sys/socket.h> |
13 |
#include <sys/un.h> |
14 |
#include "hw/virtio/virtio.h" |
15 |
#include "virtio-9p.h" |
16 |
#include "qemu/error-report.h" |
17 |
#include "fsdev/qemu-fsdev.h" |
18 |
#include "virtio-9p-proxy.h" |
19 |
|
20 |
typedef struct V9fsProxy { |
21 |
int sockfd;
|
22 |
QemuMutex mutex; |
23 |
struct iovec in_iovec;
|
24 |
struct iovec out_iovec;
|
25 |
} V9fsProxy; |
26 |
|
27 |
/*
|
28 |
* Return received file descriptor on success in *status.
|
29 |
* errno is also returned on *status (which will be < 0)
|
30 |
* return < 0 on transport error.
|
31 |
*/
|
32 |
static int v9fs_receivefd(int sockfd, int *status) |
33 |
{ |
34 |
struct iovec iov;
|
35 |
struct msghdr msg;
|
36 |
struct cmsghdr *cmsg;
|
37 |
int retval, data, fd;
|
38 |
union MsgControl msg_control;
|
39 |
|
40 |
iov.iov_base = &data; |
41 |
iov.iov_len = sizeof(data);
|
42 |
|
43 |
memset(&msg, 0, sizeof(msg)); |
44 |
msg.msg_iov = &iov; |
45 |
msg.msg_iovlen = 1;
|
46 |
msg.msg_control = &msg_control; |
47 |
msg.msg_controllen = sizeof(msg_control);
|
48 |
|
49 |
do {
|
50 |
retval = recvmsg(sockfd, &msg, 0);
|
51 |
} while (retval < 0 && errno == EINTR); |
52 |
if (retval <= 0) { |
53 |
return retval;
|
54 |
} |
55 |
/*
|
56 |
* data is set to V9FS_FD_VALID, if ancillary data is sent. If this
|
57 |
* request doesn't need ancillary data (fd) or an error occurred,
|
58 |
* data is set to negative errno value.
|
59 |
*/
|
60 |
if (data != V9FS_FD_VALID) {
|
61 |
*status = data; |
62 |
return 0; |
63 |
} |
64 |
/*
|
65 |
* File descriptor (fd) is sent in the ancillary data. Check if we
|
66 |
* indeed received it. One of the reasons to fail to receive it is if
|
67 |
* we exceeded the maximum number of file descriptors!
|
68 |
*/
|
69 |
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
70 |
if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || |
71 |
cmsg->cmsg_level != SOL_SOCKET || |
72 |
cmsg->cmsg_type != SCM_RIGHTS) { |
73 |
continue;
|
74 |
} |
75 |
fd = *((int *)CMSG_DATA(cmsg));
|
76 |
*status = fd; |
77 |
return 0; |
78 |
} |
79 |
*status = -ENFILE; /* Ancillary data sent but not received */
|
80 |
return 0; |
81 |
} |
82 |
|
83 |
static ssize_t socket_read(int sockfd, void *buff, size_t size) |
84 |
{ |
85 |
ssize_t retval, total = 0;
|
86 |
|
87 |
while (size) {
|
88 |
retval = read(sockfd, buff, size); |
89 |
if (retval == 0) { |
90 |
return -EIO;
|
91 |
} |
92 |
if (retval < 0) { |
93 |
if (errno == EINTR) {
|
94 |
continue;
|
95 |
} |
96 |
return -errno;
|
97 |
} |
98 |
size -= retval; |
99 |
buff += retval; |
100 |
total += retval; |
101 |
} |
102 |
return total;
|
103 |
} |
104 |
|
105 |
/* Converts proxy_statfs to VFS statfs structure */
|
106 |
static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs) |
107 |
{ |
108 |
memset(stfs, 0, sizeof(*stfs)); |
109 |
stfs->f_type = prstfs->f_type; |
110 |
stfs->f_bsize = prstfs->f_bsize; |
111 |
stfs->f_blocks = prstfs->f_blocks; |
112 |
stfs->f_bfree = prstfs->f_bfree; |
113 |
stfs->f_bavail = prstfs->f_bavail; |
114 |
stfs->f_files = prstfs->f_files; |
115 |
stfs->f_ffree = prstfs->f_ffree; |
116 |
stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU; |
117 |
stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU; |
118 |
stfs->f_namelen = prstfs->f_namelen; |
119 |
stfs->f_frsize = prstfs->f_frsize; |
120 |
} |
121 |
|
122 |
/* Converts proxy_stat structure to VFS stat structure */
|
123 |
static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat) |
124 |
{ |
125 |
memset(stbuf, 0, sizeof(*stbuf)); |
126 |
stbuf->st_dev = prstat->st_dev; |
127 |
stbuf->st_ino = prstat->st_ino; |
128 |
stbuf->st_nlink = prstat->st_nlink; |
129 |
stbuf->st_mode = prstat->st_mode; |
130 |
stbuf->st_uid = prstat->st_uid; |
131 |
stbuf->st_gid = prstat->st_gid; |
132 |
stbuf->st_rdev = prstat->st_rdev; |
133 |
stbuf->st_size = prstat->st_size; |
134 |
stbuf->st_blksize = prstat->st_blksize; |
135 |
stbuf->st_blocks = prstat->st_blocks; |
136 |
stbuf->st_atim.tv_sec = prstat->st_atim_sec; |
137 |
stbuf->st_atim.tv_nsec = prstat->st_atim_nsec; |
138 |
stbuf->st_mtime = prstat->st_mtim_sec; |
139 |
stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec; |
140 |
stbuf->st_ctime = prstat->st_ctim_sec; |
141 |
stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec; |
142 |
} |
143 |
|
144 |
/*
|
145 |
* Response contains two parts
|
146 |
* {header, data}
|
147 |
* header.type == T_ERROR, data -> -errno
|
148 |
* header.type == T_SUCCESS, data -> response
|
149 |
* size of errno/response is given by header.size
|
150 |
* returns < 0, on transport error. response is
|
151 |
* valid only if status >= 0.
|
152 |
*/
|
153 |
static int v9fs_receive_response(V9fsProxy *proxy, int type, |
154 |
int *status, void *response) |
155 |
{ |
156 |
int retval;
|
157 |
ProxyHeader header; |
158 |
struct iovec *reply = &proxy->in_iovec;
|
159 |
|
160 |
*status = 0;
|
161 |
reply->iov_len = 0;
|
162 |
retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); |
163 |
if (retval < 0) { |
164 |
return retval;
|
165 |
} |
166 |
reply->iov_len = PROXY_HDR_SZ; |
167 |
proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); |
168 |
/*
|
169 |
* if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
|
170 |
* return -ENOBUFS
|
171 |
*/
|
172 |
if (header.size > PROXY_MAX_IO_SZ) {
|
173 |
int count;
|
174 |
while (header.size > 0) { |
175 |
count = MIN(PROXY_MAX_IO_SZ, header.size); |
176 |
count = socket_read(proxy->sockfd, reply->iov_base, count); |
177 |
if (count < 0) { |
178 |
return count;
|
179 |
} |
180 |
header.size -= count; |
181 |
} |
182 |
*status = -ENOBUFS; |
183 |
return 0; |
184 |
} |
185 |
|
186 |
retval = socket_read(proxy->sockfd, |
187 |
reply->iov_base + PROXY_HDR_SZ, header.size); |
188 |
if (retval < 0) { |
189 |
return retval;
|
190 |
} |
191 |
reply->iov_len += header.size; |
192 |
/* there was an error during processing request */
|
193 |
if (header.type == T_ERROR) {
|
194 |
int ret;
|
195 |
ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
|
196 |
if (ret < 0) { |
197 |
*status = ret; |
198 |
} |
199 |
return 0; |
200 |
} |
201 |
|
202 |
switch (type) {
|
203 |
case T_LSTAT: {
|
204 |
ProxyStat prstat; |
205 |
retval = proxy_unmarshal(reply, PROXY_HDR_SZ, |
206 |
"qqqdddqqqqqqqqqq", &prstat.st_dev,
|
207 |
&prstat.st_ino, &prstat.st_nlink, |
208 |
&prstat.st_mode, &prstat.st_uid, |
209 |
&prstat.st_gid, &prstat.st_rdev, |
210 |
&prstat.st_size, &prstat.st_blksize, |
211 |
&prstat.st_blocks, |
212 |
&prstat.st_atim_sec, &prstat.st_atim_nsec, |
213 |
&prstat.st_mtim_sec, &prstat.st_mtim_nsec, |
214 |
&prstat.st_ctim_sec, &prstat.st_ctim_nsec); |
215 |
prstat_to_stat(response, &prstat); |
216 |
break;
|
217 |
} |
218 |
case T_STATFS: {
|
219 |
ProxyStatFS prstfs; |
220 |
retval = proxy_unmarshal(reply, PROXY_HDR_SZ, |
221 |
"qqqqqqqqqqq", &prstfs.f_type,
|
222 |
&prstfs.f_bsize, &prstfs.f_blocks, |
223 |
&prstfs.f_bfree, &prstfs.f_bavail, |
224 |
&prstfs.f_files, &prstfs.f_ffree, |
225 |
&prstfs.f_fsid[0], &prstfs.f_fsid[1], |
226 |
&prstfs.f_namelen, &prstfs.f_frsize); |
227 |
prstatfs_to_statfs(response, &prstfs); |
228 |
break;
|
229 |
} |
230 |
case T_READLINK: {
|
231 |
V9fsString target; |
232 |
v9fs_string_init(&target); |
233 |
retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target);
|
234 |
strcpy(response, target.data); |
235 |
v9fs_string_free(&target); |
236 |
break;
|
237 |
} |
238 |
case T_LGETXATTR:
|
239 |
case T_LLISTXATTR: {
|
240 |
V9fsString xattr; |
241 |
v9fs_string_init(&xattr); |
242 |
retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr);
|
243 |
memcpy(response, xattr.data, xattr.size); |
244 |
v9fs_string_free(&xattr); |
245 |
break;
|
246 |
} |
247 |
case T_GETVERSION:
|
248 |
proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
|
249 |
break;
|
250 |
default:
|
251 |
return -1; |
252 |
} |
253 |
if (retval < 0) { |
254 |
*status = retval; |
255 |
} |
256 |
return 0; |
257 |
} |
258 |
|
259 |
/*
|
260 |
* return < 0 on transport error.
|
261 |
* *status is valid only if return >= 0
|
262 |
*/
|
263 |
static int v9fs_receive_status(V9fsProxy *proxy, |
264 |
struct iovec *reply, int *status) |
265 |
{ |
266 |
int retval;
|
267 |
ProxyHeader header; |
268 |
|
269 |
*status = 0;
|
270 |
reply->iov_len = 0;
|
271 |
retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); |
272 |
if (retval < 0) { |
273 |
return retval;
|
274 |
} |
275 |
reply->iov_len = PROXY_HDR_SZ; |
276 |
proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); |
277 |
if (header.size != sizeof(int)) { |
278 |
*status = -ENOBUFS; |
279 |
return 0; |
280 |
} |
281 |
retval = socket_read(proxy->sockfd, |
282 |
reply->iov_base + PROXY_HDR_SZ, header.size); |
283 |
if (retval < 0) { |
284 |
return retval;
|
285 |
} |
286 |
reply->iov_len += header.size; |
287 |
proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
|
288 |
return 0; |
289 |
} |
290 |
|
291 |
/*
|
292 |
* Proxy->header and proxy->request written to socket by QEMU process.
|
293 |
* This request read by proxy helper process
|
294 |
* returns 0 on success and -errno on error
|
295 |
*/
|
296 |
static int v9fs_request(V9fsProxy *proxy, int type, |
297 |
void *response, const char *fmt, ...) |
298 |
{ |
299 |
dev_t rdev; |
300 |
va_list ap; |
301 |
int size = 0; |
302 |
int retval = 0; |
303 |
uint64_t offset; |
304 |
ProxyHeader header = { 0, 0}; |
305 |
struct timespec spec[2]; |
306 |
int flags, mode, uid, gid;
|
307 |
V9fsString *name, *value; |
308 |
V9fsString *path, *oldpath; |
309 |
struct iovec *iovec = NULL, *reply = NULL; |
310 |
|
311 |
qemu_mutex_lock(&proxy->mutex); |
312 |
|
313 |
if (proxy->sockfd == -1) { |
314 |
retval = -EIO; |
315 |
goto err_out;
|
316 |
} |
317 |
iovec = &proxy->out_iovec; |
318 |
reply = &proxy->in_iovec; |
319 |
va_start(ap, fmt); |
320 |
switch (type) {
|
321 |
case T_OPEN:
|
322 |
path = va_arg(ap, V9fsString *); |
323 |
flags = va_arg(ap, int);
|
324 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags);
|
325 |
if (retval > 0) { |
326 |
header.size = retval; |
327 |
header.type = T_OPEN; |
328 |
} |
329 |
break;
|
330 |
case T_CREATE:
|
331 |
path = va_arg(ap, V9fsString *); |
332 |
flags = va_arg(ap, int);
|
333 |
mode = va_arg(ap, int);
|
334 |
uid = va_arg(ap, int);
|
335 |
gid = va_arg(ap, int);
|
336 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path,
|
337 |
flags, mode, uid, gid); |
338 |
if (retval > 0) { |
339 |
header.size = retval; |
340 |
header.type = T_CREATE; |
341 |
} |
342 |
break;
|
343 |
case T_MKNOD:
|
344 |
path = va_arg(ap, V9fsString *); |
345 |
mode = va_arg(ap, int);
|
346 |
rdev = va_arg(ap, long int); |
347 |
uid = va_arg(ap, int);
|
348 |
gid = va_arg(ap, int);
|
349 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq",
|
350 |
uid, gid, path, mode, rdev); |
351 |
if (retval > 0) { |
352 |
header.size = retval; |
353 |
header.type = T_MKNOD; |
354 |
} |
355 |
break;
|
356 |
case T_MKDIR:
|
357 |
path = va_arg(ap, V9fsString *); |
358 |
mode = va_arg(ap, int);
|
359 |
uid = va_arg(ap, int);
|
360 |
gid = va_arg(ap, int);
|
361 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd",
|
362 |
uid, gid, path, mode); |
363 |
if (retval > 0) { |
364 |
header.size = retval; |
365 |
header.type = T_MKDIR; |
366 |
} |
367 |
break;
|
368 |
case T_SYMLINK:
|
369 |
oldpath = va_arg(ap, V9fsString *); |
370 |
path = va_arg(ap, V9fsString *); |
371 |
uid = va_arg(ap, int);
|
372 |
gid = va_arg(ap, int);
|
373 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss",
|
374 |
uid, gid, oldpath, path); |
375 |
if (retval > 0) { |
376 |
header.size = retval; |
377 |
header.type = T_SYMLINK; |
378 |
} |
379 |
break;
|
380 |
case T_LINK:
|
381 |
oldpath = va_arg(ap, V9fsString *); |
382 |
path = va_arg(ap, V9fsString *); |
383 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss",
|
384 |
oldpath, path); |
385 |
if (retval > 0) { |
386 |
header.size = retval; |
387 |
header.type = T_LINK; |
388 |
} |
389 |
break;
|
390 |
case T_LSTAT:
|
391 |
path = va_arg(ap, V9fsString *); |
392 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
|
393 |
if (retval > 0) { |
394 |
header.size = retval; |
395 |
header.type = T_LSTAT; |
396 |
} |
397 |
break;
|
398 |
case T_READLINK:
|
399 |
path = va_arg(ap, V9fsString *); |
400 |
size = va_arg(ap, int);
|
401 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size);
|
402 |
if (retval > 0) { |
403 |
header.size = retval; |
404 |
header.type = T_READLINK; |
405 |
} |
406 |
break;
|
407 |
case T_STATFS:
|
408 |
path = va_arg(ap, V9fsString *); |
409 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
|
410 |
if (retval > 0) { |
411 |
header.size = retval; |
412 |
header.type = T_STATFS; |
413 |
} |
414 |
break;
|
415 |
case T_CHMOD:
|
416 |
path = va_arg(ap, V9fsString *); |
417 |
mode = va_arg(ap, int);
|
418 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode);
|
419 |
if (retval > 0) { |
420 |
header.size = retval; |
421 |
header.type = T_CHMOD; |
422 |
} |
423 |
break;
|
424 |
case T_CHOWN:
|
425 |
path = va_arg(ap, V9fsString *); |
426 |
uid = va_arg(ap, int);
|
427 |
gid = va_arg(ap, int);
|
428 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid);
|
429 |
if (retval > 0) { |
430 |
header.size = retval; |
431 |
header.type = T_CHOWN; |
432 |
} |
433 |
break;
|
434 |
case T_TRUNCATE:
|
435 |
path = va_arg(ap, V9fsString *); |
436 |
offset = va_arg(ap, uint64_t); |
437 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset);
|
438 |
if (retval > 0) { |
439 |
header.size = retval; |
440 |
header.type = T_TRUNCATE; |
441 |
} |
442 |
break;
|
443 |
case T_UTIME:
|
444 |
path = va_arg(ap, V9fsString *); |
445 |
spec[0].tv_sec = va_arg(ap, long); |
446 |
spec[0].tv_nsec = va_arg(ap, long); |
447 |
spec[1].tv_sec = va_arg(ap, long); |
448 |
spec[1].tv_nsec = va_arg(ap, long); |
449 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path,
|
450 |
spec[0].tv_sec, spec[1].tv_nsec, |
451 |
spec[1].tv_sec, spec[1].tv_nsec); |
452 |
if (retval > 0) { |
453 |
header.size = retval; |
454 |
header.type = T_UTIME; |
455 |
} |
456 |
break;
|
457 |
case T_RENAME:
|
458 |
oldpath = va_arg(ap, V9fsString *); |
459 |
path = va_arg(ap, V9fsString *); |
460 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path);
|
461 |
if (retval > 0) { |
462 |
header.size = retval; |
463 |
header.type = T_RENAME; |
464 |
} |
465 |
break;
|
466 |
case T_REMOVE:
|
467 |
path = va_arg(ap, V9fsString *); |
468 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
|
469 |
if (retval > 0) { |
470 |
header.size = retval; |
471 |
header.type = T_REMOVE; |
472 |
} |
473 |
break;
|
474 |
case T_LGETXATTR:
|
475 |
size = va_arg(ap, int);
|
476 |
path = va_arg(ap, V9fsString *); |
477 |
name = va_arg(ap, V9fsString *); |
478 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, |
479 |
"dss", size, path, name);
|
480 |
if (retval > 0) { |
481 |
header.size = retval; |
482 |
header.type = T_LGETXATTR; |
483 |
} |
484 |
break;
|
485 |
case T_LLISTXATTR:
|
486 |
size = va_arg(ap, int);
|
487 |
path = va_arg(ap, V9fsString *); |
488 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path);
|
489 |
if (retval > 0) { |
490 |
header.size = retval; |
491 |
header.type = T_LLISTXATTR; |
492 |
} |
493 |
break;
|
494 |
case T_LSETXATTR:
|
495 |
path = va_arg(ap, V9fsString *); |
496 |
name = va_arg(ap, V9fsString *); |
497 |
value = va_arg(ap, V9fsString *); |
498 |
size = va_arg(ap, int);
|
499 |
flags = va_arg(ap, int);
|
500 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd",
|
501 |
path, name, value, size, flags); |
502 |
if (retval > 0) { |
503 |
header.size = retval; |
504 |
header.type = T_LSETXATTR; |
505 |
} |
506 |
break;
|
507 |
case T_LREMOVEXATTR:
|
508 |
path = va_arg(ap, V9fsString *); |
509 |
name = va_arg(ap, V9fsString *); |
510 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name);
|
511 |
if (retval > 0) { |
512 |
header.size = retval; |
513 |
header.type = T_LREMOVEXATTR; |
514 |
} |
515 |
break;
|
516 |
case T_GETVERSION:
|
517 |
path = va_arg(ap, V9fsString *); |
518 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
|
519 |
if (retval > 0) { |
520 |
header.size = retval; |
521 |
header.type = T_GETVERSION; |
522 |
} |
523 |
break;
|
524 |
default:
|
525 |
error_report("Invalid type %d", type);
|
526 |
retval = -EINVAL; |
527 |
break;
|
528 |
} |
529 |
va_end(ap); |
530 |
|
531 |
if (retval < 0) { |
532 |
goto err_out;
|
533 |
} |
534 |
|
535 |
/* marshal the header details */
|
536 |
proxy_marshal(iovec, 0, "dd", header.type, header.size); |
537 |
header.size += PROXY_HDR_SZ; |
538 |
|
539 |
retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size); |
540 |
if (retval != header.size) {
|
541 |
goto close_error;
|
542 |
} |
543 |
|
544 |
switch (type) {
|
545 |
case T_OPEN:
|
546 |
case T_CREATE:
|
547 |
/*
|
548 |
* A file descriptor is returned as response for
|
549 |
* T_OPEN,T_CREATE on success
|
550 |
*/
|
551 |
if (v9fs_receivefd(proxy->sockfd, &retval) < 0) { |
552 |
goto close_error;
|
553 |
} |
554 |
break;
|
555 |
case T_MKNOD:
|
556 |
case T_MKDIR:
|
557 |
case T_SYMLINK:
|
558 |
case T_LINK:
|
559 |
case T_CHMOD:
|
560 |
case T_CHOWN:
|
561 |
case T_RENAME:
|
562 |
case T_TRUNCATE:
|
563 |
case T_UTIME:
|
564 |
case T_REMOVE:
|
565 |
case T_LSETXATTR:
|
566 |
case T_LREMOVEXATTR:
|
567 |
if (v9fs_receive_status(proxy, reply, &retval) < 0) { |
568 |
goto close_error;
|
569 |
} |
570 |
break;
|
571 |
case T_LSTAT:
|
572 |
case T_READLINK:
|
573 |
case T_STATFS:
|
574 |
case T_GETVERSION:
|
575 |
if (v9fs_receive_response(proxy, type, &retval, response) < 0) { |
576 |
goto close_error;
|
577 |
} |
578 |
break;
|
579 |
case T_LGETXATTR:
|
580 |
case T_LLISTXATTR:
|
581 |
if (!size) {
|
582 |
if (v9fs_receive_status(proxy, reply, &retval) < 0) { |
583 |
goto close_error;
|
584 |
} |
585 |
} else {
|
586 |
if (v9fs_receive_response(proxy, type, &retval, response) < 0) { |
587 |
goto close_error;
|
588 |
} |
589 |
} |
590 |
break;
|
591 |
} |
592 |
|
593 |
err_out:
|
594 |
qemu_mutex_unlock(&proxy->mutex); |
595 |
return retval;
|
596 |
|
597 |
close_error:
|
598 |
close(proxy->sockfd); |
599 |
proxy->sockfd = -1;
|
600 |
qemu_mutex_unlock(&proxy->mutex); |
601 |
return -EIO;
|
602 |
} |
603 |
|
604 |
static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) |
605 |
{ |
606 |
int retval;
|
607 |
retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path);
|
608 |
if (retval < 0) { |
609 |
errno = -retval; |
610 |
return -1; |
611 |
} |
612 |
return retval;
|
613 |
} |
614 |
|
615 |
static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
616 |
char *buf, size_t bufsz)
|
617 |
{ |
618 |
int retval;
|
619 |
retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd",
|
620 |
fs_path, bufsz); |
621 |
if (retval < 0) { |
622 |
errno = -retval; |
623 |
return -1; |
624 |
} |
625 |
return strlen(buf);
|
626 |
} |
627 |
|
628 |
static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs) |
629 |
{ |
630 |
return close(fs->fd);
|
631 |
} |
632 |
|
633 |
static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs) |
634 |
{ |
635 |
return closedir(fs->dir);
|
636 |
} |
637 |
|
638 |
static int proxy_open(FsContext *ctx, V9fsPath *fs_path, |
639 |
int flags, V9fsFidOpenState *fs)
|
640 |
{ |
641 |
fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, flags); |
642 |
if (fs->fd < 0) { |
643 |
errno = -fs->fd; |
644 |
fs->fd = -1;
|
645 |
} |
646 |
return fs->fd;
|
647 |
} |
648 |
|
649 |
static int proxy_opendir(FsContext *ctx, |
650 |
V9fsPath *fs_path, V9fsFidOpenState *fs) |
651 |
{ |
652 |
int serrno, fd;
|
653 |
|
654 |
fs->dir = NULL;
|
655 |
fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY); |
656 |
if (fd < 0) { |
657 |
errno = -fd; |
658 |
return -1; |
659 |
} |
660 |
fs->dir = fdopendir(fd); |
661 |
if (!fs->dir) {
|
662 |
serrno = errno; |
663 |
close(fd); |
664 |
errno = serrno; |
665 |
return -1; |
666 |
} |
667 |
return 0; |
668 |
} |
669 |
|
670 |
static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) |
671 |
{ |
672 |
return rewinddir(fs->dir);
|
673 |
} |
674 |
|
675 |
static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
|
676 |
{ |
677 |
return telldir(fs->dir);
|
678 |
} |
679 |
|
680 |
static int proxy_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, |
681 |
struct dirent *entry,
|
682 |
struct dirent **result)
|
683 |
{ |
684 |
return readdir_r(fs->dir, entry, result);
|
685 |
} |
686 |
|
687 |
static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) |
688 |
{ |
689 |
return seekdir(fs->dir, off);
|
690 |
} |
691 |
|
692 |
static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
|
693 |
const struct iovec *iov, |
694 |
int iovcnt, off_t offset)
|
695 |
{ |
696 |
#ifdef CONFIG_PREADV
|
697 |
return preadv(fs->fd, iov, iovcnt, offset);
|
698 |
#else
|
699 |
int err = lseek(fs->fd, offset, SEEK_SET);
|
700 |
if (err == -1) { |
701 |
return err;
|
702 |
} else {
|
703 |
return readv(fs->fd, iov, iovcnt);
|
704 |
} |
705 |
#endif
|
706 |
} |
707 |
|
708 |
static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
|
709 |
const struct iovec *iov, |
710 |
int iovcnt, off_t offset)
|
711 |
{ |
712 |
ssize_t ret; |
713 |
|
714 |
#ifdef CONFIG_PREADV
|
715 |
ret = pwritev(fs->fd, iov, iovcnt, offset); |
716 |
#else
|
717 |
int err = lseek(fs->fd, offset, SEEK_SET);
|
718 |
if (err == -1) { |
719 |
return err;
|
720 |
} else {
|
721 |
ret = writev(fs->fd, iov, iovcnt); |
722 |
} |
723 |
#endif
|
724 |
#ifdef CONFIG_SYNC_FILE_RANGE
|
725 |
if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { |
726 |
/*
|
727 |
* Initiate a writeback. This is not a data integrity sync.
|
728 |
* We want to ensure that we don't leave dirty pages in the cache
|
729 |
* after write when writeout=immediate is sepcified.
|
730 |
*/
|
731 |
sync_file_range(fs->fd, offset, ret, |
732 |
SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); |
733 |
} |
734 |
#endif
|
735 |
return ret;
|
736 |
} |
737 |
|
738 |
static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) |
739 |
{ |
740 |
int retval;
|
741 |
retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, "sd", |
742 |
fs_path, credp->fc_mode); |
743 |
if (retval < 0) { |
744 |
errno = -retval; |
745 |
} |
746 |
return retval;
|
747 |
} |
748 |
|
749 |
static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path, |
750 |
const char *name, FsCred *credp) |
751 |
{ |
752 |
int retval;
|
753 |
V9fsString fullname; |
754 |
|
755 |
v9fs_string_init(&fullname); |
756 |
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
757 |
|
758 |
retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd", |
759 |
&fullname, credp->fc_mode, credp->fc_rdev, |
760 |
credp->fc_uid, credp->fc_gid); |
761 |
v9fs_string_free(&fullname); |
762 |
if (retval < 0) { |
763 |
errno = -retval; |
764 |
retval = -1;
|
765 |
} |
766 |
return retval;
|
767 |
} |
768 |
|
769 |
static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, |
770 |
const char *name, FsCred *credp) |
771 |
{ |
772 |
int retval;
|
773 |
V9fsString fullname; |
774 |
|
775 |
v9fs_string_init(&fullname); |
776 |
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
777 |
|
778 |
retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname, |
779 |
credp->fc_mode, credp->fc_uid, credp->fc_gid); |
780 |
v9fs_string_free(&fullname); |
781 |
if (retval < 0) { |
782 |
errno = -retval; |
783 |
retval = -1;
|
784 |
} |
785 |
v9fs_string_free(&fullname); |
786 |
return retval;
|
787 |
} |
788 |
|
789 |
static int proxy_fstat(FsContext *fs_ctx, int fid_type, |
790 |
V9fsFidOpenState *fs, struct stat *stbuf)
|
791 |
{ |
792 |
int fd;
|
793 |
|
794 |
if (fid_type == P9_FID_DIR) {
|
795 |
fd = dirfd(fs->dir); |
796 |
} else {
|
797 |
fd = fs->fd; |
798 |
} |
799 |
return fstat(fd, stbuf);
|
800 |
} |
801 |
|
802 |
static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, |
803 |
int flags, FsCred *credp, V9fsFidOpenState *fs)
|
804 |
{ |
805 |
V9fsString fullname; |
806 |
|
807 |
v9fs_string_init(&fullname); |
808 |
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
809 |
|
810 |
fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd", |
811 |
&fullname, flags, credp->fc_mode, |
812 |
credp->fc_uid, credp->fc_gid); |
813 |
v9fs_string_free(&fullname); |
814 |
if (fs->fd < 0) { |
815 |
errno = -fs->fd; |
816 |
fs->fd = -1;
|
817 |
} |
818 |
return fs->fd;
|
819 |
} |
820 |
|
821 |
static int proxy_symlink(FsContext *fs_ctx, const char *oldpath, |
822 |
V9fsPath *dir_path, const char *name, FsCred *credp) |
823 |
{ |
824 |
int retval;
|
825 |
V9fsString fullname, target; |
826 |
|
827 |
v9fs_string_init(&fullname); |
828 |
v9fs_string_init(&target); |
829 |
|
830 |
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
831 |
v9fs_string_sprintf(&target, "%s", oldpath);
|
832 |
|
833 |
retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd", |
834 |
&target, &fullname, credp->fc_uid, credp->fc_gid); |
835 |
v9fs_string_free(&fullname); |
836 |
v9fs_string_free(&target); |
837 |
if (retval < 0) { |
838 |
errno = -retval; |
839 |
retval = -1;
|
840 |
} |
841 |
return retval;
|
842 |
} |
843 |
|
844 |
static int proxy_link(FsContext *ctx, V9fsPath *oldpath, |
845 |
V9fsPath *dirpath, const char *name) |
846 |
{ |
847 |
int retval;
|
848 |
V9fsString newpath; |
849 |
|
850 |
v9fs_string_init(&newpath); |
851 |
v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
|
852 |
|
853 |
retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath); |
854 |
v9fs_string_free(&newpath); |
855 |
if (retval < 0) { |
856 |
errno = -retval; |
857 |
retval = -1;
|
858 |
} |
859 |
return retval;
|
860 |
} |
861 |
|
862 |
static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) |
863 |
{ |
864 |
int retval;
|
865 |
|
866 |
retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, "sq", fs_path, size); |
867 |
if (retval < 0) { |
868 |
errno = -retval; |
869 |
return -1; |
870 |
} |
871 |
return 0; |
872 |
} |
873 |
|
874 |
static int proxy_rename(FsContext *ctx, const char *oldpath, |
875 |
const char *newpath) |
876 |
{ |
877 |
int retval;
|
878 |
V9fsString oldname, newname; |
879 |
|
880 |
v9fs_string_init(&oldname); |
881 |
v9fs_string_init(&newname); |
882 |
|
883 |
v9fs_string_sprintf(&oldname, "%s", oldpath);
|
884 |
v9fs_string_sprintf(&newname, "%s", newpath);
|
885 |
retval = v9fs_request(ctx->private, T_RENAME, NULL, "ss", |
886 |
&oldname, &newname); |
887 |
v9fs_string_free(&oldname); |
888 |
v9fs_string_free(&newname); |
889 |
if (retval < 0) { |
890 |
errno = -retval; |
891 |
} |
892 |
return retval;
|
893 |
} |
894 |
|
895 |
static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) |
896 |
{ |
897 |
int retval;
|
898 |
retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, "sdd", |
899 |
fs_path, credp->fc_uid, credp->fc_gid); |
900 |
if (retval < 0) { |
901 |
errno = -retval; |
902 |
} |
903 |
return retval;
|
904 |
} |
905 |
|
906 |
static int proxy_utimensat(FsContext *s, V9fsPath *fs_path, |
907 |
const struct timespec *buf) |
908 |
{ |
909 |
int retval;
|
910 |
retval = v9fs_request(s->private, T_UTIME, NULL, "sqqqq", |
911 |
fs_path, |
912 |
buf[0].tv_sec, buf[0].tv_nsec, |
913 |
buf[1].tv_sec, buf[1].tv_nsec); |
914 |
if (retval < 0) { |
915 |
errno = -retval; |
916 |
} |
917 |
return retval;
|
918 |
} |
919 |
|
920 |
static int proxy_remove(FsContext *ctx, const char *path) |
921 |
{ |
922 |
int retval;
|
923 |
V9fsString name; |
924 |
v9fs_string_init(&name); |
925 |
v9fs_string_sprintf(&name, "%s", path);
|
926 |
retval = v9fs_request(ctx->private, T_REMOVE, NULL, "s", &name); |
927 |
v9fs_string_free(&name); |
928 |
if (retval < 0) { |
929 |
errno = -retval; |
930 |
} |
931 |
return retval;
|
932 |
} |
933 |
|
934 |
static int proxy_fsync(FsContext *ctx, int fid_type, |
935 |
V9fsFidOpenState *fs, int datasync)
|
936 |
{ |
937 |
int fd;
|
938 |
|
939 |
if (fid_type == P9_FID_DIR) {
|
940 |
fd = dirfd(fs->dir); |
941 |
} else {
|
942 |
fd = fs->fd; |
943 |
} |
944 |
|
945 |
if (datasync) {
|
946 |
return qemu_fdatasync(fd);
|
947 |
} else {
|
948 |
return fsync(fd);
|
949 |
} |
950 |
} |
951 |
|
952 |
static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) |
953 |
{ |
954 |
int retval;
|
955 |
retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path);
|
956 |
if (retval < 0) { |
957 |
errno = -retval; |
958 |
return -1; |
959 |
} |
960 |
return retval;
|
961 |
} |
962 |
|
963 |
static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
|
964 |
const char *name, void *value, size_t size) |
965 |
{ |
966 |
int retval;
|
967 |
V9fsString xname; |
968 |
|
969 |
v9fs_string_init(&xname); |
970 |
v9fs_string_sprintf(&xname, "%s", name);
|
971 |
retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size,
|
972 |
fs_path, &xname); |
973 |
v9fs_string_free(&xname); |
974 |
if (retval < 0) { |
975 |
errno = -retval; |
976 |
} |
977 |
return retval;
|
978 |
} |
979 |
|
980 |
static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
|
981 |
void *value, size_t size)
|
982 |
{ |
983 |
int retval;
|
984 |
retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size,
|
985 |
fs_path); |
986 |
if (retval < 0) { |
987 |
errno = -retval; |
988 |
} |
989 |
return retval;
|
990 |
} |
991 |
|
992 |
static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, |
993 |
void *value, size_t size, int flags) |
994 |
{ |
995 |
int retval;
|
996 |
V9fsString xname, xvalue; |
997 |
|
998 |
v9fs_string_init(&xname); |
999 |
v9fs_string_sprintf(&xname, "%s", name);
|
1000 |
|
1001 |
v9fs_string_init(&xvalue); |
1002 |
xvalue.size = size; |
1003 |
xvalue.data = g_malloc(size); |
1004 |
memcpy(xvalue.data, value, size); |
1005 |
|
1006 |
retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd",
|
1007 |
fs_path, &xname, &xvalue, size, flags); |
1008 |
v9fs_string_free(&xname); |
1009 |
v9fs_string_free(&xvalue); |
1010 |
if (retval < 0) { |
1011 |
errno = -retval; |
1012 |
} |
1013 |
return retval;
|
1014 |
} |
1015 |
|
1016 |
static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path, |
1017 |
const char *name) |
1018 |
{ |
1019 |
int retval;
|
1020 |
V9fsString xname; |
1021 |
|
1022 |
v9fs_string_init(&xname); |
1023 |
v9fs_string_sprintf(&xname, "%s", name);
|
1024 |
retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss", |
1025 |
fs_path, &xname); |
1026 |
v9fs_string_free(&xname); |
1027 |
if (retval < 0) { |
1028 |
errno = -retval; |
1029 |
} |
1030 |
return retval;
|
1031 |
} |
1032 |
|
1033 |
static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path, |
1034 |
const char *name, V9fsPath *target) |
1035 |
{ |
1036 |
if (dir_path) {
|
1037 |
v9fs_string_sprintf((V9fsString *)target, "%s/%s",
|
1038 |
dir_path->data, name); |
1039 |
} else {
|
1040 |
v9fs_string_sprintf((V9fsString *)target, "%s", name);
|
1041 |
} |
1042 |
/* Bump the size for including terminating NULL */
|
1043 |
target->size++; |
1044 |
return 0; |
1045 |
} |
1046 |
|
1047 |
static int proxy_renameat(FsContext *ctx, V9fsPath *olddir, |
1048 |
const char *old_name, V9fsPath *newdir, |
1049 |
const char *new_name) |
1050 |
{ |
1051 |
int ret;
|
1052 |
V9fsString old_full_name, new_full_name; |
1053 |
|
1054 |
v9fs_string_init(&old_full_name); |
1055 |
v9fs_string_init(&new_full_name); |
1056 |
|
1057 |
v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
|
1058 |
v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
|
1059 |
|
1060 |
ret = proxy_rename(ctx, old_full_name.data, new_full_name.data); |
1061 |
v9fs_string_free(&old_full_name); |
1062 |
v9fs_string_free(&new_full_name); |
1063 |
return ret;
|
1064 |
} |
1065 |
|
1066 |
static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir, |
1067 |
const char *name, int flags) |
1068 |
{ |
1069 |
int ret;
|
1070 |
V9fsString fullname; |
1071 |
v9fs_string_init(&fullname); |
1072 |
|
1073 |
v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
|
1074 |
ret = proxy_remove(ctx, fullname.data); |
1075 |
v9fs_string_free(&fullname); |
1076 |
|
1077 |
return ret;
|
1078 |
} |
1079 |
|
1080 |
static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path, |
1081 |
mode_t st_mode, uint64_t *st_gen) |
1082 |
{ |
1083 |
int err;
|
1084 |
|
1085 |
/* Do not try to open special files like device nodes, fifos etc
|
1086 |
* we can get fd for regular files and directories only
|
1087 |
*/
|
1088 |
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
|
1089 |
errno = ENOTTY; |
1090 |
return -1; |
1091 |
} |
1092 |
err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path);
|
1093 |
if (err < 0) { |
1094 |
errno = -err; |
1095 |
err = -1;
|
1096 |
} |
1097 |
return err;
|
1098 |
} |
1099 |
|
1100 |
static int connect_namedsocket(const char *path) |
1101 |
{ |
1102 |
int sockfd, size;
|
1103 |
struct sockaddr_un helper;
|
1104 |
|
1105 |
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
1106 |
if (sockfd < 0) { |
1107 |
fprintf(stderr, "socket %s\n", strerror(errno));
|
1108 |
return -1; |
1109 |
} |
1110 |
strcpy(helper.sun_path, path); |
1111 |
helper.sun_family = AF_UNIX; |
1112 |
size = strlen(helper.sun_path) + sizeof(helper.sun_family);
|
1113 |
if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) { |
1114 |
fprintf(stderr, "socket error\n");
|
1115 |
return -1; |
1116 |
} |
1117 |
|
1118 |
/* remove the socket for security reasons */
|
1119 |
unlink(path); |
1120 |
return sockfd;
|
1121 |
} |
1122 |
|
1123 |
static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs) |
1124 |
{ |
1125 |
const char *socket = qemu_opt_get(opts, "socket"); |
1126 |
const char *sock_fd = qemu_opt_get(opts, "sock_fd"); |
1127 |
|
1128 |
if (!socket && !sock_fd) {
|
1129 |
fprintf(stderr, "socket and sock_fd none of the option specified\n");
|
1130 |
return -1; |
1131 |
} |
1132 |
if (socket && sock_fd) {
|
1133 |
fprintf(stderr, "Both socket and sock_fd options specified\n");
|
1134 |
return -1; |
1135 |
} |
1136 |
if (socket) {
|
1137 |
fs->path = g_strdup(socket); |
1138 |
fs->export_flags = V9FS_PROXY_SOCK_NAME; |
1139 |
} else {
|
1140 |
fs->path = g_strdup(sock_fd); |
1141 |
fs->export_flags = V9FS_PROXY_SOCK_FD; |
1142 |
} |
1143 |
return 0; |
1144 |
} |
1145 |
|
1146 |
static int proxy_init(FsContext *ctx) |
1147 |
{ |
1148 |
V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
|
1149 |
int sock_id;
|
1150 |
|
1151 |
if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
|
1152 |
sock_id = connect_namedsocket(ctx->fs_root); |
1153 |
} else {
|
1154 |
sock_id = atoi(ctx->fs_root); |
1155 |
if (sock_id < 0) { |
1156 |
fprintf(stderr, "socket descriptor not initialized\n");
|
1157 |
g_free(proxy); |
1158 |
return -1; |
1159 |
} |
1160 |
} |
1161 |
g_free(ctx->fs_root); |
1162 |
ctx->fs_root = NULL;
|
1163 |
|
1164 |
proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); |
1165 |
proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; |
1166 |
proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); |
1167 |
proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; |
1168 |
|
1169 |
ctx->private = proxy; |
1170 |
proxy->sockfd = sock_id; |
1171 |
qemu_mutex_init(&proxy->mutex); |
1172 |
|
1173 |
ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; |
1174 |
ctx->exops.get_st_gen = proxy_ioc_getversion; |
1175 |
return 0; |
1176 |
} |
1177 |
|
1178 |
FileOperations proxy_ops = { |
1179 |
.parse_opts = proxy_parse_opts, |
1180 |
.init = proxy_init, |
1181 |
.lstat = proxy_lstat, |
1182 |
.readlink = proxy_readlink, |
1183 |
.close = proxy_close, |
1184 |
.closedir = proxy_closedir, |
1185 |
.open = proxy_open, |
1186 |
.opendir = proxy_opendir, |
1187 |
.rewinddir = proxy_rewinddir, |
1188 |
.telldir = proxy_telldir, |
1189 |
.readdir_r = proxy_readdir_r, |
1190 |
.seekdir = proxy_seekdir, |
1191 |
.preadv = proxy_preadv, |
1192 |
.pwritev = proxy_pwritev, |
1193 |
.chmod = proxy_chmod, |
1194 |
.mknod = proxy_mknod, |
1195 |
.mkdir = proxy_mkdir, |
1196 |
.fstat = proxy_fstat, |
1197 |
.open2 = proxy_open2, |
1198 |
.symlink = proxy_symlink, |
1199 |
.link = proxy_link, |
1200 |
.truncate = proxy_truncate, |
1201 |
.rename = proxy_rename, |
1202 |
.chown = proxy_chown, |
1203 |
.utimensat = proxy_utimensat, |
1204 |
.remove = proxy_remove, |
1205 |
.fsync = proxy_fsync, |
1206 |
.statfs = proxy_statfs, |
1207 |
.lgetxattr = proxy_lgetxattr, |
1208 |
.llistxattr = proxy_llistxattr, |
1209 |
.lsetxattr = proxy_lsetxattr, |
1210 |
.lremovexattr = proxy_lremovexattr, |
1211 |
.name_to_path = proxy_name_to_path, |
1212 |
.renameat = proxy_renameat, |
1213 |
.unlinkat = proxy_unlinkat, |
1214 |
}; |