1 /* 2 * 9p Proxy callback 3 * 4 * Copyright IBM, Corp. 2011 5 * 6 * Authors: 7 * M. Mohan Kumar <mohan@in.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 */ 12 13 /* 14 * Not so fast! You might want to read the 9p developer docs first: 15 * https://wiki.qemu.org/Documentation/9p 16 */ 17 18 #include "qemu/osdep.h" 19 #include <sys/socket.h> 20 #include <sys/un.h> 21 #include "qemu-common.h" 22 #include "9p.h" 23 #include "qapi/error.h" 24 #include "qemu/cutils.h" 25 #include "qemu/error-report.h" 26 #include "qemu/option.h" 27 #include "fsdev/qemu-fsdev.h" 28 #include "9p-proxy.h" 29 30 typedef struct V9fsProxy { 31 int sockfd; 32 QemuMutex mutex; 33 struct iovec in_iovec; 34 struct iovec out_iovec; 35 } V9fsProxy; 36 37 /* 38 * Return received file descriptor on success in *status. 39 * errno is also returned on *status (which will be < 0) 40 * return < 0 on transport error. 41 */ 42 static int v9fs_receivefd(int sockfd, int *status) 43 { 44 struct iovec iov; 45 struct msghdr msg; 46 struct cmsghdr *cmsg; 47 int retval, data, fd; 48 union MsgControl msg_control; 49 50 iov.iov_base = &data; 51 iov.iov_len = sizeof(data); 52 53 memset(&msg, 0, sizeof(msg)); 54 msg.msg_iov = &iov; 55 msg.msg_iovlen = 1; 56 msg.msg_control = &msg_control; 57 msg.msg_controllen = sizeof(msg_control); 58 59 do { 60 retval = recvmsg(sockfd, &msg, 0); 61 } while (retval < 0 && errno == EINTR); 62 if (retval <= 0) { 63 return retval; 64 } 65 /* 66 * data is set to V9FS_FD_VALID, if ancillary data is sent. If this 67 * request doesn't need ancillary data (fd) or an error occurred, 68 * data is set to negative errno value. 69 */ 70 if (data != V9FS_FD_VALID) { 71 *status = data; 72 return 0; 73 } 74 /* 75 * File descriptor (fd) is sent in the ancillary data. Check if we 76 * indeed received it. One of the reasons to fail to receive it is if 77 * we exceeded the maximum number of file descriptors! 78 */ 79 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 80 if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || 81 cmsg->cmsg_level != SOL_SOCKET || 82 cmsg->cmsg_type != SCM_RIGHTS) { 83 continue; 84 } 85 fd = *((int *)CMSG_DATA(cmsg)); 86 *status = fd; 87 return 0; 88 } 89 *status = -ENFILE; /* Ancillary data sent but not received */ 90 return 0; 91 } 92 93 static ssize_t socket_read(int sockfd, void *buff, size_t size) 94 { 95 ssize_t retval, total = 0; 96 97 while (size) { 98 retval = read(sockfd, buff, size); 99 if (retval == 0) { 100 return -EIO; 101 } 102 if (retval < 0) { 103 if (errno == EINTR) { 104 continue; 105 } 106 return -errno; 107 } 108 size -= retval; 109 buff += retval; 110 total += retval; 111 } 112 return total; 113 } 114 115 /* Converts proxy_statfs to VFS statfs structure */ 116 static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs) 117 { 118 memset(stfs, 0, sizeof(*stfs)); 119 stfs->f_type = prstfs->f_type; 120 stfs->f_bsize = prstfs->f_bsize; 121 stfs->f_blocks = prstfs->f_blocks; 122 stfs->f_bfree = prstfs->f_bfree; 123 stfs->f_bavail = prstfs->f_bavail; 124 stfs->f_files = prstfs->f_files; 125 stfs->f_ffree = prstfs->f_ffree; 126 #ifdef CONFIG_DARWIN 127 /* f_namelen and f_frsize do not exist on Darwin */ 128 stfs->f_fsid.val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU; 129 stfs->f_fsid.val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU; 130 #else 131 stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU; 132 stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU; 133 stfs->f_namelen = prstfs->f_namelen; 134 stfs->f_frsize = prstfs->f_frsize; 135 #endif 136 } 137 138 /* Converts proxy_stat structure to VFS stat structure */ 139 static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat) 140 { 141 memset(stbuf, 0, sizeof(*stbuf)); 142 stbuf->st_dev = prstat->st_dev; 143 stbuf->st_ino = prstat->st_ino; 144 stbuf->st_nlink = prstat->st_nlink; 145 stbuf->st_mode = prstat->st_mode; 146 stbuf->st_uid = prstat->st_uid; 147 stbuf->st_gid = prstat->st_gid; 148 stbuf->st_rdev = prstat->st_rdev; 149 stbuf->st_size = prstat->st_size; 150 stbuf->st_blksize = prstat->st_blksize; 151 stbuf->st_blocks = prstat->st_blocks; 152 stbuf->st_atime = prstat->st_atim_sec; 153 stbuf->st_mtime = prstat->st_mtim_sec; 154 stbuf->st_ctime = prstat->st_ctim_sec; 155 #ifdef CONFIG_DARWIN 156 stbuf->st_atimespec.tv_sec = prstat->st_atim_sec; 157 stbuf->st_mtimespec.tv_sec = prstat->st_mtim_sec; 158 stbuf->st_ctimespec.tv_sec = prstat->st_ctim_sec; 159 stbuf->st_atimespec.tv_nsec = prstat->st_atim_nsec; 160 stbuf->st_mtimespec.tv_nsec = prstat->st_mtim_nsec; 161 stbuf->st_ctimespec.tv_nsec = prstat->st_ctim_nsec; 162 #else 163 stbuf->st_atim.tv_sec = prstat->st_atim_sec; 164 stbuf->st_mtim.tv_sec = prstat->st_mtim_sec; 165 stbuf->st_ctim.tv_sec = prstat->st_ctim_sec; 166 stbuf->st_atim.tv_nsec = prstat->st_atim_nsec; 167 stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec; 168 stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec; 169 #endif 170 } 171 172 /* 173 * Response contains two parts 174 * {header, data} 175 * header.type == T_ERROR, data -> -errno 176 * header.type == T_SUCCESS, data -> response 177 * size of errno/response is given by header.size 178 * returns < 0, on transport error. response is 179 * valid only if status >= 0. 180 */ 181 static int v9fs_receive_response(V9fsProxy *proxy, int type, 182 int *status, void *response) 183 { 184 int retval; 185 ProxyHeader header; 186 struct iovec *reply = &proxy->in_iovec; 187 188 *status = 0; 189 reply->iov_len = 0; 190 retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); 191 if (retval < 0) { 192 return retval; 193 } 194 reply->iov_len = PROXY_HDR_SZ; 195 retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); 196 assert(retval == 4 * 2); 197 /* 198 * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and 199 * return -ENOBUFS 200 */ 201 if (header.size > PROXY_MAX_IO_SZ) { 202 int count; 203 while (header.size > 0) { 204 count = MIN(PROXY_MAX_IO_SZ, header.size); 205 count = socket_read(proxy->sockfd, reply->iov_base, count); 206 if (count < 0) { 207 return count; 208 } 209 header.size -= count; 210 } 211 *status = -ENOBUFS; 212 return 0; 213 } 214 215 retval = socket_read(proxy->sockfd, 216 reply->iov_base + PROXY_HDR_SZ, header.size); 217 if (retval < 0) { 218 return retval; 219 } 220 reply->iov_len += header.size; 221 /* there was an error during processing request */ 222 if (header.type == T_ERROR) { 223 int ret; 224 ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status); 225 assert(ret == 4); 226 return 0; 227 } 228 229 switch (type) { 230 case T_LSTAT: { 231 ProxyStat prstat; 232 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, 233 "qqqdddqqqqqqqqqq", &prstat.st_dev, 234 &prstat.st_ino, &prstat.st_nlink, 235 &prstat.st_mode, &prstat.st_uid, 236 &prstat.st_gid, &prstat.st_rdev, 237 &prstat.st_size, &prstat.st_blksize, 238 &prstat.st_blocks, 239 &prstat.st_atim_sec, &prstat.st_atim_nsec, 240 &prstat.st_mtim_sec, &prstat.st_mtim_nsec, 241 &prstat.st_ctim_sec, &prstat.st_ctim_nsec); 242 assert(retval == 8 * 3 + 4 * 3 + 8 * 10); 243 prstat_to_stat(response, &prstat); 244 break; 245 } 246 case T_STATFS: { 247 ProxyStatFS prstfs; 248 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, 249 "qqqqqqqqqqq", &prstfs.f_type, 250 &prstfs.f_bsize, &prstfs.f_blocks, 251 &prstfs.f_bfree, &prstfs.f_bavail, 252 &prstfs.f_files, &prstfs.f_ffree, 253 &prstfs.f_fsid[0], &prstfs.f_fsid[1], 254 &prstfs.f_namelen, &prstfs.f_frsize); 255 assert(retval == 8 * 11); 256 prstatfs_to_statfs(response, &prstfs); 257 break; 258 } 259 case T_READLINK: { 260 V9fsString target; 261 v9fs_string_init(&target); 262 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target); 263 strcpy(response, target.data); 264 v9fs_string_free(&target); 265 break; 266 } 267 case T_LGETXATTR: 268 case T_LLISTXATTR: { 269 V9fsString xattr; 270 v9fs_string_init(&xattr); 271 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr); 272 memcpy(response, xattr.data, xattr.size); 273 v9fs_string_free(&xattr); 274 break; 275 } 276 case T_GETVERSION: 277 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response); 278 assert(retval == 8); 279 break; 280 default: 281 return -1; 282 } 283 if (retval < 0) { 284 *status = retval; 285 } 286 return 0; 287 } 288 289 /* 290 * return < 0 on transport error. 291 * *status is valid only if return >= 0 292 */ 293 static int v9fs_receive_status(V9fsProxy *proxy, 294 struct iovec *reply, int *status) 295 { 296 int retval; 297 ProxyHeader header; 298 299 *status = 0; 300 reply->iov_len = 0; 301 retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); 302 if (retval < 0) { 303 return retval; 304 } 305 reply->iov_len = PROXY_HDR_SZ; 306 retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); 307 assert(retval == 4 * 2); 308 retval = socket_read(proxy->sockfd, 309 reply->iov_base + PROXY_HDR_SZ, header.size); 310 if (retval < 0) { 311 return retval; 312 } 313 reply->iov_len += header.size; 314 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status); 315 assert(retval == 4); 316 return 0; 317 } 318 319 /* 320 * Proxy->header and proxy->request written to socket by QEMU process. 321 * This request read by proxy helper process 322 * returns 0 on success and -errno on error 323 */ 324 static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...) 325 { 326 dev_t rdev; 327 va_list ap; 328 int size = 0; 329 int retval = 0; 330 uint64_t offset; 331 ProxyHeader header = { 0, 0}; 332 struct timespec spec[2]; 333 int flags, mode, uid, gid; 334 V9fsString *name, *value; 335 V9fsString *path, *oldpath; 336 struct iovec *iovec = NULL, *reply = NULL; 337 338 qemu_mutex_lock(&proxy->mutex); 339 340 if (proxy->sockfd == -1) { 341 retval = -EIO; 342 goto err_out; 343 } 344 iovec = &proxy->out_iovec; 345 reply = &proxy->in_iovec; 346 va_start(ap, response); 347 switch (type) { 348 case T_OPEN: 349 path = va_arg(ap, V9fsString *); 350 flags = va_arg(ap, int); 351 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags); 352 if (retval > 0) { 353 header.size = retval; 354 header.type = T_OPEN; 355 } 356 break; 357 case T_CREATE: 358 path = va_arg(ap, V9fsString *); 359 flags = va_arg(ap, int); 360 mode = va_arg(ap, int); 361 uid = va_arg(ap, int); 362 gid = va_arg(ap, int); 363 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path, 364 flags, mode, uid, gid); 365 if (retval > 0) { 366 header.size = retval; 367 header.type = T_CREATE; 368 } 369 break; 370 case T_MKNOD: 371 path = va_arg(ap, V9fsString *); 372 mode = va_arg(ap, int); 373 rdev = va_arg(ap, long int); 374 uid = va_arg(ap, int); 375 gid = va_arg(ap, int); 376 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq", 377 uid, gid, path, mode, rdev); 378 if (retval > 0) { 379 header.size = retval; 380 header.type = T_MKNOD; 381 } 382 break; 383 case T_MKDIR: 384 path = va_arg(ap, V9fsString *); 385 mode = va_arg(ap, int); 386 uid = va_arg(ap, int); 387 gid = va_arg(ap, int); 388 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd", 389 uid, gid, path, mode); 390 if (retval > 0) { 391 header.size = retval; 392 header.type = T_MKDIR; 393 } 394 break; 395 case T_SYMLINK: 396 oldpath = va_arg(ap, V9fsString *); 397 path = va_arg(ap, V9fsString *); 398 uid = va_arg(ap, int); 399 gid = va_arg(ap, int); 400 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss", 401 uid, gid, oldpath, path); 402 if (retval > 0) { 403 header.size = retval; 404 header.type = T_SYMLINK; 405 } 406 break; 407 case T_LINK: 408 oldpath = va_arg(ap, V9fsString *); 409 path = va_arg(ap, V9fsString *); 410 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", 411 oldpath, path); 412 if (retval > 0) { 413 header.size = retval; 414 header.type = T_LINK; 415 } 416 break; 417 case T_LSTAT: 418 path = va_arg(ap, V9fsString *); 419 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 420 if (retval > 0) { 421 header.size = retval; 422 header.type = T_LSTAT; 423 } 424 break; 425 case T_READLINK: 426 path = va_arg(ap, V9fsString *); 427 size = va_arg(ap, int); 428 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size); 429 if (retval > 0) { 430 header.size = retval; 431 header.type = T_READLINK; 432 } 433 break; 434 case T_STATFS: 435 path = va_arg(ap, V9fsString *); 436 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 437 if (retval > 0) { 438 header.size = retval; 439 header.type = T_STATFS; 440 } 441 break; 442 case T_CHMOD: 443 path = va_arg(ap, V9fsString *); 444 mode = va_arg(ap, int); 445 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode); 446 if (retval > 0) { 447 header.size = retval; 448 header.type = T_CHMOD; 449 } 450 break; 451 case T_CHOWN: 452 path = va_arg(ap, V9fsString *); 453 uid = va_arg(ap, int); 454 gid = va_arg(ap, int); 455 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid); 456 if (retval > 0) { 457 header.size = retval; 458 header.type = T_CHOWN; 459 } 460 break; 461 case T_TRUNCATE: 462 path = va_arg(ap, V9fsString *); 463 offset = va_arg(ap, uint64_t); 464 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset); 465 if (retval > 0) { 466 header.size = retval; 467 header.type = T_TRUNCATE; 468 } 469 break; 470 case T_UTIME: 471 path = va_arg(ap, V9fsString *); 472 spec[0].tv_sec = va_arg(ap, long); 473 spec[0].tv_nsec = va_arg(ap, long); 474 spec[1].tv_sec = va_arg(ap, long); 475 spec[1].tv_nsec = va_arg(ap, long); 476 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path, 477 spec[0].tv_sec, spec[1].tv_nsec, 478 spec[1].tv_sec, spec[1].tv_nsec); 479 if (retval > 0) { 480 header.size = retval; 481 header.type = T_UTIME; 482 } 483 break; 484 case T_RENAME: 485 oldpath = va_arg(ap, V9fsString *); 486 path = va_arg(ap, V9fsString *); 487 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path); 488 if (retval > 0) { 489 header.size = retval; 490 header.type = T_RENAME; 491 } 492 break; 493 case T_REMOVE: 494 path = va_arg(ap, V9fsString *); 495 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 496 if (retval > 0) { 497 header.size = retval; 498 header.type = T_REMOVE; 499 } 500 break; 501 case T_LGETXATTR: 502 size = va_arg(ap, int); 503 path = va_arg(ap, V9fsString *); 504 name = va_arg(ap, V9fsString *); 505 retval = proxy_marshal(iovec, PROXY_HDR_SZ, 506 "dss", size, path, name); 507 if (retval > 0) { 508 header.size = retval; 509 header.type = T_LGETXATTR; 510 } 511 break; 512 case T_LLISTXATTR: 513 size = va_arg(ap, int); 514 path = va_arg(ap, V9fsString *); 515 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path); 516 if (retval > 0) { 517 header.size = retval; 518 header.type = T_LLISTXATTR; 519 } 520 break; 521 case T_LSETXATTR: 522 path = va_arg(ap, V9fsString *); 523 name = va_arg(ap, V9fsString *); 524 value = va_arg(ap, V9fsString *); 525 size = va_arg(ap, int); 526 flags = va_arg(ap, int); 527 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd", 528 path, name, value, size, flags); 529 if (retval > 0) { 530 header.size = retval; 531 header.type = T_LSETXATTR; 532 } 533 break; 534 case T_LREMOVEXATTR: 535 path = va_arg(ap, V9fsString *); 536 name = va_arg(ap, V9fsString *); 537 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name); 538 if (retval > 0) { 539 header.size = retval; 540 header.type = T_LREMOVEXATTR; 541 } 542 break; 543 case T_GETVERSION: 544 path = va_arg(ap, V9fsString *); 545 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 546 if (retval > 0) { 547 header.size = retval; 548 header.type = T_GETVERSION; 549 } 550 break; 551 default: 552 error_report("Invalid type %d", type); 553 retval = -EINVAL; 554 break; 555 } 556 va_end(ap); 557 558 if (retval < 0) { 559 goto err_out; 560 } 561 562 /* marshal the header details */ 563 retval = proxy_marshal(iovec, 0, "dd", header.type, header.size); 564 assert(retval == 4 * 2); 565 header.size += PROXY_HDR_SZ; 566 567 retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size); 568 if (retval != header.size) { 569 goto close_error; 570 } 571 572 switch (type) { 573 case T_OPEN: 574 case T_CREATE: 575 /* 576 * A file descriptor is returned as response for 577 * T_OPEN,T_CREATE on success 578 */ 579 if (v9fs_receivefd(proxy->sockfd, &retval) < 0) { 580 goto close_error; 581 } 582 break; 583 case T_MKNOD: 584 case T_MKDIR: 585 case T_SYMLINK: 586 case T_LINK: 587 case T_CHMOD: 588 case T_CHOWN: 589 case T_RENAME: 590 case T_TRUNCATE: 591 case T_UTIME: 592 case T_REMOVE: 593 case T_LSETXATTR: 594 case T_LREMOVEXATTR: 595 if (v9fs_receive_status(proxy, reply, &retval) < 0) { 596 goto close_error; 597 } 598 break; 599 case T_LSTAT: 600 case T_READLINK: 601 case T_STATFS: 602 case T_GETVERSION: 603 if (v9fs_receive_response(proxy, type, &retval, response) < 0) { 604 goto close_error; 605 } 606 break; 607 case T_LGETXATTR: 608 case T_LLISTXATTR: 609 if (!size) { 610 if (v9fs_receive_status(proxy, reply, &retval) < 0) { 611 goto close_error; 612 } 613 } else { 614 if (v9fs_receive_response(proxy, type, &retval, response) < 0) { 615 goto close_error; 616 } 617 } 618 break; 619 } 620 621 err_out: 622 qemu_mutex_unlock(&proxy->mutex); 623 return retval; 624 625 close_error: 626 close(proxy->sockfd); 627 proxy->sockfd = -1; 628 qemu_mutex_unlock(&proxy->mutex); 629 return -EIO; 630 } 631 632 static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) 633 { 634 int retval; 635 retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path); 636 if (retval < 0) { 637 errno = -retval; 638 return -1; 639 } 640 return retval; 641 } 642 643 static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path, 644 char *buf, size_t bufsz) 645 { 646 int retval; 647 retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz); 648 if (retval < 0) { 649 errno = -retval; 650 return -1; 651 } 652 return strlen(buf); 653 } 654 655 static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs) 656 { 657 return close(fs->fd); 658 } 659 660 static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs) 661 { 662 return closedir(fs->dir.stream); 663 } 664 665 static int proxy_open(FsContext *ctx, V9fsPath *fs_path, 666 int flags, V9fsFidOpenState *fs) 667 { 668 fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags); 669 if (fs->fd < 0) { 670 errno = -fs->fd; 671 fs->fd = -1; 672 } 673 return fs->fd; 674 } 675 676 static int proxy_opendir(FsContext *ctx, 677 V9fsPath *fs_path, V9fsFidOpenState *fs) 678 { 679 int serrno, fd; 680 681 fs->dir.stream = NULL; 682 fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY); 683 if (fd < 0) { 684 errno = -fd; 685 return -1; 686 } 687 fs->dir.stream = fdopendir(fd); 688 if (!fs->dir.stream) { 689 serrno = errno; 690 close(fd); 691 errno = serrno; 692 return -1; 693 } 694 return 0; 695 } 696 697 static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) 698 { 699 rewinddir(fs->dir.stream); 700 } 701 702 static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs) 703 { 704 return telldir(fs->dir.stream); 705 } 706 707 static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs) 708 { 709 struct dirent *entry; 710 entry = readdir(fs->dir.stream); 711 #ifdef CONFIG_DARWIN 712 if (!entry) { 713 return NULL; 714 } 715 int td; 716 td = telldir(fs->dir.stream); 717 /* If telldir fails, fail the entire readdir call */ 718 if (td < 0) { 719 return NULL; 720 } 721 entry->d_seekoff = td; 722 #endif 723 return entry; 724 } 725 726 static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) 727 { 728 seekdir(fs->dir.stream, off); 729 } 730 731 static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs, 732 const struct iovec *iov, 733 int iovcnt, off_t offset) 734 { 735 ssize_t ret; 736 #ifdef CONFIG_PREADV 737 ret = preadv(fs->fd, iov, iovcnt, offset); 738 #else 739 ret = lseek(fs->fd, offset, SEEK_SET); 740 if (ret >= 0) { 741 ret = readv(fs->fd, iov, iovcnt); 742 } 743 #endif 744 return ret; 745 } 746 747 static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs, 748 const struct iovec *iov, 749 int iovcnt, off_t offset) 750 { 751 ssize_t ret; 752 753 #ifdef CONFIG_PREADV 754 ret = pwritev(fs->fd, iov, iovcnt, offset); 755 #else 756 ret = lseek(fs->fd, offset, SEEK_SET); 757 if (ret >= 0) { 758 ret = writev(fs->fd, iov, iovcnt); 759 } 760 #endif 761 #ifdef CONFIG_SYNC_FILE_RANGE 762 if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { 763 /* 764 * Initiate a writeback. This is not a data integrity sync. 765 * We want to ensure that we don't leave dirty pages in the cache 766 * after write when writeout=immediate is sepcified. 767 */ 768 sync_file_range(fs->fd, offset, ret, 769 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); 770 } 771 #endif 772 return ret; 773 } 774 775 static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 776 { 777 int retval; 778 retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path, 779 credp->fc_mode); 780 if (retval < 0) { 781 errno = -retval; 782 } 783 return retval; 784 } 785 786 static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path, 787 const char *name, FsCred *credp) 788 { 789 int retval; 790 V9fsString fullname; 791 792 v9fs_string_init(&fullname); 793 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 794 795 retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname, 796 credp->fc_mode, credp->fc_rdev, 797 credp->fc_uid, credp->fc_gid); 798 v9fs_string_free(&fullname); 799 if (retval < 0) { 800 errno = -retval; 801 retval = -1; 802 } 803 return retval; 804 } 805 806 static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, 807 const char *name, FsCred *credp) 808 { 809 int retval; 810 V9fsString fullname; 811 812 v9fs_string_init(&fullname); 813 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 814 815 retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname, 816 credp->fc_mode, credp->fc_uid, credp->fc_gid); 817 v9fs_string_free(&fullname); 818 if (retval < 0) { 819 errno = -retval; 820 retval = -1; 821 } 822 return retval; 823 } 824 825 static int proxy_fstat(FsContext *fs_ctx, int fid_type, 826 V9fsFidOpenState *fs, struct stat *stbuf) 827 { 828 int fd; 829 830 if (fid_type == P9_FID_DIR) { 831 fd = dirfd(fs->dir.stream); 832 } else { 833 fd = fs->fd; 834 } 835 return fstat(fd, stbuf); 836 } 837 838 static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, 839 int flags, FsCred *credp, V9fsFidOpenState *fs) 840 { 841 V9fsString fullname; 842 843 v9fs_string_init(&fullname); 844 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 845 846 fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags, 847 credp->fc_mode, credp->fc_uid, credp->fc_gid); 848 v9fs_string_free(&fullname); 849 if (fs->fd < 0) { 850 errno = -fs->fd; 851 fs->fd = -1; 852 } 853 return fs->fd; 854 } 855 856 static int proxy_symlink(FsContext *fs_ctx, const char *oldpath, 857 V9fsPath *dir_path, const char *name, FsCred *credp) 858 { 859 int retval; 860 V9fsString fullname, target; 861 862 v9fs_string_init(&fullname); 863 v9fs_string_init(&target); 864 865 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 866 v9fs_string_sprintf(&target, "%s", oldpath); 867 868 retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname, 869 credp->fc_uid, credp->fc_gid); 870 v9fs_string_free(&fullname); 871 v9fs_string_free(&target); 872 if (retval < 0) { 873 errno = -retval; 874 retval = -1; 875 } 876 return retval; 877 } 878 879 static int proxy_link(FsContext *ctx, V9fsPath *oldpath, 880 V9fsPath *dirpath, const char *name) 881 { 882 int retval; 883 V9fsString newpath; 884 885 v9fs_string_init(&newpath); 886 v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); 887 888 retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath); 889 v9fs_string_free(&newpath); 890 if (retval < 0) { 891 errno = -retval; 892 retval = -1; 893 } 894 return retval; 895 } 896 897 static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) 898 { 899 int retval; 900 901 retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size); 902 if (retval < 0) { 903 errno = -retval; 904 return -1; 905 } 906 return 0; 907 } 908 909 static int proxy_rename(FsContext *ctx, const char *oldpath, 910 const char *newpath) 911 { 912 int retval; 913 V9fsString oldname, newname; 914 915 v9fs_string_init(&oldname); 916 v9fs_string_init(&newname); 917 918 v9fs_string_sprintf(&oldname, "%s", oldpath); 919 v9fs_string_sprintf(&newname, "%s", newpath); 920 retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname); 921 v9fs_string_free(&oldname); 922 v9fs_string_free(&newname); 923 if (retval < 0) { 924 errno = -retval; 925 } 926 return retval; 927 } 928 929 static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 930 { 931 int retval; 932 retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path, 933 credp->fc_uid, credp->fc_gid); 934 if (retval < 0) { 935 errno = -retval; 936 } 937 return retval; 938 } 939 940 static int proxy_utimensat(FsContext *s, V9fsPath *fs_path, 941 const struct timespec *buf) 942 { 943 int retval; 944 retval = v9fs_request(s->private, T_UTIME, NULL, fs_path, 945 buf[0].tv_sec, buf[0].tv_nsec, 946 buf[1].tv_sec, buf[1].tv_nsec); 947 if (retval < 0) { 948 errno = -retval; 949 } 950 return retval; 951 } 952 953 static int proxy_remove(FsContext *ctx, const char *path) 954 { 955 int retval; 956 V9fsString name; 957 v9fs_string_init(&name); 958 v9fs_string_sprintf(&name, "%s", path); 959 retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name); 960 v9fs_string_free(&name); 961 if (retval < 0) { 962 errno = -retval; 963 } 964 return retval; 965 } 966 967 static int proxy_fsync(FsContext *ctx, int fid_type, 968 V9fsFidOpenState *fs, int datasync) 969 { 970 int fd; 971 972 if (fid_type == P9_FID_DIR) { 973 fd = dirfd(fs->dir.stream); 974 } else { 975 fd = fs->fd; 976 } 977 978 if (datasync) { 979 return qemu_fdatasync(fd); 980 } else { 981 return fsync(fd); 982 } 983 } 984 985 static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) 986 { 987 int retval; 988 retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path); 989 if (retval < 0) { 990 errno = -retval; 991 return -1; 992 } 993 return retval; 994 } 995 996 static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path, 997 const char *name, void *value, size_t size) 998 { 999 int retval; 1000 V9fsString xname; 1001 1002 v9fs_string_init(&xname); 1003 v9fs_string_sprintf(&xname, "%s", name); 1004 retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path, 1005 &xname); 1006 v9fs_string_free(&xname); 1007 if (retval < 0) { 1008 errno = -retval; 1009 } 1010 return retval; 1011 } 1012 1013 static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path, 1014 void *value, size_t size) 1015 { 1016 int retval; 1017 retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path); 1018 if (retval < 0) { 1019 errno = -retval; 1020 } 1021 return retval; 1022 } 1023 1024 static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, 1025 void *value, size_t size, int flags) 1026 { 1027 int retval; 1028 V9fsString xname, xvalue; 1029 1030 v9fs_string_init(&xname); 1031 v9fs_string_sprintf(&xname, "%s", name); 1032 1033 v9fs_string_init(&xvalue); 1034 xvalue.size = size; 1035 xvalue.data = g_malloc(size); 1036 memcpy(xvalue.data, value, size); 1037 1038 retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname, 1039 &xvalue, size, flags); 1040 v9fs_string_free(&xname); 1041 v9fs_string_free(&xvalue); 1042 if (retval < 0) { 1043 errno = -retval; 1044 } 1045 return retval; 1046 } 1047 1048 static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path, 1049 const char *name) 1050 { 1051 int retval; 1052 V9fsString xname; 1053 1054 v9fs_string_init(&xname); 1055 v9fs_string_sprintf(&xname, "%s", name); 1056 retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname); 1057 v9fs_string_free(&xname); 1058 if (retval < 0) { 1059 errno = -retval; 1060 } 1061 return retval; 1062 } 1063 1064 static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path, 1065 const char *name, V9fsPath *target) 1066 { 1067 if (dir_path) { 1068 v9fs_path_sprintf(target, "%s/%s", dir_path->data, name); 1069 } else { 1070 v9fs_path_sprintf(target, "%s", name); 1071 } 1072 return 0; 1073 } 1074 1075 static int proxy_renameat(FsContext *ctx, V9fsPath *olddir, 1076 const char *old_name, V9fsPath *newdir, 1077 const char *new_name) 1078 { 1079 int ret; 1080 V9fsString old_full_name, new_full_name; 1081 1082 v9fs_string_init(&old_full_name); 1083 v9fs_string_init(&new_full_name); 1084 1085 v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); 1086 v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); 1087 1088 ret = proxy_rename(ctx, old_full_name.data, new_full_name.data); 1089 v9fs_string_free(&old_full_name); 1090 v9fs_string_free(&new_full_name); 1091 return ret; 1092 } 1093 1094 static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir, 1095 const char *name, int flags) 1096 { 1097 int ret; 1098 V9fsString fullname; 1099 v9fs_string_init(&fullname); 1100 1101 v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); 1102 ret = proxy_remove(ctx, fullname.data); 1103 v9fs_string_free(&fullname); 1104 1105 return ret; 1106 } 1107 1108 static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path, 1109 mode_t st_mode, uint64_t *st_gen) 1110 { 1111 int err; 1112 1113 /* Do not try to open special files like device nodes, fifos etc 1114 * we can get fd for regular files and directories only 1115 */ 1116 if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { 1117 errno = ENOTTY; 1118 return -1; 1119 } 1120 err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path); 1121 if (err < 0) { 1122 errno = -err; 1123 err = -1; 1124 } 1125 return err; 1126 } 1127 1128 static int connect_namedsocket(const char *path, Error **errp) 1129 { 1130 int sockfd; 1131 struct sockaddr_un helper; 1132 1133 if (strlen(path) >= sizeof(helper.sun_path)) { 1134 error_setg(errp, "socket name too long"); 1135 return -1; 1136 } 1137 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 1138 if (sockfd < 0) { 1139 error_setg_errno(errp, errno, "failed to create client socket"); 1140 return -1; 1141 } 1142 strcpy(helper.sun_path, path); 1143 helper.sun_family = AF_UNIX; 1144 if (connect(sockfd, (struct sockaddr *)&helper, sizeof(helper)) < 0) { 1145 error_setg_errno(errp, errno, "failed to connect to '%s'", path); 1146 close(sockfd); 1147 return -1; 1148 } 1149 1150 /* remove the socket for security reasons */ 1151 unlink(path); 1152 return sockfd; 1153 } 1154 1155 static void error_append_socket_sockfd_hint(Error *const *errp) 1156 { 1157 error_append_hint(errp, "Either specify socket=/some/path where /some/path" 1158 " points to a listening AF_UNIX socket or sock_fd=fd" 1159 " where fd is a file descriptor to a connected AF_UNIX" 1160 " socket\n"); 1161 } 1162 1163 static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp) 1164 { 1165 const char *socket = qemu_opt_get(opts, "socket"); 1166 const char *sock_fd = qemu_opt_get(opts, "sock_fd"); 1167 1168 if (!socket && !sock_fd) { 1169 error_setg(errp, "both socket and sock_fd properties are missing"); 1170 error_append_socket_sockfd_hint(errp); 1171 return -1; 1172 } 1173 if (socket && sock_fd) { 1174 error_setg(errp, "both socket and sock_fd properties are set"); 1175 error_append_socket_sockfd_hint(errp); 1176 return -1; 1177 } 1178 if (socket) { 1179 fs->path = g_strdup(socket); 1180 fs->export_flags |= V9FS_PROXY_SOCK_NAME; 1181 } else { 1182 fs->path = g_strdup(sock_fd); 1183 fs->export_flags |= V9FS_PROXY_SOCK_FD; 1184 } 1185 return 0; 1186 } 1187 1188 static int proxy_init(FsContext *ctx, Error **errp) 1189 { 1190 V9fsProxy *proxy = g_new(V9fsProxy, 1); 1191 int sock_id; 1192 1193 if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) { 1194 sock_id = connect_namedsocket(ctx->fs_root, errp); 1195 } else { 1196 sock_id = atoi(ctx->fs_root); 1197 if (sock_id < 0) { 1198 error_setg(errp, "socket descriptor not initialized"); 1199 } 1200 } 1201 if (sock_id < 0) { 1202 g_free(proxy); 1203 return -1; 1204 } 1205 g_free(ctx->fs_root); 1206 ctx->fs_root = NULL; 1207 1208 proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 1209 proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 1210 proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 1211 proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 1212 1213 ctx->private = proxy; 1214 proxy->sockfd = sock_id; 1215 qemu_mutex_init(&proxy->mutex); 1216 1217 ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; 1218 ctx->exops.get_st_gen = proxy_ioc_getversion; 1219 return 0; 1220 } 1221 1222 static void proxy_cleanup(FsContext *ctx) 1223 { 1224 V9fsProxy *proxy = ctx->private; 1225 1226 if (!proxy) { 1227 return; 1228 } 1229 1230 g_free(proxy->out_iovec.iov_base); 1231 g_free(proxy->in_iovec.iov_base); 1232 if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) { 1233 close(proxy->sockfd); 1234 } 1235 g_free(proxy); 1236 } 1237 1238 FileOperations proxy_ops = { 1239 .parse_opts = proxy_parse_opts, 1240 .init = proxy_init, 1241 .cleanup = proxy_cleanup, 1242 .lstat = proxy_lstat, 1243 .readlink = proxy_readlink, 1244 .close = proxy_close, 1245 .closedir = proxy_closedir, 1246 .open = proxy_open, 1247 .opendir = proxy_opendir, 1248 .rewinddir = proxy_rewinddir, 1249 .telldir = proxy_telldir, 1250 .readdir = proxy_readdir, 1251 .seekdir = proxy_seekdir, 1252 .preadv = proxy_preadv, 1253 .pwritev = proxy_pwritev, 1254 .chmod = proxy_chmod, 1255 .mknod = proxy_mknod, 1256 .mkdir = proxy_mkdir, 1257 .fstat = proxy_fstat, 1258 .open2 = proxy_open2, 1259 .symlink = proxy_symlink, 1260 .link = proxy_link, 1261 .truncate = proxy_truncate, 1262 .rename = proxy_rename, 1263 .chown = proxy_chown, 1264 .utimensat = proxy_utimensat, 1265 .remove = proxy_remove, 1266 .fsync = proxy_fsync, 1267 .statfs = proxy_statfs, 1268 .lgetxattr = proxy_lgetxattr, 1269 .llistxattr = proxy_llistxattr, 1270 .lsetxattr = proxy_lsetxattr, 1271 .lremovexattr = proxy_lremovexattr, 1272 .name_to_path = proxy_name_to_path, 1273 .renameat = proxy_renameat, 1274 .unlinkat = proxy_unlinkat, 1275 }; 1276