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 */ 12*fbc04127SPeter Maydell #include "qemu/osdep.h" 13494a8ebeSWei Liu #include <sys/socket.h> 14494a8ebeSWei Liu #include <sys/un.h> 15ebe74f8bSWei Liu #include "9p.h" 16494a8ebeSWei Liu #include "qemu/error-report.h" 17494a8ebeSWei Liu #include "fsdev/qemu-fsdev.h" 18494a8ebeSWei Liu #include "9p-proxy.h" 19494a8ebeSWei Liu 20494a8ebeSWei Liu typedef struct V9fsProxy { 21494a8ebeSWei Liu int sockfd; 22494a8ebeSWei Liu QemuMutex mutex; 23494a8ebeSWei Liu struct iovec in_iovec; 24494a8ebeSWei Liu struct iovec out_iovec; 25494a8ebeSWei Liu } V9fsProxy; 26494a8ebeSWei Liu 27494a8ebeSWei Liu /* 28494a8ebeSWei Liu * Return received file descriptor on success in *status. 29494a8ebeSWei Liu * errno is also returned on *status (which will be < 0) 30494a8ebeSWei Liu * return < 0 on transport error. 31494a8ebeSWei Liu */ 32494a8ebeSWei Liu static int v9fs_receivefd(int sockfd, int *status) 33494a8ebeSWei Liu { 34494a8ebeSWei Liu struct iovec iov; 35494a8ebeSWei Liu struct msghdr msg; 36494a8ebeSWei Liu struct cmsghdr *cmsg; 37494a8ebeSWei Liu int retval, data, fd; 38494a8ebeSWei Liu union MsgControl msg_control; 39494a8ebeSWei Liu 40494a8ebeSWei Liu iov.iov_base = &data; 41494a8ebeSWei Liu iov.iov_len = sizeof(data); 42494a8ebeSWei Liu 43494a8ebeSWei Liu memset(&msg, 0, sizeof(msg)); 44494a8ebeSWei Liu msg.msg_iov = &iov; 45494a8ebeSWei Liu msg.msg_iovlen = 1; 46494a8ebeSWei Liu msg.msg_control = &msg_control; 47494a8ebeSWei Liu msg.msg_controllen = sizeof(msg_control); 48494a8ebeSWei Liu 49494a8ebeSWei Liu do { 50494a8ebeSWei Liu retval = recvmsg(sockfd, &msg, 0); 51494a8ebeSWei Liu } while (retval < 0 && errno == EINTR); 52494a8ebeSWei Liu if (retval <= 0) { 53494a8ebeSWei Liu return retval; 54494a8ebeSWei Liu } 55494a8ebeSWei Liu /* 56494a8ebeSWei Liu * data is set to V9FS_FD_VALID, if ancillary data is sent. If this 57494a8ebeSWei Liu * request doesn't need ancillary data (fd) or an error occurred, 58494a8ebeSWei Liu * data is set to negative errno value. 59494a8ebeSWei Liu */ 60494a8ebeSWei Liu if (data != V9FS_FD_VALID) { 61494a8ebeSWei Liu *status = data; 62494a8ebeSWei Liu return 0; 63494a8ebeSWei Liu } 64494a8ebeSWei Liu /* 65494a8ebeSWei Liu * File descriptor (fd) is sent in the ancillary data. Check if we 66494a8ebeSWei Liu * indeed received it. One of the reasons to fail to receive it is if 67494a8ebeSWei Liu * we exceeded the maximum number of file descriptors! 68494a8ebeSWei Liu */ 69494a8ebeSWei Liu for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 70494a8ebeSWei Liu if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || 71494a8ebeSWei Liu cmsg->cmsg_level != SOL_SOCKET || 72494a8ebeSWei Liu cmsg->cmsg_type != SCM_RIGHTS) { 73494a8ebeSWei Liu continue; 74494a8ebeSWei Liu } 75494a8ebeSWei Liu fd = *((int *)CMSG_DATA(cmsg)); 76494a8ebeSWei Liu *status = fd; 77494a8ebeSWei Liu return 0; 78494a8ebeSWei Liu } 79494a8ebeSWei Liu *status = -ENFILE; /* Ancillary data sent but not received */ 80494a8ebeSWei Liu return 0; 81494a8ebeSWei Liu } 82494a8ebeSWei Liu 83494a8ebeSWei Liu static ssize_t socket_read(int sockfd, void *buff, size_t size) 84494a8ebeSWei Liu { 85494a8ebeSWei Liu ssize_t retval, total = 0; 86494a8ebeSWei Liu 87494a8ebeSWei Liu while (size) { 88494a8ebeSWei Liu retval = read(sockfd, buff, size); 89494a8ebeSWei Liu if (retval == 0) { 90494a8ebeSWei Liu return -EIO; 91494a8ebeSWei Liu } 92494a8ebeSWei Liu if (retval < 0) { 93494a8ebeSWei Liu if (errno == EINTR) { 94494a8ebeSWei Liu continue; 95494a8ebeSWei Liu } 96494a8ebeSWei Liu return -errno; 97494a8ebeSWei Liu } 98494a8ebeSWei Liu size -= retval; 99494a8ebeSWei Liu buff += retval; 100494a8ebeSWei Liu total += retval; 101494a8ebeSWei Liu } 102494a8ebeSWei Liu return total; 103494a8ebeSWei Liu } 104494a8ebeSWei Liu 105494a8ebeSWei Liu /* Converts proxy_statfs to VFS statfs structure */ 106494a8ebeSWei Liu static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs) 107494a8ebeSWei Liu { 108494a8ebeSWei Liu memset(stfs, 0, sizeof(*stfs)); 109494a8ebeSWei Liu stfs->f_type = prstfs->f_type; 110494a8ebeSWei Liu stfs->f_bsize = prstfs->f_bsize; 111494a8ebeSWei Liu stfs->f_blocks = prstfs->f_blocks; 112494a8ebeSWei Liu stfs->f_bfree = prstfs->f_bfree; 113494a8ebeSWei Liu stfs->f_bavail = prstfs->f_bavail; 114494a8ebeSWei Liu stfs->f_files = prstfs->f_files; 115494a8ebeSWei Liu stfs->f_ffree = prstfs->f_ffree; 116494a8ebeSWei Liu stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU; 117494a8ebeSWei Liu stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU; 118494a8ebeSWei Liu stfs->f_namelen = prstfs->f_namelen; 119494a8ebeSWei Liu stfs->f_frsize = prstfs->f_frsize; 120494a8ebeSWei Liu } 121494a8ebeSWei Liu 122494a8ebeSWei Liu /* Converts proxy_stat structure to VFS stat structure */ 123494a8ebeSWei Liu static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat) 124494a8ebeSWei Liu { 125494a8ebeSWei Liu memset(stbuf, 0, sizeof(*stbuf)); 126494a8ebeSWei Liu stbuf->st_dev = prstat->st_dev; 127494a8ebeSWei Liu stbuf->st_ino = prstat->st_ino; 128494a8ebeSWei Liu stbuf->st_nlink = prstat->st_nlink; 129494a8ebeSWei Liu stbuf->st_mode = prstat->st_mode; 130494a8ebeSWei Liu stbuf->st_uid = prstat->st_uid; 131494a8ebeSWei Liu stbuf->st_gid = prstat->st_gid; 132494a8ebeSWei Liu stbuf->st_rdev = prstat->st_rdev; 133494a8ebeSWei Liu stbuf->st_size = prstat->st_size; 134494a8ebeSWei Liu stbuf->st_blksize = prstat->st_blksize; 135494a8ebeSWei Liu stbuf->st_blocks = prstat->st_blocks; 136494a8ebeSWei Liu stbuf->st_atim.tv_sec = prstat->st_atim_sec; 137494a8ebeSWei Liu stbuf->st_atim.tv_nsec = prstat->st_atim_nsec; 138494a8ebeSWei Liu stbuf->st_mtime = prstat->st_mtim_sec; 139494a8ebeSWei Liu stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec; 140494a8ebeSWei Liu stbuf->st_ctime = prstat->st_ctim_sec; 141494a8ebeSWei Liu stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec; 142494a8ebeSWei Liu } 143494a8ebeSWei Liu 144494a8ebeSWei Liu /* 145494a8ebeSWei Liu * Response contains two parts 146494a8ebeSWei Liu * {header, data} 147494a8ebeSWei Liu * header.type == T_ERROR, data -> -errno 148494a8ebeSWei Liu * header.type == T_SUCCESS, data -> response 149494a8ebeSWei Liu * size of errno/response is given by header.size 150494a8ebeSWei Liu * returns < 0, on transport error. response is 151494a8ebeSWei Liu * valid only if status >= 0. 152494a8ebeSWei Liu */ 153494a8ebeSWei Liu static int v9fs_receive_response(V9fsProxy *proxy, int type, 154494a8ebeSWei Liu int *status, void *response) 155494a8ebeSWei Liu { 156494a8ebeSWei Liu int retval; 157494a8ebeSWei Liu ProxyHeader header; 158494a8ebeSWei Liu struct iovec *reply = &proxy->in_iovec; 159494a8ebeSWei Liu 160494a8ebeSWei Liu *status = 0; 161494a8ebeSWei Liu reply->iov_len = 0; 162494a8ebeSWei Liu retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); 163494a8ebeSWei Liu if (retval < 0) { 164494a8ebeSWei Liu return retval; 165494a8ebeSWei Liu } 166494a8ebeSWei Liu reply->iov_len = PROXY_HDR_SZ; 167494a8ebeSWei Liu proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); 168494a8ebeSWei Liu /* 169494a8ebeSWei Liu * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and 170494a8ebeSWei Liu * return -ENOBUFS 171494a8ebeSWei Liu */ 172494a8ebeSWei Liu if (header.size > PROXY_MAX_IO_SZ) { 173494a8ebeSWei Liu int count; 174494a8ebeSWei Liu while (header.size > 0) { 175494a8ebeSWei Liu count = MIN(PROXY_MAX_IO_SZ, header.size); 176494a8ebeSWei Liu count = socket_read(proxy->sockfd, reply->iov_base, count); 177494a8ebeSWei Liu if (count < 0) { 178494a8ebeSWei Liu return count; 179494a8ebeSWei Liu } 180494a8ebeSWei Liu header.size -= count; 181494a8ebeSWei Liu } 182494a8ebeSWei Liu *status = -ENOBUFS; 183494a8ebeSWei Liu return 0; 184494a8ebeSWei Liu } 185494a8ebeSWei Liu 186494a8ebeSWei Liu retval = socket_read(proxy->sockfd, 187494a8ebeSWei Liu reply->iov_base + PROXY_HDR_SZ, header.size); 188494a8ebeSWei Liu if (retval < 0) { 189494a8ebeSWei Liu return retval; 190494a8ebeSWei Liu } 191494a8ebeSWei Liu reply->iov_len += header.size; 192494a8ebeSWei Liu /* there was an error during processing request */ 193494a8ebeSWei Liu if (header.type == T_ERROR) { 194494a8ebeSWei Liu int ret; 195494a8ebeSWei Liu ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status); 196494a8ebeSWei Liu if (ret < 0) { 197494a8ebeSWei Liu *status = ret; 198494a8ebeSWei Liu } 199494a8ebeSWei Liu return 0; 200494a8ebeSWei Liu } 201494a8ebeSWei Liu 202494a8ebeSWei Liu switch (type) { 203494a8ebeSWei Liu case T_LSTAT: { 204494a8ebeSWei Liu ProxyStat prstat; 205494a8ebeSWei Liu retval = proxy_unmarshal(reply, PROXY_HDR_SZ, 206494a8ebeSWei Liu "qqqdddqqqqqqqqqq", &prstat.st_dev, 207494a8ebeSWei Liu &prstat.st_ino, &prstat.st_nlink, 208494a8ebeSWei Liu &prstat.st_mode, &prstat.st_uid, 209494a8ebeSWei Liu &prstat.st_gid, &prstat.st_rdev, 210494a8ebeSWei Liu &prstat.st_size, &prstat.st_blksize, 211494a8ebeSWei Liu &prstat.st_blocks, 212494a8ebeSWei Liu &prstat.st_atim_sec, &prstat.st_atim_nsec, 213494a8ebeSWei Liu &prstat.st_mtim_sec, &prstat.st_mtim_nsec, 214494a8ebeSWei Liu &prstat.st_ctim_sec, &prstat.st_ctim_nsec); 215494a8ebeSWei Liu prstat_to_stat(response, &prstat); 216494a8ebeSWei Liu break; 217494a8ebeSWei Liu } 218494a8ebeSWei Liu case T_STATFS: { 219494a8ebeSWei Liu ProxyStatFS prstfs; 220494a8ebeSWei Liu retval = proxy_unmarshal(reply, PROXY_HDR_SZ, 221494a8ebeSWei Liu "qqqqqqqqqqq", &prstfs.f_type, 222494a8ebeSWei Liu &prstfs.f_bsize, &prstfs.f_blocks, 223494a8ebeSWei Liu &prstfs.f_bfree, &prstfs.f_bavail, 224494a8ebeSWei Liu &prstfs.f_files, &prstfs.f_ffree, 225494a8ebeSWei Liu &prstfs.f_fsid[0], &prstfs.f_fsid[1], 226494a8ebeSWei Liu &prstfs.f_namelen, &prstfs.f_frsize); 227494a8ebeSWei Liu prstatfs_to_statfs(response, &prstfs); 228494a8ebeSWei Liu break; 229494a8ebeSWei Liu } 230494a8ebeSWei Liu case T_READLINK: { 231494a8ebeSWei Liu V9fsString target; 232494a8ebeSWei Liu v9fs_string_init(&target); 233494a8ebeSWei Liu retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target); 234494a8ebeSWei Liu strcpy(response, target.data); 235494a8ebeSWei Liu v9fs_string_free(&target); 236494a8ebeSWei Liu break; 237494a8ebeSWei Liu } 238494a8ebeSWei Liu case T_LGETXATTR: 239494a8ebeSWei Liu case T_LLISTXATTR: { 240494a8ebeSWei Liu V9fsString xattr; 241494a8ebeSWei Liu v9fs_string_init(&xattr); 242494a8ebeSWei Liu retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr); 243494a8ebeSWei Liu memcpy(response, xattr.data, xattr.size); 244494a8ebeSWei Liu v9fs_string_free(&xattr); 245494a8ebeSWei Liu break; 246494a8ebeSWei Liu } 247494a8ebeSWei Liu case T_GETVERSION: 248494a8ebeSWei Liu proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response); 249494a8ebeSWei Liu break; 250494a8ebeSWei Liu default: 251494a8ebeSWei Liu return -1; 252494a8ebeSWei Liu } 253494a8ebeSWei Liu if (retval < 0) { 254494a8ebeSWei Liu *status = retval; 255494a8ebeSWei Liu } 256494a8ebeSWei Liu return 0; 257494a8ebeSWei Liu } 258494a8ebeSWei Liu 259494a8ebeSWei Liu /* 260494a8ebeSWei Liu * return < 0 on transport error. 261494a8ebeSWei Liu * *status is valid only if return >= 0 262494a8ebeSWei Liu */ 263494a8ebeSWei Liu static int v9fs_receive_status(V9fsProxy *proxy, 264494a8ebeSWei Liu struct iovec *reply, int *status) 265494a8ebeSWei Liu { 266494a8ebeSWei Liu int retval; 267494a8ebeSWei Liu ProxyHeader header; 268494a8ebeSWei Liu 269494a8ebeSWei Liu *status = 0; 270494a8ebeSWei Liu reply->iov_len = 0; 271494a8ebeSWei Liu retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); 272494a8ebeSWei Liu if (retval < 0) { 273494a8ebeSWei Liu return retval; 274494a8ebeSWei Liu } 275494a8ebeSWei Liu reply->iov_len = PROXY_HDR_SZ; 276494a8ebeSWei Liu proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); 277494a8ebeSWei Liu if (header.size != sizeof(int)) { 278494a8ebeSWei Liu *status = -ENOBUFS; 279494a8ebeSWei Liu return 0; 280494a8ebeSWei Liu } 281494a8ebeSWei Liu retval = socket_read(proxy->sockfd, 282494a8ebeSWei Liu reply->iov_base + PROXY_HDR_SZ, header.size); 283494a8ebeSWei Liu if (retval < 0) { 284494a8ebeSWei Liu return retval; 285494a8ebeSWei Liu } 286494a8ebeSWei Liu reply->iov_len += header.size; 287494a8ebeSWei Liu proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status); 288494a8ebeSWei Liu return 0; 289494a8ebeSWei Liu } 290494a8ebeSWei Liu 291494a8ebeSWei Liu /* 292494a8ebeSWei Liu * Proxy->header and proxy->request written to socket by QEMU process. 293494a8ebeSWei Liu * This request read by proxy helper process 294494a8ebeSWei Liu * returns 0 on success and -errno on error 295494a8ebeSWei Liu */ 296494a8ebeSWei Liu static int v9fs_request(V9fsProxy *proxy, int type, 297494a8ebeSWei Liu void *response, const char *fmt, ...) 298494a8ebeSWei Liu { 299494a8ebeSWei Liu dev_t rdev; 300494a8ebeSWei Liu va_list ap; 301494a8ebeSWei Liu int size = 0; 302494a8ebeSWei Liu int retval = 0; 303494a8ebeSWei Liu uint64_t offset; 304494a8ebeSWei Liu ProxyHeader header = { 0, 0}; 305494a8ebeSWei Liu struct timespec spec[2]; 306494a8ebeSWei Liu int flags, mode, uid, gid; 307494a8ebeSWei Liu V9fsString *name, *value; 308494a8ebeSWei Liu V9fsString *path, *oldpath; 309494a8ebeSWei Liu struct iovec *iovec = NULL, *reply = NULL; 310494a8ebeSWei Liu 311494a8ebeSWei Liu qemu_mutex_lock(&proxy->mutex); 312494a8ebeSWei Liu 313494a8ebeSWei Liu if (proxy->sockfd == -1) { 314494a8ebeSWei Liu retval = -EIO; 315494a8ebeSWei Liu goto err_out; 316494a8ebeSWei Liu } 317494a8ebeSWei Liu iovec = &proxy->out_iovec; 318494a8ebeSWei Liu reply = &proxy->in_iovec; 319494a8ebeSWei Liu va_start(ap, fmt); 320494a8ebeSWei Liu switch (type) { 321494a8ebeSWei Liu case T_OPEN: 322494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 323494a8ebeSWei Liu flags = va_arg(ap, int); 324494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags); 325494a8ebeSWei Liu if (retval > 0) { 326494a8ebeSWei Liu header.size = retval; 327494a8ebeSWei Liu header.type = T_OPEN; 328494a8ebeSWei Liu } 329494a8ebeSWei Liu break; 330494a8ebeSWei Liu case T_CREATE: 331494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 332494a8ebeSWei Liu flags = va_arg(ap, int); 333494a8ebeSWei Liu mode = va_arg(ap, int); 334494a8ebeSWei Liu uid = va_arg(ap, int); 335494a8ebeSWei Liu gid = va_arg(ap, int); 336494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path, 337494a8ebeSWei Liu flags, mode, uid, gid); 338494a8ebeSWei Liu if (retval > 0) { 339494a8ebeSWei Liu header.size = retval; 340494a8ebeSWei Liu header.type = T_CREATE; 341494a8ebeSWei Liu } 342494a8ebeSWei Liu break; 343494a8ebeSWei Liu case T_MKNOD: 344494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 345494a8ebeSWei Liu mode = va_arg(ap, int); 346494a8ebeSWei Liu rdev = va_arg(ap, long int); 347494a8ebeSWei Liu uid = va_arg(ap, int); 348494a8ebeSWei Liu gid = va_arg(ap, int); 349494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq", 350494a8ebeSWei Liu uid, gid, path, mode, rdev); 351494a8ebeSWei Liu if (retval > 0) { 352494a8ebeSWei Liu header.size = retval; 353494a8ebeSWei Liu header.type = T_MKNOD; 354494a8ebeSWei Liu } 355494a8ebeSWei Liu break; 356494a8ebeSWei Liu case T_MKDIR: 357494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 358494a8ebeSWei Liu mode = va_arg(ap, int); 359494a8ebeSWei Liu uid = va_arg(ap, int); 360494a8ebeSWei Liu gid = va_arg(ap, int); 361494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd", 362494a8ebeSWei Liu uid, gid, path, mode); 363494a8ebeSWei Liu if (retval > 0) { 364494a8ebeSWei Liu header.size = retval; 365494a8ebeSWei Liu header.type = T_MKDIR; 366494a8ebeSWei Liu } 367494a8ebeSWei Liu break; 368494a8ebeSWei Liu case T_SYMLINK: 369494a8ebeSWei Liu oldpath = va_arg(ap, V9fsString *); 370494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 371494a8ebeSWei Liu uid = va_arg(ap, int); 372494a8ebeSWei Liu gid = va_arg(ap, int); 373494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss", 374494a8ebeSWei Liu uid, gid, oldpath, path); 375494a8ebeSWei Liu if (retval > 0) { 376494a8ebeSWei Liu header.size = retval; 377494a8ebeSWei Liu header.type = T_SYMLINK; 378494a8ebeSWei Liu } 379494a8ebeSWei Liu break; 380494a8ebeSWei Liu case T_LINK: 381494a8ebeSWei Liu oldpath = va_arg(ap, V9fsString *); 382494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 383494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", 384494a8ebeSWei Liu oldpath, path); 385494a8ebeSWei Liu if (retval > 0) { 386494a8ebeSWei Liu header.size = retval; 387494a8ebeSWei Liu header.type = T_LINK; 388494a8ebeSWei Liu } 389494a8ebeSWei Liu break; 390494a8ebeSWei Liu case T_LSTAT: 391494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 392494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 393494a8ebeSWei Liu if (retval > 0) { 394494a8ebeSWei Liu header.size = retval; 395494a8ebeSWei Liu header.type = T_LSTAT; 396494a8ebeSWei Liu } 397494a8ebeSWei Liu break; 398494a8ebeSWei Liu case T_READLINK: 399494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 400494a8ebeSWei Liu size = va_arg(ap, int); 401494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size); 402494a8ebeSWei Liu if (retval > 0) { 403494a8ebeSWei Liu header.size = retval; 404494a8ebeSWei Liu header.type = T_READLINK; 405494a8ebeSWei Liu } 406494a8ebeSWei Liu break; 407494a8ebeSWei Liu case T_STATFS: 408494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 409494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 410494a8ebeSWei Liu if (retval > 0) { 411494a8ebeSWei Liu header.size = retval; 412494a8ebeSWei Liu header.type = T_STATFS; 413494a8ebeSWei Liu } 414494a8ebeSWei Liu break; 415494a8ebeSWei Liu case T_CHMOD: 416494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 417494a8ebeSWei Liu mode = va_arg(ap, int); 418494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode); 419494a8ebeSWei Liu if (retval > 0) { 420494a8ebeSWei Liu header.size = retval; 421494a8ebeSWei Liu header.type = T_CHMOD; 422494a8ebeSWei Liu } 423494a8ebeSWei Liu break; 424494a8ebeSWei Liu case T_CHOWN: 425494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 426494a8ebeSWei Liu uid = va_arg(ap, int); 427494a8ebeSWei Liu gid = va_arg(ap, int); 428494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid); 429494a8ebeSWei Liu if (retval > 0) { 430494a8ebeSWei Liu header.size = retval; 431494a8ebeSWei Liu header.type = T_CHOWN; 432494a8ebeSWei Liu } 433494a8ebeSWei Liu break; 434494a8ebeSWei Liu case T_TRUNCATE: 435494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 436494a8ebeSWei Liu offset = va_arg(ap, uint64_t); 437494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset); 438494a8ebeSWei Liu if (retval > 0) { 439494a8ebeSWei Liu header.size = retval; 440494a8ebeSWei Liu header.type = T_TRUNCATE; 441494a8ebeSWei Liu } 442494a8ebeSWei Liu break; 443494a8ebeSWei Liu case T_UTIME: 444494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 445494a8ebeSWei Liu spec[0].tv_sec = va_arg(ap, long); 446494a8ebeSWei Liu spec[0].tv_nsec = va_arg(ap, long); 447494a8ebeSWei Liu spec[1].tv_sec = va_arg(ap, long); 448494a8ebeSWei Liu spec[1].tv_nsec = va_arg(ap, long); 449494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path, 450494a8ebeSWei Liu spec[0].tv_sec, spec[1].tv_nsec, 451494a8ebeSWei Liu spec[1].tv_sec, spec[1].tv_nsec); 452494a8ebeSWei Liu if (retval > 0) { 453494a8ebeSWei Liu header.size = retval; 454494a8ebeSWei Liu header.type = T_UTIME; 455494a8ebeSWei Liu } 456494a8ebeSWei Liu break; 457494a8ebeSWei Liu case T_RENAME: 458494a8ebeSWei Liu oldpath = va_arg(ap, V9fsString *); 459494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 460494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path); 461494a8ebeSWei Liu if (retval > 0) { 462494a8ebeSWei Liu header.size = retval; 463494a8ebeSWei Liu header.type = T_RENAME; 464494a8ebeSWei Liu } 465494a8ebeSWei Liu break; 466494a8ebeSWei Liu case T_REMOVE: 467494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 468494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 469494a8ebeSWei Liu if (retval > 0) { 470494a8ebeSWei Liu header.size = retval; 471494a8ebeSWei Liu header.type = T_REMOVE; 472494a8ebeSWei Liu } 473494a8ebeSWei Liu break; 474494a8ebeSWei Liu case T_LGETXATTR: 475494a8ebeSWei Liu size = va_arg(ap, int); 476494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 477494a8ebeSWei Liu name = va_arg(ap, V9fsString *); 478494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, 479494a8ebeSWei Liu "dss", size, path, name); 480494a8ebeSWei Liu if (retval > 0) { 481494a8ebeSWei Liu header.size = retval; 482494a8ebeSWei Liu header.type = T_LGETXATTR; 483494a8ebeSWei Liu } 484494a8ebeSWei Liu break; 485494a8ebeSWei Liu case T_LLISTXATTR: 486494a8ebeSWei Liu size = va_arg(ap, int); 487494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 488494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path); 489494a8ebeSWei Liu if (retval > 0) { 490494a8ebeSWei Liu header.size = retval; 491494a8ebeSWei Liu header.type = T_LLISTXATTR; 492494a8ebeSWei Liu } 493494a8ebeSWei Liu break; 494494a8ebeSWei Liu case T_LSETXATTR: 495494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 496494a8ebeSWei Liu name = va_arg(ap, V9fsString *); 497494a8ebeSWei Liu value = va_arg(ap, V9fsString *); 498494a8ebeSWei Liu size = va_arg(ap, int); 499494a8ebeSWei Liu flags = va_arg(ap, int); 500494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd", 501494a8ebeSWei Liu path, name, value, size, flags); 502494a8ebeSWei Liu if (retval > 0) { 503494a8ebeSWei Liu header.size = retval; 504494a8ebeSWei Liu header.type = T_LSETXATTR; 505494a8ebeSWei Liu } 506494a8ebeSWei Liu break; 507494a8ebeSWei Liu case T_LREMOVEXATTR: 508494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 509494a8ebeSWei Liu name = va_arg(ap, V9fsString *); 510494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name); 511494a8ebeSWei Liu if (retval > 0) { 512494a8ebeSWei Liu header.size = retval; 513494a8ebeSWei Liu header.type = T_LREMOVEXATTR; 514494a8ebeSWei Liu } 515494a8ebeSWei Liu break; 516494a8ebeSWei Liu case T_GETVERSION: 517494a8ebeSWei Liu path = va_arg(ap, V9fsString *); 518494a8ebeSWei Liu retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 519494a8ebeSWei Liu if (retval > 0) { 520494a8ebeSWei Liu header.size = retval; 521494a8ebeSWei Liu header.type = T_GETVERSION; 522494a8ebeSWei Liu } 523494a8ebeSWei Liu break; 524494a8ebeSWei Liu default: 525494a8ebeSWei Liu error_report("Invalid type %d", type); 526494a8ebeSWei Liu retval = -EINVAL; 527494a8ebeSWei Liu break; 528494a8ebeSWei Liu } 529494a8ebeSWei Liu va_end(ap); 530494a8ebeSWei Liu 531494a8ebeSWei Liu if (retval < 0) { 532494a8ebeSWei Liu goto err_out; 533494a8ebeSWei Liu } 534494a8ebeSWei Liu 535494a8ebeSWei Liu /* marshal the header details */ 536494a8ebeSWei Liu proxy_marshal(iovec, 0, "dd", header.type, header.size); 537494a8ebeSWei Liu header.size += PROXY_HDR_SZ; 538494a8ebeSWei Liu 539494a8ebeSWei Liu retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size); 540494a8ebeSWei Liu if (retval != header.size) { 541494a8ebeSWei Liu goto close_error; 542494a8ebeSWei Liu } 543494a8ebeSWei Liu 544494a8ebeSWei Liu switch (type) { 545494a8ebeSWei Liu case T_OPEN: 546494a8ebeSWei Liu case T_CREATE: 547494a8ebeSWei Liu /* 548494a8ebeSWei Liu * A file descriptor is returned as response for 549494a8ebeSWei Liu * T_OPEN,T_CREATE on success 550494a8ebeSWei Liu */ 551494a8ebeSWei Liu if (v9fs_receivefd(proxy->sockfd, &retval) < 0) { 552494a8ebeSWei Liu goto close_error; 553494a8ebeSWei Liu } 554494a8ebeSWei Liu break; 555494a8ebeSWei Liu case T_MKNOD: 556494a8ebeSWei Liu case T_MKDIR: 557494a8ebeSWei Liu case T_SYMLINK: 558494a8ebeSWei Liu case T_LINK: 559494a8ebeSWei Liu case T_CHMOD: 560494a8ebeSWei Liu case T_CHOWN: 561494a8ebeSWei Liu case T_RENAME: 562494a8ebeSWei Liu case T_TRUNCATE: 563494a8ebeSWei Liu case T_UTIME: 564494a8ebeSWei Liu case T_REMOVE: 565494a8ebeSWei Liu case T_LSETXATTR: 566494a8ebeSWei Liu case T_LREMOVEXATTR: 567494a8ebeSWei Liu if (v9fs_receive_status(proxy, reply, &retval) < 0) { 568494a8ebeSWei Liu goto close_error; 569494a8ebeSWei Liu } 570494a8ebeSWei Liu break; 571494a8ebeSWei Liu case T_LSTAT: 572494a8ebeSWei Liu case T_READLINK: 573494a8ebeSWei Liu case T_STATFS: 574494a8ebeSWei Liu case T_GETVERSION: 575494a8ebeSWei Liu if (v9fs_receive_response(proxy, type, &retval, response) < 0) { 576494a8ebeSWei Liu goto close_error; 577494a8ebeSWei Liu } 578494a8ebeSWei Liu break; 579494a8ebeSWei Liu case T_LGETXATTR: 580494a8ebeSWei Liu case T_LLISTXATTR: 581494a8ebeSWei Liu if (!size) { 582494a8ebeSWei Liu if (v9fs_receive_status(proxy, reply, &retval) < 0) { 583494a8ebeSWei Liu goto close_error; 584494a8ebeSWei Liu } 585494a8ebeSWei Liu } else { 586494a8ebeSWei Liu if (v9fs_receive_response(proxy, type, &retval, response) < 0) { 587494a8ebeSWei Liu goto close_error; 588494a8ebeSWei Liu } 589494a8ebeSWei Liu } 590494a8ebeSWei Liu break; 591494a8ebeSWei Liu } 592494a8ebeSWei Liu 593494a8ebeSWei Liu err_out: 594494a8ebeSWei Liu qemu_mutex_unlock(&proxy->mutex); 595494a8ebeSWei Liu return retval; 596494a8ebeSWei Liu 597494a8ebeSWei Liu close_error: 598494a8ebeSWei Liu close(proxy->sockfd); 599494a8ebeSWei Liu proxy->sockfd = -1; 600494a8ebeSWei Liu qemu_mutex_unlock(&proxy->mutex); 601494a8ebeSWei Liu return -EIO; 602494a8ebeSWei Liu } 603494a8ebeSWei Liu 604494a8ebeSWei Liu static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) 605494a8ebeSWei Liu { 606494a8ebeSWei Liu int retval; 607494a8ebeSWei Liu retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path); 608494a8ebeSWei Liu if (retval < 0) { 609494a8ebeSWei Liu errno = -retval; 610494a8ebeSWei Liu return -1; 611494a8ebeSWei Liu } 612494a8ebeSWei Liu return retval; 613494a8ebeSWei Liu } 614494a8ebeSWei Liu 615494a8ebeSWei Liu static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path, 616494a8ebeSWei Liu char *buf, size_t bufsz) 617494a8ebeSWei Liu { 618494a8ebeSWei Liu int retval; 619494a8ebeSWei Liu retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd", 620494a8ebeSWei Liu fs_path, bufsz); 621494a8ebeSWei Liu if (retval < 0) { 622494a8ebeSWei Liu errno = -retval; 623494a8ebeSWei Liu return -1; 624494a8ebeSWei Liu } 625494a8ebeSWei Liu return strlen(buf); 626494a8ebeSWei Liu } 627494a8ebeSWei Liu 628494a8ebeSWei Liu static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs) 629494a8ebeSWei Liu { 630494a8ebeSWei Liu return close(fs->fd); 631494a8ebeSWei Liu } 632494a8ebeSWei Liu 633494a8ebeSWei Liu static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs) 634494a8ebeSWei Liu { 635494a8ebeSWei Liu return closedir(fs->dir); 636494a8ebeSWei Liu } 637494a8ebeSWei Liu 638494a8ebeSWei Liu static int proxy_open(FsContext *ctx, V9fsPath *fs_path, 639494a8ebeSWei Liu int flags, V9fsFidOpenState *fs) 640494a8ebeSWei Liu { 641494a8ebeSWei Liu fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, flags); 642494a8ebeSWei Liu if (fs->fd < 0) { 643494a8ebeSWei Liu errno = -fs->fd; 644494a8ebeSWei Liu fs->fd = -1; 645494a8ebeSWei Liu } 646494a8ebeSWei Liu return fs->fd; 647494a8ebeSWei Liu } 648494a8ebeSWei Liu 649494a8ebeSWei Liu static int proxy_opendir(FsContext *ctx, 650494a8ebeSWei Liu V9fsPath *fs_path, V9fsFidOpenState *fs) 651494a8ebeSWei Liu { 652494a8ebeSWei Liu int serrno, fd; 653494a8ebeSWei Liu 654494a8ebeSWei Liu fs->dir = NULL; 655494a8ebeSWei Liu fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY); 656494a8ebeSWei Liu if (fd < 0) { 657494a8ebeSWei Liu errno = -fd; 658494a8ebeSWei Liu return -1; 659494a8ebeSWei Liu } 660494a8ebeSWei Liu fs->dir = fdopendir(fd); 661494a8ebeSWei Liu if (!fs->dir) { 662494a8ebeSWei Liu serrno = errno; 663494a8ebeSWei Liu close(fd); 664494a8ebeSWei Liu errno = serrno; 665494a8ebeSWei Liu return -1; 666494a8ebeSWei Liu } 667494a8ebeSWei Liu return 0; 668494a8ebeSWei Liu } 669494a8ebeSWei Liu 670494a8ebeSWei Liu static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) 671494a8ebeSWei Liu { 672494a8ebeSWei Liu rewinddir(fs->dir); 673494a8ebeSWei Liu } 674494a8ebeSWei Liu 675494a8ebeSWei Liu static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs) 676494a8ebeSWei Liu { 677494a8ebeSWei Liu return telldir(fs->dir); 678494a8ebeSWei Liu } 679494a8ebeSWei Liu 680494a8ebeSWei Liu static int proxy_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, 681494a8ebeSWei Liu struct dirent *entry, 682494a8ebeSWei Liu struct dirent **result) 683494a8ebeSWei Liu { 684494a8ebeSWei Liu return readdir_r(fs->dir, entry, result); 685494a8ebeSWei Liu } 686494a8ebeSWei Liu 687494a8ebeSWei Liu static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) 688494a8ebeSWei Liu { 689494a8ebeSWei Liu seekdir(fs->dir, off); 690494a8ebeSWei Liu } 691494a8ebeSWei Liu 692494a8ebeSWei Liu static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs, 693494a8ebeSWei Liu const struct iovec *iov, 694494a8ebeSWei Liu int iovcnt, off_t offset) 695494a8ebeSWei Liu { 696494a8ebeSWei Liu ssize_t ret; 697494a8ebeSWei Liu #ifdef CONFIG_PREADV 698494a8ebeSWei Liu ret = preadv(fs->fd, iov, iovcnt, offset); 699494a8ebeSWei Liu #else 700494a8ebeSWei Liu ret = lseek(fs->fd, offset, SEEK_SET); 701494a8ebeSWei Liu if (ret >= 0) { 702494a8ebeSWei Liu ret = readv(fs->fd, iov, iovcnt); 703494a8ebeSWei Liu } 704494a8ebeSWei Liu #endif 705494a8ebeSWei Liu return ret; 706494a8ebeSWei Liu } 707494a8ebeSWei Liu 708494a8ebeSWei Liu static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs, 709494a8ebeSWei Liu const struct iovec *iov, 710494a8ebeSWei Liu int iovcnt, off_t offset) 711494a8ebeSWei Liu { 712494a8ebeSWei Liu ssize_t ret; 713494a8ebeSWei Liu 714494a8ebeSWei Liu #ifdef CONFIG_PREADV 715494a8ebeSWei Liu ret = pwritev(fs->fd, iov, iovcnt, offset); 716494a8ebeSWei Liu #else 717494a8ebeSWei Liu ret = lseek(fs->fd, offset, SEEK_SET); 718494a8ebeSWei Liu if (ret >= 0) { 719494a8ebeSWei Liu ret = writev(fs->fd, iov, iovcnt); 720494a8ebeSWei Liu } 721494a8ebeSWei Liu #endif 722494a8ebeSWei Liu #ifdef CONFIG_SYNC_FILE_RANGE 723494a8ebeSWei Liu if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { 724494a8ebeSWei Liu /* 725494a8ebeSWei Liu * Initiate a writeback. This is not a data integrity sync. 726494a8ebeSWei Liu * We want to ensure that we don't leave dirty pages in the cache 727494a8ebeSWei Liu * after write when writeout=immediate is sepcified. 728494a8ebeSWei Liu */ 729494a8ebeSWei Liu sync_file_range(fs->fd, offset, ret, 730494a8ebeSWei Liu SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); 731494a8ebeSWei Liu } 732494a8ebeSWei Liu #endif 733494a8ebeSWei Liu return ret; 734494a8ebeSWei Liu } 735494a8ebeSWei Liu 736494a8ebeSWei Liu static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 737494a8ebeSWei Liu { 738494a8ebeSWei Liu int retval; 739494a8ebeSWei Liu retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, "sd", 740494a8ebeSWei Liu fs_path, credp->fc_mode); 741494a8ebeSWei Liu if (retval < 0) { 742494a8ebeSWei Liu errno = -retval; 743494a8ebeSWei Liu } 744494a8ebeSWei Liu return retval; 745494a8ebeSWei Liu } 746494a8ebeSWei Liu 747494a8ebeSWei Liu static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path, 748494a8ebeSWei Liu const char *name, FsCred *credp) 749494a8ebeSWei Liu { 750494a8ebeSWei Liu int retval; 751494a8ebeSWei Liu V9fsString fullname; 752494a8ebeSWei Liu 753494a8ebeSWei Liu v9fs_string_init(&fullname); 754494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 755494a8ebeSWei Liu 756494a8ebeSWei Liu retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd", 757494a8ebeSWei Liu &fullname, credp->fc_mode, credp->fc_rdev, 758494a8ebeSWei Liu credp->fc_uid, credp->fc_gid); 759494a8ebeSWei Liu v9fs_string_free(&fullname); 760494a8ebeSWei Liu if (retval < 0) { 761494a8ebeSWei Liu errno = -retval; 762494a8ebeSWei Liu retval = -1; 763494a8ebeSWei Liu } 764494a8ebeSWei Liu return retval; 765494a8ebeSWei Liu } 766494a8ebeSWei Liu 767494a8ebeSWei Liu static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, 768494a8ebeSWei Liu const char *name, FsCred *credp) 769494a8ebeSWei Liu { 770494a8ebeSWei Liu int retval; 771494a8ebeSWei Liu V9fsString fullname; 772494a8ebeSWei Liu 773494a8ebeSWei Liu v9fs_string_init(&fullname); 774494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 775494a8ebeSWei Liu 776494a8ebeSWei Liu retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname, 777494a8ebeSWei Liu credp->fc_mode, credp->fc_uid, credp->fc_gid); 778494a8ebeSWei Liu v9fs_string_free(&fullname); 779494a8ebeSWei Liu if (retval < 0) { 780494a8ebeSWei Liu errno = -retval; 781494a8ebeSWei Liu retval = -1; 782494a8ebeSWei Liu } 783494a8ebeSWei Liu v9fs_string_free(&fullname); 784494a8ebeSWei Liu return retval; 785494a8ebeSWei Liu } 786494a8ebeSWei Liu 787494a8ebeSWei Liu static int proxy_fstat(FsContext *fs_ctx, int fid_type, 788494a8ebeSWei Liu V9fsFidOpenState *fs, struct stat *stbuf) 789494a8ebeSWei Liu { 790494a8ebeSWei Liu int fd; 791494a8ebeSWei Liu 792494a8ebeSWei Liu if (fid_type == P9_FID_DIR) { 793494a8ebeSWei Liu fd = dirfd(fs->dir); 794494a8ebeSWei Liu } else { 795494a8ebeSWei Liu fd = fs->fd; 796494a8ebeSWei Liu } 797494a8ebeSWei Liu return fstat(fd, stbuf); 798494a8ebeSWei Liu } 799494a8ebeSWei Liu 800494a8ebeSWei Liu static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, 801494a8ebeSWei Liu int flags, FsCred *credp, V9fsFidOpenState *fs) 802494a8ebeSWei Liu { 803494a8ebeSWei Liu V9fsString fullname; 804494a8ebeSWei Liu 805494a8ebeSWei Liu v9fs_string_init(&fullname); 806494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 807494a8ebeSWei Liu 808494a8ebeSWei Liu fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd", 809494a8ebeSWei Liu &fullname, flags, credp->fc_mode, 810494a8ebeSWei Liu credp->fc_uid, credp->fc_gid); 811494a8ebeSWei Liu v9fs_string_free(&fullname); 812494a8ebeSWei Liu if (fs->fd < 0) { 813494a8ebeSWei Liu errno = -fs->fd; 814494a8ebeSWei Liu fs->fd = -1; 815494a8ebeSWei Liu } 816494a8ebeSWei Liu return fs->fd; 817494a8ebeSWei Liu } 818494a8ebeSWei Liu 819494a8ebeSWei Liu static int proxy_symlink(FsContext *fs_ctx, const char *oldpath, 820494a8ebeSWei Liu V9fsPath *dir_path, const char *name, FsCred *credp) 821494a8ebeSWei Liu { 822494a8ebeSWei Liu int retval; 823494a8ebeSWei Liu V9fsString fullname, target; 824494a8ebeSWei Liu 825494a8ebeSWei Liu v9fs_string_init(&fullname); 826494a8ebeSWei Liu v9fs_string_init(&target); 827494a8ebeSWei Liu 828494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 829494a8ebeSWei Liu v9fs_string_sprintf(&target, "%s", oldpath); 830494a8ebeSWei Liu 831494a8ebeSWei Liu retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd", 832494a8ebeSWei Liu &target, &fullname, credp->fc_uid, credp->fc_gid); 833494a8ebeSWei Liu v9fs_string_free(&fullname); 834494a8ebeSWei Liu v9fs_string_free(&target); 835494a8ebeSWei Liu if (retval < 0) { 836494a8ebeSWei Liu errno = -retval; 837494a8ebeSWei Liu retval = -1; 838494a8ebeSWei Liu } 839494a8ebeSWei Liu return retval; 840494a8ebeSWei Liu } 841494a8ebeSWei Liu 842494a8ebeSWei Liu static int proxy_link(FsContext *ctx, V9fsPath *oldpath, 843494a8ebeSWei Liu V9fsPath *dirpath, const char *name) 844494a8ebeSWei Liu { 845494a8ebeSWei Liu int retval; 846494a8ebeSWei Liu V9fsString newpath; 847494a8ebeSWei Liu 848494a8ebeSWei Liu v9fs_string_init(&newpath); 849494a8ebeSWei Liu v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); 850494a8ebeSWei Liu 851494a8ebeSWei Liu retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath); 852494a8ebeSWei Liu v9fs_string_free(&newpath); 853494a8ebeSWei Liu if (retval < 0) { 854494a8ebeSWei Liu errno = -retval; 855494a8ebeSWei Liu retval = -1; 856494a8ebeSWei Liu } 857494a8ebeSWei Liu return retval; 858494a8ebeSWei Liu } 859494a8ebeSWei Liu 860494a8ebeSWei Liu static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) 861494a8ebeSWei Liu { 862494a8ebeSWei Liu int retval; 863494a8ebeSWei Liu 864494a8ebeSWei Liu retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, "sq", fs_path, size); 865494a8ebeSWei Liu if (retval < 0) { 866494a8ebeSWei Liu errno = -retval; 867494a8ebeSWei Liu return -1; 868494a8ebeSWei Liu } 869494a8ebeSWei Liu return 0; 870494a8ebeSWei Liu } 871494a8ebeSWei Liu 872494a8ebeSWei Liu static int proxy_rename(FsContext *ctx, const char *oldpath, 873494a8ebeSWei Liu const char *newpath) 874494a8ebeSWei Liu { 875494a8ebeSWei Liu int retval; 876494a8ebeSWei Liu V9fsString oldname, newname; 877494a8ebeSWei Liu 878494a8ebeSWei Liu v9fs_string_init(&oldname); 879494a8ebeSWei Liu v9fs_string_init(&newname); 880494a8ebeSWei Liu 881494a8ebeSWei Liu v9fs_string_sprintf(&oldname, "%s", oldpath); 882494a8ebeSWei Liu v9fs_string_sprintf(&newname, "%s", newpath); 883494a8ebeSWei Liu retval = v9fs_request(ctx->private, T_RENAME, NULL, "ss", 884494a8ebeSWei Liu &oldname, &newname); 885494a8ebeSWei Liu v9fs_string_free(&oldname); 886494a8ebeSWei Liu v9fs_string_free(&newname); 887494a8ebeSWei Liu if (retval < 0) { 888494a8ebeSWei Liu errno = -retval; 889494a8ebeSWei Liu } 890494a8ebeSWei Liu return retval; 891494a8ebeSWei Liu } 892494a8ebeSWei Liu 893494a8ebeSWei Liu static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 894494a8ebeSWei Liu { 895494a8ebeSWei Liu int retval; 896494a8ebeSWei Liu retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, "sdd", 897494a8ebeSWei Liu fs_path, credp->fc_uid, credp->fc_gid); 898494a8ebeSWei Liu if (retval < 0) { 899494a8ebeSWei Liu errno = -retval; 900494a8ebeSWei Liu } 901494a8ebeSWei Liu return retval; 902494a8ebeSWei Liu } 903494a8ebeSWei Liu 904494a8ebeSWei Liu static int proxy_utimensat(FsContext *s, V9fsPath *fs_path, 905494a8ebeSWei Liu const struct timespec *buf) 906494a8ebeSWei Liu { 907494a8ebeSWei Liu int retval; 908494a8ebeSWei Liu retval = v9fs_request(s->private, T_UTIME, NULL, "sqqqq", 909494a8ebeSWei Liu fs_path, 910494a8ebeSWei Liu buf[0].tv_sec, buf[0].tv_nsec, 911494a8ebeSWei Liu buf[1].tv_sec, buf[1].tv_nsec); 912494a8ebeSWei Liu if (retval < 0) { 913494a8ebeSWei Liu errno = -retval; 914494a8ebeSWei Liu } 915494a8ebeSWei Liu return retval; 916494a8ebeSWei Liu } 917494a8ebeSWei Liu 918494a8ebeSWei Liu static int proxy_remove(FsContext *ctx, const char *path) 919494a8ebeSWei Liu { 920494a8ebeSWei Liu int retval; 921494a8ebeSWei Liu V9fsString name; 922494a8ebeSWei Liu v9fs_string_init(&name); 923494a8ebeSWei Liu v9fs_string_sprintf(&name, "%s", path); 924494a8ebeSWei Liu retval = v9fs_request(ctx->private, T_REMOVE, NULL, "s", &name); 925494a8ebeSWei Liu v9fs_string_free(&name); 926494a8ebeSWei Liu if (retval < 0) { 927494a8ebeSWei Liu errno = -retval; 928494a8ebeSWei Liu } 929494a8ebeSWei Liu return retval; 930494a8ebeSWei Liu } 931494a8ebeSWei Liu 932494a8ebeSWei Liu static int proxy_fsync(FsContext *ctx, int fid_type, 933494a8ebeSWei Liu V9fsFidOpenState *fs, int datasync) 934494a8ebeSWei Liu { 935494a8ebeSWei Liu int fd; 936494a8ebeSWei Liu 937494a8ebeSWei Liu if (fid_type == P9_FID_DIR) { 938494a8ebeSWei Liu fd = dirfd(fs->dir); 939494a8ebeSWei Liu } else { 940494a8ebeSWei Liu fd = fs->fd; 941494a8ebeSWei Liu } 942494a8ebeSWei Liu 943494a8ebeSWei Liu if (datasync) { 944494a8ebeSWei Liu return qemu_fdatasync(fd); 945494a8ebeSWei Liu } else { 946494a8ebeSWei Liu return fsync(fd); 947494a8ebeSWei Liu } 948494a8ebeSWei Liu } 949494a8ebeSWei Liu 950494a8ebeSWei Liu static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) 951494a8ebeSWei Liu { 952494a8ebeSWei Liu int retval; 953494a8ebeSWei Liu retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path); 954494a8ebeSWei Liu if (retval < 0) { 955494a8ebeSWei Liu errno = -retval; 956494a8ebeSWei Liu return -1; 957494a8ebeSWei Liu } 958494a8ebeSWei Liu return retval; 959494a8ebeSWei Liu } 960494a8ebeSWei Liu 961494a8ebeSWei Liu static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path, 962494a8ebeSWei Liu const char *name, void *value, size_t size) 963494a8ebeSWei Liu { 964494a8ebeSWei Liu int retval; 965494a8ebeSWei Liu V9fsString xname; 966494a8ebeSWei Liu 967494a8ebeSWei Liu v9fs_string_init(&xname); 968494a8ebeSWei Liu v9fs_string_sprintf(&xname, "%s", name); 969494a8ebeSWei Liu retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size, 970494a8ebeSWei Liu fs_path, &xname); 971494a8ebeSWei Liu v9fs_string_free(&xname); 972494a8ebeSWei Liu if (retval < 0) { 973494a8ebeSWei Liu errno = -retval; 974494a8ebeSWei Liu } 975494a8ebeSWei Liu return retval; 976494a8ebeSWei Liu } 977494a8ebeSWei Liu 978494a8ebeSWei Liu static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path, 979494a8ebeSWei Liu void *value, size_t size) 980494a8ebeSWei Liu { 981494a8ebeSWei Liu int retval; 982494a8ebeSWei Liu retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size, 983494a8ebeSWei Liu fs_path); 984494a8ebeSWei Liu if (retval < 0) { 985494a8ebeSWei Liu errno = -retval; 986494a8ebeSWei Liu } 987494a8ebeSWei Liu return retval; 988494a8ebeSWei Liu } 989494a8ebeSWei Liu 990494a8ebeSWei Liu static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, 991494a8ebeSWei Liu void *value, size_t size, int flags) 992494a8ebeSWei Liu { 993494a8ebeSWei Liu int retval; 994494a8ebeSWei Liu V9fsString xname, xvalue; 995494a8ebeSWei Liu 996494a8ebeSWei Liu v9fs_string_init(&xname); 997494a8ebeSWei Liu v9fs_string_sprintf(&xname, "%s", name); 998494a8ebeSWei Liu 999494a8ebeSWei Liu v9fs_string_init(&xvalue); 1000494a8ebeSWei Liu xvalue.size = size; 1001494a8ebeSWei Liu xvalue.data = g_malloc(size); 1002494a8ebeSWei Liu memcpy(xvalue.data, value, size); 1003494a8ebeSWei Liu 1004494a8ebeSWei Liu retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd", 1005494a8ebeSWei Liu fs_path, &xname, &xvalue, size, flags); 1006494a8ebeSWei Liu v9fs_string_free(&xname); 1007494a8ebeSWei Liu v9fs_string_free(&xvalue); 1008494a8ebeSWei Liu if (retval < 0) { 1009494a8ebeSWei Liu errno = -retval; 1010494a8ebeSWei Liu } 1011494a8ebeSWei Liu return retval; 1012494a8ebeSWei Liu } 1013494a8ebeSWei Liu 1014494a8ebeSWei Liu static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path, 1015494a8ebeSWei Liu const char *name) 1016494a8ebeSWei Liu { 1017494a8ebeSWei Liu int retval; 1018494a8ebeSWei Liu V9fsString xname; 1019494a8ebeSWei Liu 1020494a8ebeSWei Liu v9fs_string_init(&xname); 1021494a8ebeSWei Liu v9fs_string_sprintf(&xname, "%s", name); 1022494a8ebeSWei Liu retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss", 1023494a8ebeSWei Liu fs_path, &xname); 1024494a8ebeSWei Liu v9fs_string_free(&xname); 1025494a8ebeSWei Liu if (retval < 0) { 1026494a8ebeSWei Liu errno = -retval; 1027494a8ebeSWei Liu } 1028494a8ebeSWei Liu return retval; 1029494a8ebeSWei Liu } 1030494a8ebeSWei Liu 1031494a8ebeSWei Liu static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path, 1032494a8ebeSWei Liu const char *name, V9fsPath *target) 1033494a8ebeSWei Liu { 1034494a8ebeSWei Liu if (dir_path) { 1035494a8ebeSWei Liu v9fs_string_sprintf((V9fsString *)target, "%s/%s", 1036494a8ebeSWei Liu dir_path->data, name); 1037494a8ebeSWei Liu } else { 1038494a8ebeSWei Liu v9fs_string_sprintf((V9fsString *)target, "%s", name); 1039494a8ebeSWei Liu } 1040494a8ebeSWei Liu /* Bump the size for including terminating NULL */ 1041494a8ebeSWei Liu target->size++; 1042494a8ebeSWei Liu return 0; 1043494a8ebeSWei Liu } 1044494a8ebeSWei Liu 1045494a8ebeSWei Liu static int proxy_renameat(FsContext *ctx, V9fsPath *olddir, 1046494a8ebeSWei Liu const char *old_name, V9fsPath *newdir, 1047494a8ebeSWei Liu const char *new_name) 1048494a8ebeSWei Liu { 1049494a8ebeSWei Liu int ret; 1050494a8ebeSWei Liu V9fsString old_full_name, new_full_name; 1051494a8ebeSWei Liu 1052494a8ebeSWei Liu v9fs_string_init(&old_full_name); 1053494a8ebeSWei Liu v9fs_string_init(&new_full_name); 1054494a8ebeSWei Liu 1055494a8ebeSWei Liu v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); 1056494a8ebeSWei Liu v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); 1057494a8ebeSWei Liu 1058494a8ebeSWei Liu ret = proxy_rename(ctx, old_full_name.data, new_full_name.data); 1059494a8ebeSWei Liu v9fs_string_free(&old_full_name); 1060494a8ebeSWei Liu v9fs_string_free(&new_full_name); 1061494a8ebeSWei Liu return ret; 1062494a8ebeSWei Liu } 1063494a8ebeSWei Liu 1064494a8ebeSWei Liu static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir, 1065494a8ebeSWei Liu const char *name, int flags) 1066494a8ebeSWei Liu { 1067494a8ebeSWei Liu int ret; 1068494a8ebeSWei Liu V9fsString fullname; 1069494a8ebeSWei Liu v9fs_string_init(&fullname); 1070494a8ebeSWei Liu 1071494a8ebeSWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); 1072494a8ebeSWei Liu ret = proxy_remove(ctx, fullname.data); 1073494a8ebeSWei Liu v9fs_string_free(&fullname); 1074494a8ebeSWei Liu 1075494a8ebeSWei Liu return ret; 1076494a8ebeSWei Liu } 1077494a8ebeSWei Liu 1078494a8ebeSWei Liu static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path, 1079494a8ebeSWei Liu mode_t st_mode, uint64_t *st_gen) 1080494a8ebeSWei Liu { 1081494a8ebeSWei Liu int err; 1082494a8ebeSWei Liu 1083494a8ebeSWei Liu /* Do not try to open special files like device nodes, fifos etc 1084494a8ebeSWei Liu * we can get fd for regular files and directories only 1085494a8ebeSWei Liu */ 1086494a8ebeSWei Liu if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { 1087494a8ebeSWei Liu errno = ENOTTY; 1088494a8ebeSWei Liu return -1; 1089494a8ebeSWei Liu } 1090494a8ebeSWei Liu err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path); 1091494a8ebeSWei Liu if (err < 0) { 1092494a8ebeSWei Liu errno = -err; 1093494a8ebeSWei Liu err = -1; 1094494a8ebeSWei Liu } 1095494a8ebeSWei Liu return err; 1096494a8ebeSWei Liu } 1097494a8ebeSWei Liu 1098494a8ebeSWei Liu static int connect_namedsocket(const char *path) 1099494a8ebeSWei Liu { 1100494a8ebeSWei Liu int sockfd, size; 1101494a8ebeSWei Liu struct sockaddr_un helper; 1102494a8ebeSWei Liu 1103494a8ebeSWei Liu if (strlen(path) >= sizeof(helper.sun_path)) { 110463325b18SGreg Kurz error_report("Socket name too long"); 1105494a8ebeSWei Liu return -1; 1106494a8ebeSWei Liu } 1107494a8ebeSWei Liu sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 1108494a8ebeSWei Liu if (sockfd < 0) { 110963325b18SGreg Kurz error_report("Failed to create socket: %s", strerror(errno)); 1110494a8ebeSWei Liu return -1; 1111494a8ebeSWei Liu } 1112494a8ebeSWei Liu strcpy(helper.sun_path, path); 1113494a8ebeSWei Liu helper.sun_family = AF_UNIX; 1114494a8ebeSWei Liu size = strlen(helper.sun_path) + sizeof(helper.sun_family); 1115494a8ebeSWei Liu if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) { 111663325b18SGreg Kurz error_report("Failed to connect to %s: %s", path, strerror(errno)); 1117494a8ebeSWei Liu close(sockfd); 1118494a8ebeSWei Liu return -1; 1119494a8ebeSWei Liu } 1120494a8ebeSWei Liu 1121494a8ebeSWei Liu /* remove the socket for security reasons */ 1122494a8ebeSWei Liu unlink(path); 1123494a8ebeSWei Liu return sockfd; 1124494a8ebeSWei Liu } 1125494a8ebeSWei Liu 1126494a8ebeSWei Liu static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs) 1127494a8ebeSWei Liu { 1128494a8ebeSWei Liu const char *socket = qemu_opt_get(opts, "socket"); 1129494a8ebeSWei Liu const char *sock_fd = qemu_opt_get(opts, "sock_fd"); 1130494a8ebeSWei Liu 1131494a8ebeSWei Liu if (!socket && !sock_fd) { 113263325b18SGreg Kurz error_report("Must specify either socket or sock_fd"); 1133494a8ebeSWei Liu return -1; 1134494a8ebeSWei Liu } 1135494a8ebeSWei Liu if (socket && sock_fd) { 113663325b18SGreg Kurz error_report("Both socket and sock_fd options specified"); 1137494a8ebeSWei Liu return -1; 1138494a8ebeSWei Liu } 1139494a8ebeSWei Liu if (socket) { 1140494a8ebeSWei Liu fs->path = g_strdup(socket); 1141494a8ebeSWei Liu fs->export_flags = V9FS_PROXY_SOCK_NAME; 1142494a8ebeSWei Liu } else { 1143494a8ebeSWei Liu fs->path = g_strdup(sock_fd); 1144494a8ebeSWei Liu fs->export_flags = V9FS_PROXY_SOCK_FD; 1145494a8ebeSWei Liu } 1146494a8ebeSWei Liu return 0; 1147494a8ebeSWei Liu } 1148494a8ebeSWei Liu 1149494a8ebeSWei Liu static int proxy_init(FsContext *ctx) 1150494a8ebeSWei Liu { 1151494a8ebeSWei Liu V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy)); 1152494a8ebeSWei Liu int sock_id; 1153494a8ebeSWei Liu 1154494a8ebeSWei Liu if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) { 1155494a8ebeSWei Liu sock_id = connect_namedsocket(ctx->fs_root); 1156494a8ebeSWei Liu } else { 1157494a8ebeSWei Liu sock_id = atoi(ctx->fs_root); 1158494a8ebeSWei Liu if (sock_id < 0) { 115963325b18SGreg Kurz error_report("Socket descriptor not initialized"); 1160494a8ebeSWei Liu } 1161494a8ebeSWei Liu } 1162494a8ebeSWei Liu if (sock_id < 0) { 1163494a8ebeSWei Liu g_free(proxy); 1164494a8ebeSWei Liu return -1; 1165494a8ebeSWei Liu } 1166494a8ebeSWei Liu g_free(ctx->fs_root); 1167494a8ebeSWei Liu ctx->fs_root = NULL; 1168494a8ebeSWei Liu 1169494a8ebeSWei Liu proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 1170494a8ebeSWei Liu proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 1171494a8ebeSWei Liu proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 1172494a8ebeSWei Liu proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 1173494a8ebeSWei Liu 1174494a8ebeSWei Liu ctx->private = proxy; 1175494a8ebeSWei Liu proxy->sockfd = sock_id; 1176494a8ebeSWei Liu qemu_mutex_init(&proxy->mutex); 1177494a8ebeSWei Liu 1178494a8ebeSWei Liu ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; 1179494a8ebeSWei Liu ctx->exops.get_st_gen = proxy_ioc_getversion; 1180494a8ebeSWei Liu return 0; 1181494a8ebeSWei Liu } 1182494a8ebeSWei Liu 1183494a8ebeSWei Liu FileOperations proxy_ops = { 1184494a8ebeSWei Liu .parse_opts = proxy_parse_opts, 1185494a8ebeSWei Liu .init = proxy_init, 1186494a8ebeSWei Liu .lstat = proxy_lstat, 1187494a8ebeSWei Liu .readlink = proxy_readlink, 1188494a8ebeSWei Liu .close = proxy_close, 1189494a8ebeSWei Liu .closedir = proxy_closedir, 1190494a8ebeSWei Liu .open = proxy_open, 1191494a8ebeSWei Liu .opendir = proxy_opendir, 1192494a8ebeSWei Liu .rewinddir = proxy_rewinddir, 1193494a8ebeSWei Liu .telldir = proxy_telldir, 1194494a8ebeSWei Liu .readdir_r = proxy_readdir_r, 1195494a8ebeSWei Liu .seekdir = proxy_seekdir, 1196494a8ebeSWei Liu .preadv = proxy_preadv, 1197494a8ebeSWei Liu .pwritev = proxy_pwritev, 1198494a8ebeSWei Liu .chmod = proxy_chmod, 1199494a8ebeSWei Liu .mknod = proxy_mknod, 1200494a8ebeSWei Liu .mkdir = proxy_mkdir, 1201494a8ebeSWei Liu .fstat = proxy_fstat, 1202494a8ebeSWei Liu .open2 = proxy_open2, 1203494a8ebeSWei Liu .symlink = proxy_symlink, 1204494a8ebeSWei Liu .link = proxy_link, 1205494a8ebeSWei Liu .truncate = proxy_truncate, 1206494a8ebeSWei Liu .rename = proxy_rename, 1207494a8ebeSWei Liu .chown = proxy_chown, 1208494a8ebeSWei Liu .utimensat = proxy_utimensat, 1209494a8ebeSWei Liu .remove = proxy_remove, 1210494a8ebeSWei Liu .fsync = proxy_fsync, 1211494a8ebeSWei Liu .statfs = proxy_statfs, 1212494a8ebeSWei Liu .lgetxattr = proxy_lgetxattr, 1213494a8ebeSWei Liu .llistxattr = proxy_llistxattr, 1214494a8ebeSWei Liu .lsetxattr = proxy_lsetxattr, 1215494a8ebeSWei Liu .lremovexattr = proxy_lremovexattr, 1216494a8ebeSWei Liu .name_to_path = proxy_name_to_path, 1217494a8ebeSWei Liu .renameat = proxy_renameat, 1218494a8ebeSWei Liu .unlinkat = proxy_unlinkat, 1219494a8ebeSWei Liu }; 1220