1494a8ebeSWei Liu /*
2494a8ebeSWei Liu * 9p Proxy callback
3494a8ebeSWei Liu *
4494a8ebeSWei Liu * Copyright IBM, Corp. 2011
5494a8ebeSWei Liu *
6494a8ebeSWei Liu * Authors:
7494a8ebeSWei Liu * M. Mohan Kumar <mohan@in.ibm.com>
8494a8ebeSWei Liu *
9494a8ebeSWei Liu * This work is licensed under the terms of the GNU GPL, version 2. See
10494a8ebeSWei Liu * the COPYING file in the top-level directory.
11494a8ebeSWei Liu */
12e688df6bSMarkus Armbruster
136f569084SChristian Schoenebeck /*
146f569084SChristian Schoenebeck * Not so fast! You might want to read the 9p developer docs first:
156f569084SChristian Schoenebeck * https://wiki.qemu.org/Documentation/9p
166f569084SChristian Schoenebeck */
176f569084SChristian Schoenebeck
1871d72eceSChristian Schoenebeck /*
1971d72eceSChristian Schoenebeck * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
2071d72eceSChristian Schoenebeck * removed in a future version of QEMU!
2171d72eceSChristian Schoenebeck */
2271d72eceSChristian Schoenebeck
23fbc04127SPeter Maydell #include "qemu/osdep.h"
24494a8ebeSWei Liu #include <sys/socket.h>
25494a8ebeSWei Liu #include <sys/un.h>
26ebe74f8bSWei Liu #include "9p.h"
27e688df6bSMarkus Armbruster #include "qapi/error.h"
28f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
29494a8ebeSWei Liu #include "qemu/error-report.h"
30922a01a0SMarkus Armbruster #include "qemu/option.h"
31494a8ebeSWei Liu #include "fsdev/qemu-fsdev.h"
32494a8ebeSWei Liu #include "9p-proxy.h"
33494a8ebeSWei Liu
34494a8ebeSWei Liu typedef struct V9fsProxy {
35494a8ebeSWei Liu int sockfd;
36494a8ebeSWei Liu QemuMutex mutex;
37494a8ebeSWei Liu struct iovec in_iovec;
38494a8ebeSWei Liu struct iovec out_iovec;
39494a8ebeSWei Liu } V9fsProxy;
40494a8ebeSWei Liu
41494a8ebeSWei Liu /*
42494a8ebeSWei Liu * Return received file descriptor on success in *status.
43494a8ebeSWei Liu * errno is also returned on *status (which will be < 0)
44494a8ebeSWei Liu * return < 0 on transport error.
45494a8ebeSWei Liu */
v9fs_receivefd(int sockfd,int * status)46494a8ebeSWei Liu static int v9fs_receivefd(int sockfd, int *status)
47494a8ebeSWei Liu {
48494a8ebeSWei Liu struct iovec iov;
49494a8ebeSWei Liu struct msghdr msg;
50494a8ebeSWei Liu struct cmsghdr *cmsg;
51494a8ebeSWei Liu int retval, data, fd;
52494a8ebeSWei Liu union MsgControl msg_control;
53494a8ebeSWei Liu
54494a8ebeSWei Liu iov.iov_base = &data;
55494a8ebeSWei Liu iov.iov_len = sizeof(data);
56494a8ebeSWei Liu
57494a8ebeSWei Liu memset(&msg, 0, sizeof(msg));
58494a8ebeSWei Liu msg.msg_iov = &iov;
59494a8ebeSWei Liu msg.msg_iovlen = 1;
60494a8ebeSWei Liu msg.msg_control = &msg_control;
61494a8ebeSWei Liu msg.msg_controllen = sizeof(msg_control);
62494a8ebeSWei Liu
63494a8ebeSWei Liu do {
64494a8ebeSWei Liu retval = recvmsg(sockfd, &msg, 0);
65494a8ebeSWei Liu } while (retval < 0 && errno == EINTR);
66494a8ebeSWei Liu if (retval <= 0) {
67494a8ebeSWei Liu return retval;
68494a8ebeSWei Liu }
69494a8ebeSWei Liu /*
70494a8ebeSWei Liu * data is set to V9FS_FD_VALID, if ancillary data is sent. If this
71494a8ebeSWei Liu * request doesn't need ancillary data (fd) or an error occurred,
72494a8ebeSWei Liu * data is set to negative errno value.
73494a8ebeSWei Liu */
74494a8ebeSWei Liu if (data != V9FS_FD_VALID) {
75494a8ebeSWei Liu *status = data;
76494a8ebeSWei Liu return 0;
77494a8ebeSWei Liu }
78494a8ebeSWei Liu /*
79494a8ebeSWei Liu * File descriptor (fd) is sent in the ancillary data. Check if we
80494a8ebeSWei Liu * indeed received it. One of the reasons to fail to receive it is if
81494a8ebeSWei Liu * we exceeded the maximum number of file descriptors!
82494a8ebeSWei Liu */
83494a8ebeSWei Liu for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
84494a8ebeSWei Liu if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
85494a8ebeSWei Liu cmsg->cmsg_level != SOL_SOCKET ||
86494a8ebeSWei Liu cmsg->cmsg_type != SCM_RIGHTS) {
87494a8ebeSWei Liu continue;
88494a8ebeSWei Liu }
89494a8ebeSWei Liu fd = *((int *)CMSG_DATA(cmsg));
90494a8ebeSWei Liu *status = fd;
91494a8ebeSWei Liu return 0;
92494a8ebeSWei Liu }
93494a8ebeSWei Liu *status = -ENFILE; /* Ancillary data sent but not received */
94494a8ebeSWei Liu return 0;
95494a8ebeSWei Liu }
96494a8ebeSWei Liu
socket_read(int sockfd,void * buff,size_t size)97494a8ebeSWei Liu static ssize_t socket_read(int sockfd, void *buff, size_t size)
98494a8ebeSWei Liu {
99494a8ebeSWei Liu ssize_t retval, total = 0;
100494a8ebeSWei Liu
101494a8ebeSWei Liu while (size) {
102494a8ebeSWei Liu retval = read(sockfd, buff, size);
103494a8ebeSWei Liu if (retval == 0) {
104494a8ebeSWei Liu return -EIO;
105494a8ebeSWei Liu }
106494a8ebeSWei Liu if (retval < 0) {
107494a8ebeSWei Liu if (errno == EINTR) {
108494a8ebeSWei Liu continue;
109494a8ebeSWei Liu }
110494a8ebeSWei Liu return -errno;
111494a8ebeSWei Liu }
112494a8ebeSWei Liu size -= retval;
113494a8ebeSWei Liu buff += retval;
114494a8ebeSWei Liu total += retval;
115494a8ebeSWei Liu }
116494a8ebeSWei Liu return total;
117494a8ebeSWei Liu }
118494a8ebeSWei Liu
119494a8ebeSWei Liu /* Converts proxy_statfs to VFS statfs structure */
prstatfs_to_statfs(struct statfs * stfs,ProxyStatFS * prstfs)120494a8ebeSWei Liu static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs)
121494a8ebeSWei Liu {
122494a8ebeSWei Liu memset(stfs, 0, sizeof(*stfs));
123494a8ebeSWei Liu stfs->f_type = prstfs->f_type;
124494a8ebeSWei Liu stfs->f_bsize = prstfs->f_bsize;
125494a8ebeSWei Liu stfs->f_blocks = prstfs->f_blocks;
126494a8ebeSWei Liu stfs->f_bfree = prstfs->f_bfree;
127494a8ebeSWei Liu stfs->f_bavail = prstfs->f_bavail;
128494a8ebeSWei Liu stfs->f_files = prstfs->f_files;
129494a8ebeSWei Liu stfs->f_ffree = prstfs->f_ffree;
130f41db099SKeno Fischer #ifdef CONFIG_DARWIN
131f41db099SKeno Fischer /* f_namelen and f_frsize do not exist on Darwin */
132f41db099SKeno Fischer stfs->f_fsid.val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
133f41db099SKeno Fischer stfs->f_fsid.val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
134f41db099SKeno Fischer #else
135494a8ebeSWei Liu stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
136494a8ebeSWei Liu stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
137494a8ebeSWei Liu stfs->f_namelen = prstfs->f_namelen;
138494a8ebeSWei Liu stfs->f_frsize = prstfs->f_frsize;
139f41db099SKeno Fischer #endif
140494a8ebeSWei Liu }
141494a8ebeSWei Liu
142494a8ebeSWei Liu /* Converts proxy_stat structure to VFS stat structure */
prstat_to_stat(struct stat * stbuf,ProxyStat * prstat)143494a8ebeSWei Liu static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat)
144494a8ebeSWei Liu {
145494a8ebeSWei Liu memset(stbuf, 0, sizeof(*stbuf));
146494a8ebeSWei Liu stbuf->st_dev = prstat->st_dev;
147494a8ebeSWei Liu stbuf->st_ino = prstat->st_ino;
148494a8ebeSWei Liu stbuf->st_nlink = prstat->st_nlink;
149494a8ebeSWei Liu stbuf->st_mode = prstat->st_mode;
150494a8ebeSWei Liu stbuf->st_uid = prstat->st_uid;
151494a8ebeSWei Liu stbuf->st_gid = prstat->st_gid;
152494a8ebeSWei Liu stbuf->st_rdev = prstat->st_rdev;
153494a8ebeSWei Liu stbuf->st_size = prstat->st_size;
154494a8ebeSWei Liu stbuf->st_blksize = prstat->st_blksize;
155494a8ebeSWei Liu stbuf->st_blocks = prstat->st_blocks;
156f41db099SKeno Fischer stbuf->st_atime = prstat->st_atim_sec;
157494a8ebeSWei Liu stbuf->st_mtime = prstat->st_mtim_sec;
158494a8ebeSWei Liu stbuf->st_ctime = prstat->st_ctim_sec;
159f41db099SKeno Fischer #ifdef CONFIG_DARWIN
160f41db099SKeno Fischer stbuf->st_atimespec.tv_sec = prstat->st_atim_sec;
161f41db099SKeno Fischer stbuf->st_mtimespec.tv_sec = prstat->st_mtim_sec;
162f41db099SKeno Fischer stbuf->st_ctimespec.tv_sec = prstat->st_ctim_sec;
163f41db099SKeno Fischer stbuf->st_atimespec.tv_nsec = prstat->st_atim_nsec;
164f41db099SKeno Fischer stbuf->st_mtimespec.tv_nsec = prstat->st_mtim_nsec;
165f41db099SKeno Fischer stbuf->st_ctimespec.tv_nsec = prstat->st_ctim_nsec;
166f41db099SKeno Fischer #else
167f41db099SKeno Fischer stbuf->st_atim.tv_sec = prstat->st_atim_sec;
168f41db099SKeno Fischer stbuf->st_mtim.tv_sec = prstat->st_mtim_sec;
169f41db099SKeno Fischer stbuf->st_ctim.tv_sec = prstat->st_ctim_sec;
170f41db099SKeno Fischer stbuf->st_atim.tv_nsec = prstat->st_atim_nsec;
171f41db099SKeno Fischer stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec;
172494a8ebeSWei Liu stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec;
173f41db099SKeno Fischer #endif
174494a8ebeSWei Liu }
175494a8ebeSWei Liu
176494a8ebeSWei Liu /*
177494a8ebeSWei Liu * Response contains two parts
178494a8ebeSWei Liu * {header, data}
179494a8ebeSWei Liu * header.type == T_ERROR, data -> -errno
180494a8ebeSWei Liu * header.type == T_SUCCESS, data -> response
181494a8ebeSWei Liu * size of errno/response is given by header.size
182494a8ebeSWei Liu * returns < 0, on transport error. response is
183494a8ebeSWei Liu * valid only if status >= 0.
184494a8ebeSWei Liu */
v9fs_receive_response(V9fsProxy * proxy,int type,int * status,void * response)185494a8ebeSWei Liu static int v9fs_receive_response(V9fsProxy *proxy, int type,
186494a8ebeSWei Liu int *status, void *response)
187494a8ebeSWei Liu {
188494a8ebeSWei Liu int retval;
189494a8ebeSWei Liu ProxyHeader header;
190494a8ebeSWei Liu struct iovec *reply = &proxy->in_iovec;
191494a8ebeSWei Liu
192494a8ebeSWei Liu *status = 0;
193494a8ebeSWei Liu reply->iov_len = 0;
194494a8ebeSWei Liu retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
195494a8ebeSWei Liu if (retval < 0) {
196494a8ebeSWei Liu return retval;
197494a8ebeSWei Liu }
198494a8ebeSWei Liu reply->iov_len = PROXY_HDR_SZ;
199262169abSGreg Kurz retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
200262169abSGreg Kurz assert(retval == 4 * 2);
201494a8ebeSWei Liu /*
202494a8ebeSWei Liu * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
203494a8ebeSWei Liu * return -ENOBUFS
204494a8ebeSWei Liu */
205494a8ebeSWei Liu if (header.size > PROXY_MAX_IO_SZ) {
206494a8ebeSWei Liu int count;
207494a8ebeSWei Liu while (header.size > 0) {
208494a8ebeSWei Liu count = MIN(PROXY_MAX_IO_SZ, header.size);
209494a8ebeSWei Liu count = socket_read(proxy->sockfd, reply->iov_base, count);
210494a8ebeSWei Liu if (count < 0) {
211494a8ebeSWei Liu return count;
212494a8ebeSWei Liu }
213494a8ebeSWei Liu header.size -= count;
214494a8ebeSWei Liu }
215494a8ebeSWei Liu *status = -ENOBUFS;
216494a8ebeSWei Liu return 0;
217494a8ebeSWei Liu }
218494a8ebeSWei Liu
219494a8ebeSWei Liu retval = socket_read(proxy->sockfd,
220494a8ebeSWei Liu reply->iov_base + PROXY_HDR_SZ, header.size);
221494a8ebeSWei Liu if (retval < 0) {
222494a8ebeSWei Liu return retval;
223494a8ebeSWei Liu }
224494a8ebeSWei Liu reply->iov_len += header.size;
225494a8ebeSWei Liu /* there was an error during processing request */
226494a8ebeSWei Liu if (header.type == T_ERROR) {
227494a8ebeSWei Liu int ret;
228494a8ebeSWei Liu ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
229262169abSGreg Kurz assert(ret == 4);
230494a8ebeSWei Liu return 0;
231494a8ebeSWei Liu }
232494a8ebeSWei Liu
233494a8ebeSWei Liu switch (type) {
234494a8ebeSWei Liu case T_LSTAT: {
235494a8ebeSWei Liu ProxyStat prstat;
236494a8ebeSWei Liu retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
237494a8ebeSWei Liu "qqqdddqqqqqqqqqq", &prstat.st_dev,
238494a8ebeSWei Liu &prstat.st_ino, &prstat.st_nlink,
239494a8ebeSWei Liu &prstat.st_mode, &prstat.st_uid,
240494a8ebeSWei Liu &prstat.st_gid, &prstat.st_rdev,
241494a8ebeSWei Liu &prstat.st_size, &prstat.st_blksize,
242494a8ebeSWei Liu &prstat.st_blocks,
243494a8ebeSWei Liu &prstat.st_atim_sec, &prstat.st_atim_nsec,
244494a8ebeSWei Liu &prstat.st_mtim_sec, &prstat.st_mtim_nsec,
245494a8ebeSWei Liu &prstat.st_ctim_sec, &prstat.st_ctim_nsec);
246262169abSGreg Kurz assert(retval == 8 * 3 + 4 * 3 + 8 * 10);
247494a8ebeSWei Liu prstat_to_stat(response, &prstat);
248494a8ebeSWei Liu break;
249494a8ebeSWei Liu }
250494a8ebeSWei Liu case T_STATFS: {
251494a8ebeSWei Liu ProxyStatFS prstfs;
252494a8ebeSWei Liu retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
253494a8ebeSWei Liu "qqqqqqqqqqq", &prstfs.f_type,
254494a8ebeSWei Liu &prstfs.f_bsize, &prstfs.f_blocks,
255494a8ebeSWei Liu &prstfs.f_bfree, &prstfs.f_bavail,
256494a8ebeSWei Liu &prstfs.f_files, &prstfs.f_ffree,
257494a8ebeSWei Liu &prstfs.f_fsid[0], &prstfs.f_fsid[1],
258494a8ebeSWei Liu &prstfs.f_namelen, &prstfs.f_frsize);
259262169abSGreg Kurz assert(retval == 8 * 11);
260494a8ebeSWei Liu prstatfs_to_statfs(response, &prstfs);
261494a8ebeSWei Liu break;
262494a8ebeSWei Liu }
263494a8ebeSWei Liu case T_READLINK: {
264494a8ebeSWei Liu V9fsString target;
265494a8ebeSWei Liu v9fs_string_init(&target);
266494a8ebeSWei Liu retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target);
267494a8ebeSWei Liu strcpy(response, target.data);
268494a8ebeSWei Liu v9fs_string_free(&target);
269494a8ebeSWei Liu break;
270494a8ebeSWei Liu }
271494a8ebeSWei Liu case T_LGETXATTR:
272494a8ebeSWei Liu case T_LLISTXATTR: {
273494a8ebeSWei Liu V9fsString xattr;
274494a8ebeSWei Liu v9fs_string_init(&xattr);
275494a8ebeSWei Liu retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr);
276494a8ebeSWei Liu memcpy(response, xattr.data, xattr.size);
277494a8ebeSWei Liu v9fs_string_free(&xattr);
278494a8ebeSWei Liu break;
279494a8ebeSWei Liu }
280494a8ebeSWei Liu case T_GETVERSION:
281262169abSGreg Kurz retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
282262169abSGreg Kurz assert(retval == 8);
283494a8ebeSWei Liu break;
284494a8ebeSWei Liu default:
285494a8ebeSWei Liu return -1;
286494a8ebeSWei Liu }
287494a8ebeSWei Liu if (retval < 0) {
288494a8ebeSWei Liu *status = retval;
289494a8ebeSWei Liu }
290494a8ebeSWei Liu return 0;
291494a8ebeSWei Liu }
292494a8ebeSWei Liu
293494a8ebeSWei Liu /*
294494a8ebeSWei Liu * return < 0 on transport error.
295494a8ebeSWei Liu * *status is valid only if return >= 0
296494a8ebeSWei Liu */
v9fs_receive_status(V9fsProxy * proxy,struct iovec * reply,int * status)297494a8ebeSWei Liu static int v9fs_receive_status(V9fsProxy *proxy,
298494a8ebeSWei Liu struct iovec *reply, int *status)
299494a8ebeSWei Liu {
300494a8ebeSWei Liu int retval;
301494a8ebeSWei Liu ProxyHeader header;
302494a8ebeSWei Liu
303494a8ebeSWei Liu *status = 0;
304494a8ebeSWei Liu reply->iov_len = 0;
305494a8ebeSWei Liu retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
306494a8ebeSWei Liu if (retval < 0) {
307494a8ebeSWei Liu return retval;
308494a8ebeSWei Liu }
309494a8ebeSWei Liu reply->iov_len = PROXY_HDR_SZ;
310262169abSGreg Kurz retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
311262169abSGreg Kurz assert(retval == 4 * 2);
312494a8ebeSWei Liu retval = socket_read(proxy->sockfd,
313494a8ebeSWei Liu reply->iov_base + PROXY_HDR_SZ, header.size);
314494a8ebeSWei Liu if (retval < 0) {
315494a8ebeSWei Liu return retval;
316494a8ebeSWei Liu }
317494a8ebeSWei Liu reply->iov_len += header.size;
318262169abSGreg Kurz retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
319262169abSGreg Kurz assert(retval == 4);
320494a8ebeSWei Liu return 0;
321494a8ebeSWei Liu }
322494a8ebeSWei Liu
323494a8ebeSWei Liu /*
324494a8ebeSWei Liu * Proxy->header and proxy->request written to socket by QEMU process.
325494a8ebeSWei Liu * This request read by proxy helper process
326494a8ebeSWei Liu * returns 0 on success and -errno on error
327494a8ebeSWei Liu */
v9fs_request(V9fsProxy * proxy,int type,void * response,...)328799fe087SGreg Kurz static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...)
329494a8ebeSWei Liu {
330494a8ebeSWei Liu dev_t rdev;
331494a8ebeSWei Liu va_list ap;
332494a8ebeSWei Liu int size = 0;
333494a8ebeSWei Liu int retval = 0;
334494a8ebeSWei Liu uint64_t offset;
335494a8ebeSWei Liu ProxyHeader header = { 0, 0};
336494a8ebeSWei Liu struct timespec spec[2];
337494a8ebeSWei Liu int flags, mode, uid, gid;
338494a8ebeSWei Liu V9fsString *name, *value;
339494a8ebeSWei Liu V9fsString *path, *oldpath;
340494a8ebeSWei Liu struct iovec *iovec = NULL, *reply = NULL;
341494a8ebeSWei Liu
342494a8ebeSWei Liu qemu_mutex_lock(&proxy->mutex);
343494a8ebeSWei Liu
344494a8ebeSWei Liu if (proxy->sockfd == -1) {
345494a8ebeSWei Liu retval = -EIO;
346494a8ebeSWei Liu goto err_out;
347494a8ebeSWei Liu }
348494a8ebeSWei Liu iovec = &proxy->out_iovec;
349494a8ebeSWei Liu reply = &proxy->in_iovec;
350799fe087SGreg Kurz va_start(ap, response);
351494a8ebeSWei Liu switch (type) {
352494a8ebeSWei Liu case T_OPEN:
353494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
354494a8ebeSWei Liu flags = va_arg(ap, int);
355494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags);
356494a8ebeSWei Liu if (retval > 0) {
357494a8ebeSWei Liu header.size = retval;
358494a8ebeSWei Liu header.type = T_OPEN;
359494a8ebeSWei Liu }
360494a8ebeSWei Liu break;
361494a8ebeSWei Liu case T_CREATE:
362494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
363494a8ebeSWei Liu flags = va_arg(ap, int);
364494a8ebeSWei Liu mode = va_arg(ap, int);
365494a8ebeSWei Liu uid = va_arg(ap, int);
366494a8ebeSWei Liu gid = va_arg(ap, int);
367494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path,
368494a8ebeSWei Liu flags, mode, uid, gid);
369494a8ebeSWei Liu if (retval > 0) {
370494a8ebeSWei Liu header.size = retval;
371494a8ebeSWei Liu header.type = T_CREATE;
372494a8ebeSWei Liu }
373494a8ebeSWei Liu break;
374494a8ebeSWei Liu case T_MKNOD:
375494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
376494a8ebeSWei Liu mode = va_arg(ap, int);
377494a8ebeSWei Liu rdev = va_arg(ap, long int);
378494a8ebeSWei Liu uid = va_arg(ap, int);
379494a8ebeSWei Liu gid = va_arg(ap, int);
380494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq",
381494a8ebeSWei Liu uid, gid, path, mode, rdev);
382494a8ebeSWei Liu if (retval > 0) {
383494a8ebeSWei Liu header.size = retval;
384494a8ebeSWei Liu header.type = T_MKNOD;
385494a8ebeSWei Liu }
386494a8ebeSWei Liu break;
387494a8ebeSWei Liu case T_MKDIR:
388494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
389494a8ebeSWei Liu mode = va_arg(ap, int);
390494a8ebeSWei Liu uid = va_arg(ap, int);
391494a8ebeSWei Liu gid = va_arg(ap, int);
392494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd",
393494a8ebeSWei Liu uid, gid, path, mode);
394494a8ebeSWei Liu if (retval > 0) {
395494a8ebeSWei Liu header.size = retval;
396494a8ebeSWei Liu header.type = T_MKDIR;
397494a8ebeSWei Liu }
398494a8ebeSWei Liu break;
399494a8ebeSWei Liu case T_SYMLINK:
400494a8ebeSWei Liu oldpath = va_arg(ap, V9fsString *);
401494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
402494a8ebeSWei Liu uid = va_arg(ap, int);
403494a8ebeSWei Liu gid = va_arg(ap, int);
404494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss",
405494a8ebeSWei Liu uid, gid, oldpath, path);
406494a8ebeSWei Liu if (retval > 0) {
407494a8ebeSWei Liu header.size = retval;
408494a8ebeSWei Liu header.type = T_SYMLINK;
409494a8ebeSWei Liu }
410494a8ebeSWei Liu break;
411494a8ebeSWei Liu case T_LINK:
412494a8ebeSWei Liu oldpath = va_arg(ap, V9fsString *);
413494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
414494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss",
415494a8ebeSWei Liu oldpath, path);
416494a8ebeSWei Liu if (retval > 0) {
417494a8ebeSWei Liu header.size = retval;
418494a8ebeSWei Liu header.type = T_LINK;
419494a8ebeSWei Liu }
420494a8ebeSWei Liu break;
421494a8ebeSWei Liu case T_LSTAT:
422494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
423494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
424494a8ebeSWei Liu if (retval > 0) {
425494a8ebeSWei Liu header.size = retval;
426494a8ebeSWei Liu header.type = T_LSTAT;
427494a8ebeSWei Liu }
428494a8ebeSWei Liu break;
429494a8ebeSWei Liu case T_READLINK:
430494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
431494a8ebeSWei Liu size = va_arg(ap, int);
432494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size);
433494a8ebeSWei Liu if (retval > 0) {
434494a8ebeSWei Liu header.size = retval;
435494a8ebeSWei Liu header.type = T_READLINK;
436494a8ebeSWei Liu }
437494a8ebeSWei Liu break;
438494a8ebeSWei Liu case T_STATFS:
439494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
440494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
441494a8ebeSWei Liu if (retval > 0) {
442494a8ebeSWei Liu header.size = retval;
443494a8ebeSWei Liu header.type = T_STATFS;
444494a8ebeSWei Liu }
445494a8ebeSWei Liu break;
446494a8ebeSWei Liu case T_CHMOD:
447494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
448494a8ebeSWei Liu mode = va_arg(ap, int);
449494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode);
450494a8ebeSWei Liu if (retval > 0) {
451494a8ebeSWei Liu header.size = retval;
452494a8ebeSWei Liu header.type = T_CHMOD;
453494a8ebeSWei Liu }
454494a8ebeSWei Liu break;
455494a8ebeSWei Liu case T_CHOWN:
456494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
457494a8ebeSWei Liu uid = va_arg(ap, int);
458494a8ebeSWei Liu gid = va_arg(ap, int);
459494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid);
460494a8ebeSWei Liu if (retval > 0) {
461494a8ebeSWei Liu header.size = retval;
462494a8ebeSWei Liu header.type = T_CHOWN;
463494a8ebeSWei Liu }
464494a8ebeSWei Liu break;
465494a8ebeSWei Liu case T_TRUNCATE:
466494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
467494a8ebeSWei Liu offset = va_arg(ap, uint64_t);
468494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset);
469494a8ebeSWei Liu if (retval > 0) {
470494a8ebeSWei Liu header.size = retval;
471494a8ebeSWei Liu header.type = T_TRUNCATE;
472494a8ebeSWei Liu }
473494a8ebeSWei Liu break;
474494a8ebeSWei Liu case T_UTIME:
475494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
476494a8ebeSWei Liu spec[0].tv_sec = va_arg(ap, long);
477494a8ebeSWei Liu spec[0].tv_nsec = va_arg(ap, long);
478494a8ebeSWei Liu spec[1].tv_sec = va_arg(ap, long);
479494a8ebeSWei Liu spec[1].tv_nsec = va_arg(ap, long);
480494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path,
481494a8ebeSWei Liu spec[0].tv_sec, spec[1].tv_nsec,
482494a8ebeSWei Liu spec[1].tv_sec, spec[1].tv_nsec);
483494a8ebeSWei Liu if (retval > 0) {
484494a8ebeSWei Liu header.size = retval;
485494a8ebeSWei Liu header.type = T_UTIME;
486494a8ebeSWei Liu }
487494a8ebeSWei Liu break;
488494a8ebeSWei Liu case T_RENAME:
489494a8ebeSWei Liu oldpath = va_arg(ap, V9fsString *);
490494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
491494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path);
492494a8ebeSWei Liu if (retval > 0) {
493494a8ebeSWei Liu header.size = retval;
494494a8ebeSWei Liu header.type = T_RENAME;
495494a8ebeSWei Liu }
496494a8ebeSWei Liu break;
497494a8ebeSWei Liu case T_REMOVE:
498494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
499494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
500494a8ebeSWei Liu if (retval > 0) {
501494a8ebeSWei Liu header.size = retval;
502494a8ebeSWei Liu header.type = T_REMOVE;
503494a8ebeSWei Liu }
504494a8ebeSWei Liu break;
505494a8ebeSWei Liu case T_LGETXATTR:
506494a8ebeSWei Liu size = va_arg(ap, int);
507494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
508494a8ebeSWei Liu name = va_arg(ap, V9fsString *);
509494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ,
510494a8ebeSWei Liu "dss", size, path, name);
511494a8ebeSWei Liu if (retval > 0) {
512494a8ebeSWei Liu header.size = retval;
513494a8ebeSWei Liu header.type = T_LGETXATTR;
514494a8ebeSWei Liu }
515494a8ebeSWei Liu break;
516494a8ebeSWei Liu case T_LLISTXATTR:
517494a8ebeSWei Liu size = va_arg(ap, int);
518494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
519494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path);
520494a8ebeSWei Liu if (retval > 0) {
521494a8ebeSWei Liu header.size = retval;
522494a8ebeSWei Liu header.type = T_LLISTXATTR;
523494a8ebeSWei Liu }
524494a8ebeSWei Liu break;
525494a8ebeSWei Liu case T_LSETXATTR:
526494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
527494a8ebeSWei Liu name = va_arg(ap, V9fsString *);
528494a8ebeSWei Liu value = va_arg(ap, V9fsString *);
529494a8ebeSWei Liu size = va_arg(ap, int);
530494a8ebeSWei Liu flags = va_arg(ap, int);
531494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd",
532494a8ebeSWei Liu path, name, value, size, flags);
533494a8ebeSWei Liu if (retval > 0) {
534494a8ebeSWei Liu header.size = retval;
535494a8ebeSWei Liu header.type = T_LSETXATTR;
536494a8ebeSWei Liu }
537494a8ebeSWei Liu break;
538494a8ebeSWei Liu case T_LREMOVEXATTR:
539494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
540494a8ebeSWei Liu name = va_arg(ap, V9fsString *);
541494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name);
542494a8ebeSWei Liu if (retval > 0) {
543494a8ebeSWei Liu header.size = retval;
544494a8ebeSWei Liu header.type = T_LREMOVEXATTR;
545494a8ebeSWei Liu }
546494a8ebeSWei Liu break;
547494a8ebeSWei Liu case T_GETVERSION:
548494a8ebeSWei Liu path = va_arg(ap, V9fsString *);
549494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
550494a8ebeSWei Liu if (retval > 0) {
551494a8ebeSWei Liu header.size = retval;
552494a8ebeSWei Liu header.type = T_GETVERSION;
553494a8ebeSWei Liu }
554494a8ebeSWei Liu break;
555494a8ebeSWei Liu default:
556494a8ebeSWei Liu error_report("Invalid type %d", type);
557494a8ebeSWei Liu retval = -EINVAL;
558494a8ebeSWei Liu break;
559494a8ebeSWei Liu }
560494a8ebeSWei Liu va_end(ap);
561494a8ebeSWei Liu
562494a8ebeSWei Liu if (retval < 0) {
563494a8ebeSWei Liu goto err_out;
564494a8ebeSWei Liu }
565494a8ebeSWei Liu
566494a8ebeSWei Liu /* marshal the header details */
567acef3f8bSGreg Kurz retval = proxy_marshal(iovec, 0, "dd", header.type, header.size);
568acef3f8bSGreg Kurz assert(retval == 4 * 2);
569494a8ebeSWei Liu header.size += PROXY_HDR_SZ;
570494a8ebeSWei Liu
571494a8ebeSWei Liu retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size);
572494a8ebeSWei Liu if (retval != header.size) {
573494a8ebeSWei Liu goto close_error;
574494a8ebeSWei Liu }
575494a8ebeSWei Liu
576494a8ebeSWei Liu switch (type) {
577494a8ebeSWei Liu case T_OPEN:
578494a8ebeSWei Liu case T_CREATE:
579494a8ebeSWei Liu /*
580494a8ebeSWei Liu * A file descriptor is returned as response for
581494a8ebeSWei Liu * T_OPEN,T_CREATE on success
582494a8ebeSWei Liu */
583494a8ebeSWei Liu if (v9fs_receivefd(proxy->sockfd, &retval) < 0) {
584494a8ebeSWei Liu goto close_error;
585494a8ebeSWei Liu }
586494a8ebeSWei Liu break;
587494a8ebeSWei Liu case T_MKNOD:
588494a8ebeSWei Liu case T_MKDIR:
589494a8ebeSWei Liu case T_SYMLINK:
590494a8ebeSWei Liu case T_LINK:
591494a8ebeSWei Liu case T_CHMOD:
592494a8ebeSWei Liu case T_CHOWN:
593494a8ebeSWei Liu case T_RENAME:
594494a8ebeSWei Liu case T_TRUNCATE:
595494a8ebeSWei Liu case T_UTIME:
596494a8ebeSWei Liu case T_REMOVE:
597494a8ebeSWei Liu case T_LSETXATTR:
598494a8ebeSWei Liu case T_LREMOVEXATTR:
599494a8ebeSWei Liu if (v9fs_receive_status(proxy, reply, &retval) < 0) {
600494a8ebeSWei Liu goto close_error;
601494a8ebeSWei Liu }
602494a8ebeSWei Liu break;
603494a8ebeSWei Liu case T_LSTAT:
604494a8ebeSWei Liu case T_READLINK:
605494a8ebeSWei Liu case T_STATFS:
606494a8ebeSWei Liu case T_GETVERSION:
607494a8ebeSWei Liu if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
608494a8ebeSWei Liu goto close_error;
609494a8ebeSWei Liu }
610494a8ebeSWei Liu break;
611494a8ebeSWei Liu case T_LGETXATTR:
612494a8ebeSWei Liu case T_LLISTXATTR:
613494a8ebeSWei Liu if (!size) {
614494a8ebeSWei Liu if (v9fs_receive_status(proxy, reply, &retval) < 0) {
615494a8ebeSWei Liu goto close_error;
616494a8ebeSWei Liu }
617494a8ebeSWei Liu } else {
618494a8ebeSWei Liu if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
619494a8ebeSWei Liu goto close_error;
620494a8ebeSWei Liu }
621494a8ebeSWei Liu }
622494a8ebeSWei Liu break;
623494a8ebeSWei Liu }
624494a8ebeSWei Liu
625494a8ebeSWei Liu err_out:
626494a8ebeSWei Liu qemu_mutex_unlock(&proxy->mutex);
627494a8ebeSWei Liu return retval;
628494a8ebeSWei Liu
629494a8ebeSWei Liu close_error:
630494a8ebeSWei Liu close(proxy->sockfd);
631494a8ebeSWei Liu proxy->sockfd = -1;
632494a8ebeSWei Liu qemu_mutex_unlock(&proxy->mutex);
633494a8ebeSWei Liu return -EIO;
634494a8ebeSWei Liu }
635494a8ebeSWei Liu
proxy_lstat(FsContext * fs_ctx,V9fsPath * fs_path,struct stat * stbuf)636494a8ebeSWei Liu static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
637494a8ebeSWei Liu {
638494a8ebeSWei Liu int retval;
639799fe087SGreg Kurz retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path);
640494a8ebeSWei Liu if (retval < 0) {
641494a8ebeSWei Liu errno = -retval;
642494a8ebeSWei Liu return -1;
643494a8ebeSWei Liu }
644494a8ebeSWei Liu return retval;
645494a8ebeSWei Liu }
646494a8ebeSWei Liu
proxy_readlink(FsContext * fs_ctx,V9fsPath * fs_path,char * buf,size_t bufsz)647494a8ebeSWei Liu static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
648494a8ebeSWei Liu char *buf, size_t bufsz)
649494a8ebeSWei Liu {
650494a8ebeSWei Liu int retval;
651799fe087SGreg Kurz retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz);
652494a8ebeSWei Liu if (retval < 0) {
653494a8ebeSWei Liu errno = -retval;
654494a8ebeSWei Liu return -1;
655494a8ebeSWei Liu }
656494a8ebeSWei Liu return strlen(buf);
657494a8ebeSWei Liu }
658494a8ebeSWei Liu
proxy_close(FsContext * ctx,V9fsFidOpenState * fs)659494a8ebeSWei Liu static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs)
660494a8ebeSWei Liu {
661494a8ebeSWei Liu return close(fs->fd);
662494a8ebeSWei Liu }
663494a8ebeSWei Liu
proxy_closedir(FsContext * ctx,V9fsFidOpenState * fs)664494a8ebeSWei Liu static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
665494a8ebeSWei Liu {
666f314ea4eSGreg Kurz return closedir(fs->dir.stream);
667494a8ebeSWei Liu }
668494a8ebeSWei Liu
proxy_open(FsContext * ctx,V9fsPath * fs_path,int flags,V9fsFidOpenState * fs)669494a8ebeSWei Liu static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
670494a8ebeSWei Liu int flags, V9fsFidOpenState *fs)
671494a8ebeSWei Liu {
672799fe087SGreg Kurz fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags);
673494a8ebeSWei Liu if (fs->fd < 0) {
674494a8ebeSWei Liu errno = -fs->fd;
675494a8ebeSWei Liu fs->fd = -1;
676494a8ebeSWei Liu }
677494a8ebeSWei Liu return fs->fd;
678494a8ebeSWei Liu }
679494a8ebeSWei Liu
proxy_opendir(FsContext * ctx,V9fsPath * fs_path,V9fsFidOpenState * fs)680494a8ebeSWei Liu static int proxy_opendir(FsContext *ctx,
681494a8ebeSWei Liu V9fsPath *fs_path, V9fsFidOpenState *fs)
682494a8ebeSWei Liu {
683494a8ebeSWei Liu int serrno, fd;
684494a8ebeSWei Liu
685f314ea4eSGreg Kurz fs->dir.stream = NULL;
686799fe087SGreg Kurz fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY);
687494a8ebeSWei Liu if (fd < 0) {
688494a8ebeSWei Liu errno = -fd;
689494a8ebeSWei Liu return -1;
690494a8ebeSWei Liu }
691f314ea4eSGreg Kurz fs->dir.stream = fdopendir(fd);
692f314ea4eSGreg Kurz if (!fs->dir.stream) {
693494a8ebeSWei Liu serrno = errno;
694494a8ebeSWei Liu close(fd);
695494a8ebeSWei Liu errno = serrno;
696494a8ebeSWei Liu return -1;
697494a8ebeSWei Liu }
698494a8ebeSWei Liu return 0;
699494a8ebeSWei Liu }
700494a8ebeSWei Liu
proxy_rewinddir(FsContext * ctx,V9fsFidOpenState * fs)701494a8ebeSWei Liu static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
702494a8ebeSWei Liu {
703f314ea4eSGreg Kurz rewinddir(fs->dir.stream);
704494a8ebeSWei Liu }
705494a8ebeSWei Liu
proxy_telldir(FsContext * ctx,V9fsFidOpenState * fs)706494a8ebeSWei Liu static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
707494a8ebeSWei Liu {
708f314ea4eSGreg Kurz return telldir(fs->dir.stream);
709494a8ebeSWei Liu }
710494a8ebeSWei Liu
proxy_readdir(FsContext * ctx,V9fsFidOpenState * fs)711635324e8SGreg Kurz static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs)
712494a8ebeSWei Liu {
7136b3b279bSKeno Fischer struct dirent *entry;
7146b3b279bSKeno Fischer entry = readdir(fs->dir.stream);
7156b3b279bSKeno Fischer #ifdef CONFIG_DARWIN
7166b3b279bSKeno Fischer if (!entry) {
7176b3b279bSKeno Fischer return NULL;
7186b3b279bSKeno Fischer }
7196b3b279bSKeno Fischer int td;
7206b3b279bSKeno Fischer td = telldir(fs->dir.stream);
7216b3b279bSKeno Fischer /* If telldir fails, fail the entire readdir call */
7226b3b279bSKeno Fischer if (td < 0) {
7236b3b279bSKeno Fischer return NULL;
7246b3b279bSKeno Fischer }
7256b3b279bSKeno Fischer entry->d_seekoff = td;
7266b3b279bSKeno Fischer #endif
7276b3b279bSKeno Fischer return entry;
728494a8ebeSWei Liu }
729494a8ebeSWei Liu
proxy_seekdir(FsContext * ctx,V9fsFidOpenState * fs,off_t off)730494a8ebeSWei Liu static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
731494a8ebeSWei Liu {
732f314ea4eSGreg Kurz seekdir(fs->dir.stream, off);
733494a8ebeSWei Liu }
734494a8ebeSWei Liu
proxy_preadv(FsContext * ctx,V9fsFidOpenState * fs,const struct iovec * iov,int iovcnt,off_t offset)735494a8ebeSWei Liu static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
736494a8ebeSWei Liu const struct iovec *iov,
737494a8ebeSWei Liu int iovcnt, off_t offset)
738494a8ebeSWei Liu {
739494a8ebeSWei Liu ssize_t ret;
740494a8ebeSWei Liu #ifdef CONFIG_PREADV
741494a8ebeSWei Liu ret = preadv(fs->fd, iov, iovcnt, offset);
742494a8ebeSWei Liu #else
743494a8ebeSWei Liu ret = lseek(fs->fd, offset, SEEK_SET);
744494a8ebeSWei Liu if (ret >= 0) {
745494a8ebeSWei Liu ret = readv(fs->fd, iov, iovcnt);
746494a8ebeSWei Liu }
747494a8ebeSWei Liu #endif
748494a8ebeSWei Liu return ret;
749494a8ebeSWei Liu }
750494a8ebeSWei Liu
proxy_pwritev(FsContext * ctx,V9fsFidOpenState * fs,const struct iovec * iov,int iovcnt,off_t offset)751494a8ebeSWei Liu static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
752494a8ebeSWei Liu const struct iovec *iov,
753494a8ebeSWei Liu int iovcnt, off_t offset)
754494a8ebeSWei Liu {
755494a8ebeSWei Liu ssize_t ret;
756494a8ebeSWei Liu
757494a8ebeSWei Liu #ifdef CONFIG_PREADV
758494a8ebeSWei Liu ret = pwritev(fs->fd, iov, iovcnt, offset);
759494a8ebeSWei Liu #else
760494a8ebeSWei Liu ret = lseek(fs->fd, offset, SEEK_SET);
761494a8ebeSWei Liu if (ret >= 0) {
762494a8ebeSWei Liu ret = writev(fs->fd, iov, iovcnt);
763494a8ebeSWei Liu }
764494a8ebeSWei Liu #endif
765494a8ebeSWei Liu #ifdef CONFIG_SYNC_FILE_RANGE
766494a8ebeSWei Liu if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
767494a8ebeSWei Liu /*
768494a8ebeSWei Liu * Initiate a writeback. This is not a data integrity sync.
769494a8ebeSWei Liu * We want to ensure that we don't leave dirty pages in the cache
770*28cbbdd2SMichael Tokarev * after write when writeout=immediate is specified.
771494a8ebeSWei Liu */
772494a8ebeSWei Liu sync_file_range(fs->fd, offset, ret,
773494a8ebeSWei Liu SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
774494a8ebeSWei Liu }
775494a8ebeSWei Liu #endif
776494a8ebeSWei Liu return ret;
777494a8ebeSWei Liu }
778494a8ebeSWei Liu
proxy_chmod(FsContext * fs_ctx,V9fsPath * fs_path,FsCred * credp)779494a8ebeSWei Liu static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
780494a8ebeSWei Liu {
781494a8ebeSWei Liu int retval;
782799fe087SGreg Kurz retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path,
783799fe087SGreg Kurz credp->fc_mode);
784494a8ebeSWei Liu if (retval < 0) {
785494a8ebeSWei Liu errno = -retval;
786494a8ebeSWei Liu }
787494a8ebeSWei Liu return retval;
788494a8ebeSWei Liu }
789494a8ebeSWei Liu
proxy_mknod(FsContext * fs_ctx,V9fsPath * dir_path,const char * name,FsCred * credp)790494a8ebeSWei Liu static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
791494a8ebeSWei Liu const char *name, FsCred *credp)
792494a8ebeSWei Liu {
793494a8ebeSWei Liu int retval;
794494a8ebeSWei Liu V9fsString fullname;
795494a8ebeSWei Liu
796494a8ebeSWei Liu v9fs_string_init(&fullname);
797494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
798494a8ebeSWei Liu
799799fe087SGreg Kurz retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname,
800799fe087SGreg Kurz credp->fc_mode, credp->fc_rdev,
801494a8ebeSWei Liu credp->fc_uid, credp->fc_gid);
802494a8ebeSWei Liu v9fs_string_free(&fullname);
803494a8ebeSWei Liu if (retval < 0) {
804494a8ebeSWei Liu errno = -retval;
805494a8ebeSWei Liu retval = -1;
806494a8ebeSWei Liu }
807494a8ebeSWei Liu return retval;
808494a8ebeSWei Liu }
809494a8ebeSWei Liu
proxy_mkdir(FsContext * fs_ctx,V9fsPath * dir_path,const char * name,FsCred * credp)810494a8ebeSWei Liu static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
811494a8ebeSWei Liu const char *name, FsCred *credp)
812494a8ebeSWei Liu {
813494a8ebeSWei Liu int retval;
814494a8ebeSWei Liu V9fsString fullname;
815494a8ebeSWei Liu
816494a8ebeSWei Liu v9fs_string_init(&fullname);
817494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
818494a8ebeSWei Liu
819799fe087SGreg Kurz retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname,
820494a8ebeSWei Liu credp->fc_mode, credp->fc_uid, credp->fc_gid);
821494a8ebeSWei Liu v9fs_string_free(&fullname);
822494a8ebeSWei Liu if (retval < 0) {
823494a8ebeSWei Liu errno = -retval;
824494a8ebeSWei Liu retval = -1;
825494a8ebeSWei Liu }
826494a8ebeSWei Liu return retval;
827494a8ebeSWei Liu }
828494a8ebeSWei Liu
proxy_fstat(FsContext * fs_ctx,int fid_type,V9fsFidOpenState * fs,struct stat * stbuf)829494a8ebeSWei Liu static int proxy_fstat(FsContext *fs_ctx, int fid_type,
830494a8ebeSWei Liu V9fsFidOpenState *fs, struct stat *stbuf)
831494a8ebeSWei Liu {
832494a8ebeSWei Liu int fd;
833494a8ebeSWei Liu
834494a8ebeSWei Liu if (fid_type == P9_FID_DIR) {
835f314ea4eSGreg Kurz fd = dirfd(fs->dir.stream);
836494a8ebeSWei Liu } else {
837494a8ebeSWei Liu fd = fs->fd;
838494a8ebeSWei Liu }
839494a8ebeSWei Liu return fstat(fd, stbuf);
840494a8ebeSWei Liu }
841494a8ebeSWei Liu
proxy_open2(FsContext * fs_ctx,V9fsPath * dir_path,const char * name,int flags,FsCred * credp,V9fsFidOpenState * fs)842494a8ebeSWei Liu static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
843494a8ebeSWei Liu int flags, FsCred *credp, V9fsFidOpenState *fs)
844494a8ebeSWei Liu {
845494a8ebeSWei Liu V9fsString fullname;
846494a8ebeSWei Liu
847494a8ebeSWei Liu v9fs_string_init(&fullname);
848494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
849494a8ebeSWei Liu
850799fe087SGreg Kurz fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags,
851799fe087SGreg Kurz credp->fc_mode, credp->fc_uid, credp->fc_gid);
852494a8ebeSWei Liu v9fs_string_free(&fullname);
853494a8ebeSWei Liu if (fs->fd < 0) {
854494a8ebeSWei Liu errno = -fs->fd;
855494a8ebeSWei Liu fs->fd = -1;
856494a8ebeSWei Liu }
857494a8ebeSWei Liu return fs->fd;
858494a8ebeSWei Liu }
859494a8ebeSWei Liu
proxy_symlink(FsContext * fs_ctx,const char * oldpath,V9fsPath * dir_path,const char * name,FsCred * credp)860494a8ebeSWei Liu static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
861494a8ebeSWei Liu V9fsPath *dir_path, const char *name, FsCred *credp)
862494a8ebeSWei Liu {
863494a8ebeSWei Liu int retval;
864494a8ebeSWei Liu V9fsString fullname, target;
865494a8ebeSWei Liu
866494a8ebeSWei Liu v9fs_string_init(&fullname);
867494a8ebeSWei Liu v9fs_string_init(&target);
868494a8ebeSWei Liu
869494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
870494a8ebeSWei Liu v9fs_string_sprintf(&target, "%s", oldpath);
871494a8ebeSWei Liu
872799fe087SGreg Kurz retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname,
873799fe087SGreg Kurz credp->fc_uid, credp->fc_gid);
874494a8ebeSWei Liu v9fs_string_free(&fullname);
875494a8ebeSWei Liu v9fs_string_free(&target);
876494a8ebeSWei Liu if (retval < 0) {
877494a8ebeSWei Liu errno = -retval;
878494a8ebeSWei Liu retval = -1;
879494a8ebeSWei Liu }
880494a8ebeSWei Liu return retval;
881494a8ebeSWei Liu }
882494a8ebeSWei Liu
proxy_link(FsContext * ctx,V9fsPath * oldpath,V9fsPath * dirpath,const char * name)883494a8ebeSWei Liu static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
884494a8ebeSWei Liu V9fsPath *dirpath, const char *name)
885494a8ebeSWei Liu {
886494a8ebeSWei Liu int retval;
887494a8ebeSWei Liu V9fsString newpath;
888494a8ebeSWei Liu
889494a8ebeSWei Liu v9fs_string_init(&newpath);
890494a8ebeSWei Liu v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
891494a8ebeSWei Liu
892799fe087SGreg Kurz retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath);
893494a8ebeSWei Liu v9fs_string_free(&newpath);
894494a8ebeSWei Liu if (retval < 0) {
895494a8ebeSWei Liu errno = -retval;
896494a8ebeSWei Liu retval = -1;
897494a8ebeSWei Liu }
898494a8ebeSWei Liu return retval;
899494a8ebeSWei Liu }
900494a8ebeSWei Liu
proxy_truncate(FsContext * ctx,V9fsPath * fs_path,off_t size)901494a8ebeSWei Liu static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
902494a8ebeSWei Liu {
903494a8ebeSWei Liu int retval;
904494a8ebeSWei Liu
905799fe087SGreg Kurz retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size);
906494a8ebeSWei Liu if (retval < 0) {
907494a8ebeSWei Liu errno = -retval;
908494a8ebeSWei Liu return -1;
909494a8ebeSWei Liu }
910494a8ebeSWei Liu return 0;
911494a8ebeSWei Liu }
912494a8ebeSWei Liu
proxy_rename(FsContext * ctx,const char * oldpath,const char * newpath)913494a8ebeSWei Liu static int proxy_rename(FsContext *ctx, const char *oldpath,
914494a8ebeSWei Liu const char *newpath)
915494a8ebeSWei Liu {
916494a8ebeSWei Liu int retval;
917494a8ebeSWei Liu V9fsString oldname, newname;
918494a8ebeSWei Liu
919494a8ebeSWei Liu v9fs_string_init(&oldname);
920494a8ebeSWei Liu v9fs_string_init(&newname);
921494a8ebeSWei Liu
922494a8ebeSWei Liu v9fs_string_sprintf(&oldname, "%s", oldpath);
923494a8ebeSWei Liu v9fs_string_sprintf(&newname, "%s", newpath);
924799fe087SGreg Kurz retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname);
925494a8ebeSWei Liu v9fs_string_free(&oldname);
926494a8ebeSWei Liu v9fs_string_free(&newname);
927494a8ebeSWei Liu if (retval < 0) {
928494a8ebeSWei Liu errno = -retval;
929494a8ebeSWei Liu }
930494a8ebeSWei Liu return retval;
931494a8ebeSWei Liu }
932494a8ebeSWei Liu
proxy_chown(FsContext * fs_ctx,V9fsPath * fs_path,FsCred * credp)933494a8ebeSWei Liu static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
934494a8ebeSWei Liu {
935494a8ebeSWei Liu int retval;
936799fe087SGreg Kurz retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path,
937799fe087SGreg Kurz credp->fc_uid, credp->fc_gid);
938494a8ebeSWei Liu if (retval < 0) {
939494a8ebeSWei Liu errno = -retval;
940494a8ebeSWei Liu }
941494a8ebeSWei Liu return retval;
942494a8ebeSWei Liu }
943494a8ebeSWei Liu
proxy_utimensat(FsContext * s,V9fsPath * fs_path,const struct timespec * buf)944494a8ebeSWei Liu static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
945494a8ebeSWei Liu const struct timespec *buf)
946494a8ebeSWei Liu {
947494a8ebeSWei Liu int retval;
948799fe087SGreg Kurz retval = v9fs_request(s->private, T_UTIME, NULL, fs_path,
949494a8ebeSWei Liu buf[0].tv_sec, buf[0].tv_nsec,
950494a8ebeSWei Liu buf[1].tv_sec, buf[1].tv_nsec);
951494a8ebeSWei Liu if (retval < 0) {
952494a8ebeSWei Liu errno = -retval;
953494a8ebeSWei Liu }
954494a8ebeSWei Liu return retval;
955494a8ebeSWei Liu }
956494a8ebeSWei Liu
proxy_remove(FsContext * ctx,const char * path)957494a8ebeSWei Liu static int proxy_remove(FsContext *ctx, const char *path)
958494a8ebeSWei Liu {
959494a8ebeSWei Liu int retval;
960494a8ebeSWei Liu V9fsString name;
961494a8ebeSWei Liu v9fs_string_init(&name);
962494a8ebeSWei Liu v9fs_string_sprintf(&name, "%s", path);
963799fe087SGreg Kurz retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name);
964494a8ebeSWei Liu v9fs_string_free(&name);
965494a8ebeSWei Liu if (retval < 0) {
966494a8ebeSWei Liu errno = -retval;
967494a8ebeSWei Liu }
968494a8ebeSWei Liu return retval;
969494a8ebeSWei Liu }
970494a8ebeSWei Liu
proxy_fsync(FsContext * ctx,int fid_type,V9fsFidOpenState * fs,int datasync)971494a8ebeSWei Liu static int proxy_fsync(FsContext *ctx, int fid_type,
972494a8ebeSWei Liu V9fsFidOpenState *fs, int datasync)
973494a8ebeSWei Liu {
974494a8ebeSWei Liu int fd;
975494a8ebeSWei Liu
976494a8ebeSWei Liu if (fid_type == P9_FID_DIR) {
977f314ea4eSGreg Kurz fd = dirfd(fs->dir.stream);
978494a8ebeSWei Liu } else {
979494a8ebeSWei Liu fd = fs->fd;
980494a8ebeSWei Liu }
981494a8ebeSWei Liu
982494a8ebeSWei Liu if (datasync) {
983494a8ebeSWei Liu return qemu_fdatasync(fd);
984494a8ebeSWei Liu } else {
985494a8ebeSWei Liu return fsync(fd);
986494a8ebeSWei Liu }
987494a8ebeSWei Liu }
988494a8ebeSWei Liu
proxy_statfs(FsContext * s,V9fsPath * fs_path,struct statfs * stbuf)989494a8ebeSWei Liu static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
990494a8ebeSWei Liu {
991494a8ebeSWei Liu int retval;
992799fe087SGreg Kurz retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path);
993494a8ebeSWei Liu if (retval < 0) {
994494a8ebeSWei Liu errno = -retval;
995494a8ebeSWei Liu return -1;
996494a8ebeSWei Liu }
997494a8ebeSWei Liu return retval;
998494a8ebeSWei Liu }
999494a8ebeSWei Liu
proxy_lgetxattr(FsContext * ctx,V9fsPath * fs_path,const char * name,void * value,size_t size)1000494a8ebeSWei Liu static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
1001494a8ebeSWei Liu const char *name, void *value, size_t size)
1002494a8ebeSWei Liu {
1003494a8ebeSWei Liu int retval;
1004494a8ebeSWei Liu V9fsString xname;
1005494a8ebeSWei Liu
1006494a8ebeSWei Liu v9fs_string_init(&xname);
1007494a8ebeSWei Liu v9fs_string_sprintf(&xname, "%s", name);
1008799fe087SGreg Kurz retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path,
1009799fe087SGreg Kurz &xname);
1010494a8ebeSWei Liu v9fs_string_free(&xname);
1011494a8ebeSWei Liu if (retval < 0) {
1012494a8ebeSWei Liu errno = -retval;
1013494a8ebeSWei Liu }
1014494a8ebeSWei Liu return retval;
1015494a8ebeSWei Liu }
1016494a8ebeSWei Liu
proxy_llistxattr(FsContext * ctx,V9fsPath * fs_path,void * value,size_t size)1017494a8ebeSWei Liu static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
1018494a8ebeSWei Liu void *value, size_t size)
1019494a8ebeSWei Liu {
1020494a8ebeSWei Liu int retval;
1021799fe087SGreg Kurz retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path);
1022494a8ebeSWei Liu if (retval < 0) {
1023494a8ebeSWei Liu errno = -retval;
1024494a8ebeSWei Liu }
1025494a8ebeSWei Liu return retval;
1026494a8ebeSWei Liu }
1027494a8ebeSWei Liu
proxy_lsetxattr(FsContext * ctx,V9fsPath * fs_path,const char * name,void * value,size_t size,int flags)1028494a8ebeSWei Liu static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
1029494a8ebeSWei Liu void *value, size_t size, int flags)
1030494a8ebeSWei Liu {
1031494a8ebeSWei Liu int retval;
1032494a8ebeSWei Liu V9fsString xname, xvalue;
1033494a8ebeSWei Liu
1034494a8ebeSWei Liu v9fs_string_init(&xname);
1035494a8ebeSWei Liu v9fs_string_sprintf(&xname, "%s", name);
1036494a8ebeSWei Liu
1037494a8ebeSWei Liu v9fs_string_init(&xvalue);
1038494a8ebeSWei Liu xvalue.size = size;
1039494a8ebeSWei Liu xvalue.data = g_malloc(size);
1040494a8ebeSWei Liu memcpy(xvalue.data, value, size);
1041494a8ebeSWei Liu
1042799fe087SGreg Kurz retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname,
1043799fe087SGreg Kurz &xvalue, size, flags);
1044494a8ebeSWei Liu v9fs_string_free(&xname);
1045494a8ebeSWei Liu v9fs_string_free(&xvalue);
1046494a8ebeSWei Liu if (retval < 0) {
1047494a8ebeSWei Liu errno = -retval;
1048494a8ebeSWei Liu }
1049494a8ebeSWei Liu return retval;
1050494a8ebeSWei Liu }
1051494a8ebeSWei Liu
proxy_lremovexattr(FsContext * ctx,V9fsPath * fs_path,const char * name)1052494a8ebeSWei Liu static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
1053494a8ebeSWei Liu const char *name)
1054494a8ebeSWei Liu {
1055494a8ebeSWei Liu int retval;
1056494a8ebeSWei Liu V9fsString xname;
1057494a8ebeSWei Liu
1058494a8ebeSWei Liu v9fs_string_init(&xname);
1059494a8ebeSWei Liu v9fs_string_sprintf(&xname, "%s", name);
1060799fe087SGreg Kurz retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname);
1061494a8ebeSWei Liu v9fs_string_free(&xname);
1062494a8ebeSWei Liu if (retval < 0) {
1063494a8ebeSWei Liu errno = -retval;
1064494a8ebeSWei Liu }
1065494a8ebeSWei Liu return retval;
1066494a8ebeSWei Liu }
1067494a8ebeSWei Liu
proxy_name_to_path(FsContext * ctx,V9fsPath * dir_path,const char * name,V9fsPath * target)1068494a8ebeSWei Liu static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
1069494a8ebeSWei Liu const char *name, V9fsPath *target)
1070494a8ebeSWei Liu {
1071494a8ebeSWei Liu if (dir_path) {
1072e3e83f2eSGreg Kurz v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
1073494a8ebeSWei Liu } else {
1074e3e83f2eSGreg Kurz v9fs_path_sprintf(target, "%s", name);
1075494a8ebeSWei Liu }
1076494a8ebeSWei Liu return 0;
1077494a8ebeSWei Liu }
1078494a8ebeSWei Liu
proxy_renameat(FsContext * ctx,V9fsPath * olddir,const char * old_name,V9fsPath * newdir,const char * new_name)1079494a8ebeSWei Liu static int proxy_renameat(FsContext *ctx, V9fsPath *olddir,
1080494a8ebeSWei Liu const char *old_name, V9fsPath *newdir,
1081494a8ebeSWei Liu const char *new_name)
1082494a8ebeSWei Liu {
1083494a8ebeSWei Liu int ret;
1084494a8ebeSWei Liu V9fsString old_full_name, new_full_name;
1085494a8ebeSWei Liu
1086494a8ebeSWei Liu v9fs_string_init(&old_full_name);
1087494a8ebeSWei Liu v9fs_string_init(&new_full_name);
1088494a8ebeSWei Liu
1089494a8ebeSWei Liu v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
1090494a8ebeSWei Liu v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
1091494a8ebeSWei Liu
1092494a8ebeSWei Liu ret = proxy_rename(ctx, old_full_name.data, new_full_name.data);
1093494a8ebeSWei Liu v9fs_string_free(&old_full_name);
1094494a8ebeSWei Liu v9fs_string_free(&new_full_name);
1095494a8ebeSWei Liu return ret;
1096494a8ebeSWei Liu }
1097494a8ebeSWei Liu
proxy_unlinkat(FsContext * ctx,V9fsPath * dir,const char * name,int flags)1098494a8ebeSWei Liu static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir,
1099494a8ebeSWei Liu const char *name, int flags)
1100494a8ebeSWei Liu {
1101494a8ebeSWei Liu int ret;
1102494a8ebeSWei Liu V9fsString fullname;
1103494a8ebeSWei Liu v9fs_string_init(&fullname);
1104494a8ebeSWei Liu
1105494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
1106494a8ebeSWei Liu ret = proxy_remove(ctx, fullname.data);
1107494a8ebeSWei Liu v9fs_string_free(&fullname);
1108494a8ebeSWei Liu
1109494a8ebeSWei Liu return ret;
1110494a8ebeSWei Liu }
1111494a8ebeSWei Liu
proxy_ioc_getversion(FsContext * fs_ctx,V9fsPath * path,mode_t st_mode,uint64_t * st_gen)1112494a8ebeSWei Liu static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
1113494a8ebeSWei Liu mode_t st_mode, uint64_t *st_gen)
1114494a8ebeSWei Liu {
1115494a8ebeSWei Liu int err;
1116494a8ebeSWei Liu
1117494a8ebeSWei Liu /* Do not try to open special files like device nodes, fifos etc
1118494a8ebeSWei Liu * we can get fd for regular files and directories only
1119494a8ebeSWei Liu */
1120494a8ebeSWei Liu if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
1121494a8ebeSWei Liu errno = ENOTTY;
1122494a8ebeSWei Liu return -1;
1123494a8ebeSWei Liu }
1124799fe087SGreg Kurz err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path);
1125494a8ebeSWei Liu if (err < 0) {
1126494a8ebeSWei Liu errno = -err;
1127494a8ebeSWei Liu err = -1;
1128494a8ebeSWei Liu }
1129494a8ebeSWei Liu return err;
1130494a8ebeSWei Liu }
1131494a8ebeSWei Liu
connect_namedsocket(const char * path,Error ** errp)113265603a80SGreg Kurz static int connect_namedsocket(const char *path, Error **errp)
1133494a8ebeSWei Liu {
1134fde1f3e4SKeno Fischer int sockfd;
1135494a8ebeSWei Liu struct sockaddr_un helper;
1136494a8ebeSWei Liu
1137494a8ebeSWei Liu if (strlen(path) >= sizeof(helper.sun_path)) {
113865603a80SGreg Kurz error_setg(errp, "socket name too long");
1139494a8ebeSWei Liu return -1;
1140494a8ebeSWei Liu }
1141494a8ebeSWei Liu sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1142494a8ebeSWei Liu if (sockfd < 0) {
114365603a80SGreg Kurz error_setg_errno(errp, errno, "failed to create client socket");
1144494a8ebeSWei Liu return -1;
1145494a8ebeSWei Liu }
1146494a8ebeSWei Liu strcpy(helper.sun_path, path);
1147494a8ebeSWei Liu helper.sun_family = AF_UNIX;
1148fde1f3e4SKeno Fischer if (connect(sockfd, (struct sockaddr *)&helper, sizeof(helper)) < 0) {
114965603a80SGreg Kurz error_setg_errno(errp, errno, "failed to connect to '%s'", path);
1150494a8ebeSWei Liu close(sockfd);
1151494a8ebeSWei Liu return -1;
1152494a8ebeSWei Liu }
1153494a8ebeSWei Liu
1154494a8ebeSWei Liu /* remove the socket for security reasons */
1155494a8ebeSWei Liu unlink(path);
1156494a8ebeSWei Liu return sockfd;
1157494a8ebeSWei Liu }
1158494a8ebeSWei Liu
error_append_socket_sockfd_hint(Error * const * errp)11594c5ec47eSVladimir Sementsov-Ogievskiy static void error_append_socket_sockfd_hint(Error *const *errp)
116091cda4e8SGreg Kurz {
116191cda4e8SGreg Kurz error_append_hint(errp, "Either specify socket=/some/path where /some/path"
116291cda4e8SGreg Kurz " points to a listening AF_UNIX socket or sock_fd=fd"
116391cda4e8SGreg Kurz " where fd is a file descriptor to a connected AF_UNIX"
116491cda4e8SGreg Kurz " socket\n");
116591cda4e8SGreg Kurz }
116691cda4e8SGreg Kurz
proxy_parse_opts(QemuOpts * opts,FsDriverEntry * fs,Error ** errp)116791cda4e8SGreg Kurz static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp)
1168494a8ebeSWei Liu {
1169494a8ebeSWei Liu const char *socket = qemu_opt_get(opts, "socket");
1170494a8ebeSWei Liu const char *sock_fd = qemu_opt_get(opts, "sock_fd");
1171494a8ebeSWei Liu
1172494a8ebeSWei Liu if (!socket && !sock_fd) {
117391cda4e8SGreg Kurz error_setg(errp, "both socket and sock_fd properties are missing");
117491cda4e8SGreg Kurz error_append_socket_sockfd_hint(errp);
1175494a8ebeSWei Liu return -1;
1176494a8ebeSWei Liu }
1177494a8ebeSWei Liu if (socket && sock_fd) {
117891cda4e8SGreg Kurz error_setg(errp, "both socket and sock_fd properties are set");
117991cda4e8SGreg Kurz error_append_socket_sockfd_hint(errp);
1180494a8ebeSWei Liu return -1;
1181494a8ebeSWei Liu }
1182494a8ebeSWei Liu if (socket) {
1183494a8ebeSWei Liu fs->path = g_strdup(socket);
1184659f1953SGreg Kurz fs->export_flags |= V9FS_PROXY_SOCK_NAME;
1185494a8ebeSWei Liu } else {
1186494a8ebeSWei Liu fs->path = g_strdup(sock_fd);
1187659f1953SGreg Kurz fs->export_flags |= V9FS_PROXY_SOCK_FD;
1188494a8ebeSWei Liu }
1189494a8ebeSWei Liu return 0;
1190494a8ebeSWei Liu }
1191494a8ebeSWei Liu
proxy_init(FsContext * ctx,Error ** errp)119265603a80SGreg Kurz static int proxy_init(FsContext *ctx, Error **errp)
1193494a8ebeSWei Liu {
11941366244aSMarkus Armbruster V9fsProxy *proxy = g_new(V9fsProxy, 1);
1195494a8ebeSWei Liu int sock_id;
1196494a8ebeSWei Liu
1197494a8ebeSWei Liu if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
119865603a80SGreg Kurz sock_id = connect_namedsocket(ctx->fs_root, errp);
1199494a8ebeSWei Liu } else {
1200494a8ebeSWei Liu sock_id = atoi(ctx->fs_root);
1201494a8ebeSWei Liu if (sock_id < 0) {
120265603a80SGreg Kurz error_setg(errp, "socket descriptor not initialized");
1203494a8ebeSWei Liu }
1204494a8ebeSWei Liu }
1205494a8ebeSWei Liu if (sock_id < 0) {
1206494a8ebeSWei Liu g_free(proxy);
1207494a8ebeSWei Liu return -1;
1208494a8ebeSWei Liu }
1209494a8ebeSWei Liu g_free(ctx->fs_root);
1210494a8ebeSWei Liu ctx->fs_root = NULL;
1211494a8ebeSWei Liu
1212494a8ebeSWei Liu proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
1213494a8ebeSWei Liu proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
1214494a8ebeSWei Liu proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
1215494a8ebeSWei Liu proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
1216494a8ebeSWei Liu
1217494a8ebeSWei Liu ctx->private = proxy;
1218494a8ebeSWei Liu proxy->sockfd = sock_id;
1219494a8ebeSWei Liu qemu_mutex_init(&proxy->mutex);
1220494a8ebeSWei Liu
1221494a8ebeSWei Liu ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
1222494a8ebeSWei Liu ctx->exops.get_st_gen = proxy_ioc_getversion;
1223494a8ebeSWei Liu return 0;
1224494a8ebeSWei Liu }
1225494a8ebeSWei Liu
proxy_cleanup(FsContext * ctx)1226898ae90aSLi Qiang static void proxy_cleanup(FsContext *ctx)
1227898ae90aSLi Qiang {
1228898ae90aSLi Qiang V9fsProxy *proxy = ctx->private;
1229898ae90aSLi Qiang
1230c0da0cb7SGreg Kurz if (!proxy) {
1231c0da0cb7SGreg Kurz return;
1232c0da0cb7SGreg Kurz }
1233c0da0cb7SGreg Kurz
1234898ae90aSLi Qiang g_free(proxy->out_iovec.iov_base);
1235898ae90aSLi Qiang g_free(proxy->in_iovec.iov_base);
1236898ae90aSLi Qiang if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
1237898ae90aSLi Qiang close(proxy->sockfd);
1238898ae90aSLi Qiang }
1239898ae90aSLi Qiang g_free(proxy);
1240898ae90aSLi Qiang }
1241898ae90aSLi Qiang
1242494a8ebeSWei Liu FileOperations proxy_ops = {
1243494a8ebeSWei Liu .parse_opts = proxy_parse_opts,
1244494a8ebeSWei Liu .init = proxy_init,
1245898ae90aSLi Qiang .cleanup = proxy_cleanup,
1246494a8ebeSWei Liu .lstat = proxy_lstat,
1247494a8ebeSWei Liu .readlink = proxy_readlink,
1248494a8ebeSWei Liu .close = proxy_close,
1249494a8ebeSWei Liu .closedir = proxy_closedir,
1250494a8ebeSWei Liu .open = proxy_open,
1251494a8ebeSWei Liu .opendir = proxy_opendir,
1252494a8ebeSWei Liu .rewinddir = proxy_rewinddir,
1253494a8ebeSWei Liu .telldir = proxy_telldir,
1254635324e8SGreg Kurz .readdir = proxy_readdir,
1255494a8ebeSWei Liu .seekdir = proxy_seekdir,
1256494a8ebeSWei Liu .preadv = proxy_preadv,
1257494a8ebeSWei Liu .pwritev = proxy_pwritev,
1258494a8ebeSWei Liu .chmod = proxy_chmod,
1259494a8ebeSWei Liu .mknod = proxy_mknod,
1260494a8ebeSWei Liu .mkdir = proxy_mkdir,
1261494a8ebeSWei Liu .fstat = proxy_fstat,
1262494a8ebeSWei Liu .open2 = proxy_open2,
1263494a8ebeSWei Liu .symlink = proxy_symlink,
1264494a8ebeSWei Liu .link = proxy_link,
1265494a8ebeSWei Liu .truncate = proxy_truncate,
1266494a8ebeSWei Liu .rename = proxy_rename,
1267494a8ebeSWei Liu .chown = proxy_chown,
1268494a8ebeSWei Liu .utimensat = proxy_utimensat,
1269494a8ebeSWei Liu .remove = proxy_remove,
1270494a8ebeSWei Liu .fsync = proxy_fsync,
1271494a8ebeSWei Liu .statfs = proxy_statfs,
1272494a8ebeSWei Liu .lgetxattr = proxy_lgetxattr,
1273494a8ebeSWei Liu .llistxattr = proxy_llistxattr,
1274494a8ebeSWei Liu .lsetxattr = proxy_lsetxattr,
1275494a8ebeSWei Liu .lremovexattr = proxy_lremovexattr,
1276494a8ebeSWei Liu .name_to_path = proxy_name_to_path,
1277494a8ebeSWei Liu .renameat = proxy_renameat,
1278494a8ebeSWei Liu .unlinkat = proxy_unlinkat,
1279494a8ebeSWei Liu };
1280