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