2 * Virtio 9p Proxy callback
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.
12 #include <sys/socket.h>
14 #include "hw/virtio.h"
15 #include "virtio-9p.h"
16 #include "fsdev/qemu-fsdev.h"
17 #include "virtio-9p-proxy.h"
19 typedef struct V9fsProxy
{
22 struct iovec in_iovec
;
23 struct iovec out_iovec
;
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.
31 static int v9fs_receivefd(int sockfd
, int *status
)
37 union MsgControl msg_control
;
40 iov
.iov_len
= sizeof(data
);
42 memset(&msg
, 0, sizeof(msg
));
45 msg
.msg_control
= &msg_control
;
46 msg
.msg_controllen
= sizeof(msg_control
);
49 retval
= recvmsg(sockfd
, &msg
, 0);
50 } while (retval
< 0 && errno
== EINTR
);
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.
59 if (data
!= V9FS_FD_VALID
) {
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!
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
) {
74 fd
= *((int *)CMSG_DATA(cmsg
));
78 *status
= -ENFILE
; /* Ancillary data sent but not received */
82 static ssize_t
socket_read(int sockfd
, void *buff
, size_t size
)
84 ssize_t retval
, total
= 0;
87 retval
= read(sockfd
, buff
, size
);
104 /* Converts proxy_statfs to VFS statfs structure */
105 static void prstatfs_to_statfs(struct statfs
*stfs
, ProxyStatFS
*prstfs
)
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
;
121 /* Converts proxy_stat structure to VFS stat structure */
122 static void prstat_to_stat(struct stat
*stbuf
, ProxyStat
*prstat
)
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
;
144 * Response contains two parts
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.
152 static int v9fs_receive_response(V9fsProxy
*proxy
, int type
,
153 int *status
, void *response
)
157 struct iovec
*reply
= &proxy
->in_iovec
;
161 retval
= socket_read(proxy
->sockfd
, reply
->iov_base
, PROXY_HDR_SZ
);
165 reply
->iov_len
= PROXY_HDR_SZ
;
166 proxy_unmarshal(reply
, 0, "dd", &header
.type
, &header
.size
);
168 * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
171 if (header
.size
> PROXY_MAX_IO_SZ
) {
173 while (header
.size
> 0) {
174 count
= MIN(PROXY_MAX_IO_SZ
, header
.size
);
175 count
= socket_read(proxy
->sockfd
, reply
->iov_base
, count
);
179 header
.size
-= count
;
185 retval
= socket_read(proxy
->sockfd
,
186 reply
->iov_base
+ PROXY_HDR_SZ
, header
.size
);
190 reply
->iov_len
+= header
.size
;
191 /* there was an error during processing request */
192 if (header
.type
== T_ERROR
) {
194 ret
= proxy_unmarshal(reply
, PROXY_HDR_SZ
, "d", status
);
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
,
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
);
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
);
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
);
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
);
247 proxy_unmarshal(reply
, PROXY_HDR_SZ
, "q", response
);
259 * return < 0 on transport error.
260 * *status is valid only if return >= 0
262 static int v9fs_receive_status(V9fsProxy
*proxy
,
263 struct iovec
*reply
, int *status
)
270 retval
= socket_read(proxy
->sockfd
, reply
->iov_base
, PROXY_HDR_SZ
);
274 reply
->iov_len
= PROXY_HDR_SZ
;
275 proxy_unmarshal(reply
, 0, "dd", &header
.type
, &header
.size
);
276 if (header
.size
!= sizeof(int)) {
280 retval
= socket_read(proxy
->sockfd
,
281 reply
->iov_base
+ PROXY_HDR_SZ
, header
.size
);
285 reply
->iov_len
+= header
.size
;
286 proxy_unmarshal(reply
, PROXY_HDR_SZ
, "d", status
);
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
295 static int v9fs_request(V9fsProxy
*proxy
, int type
,
296 void *response
, const char *fmt
, ...)
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
;
310 qemu_mutex_lock(&proxy
->mutex
);
312 if (proxy
->sockfd
== -1) {
316 iovec
= &proxy
->out_iovec
;
317 reply
= &proxy
->in_iovec
;
321 path
= va_arg(ap
, V9fsString
*);
322 flags
= va_arg(ap
, int);
323 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sd", path
, flags
);
325 header
.size
= retval
;
326 header
.type
= T_OPEN
;
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
);
338 header
.size
= retval
;
339 header
.type
= T_CREATE
;
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
);
351 header
.size
= retval
;
352 header
.type
= T_MKNOD
;
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
);
363 header
.size
= retval
;
364 header
.type
= T_MKDIR
;
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
);
375 header
.size
= retval
;
376 header
.type
= T_SYMLINK
;
380 oldpath
= va_arg(ap
, V9fsString
*);
381 path
= va_arg(ap
, V9fsString
*);
382 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ss",
385 header
.size
= retval
;
386 header
.type
= T_LINK
;
390 path
= va_arg(ap
, V9fsString
*);
391 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "s", path
);
393 header
.size
= retval
;
394 header
.type
= T_LSTAT
;
398 path
= va_arg(ap
, V9fsString
*);
399 size
= va_arg(ap
, int);
400 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sd", path
, size
);
402 header
.size
= retval
;
403 header
.type
= T_READLINK
;
407 path
= va_arg(ap
, V9fsString
*);
408 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "s", path
);
410 header
.size
= retval
;
411 header
.type
= T_STATFS
;
415 path
= va_arg(ap
, V9fsString
*);
416 mode
= va_arg(ap
, int);
417 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sd", path
, mode
);
419 header
.size
= retval
;
420 header
.type
= T_CHMOD
;
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
);
429 header
.size
= retval
;
430 header
.type
= T_CHOWN
;
434 path
= va_arg(ap
, V9fsString
*);
435 offset
= va_arg(ap
, uint64_t);
436 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "sq", path
, offset
);
438 header
.size
= retval
;
439 header
.type
= T_TRUNCATE
;
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
);
452 header
.size
= retval
;
453 header
.type
= T_UTIME
;
457 oldpath
= va_arg(ap
, V9fsString
*);
458 path
= va_arg(ap
, V9fsString
*);
459 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ss", oldpath
, path
);
461 header
.size
= retval
;
462 header
.type
= T_RENAME
;
466 path
= va_arg(ap
, V9fsString
*);
467 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "s", path
);
469 header
.size
= retval
;
470 header
.type
= T_REMOVE
;
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
);
480 header
.size
= retval
;
481 header
.type
= T_LGETXATTR
;
485 size
= va_arg(ap
, int);
486 path
= va_arg(ap
, V9fsString
*);
487 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ds", size
, path
);
489 header
.size
= retval
;
490 header
.type
= T_LLISTXATTR
;
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
);
502 header
.size
= retval
;
503 header
.type
= T_LSETXATTR
;
507 path
= va_arg(ap
, V9fsString
*);
508 name
= va_arg(ap
, V9fsString
*);
509 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "ss", path
, name
);
511 header
.size
= retval
;
512 header
.type
= T_LREMOVEXATTR
;
516 path
= va_arg(ap
, V9fsString
*);
517 retval
= proxy_marshal(iovec
, PROXY_HDR_SZ
, "s", path
);
519 header
.size
= retval
;
520 header
.type
= T_GETVERSION
;
524 error_report("Invalid type %d", type
);
534 /* marshal the header details */
535 proxy_marshal(iovec
, 0, "dd", header
.type
, header
.size
);
536 header
.size
+= PROXY_HDR_SZ
;
538 retval
= qemu_write_full(proxy
->sockfd
, iovec
->iov_base
, header
.size
);
539 if (retval
!= header
.size
) {
547 * A file descriptor is returned as response for
548 * T_OPEN,T_CREATE on success
550 if (v9fs_receivefd(proxy
->sockfd
, &retval
) < 0) {
566 if (v9fs_receive_status(proxy
, reply
, &retval
) < 0) {
574 if (v9fs_receive_response(proxy
, type
, &retval
, response
) < 0) {
581 if (v9fs_receive_status(proxy
, reply
, &retval
) < 0) {
585 if (v9fs_receive_response(proxy
, type
, &retval
, response
) < 0) {
593 qemu_mutex_unlock(&proxy
->mutex
);
597 close(proxy
->sockfd
);
599 qemu_mutex_unlock(&proxy
->mutex
);
603 static int proxy_lstat(FsContext
*fs_ctx
, V9fsPath
*fs_path
, struct stat
*stbuf
)
606 retval
= v9fs_request(fs_ctx
->private, T_LSTAT
, stbuf
, "s", fs_path
);
614 static ssize_t
proxy_readlink(FsContext
*fs_ctx
, V9fsPath
*fs_path
,
615 char *buf
, size_t bufsz
)
618 retval
= v9fs_request(fs_ctx
->private, T_READLINK
, buf
, "sd",
627 static int proxy_close(FsContext
*ctx
, V9fsFidOpenState
*fs
)
629 return close(fs
->fd
);
632 static int proxy_closedir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
634 return closedir(fs
->dir
);
637 static int proxy_open(FsContext
*ctx
, V9fsPath
*fs_path
,
638 int flags
, V9fsFidOpenState
*fs
)
640 fs
->fd
= v9fs_request(ctx
->private, T_OPEN
, NULL
, "sd", fs_path
, flags
);
648 static int proxy_opendir(FsContext
*ctx
,
649 V9fsPath
*fs_path
, V9fsFidOpenState
*fs
)
654 fd
= v9fs_request(ctx
->private, T_OPEN
, NULL
, "sd", fs_path
, O_DIRECTORY
);
659 fs
->dir
= fdopendir(fd
);
669 static void proxy_rewinddir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
671 return rewinddir(fs
->dir
);
674 static off_t
proxy_telldir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
676 return telldir(fs
->dir
);
679 static int proxy_readdir_r(FsContext
*ctx
, V9fsFidOpenState
*fs
,
680 struct dirent
*entry
,
681 struct dirent
**result
)
683 return readdir_r(fs
->dir
, entry
, result
);
686 static void proxy_seekdir(FsContext
*ctx
, V9fsFidOpenState
*fs
, off_t off
)
688 return seekdir(fs
->dir
, off
);
691 static ssize_t
proxy_preadv(FsContext
*ctx
, V9fsFidOpenState
*fs
,
692 const struct iovec
*iov
,
693 int iovcnt
, off_t offset
)
696 return preadv(fs
->fd
, iov
, iovcnt
, offset
);
698 int err
= lseek(fs
->fd
, offset
, SEEK_SET
);
702 return readv(fs
->fd
, iov
, iovcnt
);
707 static ssize_t
proxy_pwritev(FsContext
*ctx
, V9fsFidOpenState
*fs
,
708 const struct iovec
*iov
,
709 int iovcnt
, off_t offset
)
714 ret
= pwritev(fs
->fd
, iov
, iovcnt
, offset
);
716 int err
= lseek(fs
->fd
, offset
, SEEK_SET
);
720 ret
= writev(fs
->fd
, iov
, iovcnt
);
723 #ifdef CONFIG_SYNC_FILE_RANGE
724 if (ret
> 0 && ctx
->export_flags
& V9FS_IMMEDIATE_WRITEOUT
) {
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.
730 sync_file_range(fs
->fd
, offset
, ret
,
731 SYNC_FILE_RANGE_WAIT_BEFORE
| SYNC_FILE_RANGE_WRITE
);
737 static int proxy_chmod(FsContext
*fs_ctx
, V9fsPath
*fs_path
, FsCred
*credp
)
740 retval
= v9fs_request(fs_ctx
->private, T_CHMOD
, NULL
, "sd",
741 fs_path
, credp
->fc_mode
);
748 static int proxy_mknod(FsContext
*fs_ctx
, V9fsPath
*dir_path
,
749 const char *name
, FsCred
*credp
)
754 v9fs_string_init(&fullname
);
755 v9fs_string_sprintf(&fullname
, "%s/%s", dir_path
->data
, name
);
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
);
768 static int proxy_mkdir(FsContext
*fs_ctx
, V9fsPath
*dir_path
,
769 const char *name
, FsCred
*credp
)
774 v9fs_string_init(&fullname
);
775 v9fs_string_sprintf(&fullname
, "%s/%s", dir_path
->data
, name
);
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
);
784 v9fs_string_free(&fullname
);
788 static int proxy_fstat(FsContext
*fs_ctx
, int fid_type
,
789 V9fsFidOpenState
*fs
, struct stat
*stbuf
)
793 if (fid_type
== P9_FID_DIR
) {
798 return fstat(fd
, stbuf
);
801 static int proxy_open2(FsContext
*fs_ctx
, V9fsPath
*dir_path
, const char *name
,
802 int flags
, FsCred
*credp
, V9fsFidOpenState
*fs
)
806 v9fs_string_init(&fullname
);
807 v9fs_string_sprintf(&fullname
, "%s/%s", dir_path
->data
, name
);
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
);
820 static int proxy_symlink(FsContext
*fs_ctx
, const char *oldpath
,
821 V9fsPath
*dir_path
, const char *name
, FsCred
*credp
)
824 V9fsString fullname
, target
;
826 v9fs_string_init(&fullname
);
827 v9fs_string_init(&target
);
829 v9fs_string_sprintf(&fullname
, "%s/%s", dir_path
->data
, name
);
830 v9fs_string_sprintf(&target
, "%s", oldpath
);
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
);
843 static int proxy_link(FsContext
*ctx
, V9fsPath
*oldpath
,
844 V9fsPath
*dirpath
, const char *name
)
849 v9fs_string_init(&newpath
);
850 v9fs_string_sprintf(&newpath
, "%s/%s", dirpath
->data
, name
);
852 retval
= v9fs_request(ctx
->private, T_LINK
, NULL
, "ss", oldpath
, &newpath
);
853 v9fs_string_free(&newpath
);
861 static int proxy_truncate(FsContext
*ctx
, V9fsPath
*fs_path
, off_t size
)
865 retval
= v9fs_request(ctx
->private, T_TRUNCATE
, NULL
, "sq", fs_path
, size
);
873 static int proxy_rename(FsContext
*ctx
, const char *oldpath
,
877 V9fsString oldname
, newname
;
879 v9fs_string_init(&oldname
);
880 v9fs_string_init(&newname
);
882 v9fs_string_sprintf(&oldname
, "%s", oldpath
);
883 v9fs_string_sprintf(&newname
, "%s", newpath
);
884 retval
= v9fs_request(ctx
->private, T_RENAME
, NULL
, "ss",
886 v9fs_string_free(&oldname
);
887 v9fs_string_free(&newname
);
894 static int proxy_chown(FsContext
*fs_ctx
, V9fsPath
*fs_path
, FsCred
*credp
)
897 retval
= v9fs_request(fs_ctx
->private, T_CHOWN
, NULL
, "sdd",
898 fs_path
, credp
->fc_uid
, credp
->fc_gid
);
905 static int proxy_utimensat(FsContext
*s
, V9fsPath
*fs_path
,
906 const struct timespec
*buf
)
909 retval
= v9fs_request(s
->private, T_UTIME
, NULL
, "sqqqq",
911 buf
[0].tv_sec
, buf
[0].tv_nsec
,
912 buf
[1].tv_sec
, buf
[1].tv_nsec
);
919 static int proxy_remove(FsContext
*ctx
, const char *path
)
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
);
933 static int proxy_fsync(FsContext
*ctx
, int fid_type
,
934 V9fsFidOpenState
*fs
, int datasync
)
938 if (fid_type
== P9_FID_DIR
) {
945 return qemu_fdatasync(fd
);
951 static int proxy_statfs(FsContext
*s
, V9fsPath
*fs_path
, struct statfs
*stbuf
)
954 retval
= v9fs_request(s
->private, T_STATFS
, stbuf
, "s", fs_path
);
962 static ssize_t
proxy_lgetxattr(FsContext
*ctx
, V9fsPath
*fs_path
,
963 const char *name
, void *value
, size_t size
)
968 v9fs_string_init(&xname
);
969 v9fs_string_sprintf(&xname
, "%s", name
);
970 retval
= v9fs_request(ctx
->private, T_LGETXATTR
, value
, "dss", size
,
972 v9fs_string_free(&xname
);
979 static ssize_t
proxy_llistxattr(FsContext
*ctx
, V9fsPath
*fs_path
,
980 void *value
, size_t size
)
983 retval
= v9fs_request(ctx
->private, T_LLISTXATTR
, value
, "ds", size
,
991 static int proxy_lsetxattr(FsContext
*ctx
, V9fsPath
*fs_path
, const char *name
,
992 void *value
, size_t size
, int flags
)
995 V9fsString xname
, xvalue
;
997 v9fs_string_init(&xname
);
998 v9fs_string_sprintf(&xname
, "%s", name
);
1000 v9fs_string_init(&xvalue
);
1002 xvalue
.data
= g_malloc(size
);
1003 memcpy(xvalue
.data
, value
, size
);
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
);
1015 static int proxy_lremovexattr(FsContext
*ctx
, V9fsPath
*fs_path
,
1021 v9fs_string_init(&xname
);
1022 v9fs_string_sprintf(&xname
, "%s", name
);
1023 retval
= v9fs_request(ctx
->private, T_LREMOVEXATTR
, NULL
, "ss",
1025 v9fs_string_free(&xname
);
1032 static int proxy_name_to_path(FsContext
*ctx
, V9fsPath
*dir_path
,
1033 const char *name
, V9fsPath
*target
)
1036 v9fs_string_sprintf((V9fsString
*)target
, "%s/%s",
1037 dir_path
->data
, name
);
1039 v9fs_string_sprintf((V9fsString
*)target
, "%s", name
);
1041 /* Bump the size for including terminating NULL */
1046 static int proxy_renameat(FsContext
*ctx
, V9fsPath
*olddir
,
1047 const char *old_name
, V9fsPath
*newdir
,
1048 const char *new_name
)
1051 V9fsString old_full_name
, new_full_name
;
1053 v9fs_string_init(&old_full_name
);
1054 v9fs_string_init(&new_full_name
);
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
);
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
);
1065 static int proxy_unlinkat(FsContext
*ctx
, V9fsPath
*dir
,
1066 const char *name
, int flags
)
1069 V9fsString fullname
;
1070 v9fs_string_init(&fullname
);
1072 v9fs_string_sprintf(&fullname
, "%s/%s", dir
->data
, name
);
1073 ret
= proxy_remove(ctx
, fullname
.data
);
1074 v9fs_string_free(&fullname
);
1079 static int proxy_ioc_getversion(FsContext
*fs_ctx
, V9fsPath
*path
,
1080 mode_t st_mode
, uint64_t *st_gen
)
1084 /* Do not try to open special files like device nodes, fifos etc
1085 * we can get fd for regular files and directories only
1087 if (!S_ISREG(st_mode
) && !S_ISDIR(st_mode
)) {
1090 err
= v9fs_request(fs_ctx
->private, T_GETVERSION
, st_gen
, "s", path
);
1098 static int connect_namedsocket(const char *path
)
1101 struct sockaddr_un helper
;
1103 sockfd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1105 fprintf(stderr
, "socket %s\n", strerror(errno
));
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");
1116 /* remove the socket for security reasons */
1121 static int proxy_parse_opts(QemuOpts
*opts
, struct FsDriverEntry
*fs
)
1123 const char *socket
= qemu_opt_get(opts
, "socket");
1124 const char *sock_fd
= qemu_opt_get(opts
, "sock_fd");
1126 if (!socket
&& !sock_fd
) {
1127 fprintf(stderr
, "socket and sock_fd none of the option specified\n");
1130 if (socket
&& sock_fd
) {
1131 fprintf(stderr
, "Both socket and sock_fd options specified\n");
1135 fs
->path
= g_strdup(socket
);
1136 fs
->export_flags
= V9FS_PROXY_SOCK_NAME
;
1138 fs
->path
= g_strdup(sock_fd
);
1139 fs
->export_flags
= V9FS_PROXY_SOCK_FD
;
1144 static int proxy_init(FsContext
*ctx
)
1146 V9fsProxy
*proxy
= g_malloc(sizeof(V9fsProxy
));
1149 if (ctx
->export_flags
& V9FS_PROXY_SOCK_NAME
) {
1150 sock_id
= connect_namedsocket(ctx
->fs_root
);
1152 sock_id
= atoi(ctx
->fs_root
);
1154 fprintf(stderr
, "socket descriptor not initialized\n");
1158 g_free(ctx
->fs_root
);
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
;
1165 ctx
->private = proxy
;
1166 proxy
->sockfd
= sock_id
;
1167 qemu_mutex_init(&proxy
->mutex
);
1169 ctx
->export_flags
|= V9FS_PATHNAME_FSCONTEXT
;
1170 ctx
->exops
.get_st_gen
= proxy_ioc_getversion
;
1174 FileOperations proxy_ops
= {
1175 .parse_opts
= proxy_parse_opts
,
1177 .lstat
= proxy_lstat
,
1178 .readlink
= proxy_readlink
,
1179 .close
= proxy_close
,
1180 .closedir
= proxy_closedir
,
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
,
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
,