4 * Copyright IBM, Corp. 2011
7 * M. Mohan Kumar <mohan@in.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
14 * Not so fast! You might want to read the 9p developer docs first:
15 * https://wiki.qemu.org/Documentation/9p
19 * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
20 * removed in a future version of QEMU!
23 #include "qemu/osdep.h"
24 #include <sys/socket.h>
27 #include "qapi/error.h"
28 #include "qemu/cutils.h"
29 #include "qemu/error-report.h"
30 #include "qemu/option.h"
31 #include "fsdev/qemu-fsdev.h"
34 typedef struct V9fsProxy
{
37 struct iovec in_iovec
;
38 struct iovec out_iovec
;
42 * Return received file descriptor on success in *status.
43 * errno is also returned on *status (which will be < 0)
44 * return < 0 on transport error.
46 static int v9fs_receivefd(int sockfd
, int *status
)
52 union MsgControl msg_control
;
55 iov
.iov_len
= sizeof(data
);
57 memset(&msg
, 0, sizeof(msg
));
60 msg
.msg_control
= &msg_control
;
61 msg
.msg_controllen
= sizeof(msg_control
);
64 retval
= recvmsg(sockfd
, &msg
, 0);
65 } while (retval
< 0 && errno
== EINTR
);
70 * data is set to V9FS_FD_VALID, if ancillary data is sent. If this
71 * request doesn't need ancillary data (fd) or an error occurred,
72 * data is set to negative errno value.
74 if (data
!= V9FS_FD_VALID
) {
79 * File descriptor (fd) is sent in the ancillary data. Check if we
80 * indeed received it. One of the reasons to fail to receive it is if
81 * we exceeded the maximum number of file descriptors!
83 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
84 if (cmsg
->cmsg_len
!= CMSG_LEN(sizeof(int)) ||
85 cmsg
->cmsg_level
!= SOL_SOCKET
||
86 cmsg
->cmsg_type
!= SCM_RIGHTS
) {
89 fd
= *((int *)CMSG_DATA(cmsg
));
93 *status
= -ENFILE
; /* Ancillary data sent but not received */
97 static ssize_t
socket_read(int sockfd
, void *buff
, size_t size
)
99 ssize_t retval
, total
= 0;
102 retval
= read(sockfd
, buff
, size
);
107 if (errno
== EINTR
) {
119 /* Converts proxy_statfs to VFS statfs structure */
120 static void prstatfs_to_statfs(struct statfs
*stfs
, ProxyStatFS
*prstfs
)
122 memset(stfs
, 0, sizeof(*stfs
));
123 stfs
->f_type
= prstfs
->f_type
;
124 stfs
->f_bsize
= prstfs
->f_bsize
;
125 stfs
->f_blocks
= prstfs
->f_blocks
;
126 stfs
->f_bfree
= prstfs
->f_bfree
;
127 stfs
->f_bavail
= prstfs
->f_bavail
;
128 stfs
->f_files
= prstfs
->f_files
;
129 stfs
->f_ffree
= prstfs
->f_ffree
;
131 /* f_namelen and f_frsize do not exist on Darwin */
132 stfs
->f_fsid
.val
[0] = prstfs
->f_fsid
[0] & 0xFFFFFFFFU
;
133 stfs
->f_fsid
.val
[1] = prstfs
->f_fsid
[1] >> 32 & 0xFFFFFFFFU
;
135 stfs
->f_fsid
.__val
[0] = prstfs
->f_fsid
[0] & 0xFFFFFFFFU
;
136 stfs
->f_fsid
.__val
[1] = prstfs
->f_fsid
[1] >> 32 & 0xFFFFFFFFU
;
137 stfs
->f_namelen
= prstfs
->f_namelen
;
138 stfs
->f_frsize
= prstfs
->f_frsize
;
142 /* Converts proxy_stat structure to VFS stat structure */
143 static void prstat_to_stat(struct stat
*stbuf
, ProxyStat
*prstat
)
145 memset(stbuf
, 0, sizeof(*stbuf
));
146 stbuf
->st_dev
= prstat
->st_dev
;
147 stbuf
->st_ino
= prstat
->st_ino
;
148 stbuf
->st_nlink
= prstat
->st_nlink
;
149 stbuf
->st_mode
= prstat
->st_mode
;
150 stbuf
->st_uid
= prstat
->st_uid
;
151 stbuf
->st_gid
= prstat
->st_gid
;
152 stbuf
->st_rdev
= prstat
->st_rdev
;
153 stbuf
->st_size
= prstat
->st_size
;
154 stbuf
->st_blksize
= prstat
->st_blksize
;
155 stbuf
->st_blocks
= prstat
->st_blocks
;
156 stbuf
->st_atime
= prstat
->st_atim_sec
;
157 stbuf
->st_mtime
= prstat
->st_mtim_sec
;
158 stbuf
->st_ctime
= prstat
->st_ctim_sec
;
160 stbuf
->st_atimespec
.tv_sec
= prstat
->st_atim_sec
;
161 stbuf
->st_mtimespec
.tv_sec
= prstat
->st_mtim_sec
;
162 stbuf
->st_ctimespec
.tv_sec
= prstat
->st_ctim_sec
;
163 stbuf
->st_atimespec
.tv_nsec
= prstat
->st_atim_nsec
;
164 stbuf
->st_mtimespec
.tv_nsec
= prstat
->st_mtim_nsec
;
165 stbuf
->st_ctimespec
.tv_nsec
= prstat
->st_ctim_nsec
;
167 stbuf
->st_atim
.tv_sec
= prstat
->st_atim_sec
;
168 stbuf
->st_mtim
.tv_sec
= prstat
->st_mtim_sec
;
169 stbuf
->st_ctim
.tv_sec
= prstat
->st_ctim_sec
;
170 stbuf
->st_atim
.tv_nsec
= prstat
->st_atim_nsec
;
171 stbuf
->st_mtim
.tv_nsec
= prstat
->st_mtim_nsec
;
172 stbuf
->st_ctim
.tv_nsec
= prstat
->st_ctim_nsec
;
177 * Response contains two parts
179 * header.type == T_ERROR, data -> -errno
180 * header.type == T_SUCCESS, data -> response
181 * size of errno/response is given by header.size
182 * returns < 0, on transport error. response is
183 * valid only if status >= 0.
185 static int v9fs_receive_response(V9fsProxy
*proxy
, int type
,
186 int *status
, void *response
)
190 struct iovec
*reply
= &proxy
->in_iovec
;
194 retval
= socket_read(proxy
->sockfd
, reply
->iov_base
, PROXY_HDR_SZ
);
198 reply
->iov_len
= PROXY_HDR_SZ
;
199 retval
= proxy_unmarshal(reply
, 0, "dd", &header
.type
, &header
.size
);
200 assert(retval
== 4 * 2);
202 * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
205 if (header
.size
> PROXY_MAX_IO_SZ
) {
207 while (header
.size
> 0) {
208 count
= MIN(PROXY_MAX_IO_SZ
, header
.size
);
209 count
= socket_read(proxy
->sockfd
, reply
->iov_base
, count
);
213 header
.size
-= count
;
219 retval
= socket_read(proxy
->sockfd
,
220 reply
->iov_base
+ PROXY_HDR_SZ
, header
.size
);
224 reply
->iov_len
+= header
.size
;
225 /* there was an error during processing request */
226 if (header
.type
== T_ERROR
) {
228 ret
= proxy_unmarshal(reply
, PROXY_HDR_SZ
, "d", status
);
236 retval
= proxy_unmarshal(reply
, PROXY_HDR_SZ
,
237 "qqqdddqqqqqqqqqq", &prstat
.st_dev
,
238 &prstat
.st_ino
, &prstat
.st_nlink
,
239 &prstat
.st_mode
, &prstat
.st_uid
,
240 &prstat
.st_gid
, &prstat
.st_rdev
,
241 &prstat
.st_size
, &prstat
.st_blksize
,
243 &prstat
.st_atim_sec
, &prstat
.st_atim_nsec
,
244 &prstat
.st_mtim_sec
, &prstat
.st_mtim_nsec
,
245 &prstat
.st_ctim_sec
, &prstat
.st_ctim_nsec
);
246 assert(retval
== 8 * 3 + 4 * 3 + 8 * 10);
247 prstat_to_stat(response
, &prstat
);
252 retval
= proxy_unmarshal(reply
, PROXY_HDR_SZ
,
253 "qqqqqqqqqqq", &prstfs
.f_type
,
254 &prstfs
.f_bsize
, &prstfs
.f_blocks
,
255 &prstfs
.f_bfree
, &prstfs
.f_bavail
,
256 &prstfs
.f_files
, &prstfs
.f_ffree
,
257 &prstfs
.f_fsid
[0], &prstfs
.f_fsid
[1],
258 &prstfs
.f_namelen
, &prstfs
.f_frsize
);
259 assert(retval
== 8 * 11);
260 prstatfs_to_statfs(response
, &prstfs
);
265 v9fs_string_init(&target
);
266 retval
= proxy_unmarshal(reply
, PROXY_HDR_SZ
, "s", &target
);
267 strcpy(response
, target
.data
);
268 v9fs_string_free(&target
);
274 v9fs_string_init(&xattr
);
275 retval
= proxy_unmarshal(reply
, PROXY_HDR_SZ
, "s", &xattr
);
276 memcpy(response
, xattr
.data
, xattr
.size
);
277 v9fs_string_free(&xattr
);
281 retval
= proxy_unmarshal(reply
, PROXY_HDR_SZ
, "q", response
);
294 * return < 0 on transport error.
295 * *status is valid only if return >= 0
297 static int v9fs_receive_status(V9fsProxy
*proxy
,
298 struct iovec
*reply
, int *status
)
305 retval
= socket_read(proxy
->sockfd
, reply
->iov_base
, PROXY_HDR_SZ
);
309 reply
->iov_len
= PROXY_HDR_SZ
;
310 retval
= proxy_unmarshal(reply
, 0, "dd", &header
.type
, &header
.size
);
311 assert(retval
== 4 * 2);
312 retval
= socket_read(proxy
->sockfd
,
313 reply
->iov_base
+ PROXY_HDR_SZ
, header
.size
);
317 reply
->iov_len
+= header
.size
;
318 retval
= proxy_unmarshal(reply
, PROXY_HDR_SZ
, "d", status
);
324 * Proxy->header and proxy->request written to socket by QEMU process.
325 * This request read by proxy helper process
326 * returns 0 on success and -errno on error
328 static int v9fs_request(V9fsProxy
*proxy
, int type
, void *response
, ...)
335 ProxyHeader header
= { 0, 0};
336 struct timespec spec
[2];
337 int flags
, mode
, uid
, gid
;
338 V9fsString
*name
, *value
;
339 V9fsString
*path
, *oldpath
;
340 struct iovec
*iovec
= NULL
, *reply
= NULL
;
342 qemu_mutex_lock(&proxy
->mutex
);
344 if (proxy
->sockfd
== -1) {
348 iovec
= &proxy
->out_iovec
;
349 reply
= &proxy
->in_iovec
;
350 va_start(ap
, response
);
353 path
= va_arg(ap
, V9fsString
*);
354 flags
= va_arg(ap
, int);
355 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sd", path
, flags
);
357 header
.size
= retval
;
358 header
.type
= T_OPEN
;
362 path
= va_arg(ap
, V9fsString
*);
363 flags
= va_arg(ap
, int);
364 mode
= va_arg(ap
, int);
365 uid
= va_arg(ap
, int);
366 gid
= va_arg(ap
, int);
367 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sdddd", path
,
368 flags
, mode
, uid
, gid
);
370 header
.size
= retval
;
371 header
.type
= T_CREATE
;
375 path
= va_arg(ap
, V9fsString
*);
376 mode
= va_arg(ap
, int);
377 rdev
= va_arg(ap
, long int);
378 uid
= va_arg(ap
, int);
379 gid
= va_arg(ap
, int);
380 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ddsdq",
381 uid
, gid
, path
, mode
, rdev
);
383 header
.size
= retval
;
384 header
.type
= T_MKNOD
;
388 path
= va_arg(ap
, V9fsString
*);
389 mode
= va_arg(ap
, int);
390 uid
= va_arg(ap
, int);
391 gid
= va_arg(ap
, int);
392 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ddsd",
393 uid
, gid
, path
, mode
);
395 header
.size
= retval
;
396 header
.type
= T_MKDIR
;
400 oldpath
= va_arg(ap
, V9fsString
*);
401 path
= va_arg(ap
, V9fsString
*);
402 uid
= va_arg(ap
, int);
403 gid
= va_arg(ap
, int);
404 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ddss",
405 uid
, gid
, oldpath
, path
);
407 header
.size
= retval
;
408 header
.type
= T_SYMLINK
;
412 oldpath
= va_arg(ap
, V9fsString
*);
413 path
= va_arg(ap
, V9fsString
*);
414 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ss",
417 header
.size
= retval
;
418 header
.type
= T_LINK
;
422 path
= va_arg(ap
, V9fsString
*);
423 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "s", path
);
425 header
.size
= retval
;
426 header
.type
= T_LSTAT
;
430 path
= va_arg(ap
, V9fsString
*);
431 size
= va_arg(ap
, int);
432 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sd", path
, size
);
434 header
.size
= retval
;
435 header
.type
= T_READLINK
;
439 path
= va_arg(ap
, V9fsString
*);
440 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "s", path
);
442 header
.size
= retval
;
443 header
.type
= T_STATFS
;
447 path
= va_arg(ap
, V9fsString
*);
448 mode
= va_arg(ap
, int);
449 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sd", path
, mode
);
451 header
.size
= retval
;
452 header
.type
= T_CHMOD
;
456 path
= va_arg(ap
, V9fsString
*);
457 uid
= va_arg(ap
, int);
458 gid
= va_arg(ap
, int);
459 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sdd", path
, uid
, gid
);
461 header
.size
= retval
;
462 header
.type
= T_CHOWN
;
466 path
= va_arg(ap
, V9fsString
*);
467 offset
= va_arg(ap
, uint64_t);
468 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sq", path
, offset
);
470 header
.size
= retval
;
471 header
.type
= T_TRUNCATE
;
475 path
= va_arg(ap
, V9fsString
*);
476 spec
[0].tv_sec
= va_arg(ap
, long);
477 spec
[0].tv_nsec
= va_arg(ap
, long);
478 spec
[1].tv_sec
= va_arg(ap
, long);
479 spec
[1].tv_nsec
= va_arg(ap
, long);
480 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sqqqq", path
,
481 spec
[0].tv_sec
, spec
[1].tv_nsec
,
482 spec
[1].tv_sec
, spec
[1].tv_nsec
);
484 header
.size
= retval
;
485 header
.type
= T_UTIME
;
489 oldpath
= va_arg(ap
, V9fsString
*);
490 path
= va_arg(ap
, V9fsString
*);
491 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ss", oldpath
, path
);
493 header
.size
= retval
;
494 header
.type
= T_RENAME
;
498 path
= va_arg(ap
, V9fsString
*);
499 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "s", path
);
501 header
.size
= retval
;
502 header
.type
= T_REMOVE
;
506 size
= va_arg(ap
, int);
507 path
= va_arg(ap
, V9fsString
*);
508 name
= va_arg(ap
, V9fsString
*);
509 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
,
510 "dss", size
, path
, name
);
512 header
.size
= retval
;
513 header
.type
= T_LGETXATTR
;
517 size
= va_arg(ap
, int);
518 path
= va_arg(ap
, V9fsString
*);
519 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ds", size
, path
);
521 header
.size
= retval
;
522 header
.type
= T_LLISTXATTR
;
526 path
= va_arg(ap
, V9fsString
*);
527 name
= va_arg(ap
, V9fsString
*);
528 value
= va_arg(ap
, V9fsString
*);
529 size
= va_arg(ap
, int);
530 flags
= va_arg(ap
, int);
531 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sssdd",
532 path
, name
, value
, size
, flags
);
534 header
.size
= retval
;
535 header
.type
= T_LSETXATTR
;
539 path
= va_arg(ap
, V9fsString
*);
540 name
= va_arg(ap
, V9fsString
*);
541 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ss", path
, name
);
543 header
.size
= retval
;
544 header
.type
= T_LREMOVEXATTR
;
548 path
= va_arg(ap
, V9fsString
*);
549 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "s", path
);
551 header
.size
= retval
;
552 header
.type
= T_GETVERSION
;
556 error_report("Invalid type %d", type
);
566 /* marshal the header details */
567 retval
= proxy_marshal(iovec
, 0, "dd", header
.type
, header
.size
);
568 assert(retval
== 4 * 2);
569 header
.size
+= PROXY_HDR_SZ
;
571 retval
= qemu_write_full(proxy
->sockfd
, iovec
->iov_base
, header
.size
);
572 if (retval
!= header
.size
) {
580 * A file descriptor is returned as response for
581 * T_OPEN,T_CREATE on success
583 if (v9fs_receivefd(proxy
->sockfd
, &retval
) < 0) {
599 if (v9fs_receive_status(proxy
, reply
, &retval
) < 0) {
607 if (v9fs_receive_response(proxy
, type
, &retval
, response
) < 0) {
614 if (v9fs_receive_status(proxy
, reply
, &retval
) < 0) {
618 if (v9fs_receive_response(proxy
, type
, &retval
, response
) < 0) {
626 qemu_mutex_unlock(&proxy
->mutex
);
630 close(proxy
->sockfd
);
632 qemu_mutex_unlock(&proxy
->mutex
);
636 static int proxy_lstat(FsContext
*fs_ctx
, V9fsPath
*fs_path
, struct stat
*stbuf
)
639 retval
= v9fs_request(fs_ctx
->private, T_LSTAT
, stbuf
, fs_path
);
647 static ssize_t
proxy_readlink(FsContext
*fs_ctx
, V9fsPath
*fs_path
,
648 char *buf
, size_t bufsz
)
651 retval
= v9fs_request(fs_ctx
->private, T_READLINK
, buf
, fs_path
, bufsz
);
659 static int proxy_close(FsContext
*ctx
, V9fsFidOpenState
*fs
)
661 return close(fs
->fd
);
664 static int proxy_closedir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
666 return closedir(fs
->dir
.stream
);
669 static int proxy_open(FsContext
*ctx
, V9fsPath
*fs_path
,
670 int flags
, V9fsFidOpenState
*fs
)
672 fs
->fd
= v9fs_request(ctx
->private, T_OPEN
, NULL
, fs_path
, flags
);
680 static int proxy_opendir(FsContext
*ctx
,
681 V9fsPath
*fs_path
, V9fsFidOpenState
*fs
)
685 fs
->dir
.stream
= NULL
;
686 fd
= v9fs_request(ctx
->private, T_OPEN
, NULL
, fs_path
, O_DIRECTORY
);
691 fs
->dir
.stream
= fdopendir(fd
);
692 if (!fs
->dir
.stream
) {
701 static void proxy_rewinddir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
703 rewinddir(fs
->dir
.stream
);
706 static off_t
proxy_telldir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
708 return telldir(fs
->dir
.stream
);
711 static struct dirent
*proxy_readdir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
713 struct dirent
*entry
;
714 entry
= readdir(fs
->dir
.stream
);
720 td
= telldir(fs
->dir
.stream
);
721 /* If telldir fails, fail the entire readdir call */
725 entry
->d_seekoff
= td
;
730 static void proxy_seekdir(FsContext
*ctx
, V9fsFidOpenState
*fs
, off_t off
)
732 seekdir(fs
->dir
.stream
, off
);
735 static ssize_t
proxy_preadv(FsContext
*ctx
, V9fsFidOpenState
*fs
,
736 const struct iovec
*iov
,
737 int iovcnt
, off_t offset
)
741 ret
= preadv(fs
->fd
, iov
, iovcnt
, offset
);
743 ret
= lseek(fs
->fd
, offset
, SEEK_SET
);
745 ret
= readv(fs
->fd
, iov
, iovcnt
);
751 static ssize_t
proxy_pwritev(FsContext
*ctx
, V9fsFidOpenState
*fs
,
752 const struct iovec
*iov
,
753 int iovcnt
, off_t offset
)
758 ret
= pwritev(fs
->fd
, iov
, iovcnt
, offset
);
760 ret
= lseek(fs
->fd
, offset
, SEEK_SET
);
762 ret
= writev(fs
->fd
, iov
, iovcnt
);
765 #ifdef CONFIG_SYNC_FILE_RANGE
766 if (ret
> 0 && ctx
->export_flags
& V9FS_IMMEDIATE_WRITEOUT
) {
768 * Initiate a writeback. This is not a data integrity sync.
769 * We want to ensure that we don't leave dirty pages in the cache
770 * after write when writeout=immediate is specified.
772 sync_file_range(fs
->fd
, offset
, ret
,
773 SYNC_FILE_RANGE_WAIT_BEFORE
| SYNC_FILE_RANGE_WRITE
);
779 static int proxy_chmod(FsContext
*fs_ctx
, V9fsPath
*fs_path
, FsCred
*credp
)
782 retval
= v9fs_request(fs_ctx
->private, T_CHMOD
, NULL
, fs_path
,
790 static int proxy_mknod(FsContext
*fs_ctx
, V9fsPath
*dir_path
,
791 const char *name
, FsCred
*credp
)
796 v9fs_string_init(&fullname
);
797 v9fs_string_sprintf(&fullname
, "%s/%s", dir_path
->data
, name
);
799 retval
= v9fs_request(fs_ctx
->private, T_MKNOD
, NULL
, &fullname
,
800 credp
->fc_mode
, credp
->fc_rdev
,
801 credp
->fc_uid
, credp
->fc_gid
);
802 v9fs_string_free(&fullname
);
810 static int proxy_mkdir(FsContext
*fs_ctx
, V9fsPath
*dir_path
,
811 const char *name
, FsCred
*credp
)
816 v9fs_string_init(&fullname
);
817 v9fs_string_sprintf(&fullname
, "%s/%s", dir_path
->data
, name
);
819 retval
= v9fs_request(fs_ctx
->private, T_MKDIR
, NULL
, &fullname
,
820 credp
->fc_mode
, credp
->fc_uid
, credp
->fc_gid
);
821 v9fs_string_free(&fullname
);
829 static int proxy_fstat(FsContext
*fs_ctx
, int fid_type
,
830 V9fsFidOpenState
*fs
, struct stat
*stbuf
)
834 if (fid_type
== P9_FID_DIR
) {
835 fd
= dirfd(fs
->dir
.stream
);
839 return fstat(fd
, stbuf
);
842 static int proxy_open2(FsContext
*fs_ctx
, V9fsPath
*dir_path
, const char *name
,
843 int flags
, FsCred
*credp
, V9fsFidOpenState
*fs
)
847 v9fs_string_init(&fullname
);
848 v9fs_string_sprintf(&fullname
, "%s/%s", dir_path
->data
, name
);
850 fs
->fd
= v9fs_request(fs_ctx
->private, T_CREATE
, NULL
, &fullname
, flags
,
851 credp
->fc_mode
, credp
->fc_uid
, credp
->fc_gid
);
852 v9fs_string_free(&fullname
);
860 static int proxy_symlink(FsContext
*fs_ctx
, const char *oldpath
,
861 V9fsPath
*dir_path
, const char *name
, FsCred
*credp
)
864 V9fsString fullname
, target
;
866 v9fs_string_init(&fullname
);
867 v9fs_string_init(&target
);
869 v9fs_string_sprintf(&fullname
, "%s/%s", dir_path
->data
, name
);
870 v9fs_string_sprintf(&target
, "%s", oldpath
);
872 retval
= v9fs_request(fs_ctx
->private, T_SYMLINK
, NULL
, &target
, &fullname
,
873 credp
->fc_uid
, credp
->fc_gid
);
874 v9fs_string_free(&fullname
);
875 v9fs_string_free(&target
);
883 static int proxy_link(FsContext
*ctx
, V9fsPath
*oldpath
,
884 V9fsPath
*dirpath
, const char *name
)
889 v9fs_string_init(&newpath
);
890 v9fs_string_sprintf(&newpath
, "%s/%s", dirpath
->data
, name
);
892 retval
= v9fs_request(ctx
->private, T_LINK
, NULL
, oldpath
, &newpath
);
893 v9fs_string_free(&newpath
);
901 static int proxy_truncate(FsContext
*ctx
, V9fsPath
*fs_path
, off_t size
)
905 retval
= v9fs_request(ctx
->private, T_TRUNCATE
, NULL
, fs_path
, size
);
913 static int proxy_rename(FsContext
*ctx
, const char *oldpath
,
917 V9fsString oldname
, newname
;
919 v9fs_string_init(&oldname
);
920 v9fs_string_init(&newname
);
922 v9fs_string_sprintf(&oldname
, "%s", oldpath
);
923 v9fs_string_sprintf(&newname
, "%s", newpath
);
924 retval
= v9fs_request(ctx
->private, T_RENAME
, NULL
, &oldname
, &newname
);
925 v9fs_string_free(&oldname
);
926 v9fs_string_free(&newname
);
933 static int proxy_chown(FsContext
*fs_ctx
, V9fsPath
*fs_path
, FsCred
*credp
)
936 retval
= v9fs_request(fs_ctx
->private, T_CHOWN
, NULL
, fs_path
,
937 credp
->fc_uid
, credp
->fc_gid
);
944 static int proxy_utimensat(FsContext
*s
, V9fsPath
*fs_path
,
945 const struct timespec
*buf
)
948 retval
= v9fs_request(s
->private, T_UTIME
, NULL
, fs_path
,
949 buf
[0].tv_sec
, buf
[0].tv_nsec
,
950 buf
[1].tv_sec
, buf
[1].tv_nsec
);
957 static int proxy_remove(FsContext
*ctx
, const char *path
)
961 v9fs_string_init(&name
);
962 v9fs_string_sprintf(&name
, "%s", path
);
963 retval
= v9fs_request(ctx
->private, T_REMOVE
, NULL
, &name
);
964 v9fs_string_free(&name
);
971 static int proxy_fsync(FsContext
*ctx
, int fid_type
,
972 V9fsFidOpenState
*fs
, int datasync
)
976 if (fid_type
== P9_FID_DIR
) {
977 fd
= dirfd(fs
->dir
.stream
);
983 return qemu_fdatasync(fd
);
989 static int proxy_statfs(FsContext
*s
, V9fsPath
*fs_path
, struct statfs
*stbuf
)
992 retval
= v9fs_request(s
->private, T_STATFS
, stbuf
, fs_path
);
1000 static ssize_t
proxy_lgetxattr(FsContext
*ctx
, V9fsPath
*fs_path
,
1001 const char *name
, void *value
, size_t size
)
1006 v9fs_string_init(&xname
);
1007 v9fs_string_sprintf(&xname
, "%s", name
);
1008 retval
= v9fs_request(ctx
->private, T_LGETXATTR
, value
, size
, fs_path
,
1010 v9fs_string_free(&xname
);
1017 static ssize_t
proxy_llistxattr(FsContext
*ctx
, V9fsPath
*fs_path
,
1018 void *value
, size_t size
)
1021 retval
= v9fs_request(ctx
->private, T_LLISTXATTR
, value
, size
, fs_path
);
1028 static int proxy_lsetxattr(FsContext
*ctx
, V9fsPath
*fs_path
, const char *name
,
1029 void *value
, size_t size
, int flags
)
1032 V9fsString xname
, xvalue
;
1034 v9fs_string_init(&xname
);
1035 v9fs_string_sprintf(&xname
, "%s", name
);
1037 v9fs_string_init(&xvalue
);
1039 xvalue
.data
= g_malloc(size
);
1040 memcpy(xvalue
.data
, value
, size
);
1042 retval
= v9fs_request(ctx
->private, T_LSETXATTR
, value
, fs_path
, &xname
,
1043 &xvalue
, size
, flags
);
1044 v9fs_string_free(&xname
);
1045 v9fs_string_free(&xvalue
);
1052 static int proxy_lremovexattr(FsContext
*ctx
, V9fsPath
*fs_path
,
1058 v9fs_string_init(&xname
);
1059 v9fs_string_sprintf(&xname
, "%s", name
);
1060 retval
= v9fs_request(ctx
->private, T_LREMOVEXATTR
, NULL
, fs_path
, &xname
);
1061 v9fs_string_free(&xname
);
1068 static int proxy_name_to_path(FsContext
*ctx
, V9fsPath
*dir_path
,
1069 const char *name
, V9fsPath
*target
)
1072 v9fs_path_sprintf(target
, "%s/%s", dir_path
->data
, name
);
1074 v9fs_path_sprintf(target
, "%s", name
);
1079 static int proxy_renameat(FsContext
*ctx
, V9fsPath
*olddir
,
1080 const char *old_name
, V9fsPath
*newdir
,
1081 const char *new_name
)
1084 V9fsString old_full_name
, new_full_name
;
1086 v9fs_string_init(&old_full_name
);
1087 v9fs_string_init(&new_full_name
);
1089 v9fs_string_sprintf(&old_full_name
, "%s/%s", olddir
->data
, old_name
);
1090 v9fs_string_sprintf(&new_full_name
, "%s/%s", newdir
->data
, new_name
);
1092 ret
= proxy_rename(ctx
, old_full_name
.data
, new_full_name
.data
);
1093 v9fs_string_free(&old_full_name
);
1094 v9fs_string_free(&new_full_name
);
1098 static int proxy_unlinkat(FsContext
*ctx
, V9fsPath
*dir
,
1099 const char *name
, int flags
)
1102 V9fsString fullname
;
1103 v9fs_string_init(&fullname
);
1105 v9fs_string_sprintf(&fullname
, "%s/%s", dir
->data
, name
);
1106 ret
= proxy_remove(ctx
, fullname
.data
);
1107 v9fs_string_free(&fullname
);
1112 static int proxy_ioc_getversion(FsContext
*fs_ctx
, V9fsPath
*path
,
1113 mode_t st_mode
, uint64_t *st_gen
)
1117 /* Do not try to open special files like device nodes, fifos etc
1118 * we can get fd for regular files and directories only
1120 if (!S_ISREG(st_mode
) && !S_ISDIR(st_mode
)) {
1124 err
= v9fs_request(fs_ctx
->private, T_GETVERSION
, st_gen
, path
);
1132 static int connect_namedsocket(const char *path
, Error
**errp
)
1135 struct sockaddr_un helper
;
1137 if (strlen(path
) >= sizeof(helper
.sun_path
)) {
1138 error_setg(errp
, "socket name too long");
1141 sockfd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1143 error_setg_errno(errp
, errno
, "failed to create client socket");
1146 strcpy(helper
.sun_path
, path
);
1147 helper
.sun_family
= AF_UNIX
;
1148 if (connect(sockfd
, (struct sockaddr
*)&helper
, sizeof(helper
)) < 0) {
1149 error_setg_errno(errp
, errno
, "failed to connect to '%s'", path
);
1154 /* remove the socket for security reasons */
1159 static void error_append_socket_sockfd_hint(Error
*const *errp
)
1161 error_append_hint(errp
, "Either specify socket=/some/path where /some/path"
1162 " points to a listening AF_UNIX socket or sock_fd=fd"
1163 " where fd is a file descriptor to a connected AF_UNIX"
1167 static int proxy_parse_opts(QemuOpts
*opts
, FsDriverEntry
*fs
, Error
**errp
)
1169 const char *socket
= qemu_opt_get(opts
, "socket");
1170 const char *sock_fd
= qemu_opt_get(opts
, "sock_fd");
1172 if (!socket
&& !sock_fd
) {
1173 error_setg(errp
, "both socket and sock_fd properties are missing");
1174 error_append_socket_sockfd_hint(errp
);
1177 if (socket
&& sock_fd
) {
1178 error_setg(errp
, "both socket and sock_fd properties are set");
1179 error_append_socket_sockfd_hint(errp
);
1183 fs
->path
= g_strdup(socket
);
1184 fs
->export_flags
|= V9FS_PROXY_SOCK_NAME
;
1186 fs
->path
= g_strdup(sock_fd
);
1187 fs
->export_flags
|= V9FS_PROXY_SOCK_FD
;
1192 static int proxy_init(FsContext
*ctx
, Error
**errp
)
1194 V9fsProxy
*proxy
= g_new(V9fsProxy
, 1);
1197 if (ctx
->export_flags
& V9FS_PROXY_SOCK_NAME
) {
1198 sock_id
= connect_namedsocket(ctx
->fs_root
, errp
);
1200 sock_id
= atoi(ctx
->fs_root
);
1202 error_setg(errp
, "socket descriptor not initialized");
1209 g_free(ctx
->fs_root
);
1210 ctx
->fs_root
= NULL
;
1212 proxy
->in_iovec
.iov_base
= g_malloc(PROXY_MAX_IO_SZ
+ PROXY_HDR_SZ
);
1213 proxy
->in_iovec
.iov_len
= PROXY_MAX_IO_SZ
+ PROXY_HDR_SZ
;
1214 proxy
->out_iovec
.iov_base
= g_malloc(PROXY_MAX_IO_SZ
+ PROXY_HDR_SZ
);
1215 proxy
->out_iovec
.iov_len
= PROXY_MAX_IO_SZ
+ PROXY_HDR_SZ
;
1217 ctx
->private = proxy
;
1218 proxy
->sockfd
= sock_id
;
1219 qemu_mutex_init(&proxy
->mutex
);
1221 ctx
->export_flags
|= V9FS_PATHNAME_FSCONTEXT
;
1222 ctx
->exops
.get_st_gen
= proxy_ioc_getversion
;
1226 static void proxy_cleanup(FsContext
*ctx
)
1228 V9fsProxy
*proxy
= ctx
->private;
1234 g_free(proxy
->out_iovec
.iov_base
);
1235 g_free(proxy
->in_iovec
.iov_base
);
1236 if (ctx
->export_flags
& V9FS_PROXY_SOCK_NAME
) {
1237 close(proxy
->sockfd
);
1242 FileOperations proxy_ops
= {
1243 .parse_opts
= proxy_parse_opts
,
1245 .cleanup
= proxy_cleanup
,
1246 .lstat
= proxy_lstat
,
1247 .readlink
= proxy_readlink
,
1248 .close
= proxy_close
,
1249 .closedir
= proxy_closedir
,
1251 .opendir
= proxy_opendir
,
1252 .rewinddir
= proxy_rewinddir
,
1253 .telldir
= proxy_telldir
,
1254 .readdir
= proxy_readdir
,
1255 .seekdir
= proxy_seekdir
,
1256 .preadv
= proxy_preadv
,
1257 .pwritev
= proxy_pwritev
,
1258 .chmod
= proxy_chmod
,
1259 .mknod
= proxy_mknod
,
1260 .mkdir
= proxy_mkdir
,
1261 .fstat
= proxy_fstat
,
1262 .open2
= proxy_open2
,
1263 .symlink
= proxy_symlink
,
1265 .truncate
= proxy_truncate
,
1266 .rename
= proxy_rename
,
1267 .chown
= proxy_chown
,
1268 .utimensat
= proxy_utimensat
,
1269 .remove
= proxy_remove
,
1270 .fsync
= proxy_fsync
,
1271 .statfs
= proxy_statfs
,
1272 .lgetxattr
= proxy_lgetxattr
,
1273 .llistxattr
= proxy_llistxattr
,
1274 .lsetxattr
= proxy_lsetxattr
,
1275 .lremovexattr
= proxy_lremovexattr
,
1276 .name_to_path
= proxy_name_to_path
,
1277 .renameat
= proxy_renameat
,
1278 .unlinkat
= proxy_unlinkat
,