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