|
|
1.1 root 1: /*
2: * Virtio 9p Proxy callback
3: *
4: * Copyright IBM, Corp. 2011
5: *
6: * Authors:
7: * M. Mohan Kumar <[email protected]>
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] & 0xFFFFFFFFU;
116: stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.