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/cutils.h" 17 #include "qemu/error-report.h" 18 #include "fsdev/qemu-fsdev.h" 19 #include "9p-proxy.h" 20 21 typedef struct V9fsProxy { 22 int sockfd; 23 QemuMutex mutex; 24 struct iovec in_iovec; 25 struct iovec out_iovec; 26 } V9fsProxy; 27 28 /* 29 * Return received file descriptor on success in *status. 30 * errno is also returned on *status (which will be < 0) 31 * return < 0 on transport error. 32 */ 33 static int v9fs_receivefd(int sockfd, int *status) 34 { 35 struct iovec iov; 36 struct msghdr msg; 37 struct cmsghdr *cmsg; 38 int retval, data, fd; 39 union MsgControl msg_control; 40 41 iov.iov_base = &data; 42 iov.iov_len = sizeof(data); 43 44 memset(&msg, 0, sizeof(msg)); 45 msg.msg_iov = &iov; 46 msg.msg_iovlen = 1; 47 msg.msg_control = &msg_control; 48 msg.msg_controllen = sizeof(msg_control); 49 50 do { 51 retval = recvmsg(sockfd, &msg, 0); 52 } while (retval < 0 && errno == EINTR); 53 if (retval <= 0) { 54 return retval; 55 } 56 /* 57 * data is set to V9FS_FD_VALID, if ancillary data is sent. If this 58 * request doesn't need ancillary data (fd) or an error occurred, 59 * data is set to negative errno value. 60 */ 61 if (data != V9FS_FD_VALID) { 62 *status = data; 63 return 0; 64 } 65 /* 66 * File descriptor (fd) is sent in the ancillary data. Check if we 67 * indeed received it. One of the reasons to fail to receive it is if 68 * we exceeded the maximum number of file descriptors! 69 */ 70 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 71 if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || 72 cmsg->cmsg_level != SOL_SOCKET || 73 cmsg->cmsg_type != SCM_RIGHTS) { 74 continue; 75 } 76 fd = *((int *)CMSG_DATA(cmsg)); 77 *status = fd; 78 return 0; 79 } 80 *status = -ENFILE; /* Ancillary data sent but not received */ 81 return 0; 82 } 83 84 static ssize_t socket_read(int sockfd, void *buff, size_t size) 85 { 86 ssize_t retval, total = 0; 87 88 while (size) { 89 retval = read(sockfd, buff, size); 90 if (retval == 0) { 91 return -EIO; 92 } 93 if (retval < 0) { 94 if (errno == EINTR) { 95 continue; 96 } 97 return -errno; 98 } 99 size -= retval; 100 buff += retval; 101 total += retval; 102 } 103 return total; 104 } 105 106 /* Converts proxy_statfs to VFS statfs structure */ 107 static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs) 108 { 109 memset(stfs, 0, sizeof(*stfs)); 110 stfs->f_type = prstfs->f_type; 111 stfs->f_bsize = prstfs->f_bsize; 112 stfs->f_blocks = prstfs->f_blocks; 113 stfs->f_bfree = prstfs->f_bfree; 114 stfs->f_bavail = prstfs->f_bavail; 115 stfs->f_files = prstfs->f_files; 116 stfs->f_ffree = prstfs->f_ffree; 117 stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU; 118 stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU; 119 stfs->f_namelen = prstfs->f_namelen; 120 stfs->f_frsize = prstfs->f_frsize; 121 } 122 123 /* Converts proxy_stat structure to VFS stat structure */ 124 static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat) 125 { 126 memset(stbuf, 0, sizeof(*stbuf)); 127 stbuf->st_dev = prstat->st_dev; 128 stbuf->st_ino = prstat->st_ino; 129 stbuf->st_nlink = prstat->st_nlink; 130 stbuf->st_mode = prstat->st_mode; 131 stbuf->st_uid = prstat->st_uid; 132 stbuf->st_gid = prstat->st_gid; 133 stbuf->st_rdev = prstat->st_rdev; 134 stbuf->st_size = prstat->st_size; 135 stbuf->st_blksize = prstat->st_blksize; 136 stbuf->st_blocks = prstat->st_blocks; 137 stbuf->st_atim.tv_sec = prstat->st_atim_sec; 138 stbuf->st_atim.tv_nsec = prstat->st_atim_nsec; 139 stbuf->st_mtime = prstat->st_mtim_sec; 140 stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec; 141 stbuf->st_ctime = prstat->st_ctim_sec; 142 stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec; 143 } 144 145 /* 146 * Response contains two parts 147 * {header, data} 148 * header.type == T_ERROR, data -> -errno 149 * header.type == T_SUCCESS, data -> response 150 * size of errno/response is given by header.size 151 * returns < 0, on transport error. response is 152 * valid only if status >= 0. 153 */ 154 static int v9fs_receive_response(V9fsProxy *proxy, int type, 155 int *status, void *response) 156 { 157 int retval; 158 ProxyHeader header; 159 struct iovec *reply = &proxy->in_iovec; 160 161 *status = 0; 162 reply->iov_len = 0; 163 retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); 164 if (retval < 0) { 165 return retval; 166 } 167 reply->iov_len = PROXY_HDR_SZ; 168 retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); 169 assert(retval == 4 * 2); 170 /* 171 * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and 172 * return -ENOBUFS 173 */ 174 if (header.size > PROXY_MAX_IO_SZ) { 175 int count; 176 while (header.size > 0) { 177 count = MIN(PROXY_MAX_IO_SZ, header.size); 178 count = socket_read(proxy->sockfd, reply->iov_base, count); 179 if (count < 0) { 180 return count; 181 } 182 header.size -= count; 183 } 184 *status = -ENOBUFS; 185 return 0; 186 } 187 188 retval = socket_read(proxy->sockfd, 189 reply->iov_base + PROXY_HDR_SZ, header.size); 190 if (retval < 0) { 191 return retval; 192 } 193 reply->iov_len += header.size; 194 /* there was an error during processing request */ 195 if (header.type == T_ERROR) { 196 int ret; 197 ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status); 198 assert(ret == 4); 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 assert(retval == 8 * 3 + 4 * 3 + 8 * 10); 216 prstat_to_stat(response, &prstat); 217 break; 218 } 219 case T_STATFS: { 220 ProxyStatFS prstfs; 221 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, 222 "qqqqqqqqqqq", &prstfs.f_type, 223 &prstfs.f_bsize, &prstfs.f_blocks, 224 &prstfs.f_bfree, &prstfs.f_bavail, 225 &prstfs.f_files, &prstfs.f_ffree, 226 &prstfs.f_fsid[0], &prstfs.f_fsid[1], 227 &prstfs.f_namelen, &prstfs.f_frsize); 228 assert(retval == 8 * 11); 229 prstatfs_to_statfs(response, &prstfs); 230 break; 231 } 232 case T_READLINK: { 233 V9fsString target; 234 v9fs_string_init(&target); 235 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target); 236 strcpy(response, target.data); 237 v9fs_string_free(&target); 238 break; 239 } 240 case T_LGETXATTR: 241 case T_LLISTXATTR: { 242 V9fsString xattr; 243 v9fs_string_init(&xattr); 244 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr); 245 memcpy(response, xattr.data, xattr.size); 246 v9fs_string_free(&xattr); 247 break; 248 } 249 case T_GETVERSION: 250 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response); 251 assert(retval == 8); 252 break; 253 default: 254 return -1; 255 } 256 if (retval < 0) { 257 *status = retval; 258 } 259 return 0; 260 } 261 262 /* 263 * return < 0 on transport error. 264 * *status is valid only if return >= 0 265 */ 266 static int v9fs_receive_status(V9fsProxy *proxy, 267 struct iovec *reply, int *status) 268 { 269 int retval; 270 ProxyHeader header; 271 272 *status = 0; 273 reply->iov_len = 0; 274 retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); 275 if (retval < 0) { 276 return retval; 277 } 278 reply->iov_len = PROXY_HDR_SZ; 279 retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); 280 assert(retval == 4 * 2); 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 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status); 288 assert(retval == 4); 289 return 0; 290 } 291 292 /* 293 * Proxy->header and proxy->request written to socket by QEMU process. 294 * This request read by proxy helper process 295 * returns 0 on success and -errno on error 296 */ 297 static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...) 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, response); 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, 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, fs_path, bufsz); 620 if (retval < 0) { 621 errno = -retval; 622 return -1; 623 } 624 return strlen(buf); 625 } 626 627 static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs) 628 { 629 return close(fs->fd); 630 } 631 632 static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs) 633 { 634 return closedir(fs->dir.stream); 635 } 636 637 static int proxy_open(FsContext *ctx, V9fsPath *fs_path, 638 int flags, V9fsFidOpenState *fs) 639 { 640 fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags); 641 if (fs->fd < 0) { 642 errno = -fs->fd; 643 fs->fd = -1; 644 } 645 return fs->fd; 646 } 647 648 static int proxy_opendir(FsContext *ctx, 649 V9fsPath *fs_path, V9fsFidOpenState *fs) 650 { 651 int serrno, fd; 652 653 fs->dir.stream = NULL; 654 fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY); 655 if (fd < 0) { 656 errno = -fd; 657 return -1; 658 } 659 fs->dir.stream = fdopendir(fd); 660 if (!fs->dir.stream) { 661 serrno = errno; 662 close(fd); 663 errno = serrno; 664 return -1; 665 } 666 return 0; 667 } 668 669 static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) 670 { 671 rewinddir(fs->dir.stream); 672 } 673 674 static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs) 675 { 676 return telldir(fs->dir.stream); 677 } 678 679 static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs) 680 { 681 return readdir(fs->dir.stream); 682 } 683 684 static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) 685 { 686 seekdir(fs->dir.stream, off); 687 } 688 689 static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs, 690 const struct iovec *iov, 691 int iovcnt, off_t offset) 692 { 693 ssize_t ret; 694 #ifdef CONFIG_PREADV 695 ret = preadv(fs->fd, iov, iovcnt, offset); 696 #else 697 ret = lseek(fs->fd, offset, SEEK_SET); 698 if (ret >= 0) { 699 ret = readv(fs->fd, iov, iovcnt); 700 } 701 #endif 702 return ret; 703 } 704 705 static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs, 706 const struct iovec *iov, 707 int iovcnt, off_t offset) 708 { 709 ssize_t ret; 710 711 #ifdef CONFIG_PREADV 712 ret = pwritev(fs->fd, iov, iovcnt, offset); 713 #else 714 ret = lseek(fs->fd, offset, SEEK_SET); 715 if (ret >= 0) { 716 ret = writev(fs->fd, iov, iovcnt); 717 } 718 #endif 719 #ifdef CONFIG_SYNC_FILE_RANGE 720 if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { 721 /* 722 * Initiate a writeback. This is not a data integrity sync. 723 * We want to ensure that we don't leave dirty pages in the cache 724 * after write when writeout=immediate is sepcified. 725 */ 726 sync_file_range(fs->fd, offset, ret, 727 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); 728 } 729 #endif 730 return ret; 731 } 732 733 static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 734 { 735 int retval; 736 retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path, 737 credp->fc_mode); 738 if (retval < 0) { 739 errno = -retval; 740 } 741 return retval; 742 } 743 744 static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path, 745 const char *name, FsCred *credp) 746 { 747 int retval; 748 V9fsString fullname; 749 750 v9fs_string_init(&fullname); 751 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 752 753 retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname, 754 credp->fc_mode, credp->fc_rdev, 755 credp->fc_uid, credp->fc_gid); 756 v9fs_string_free(&fullname); 757 if (retval < 0) { 758 errno = -retval; 759 retval = -1; 760 } 761 return retval; 762 } 763 764 static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, 765 const char *name, FsCred *credp) 766 { 767 int retval; 768 V9fsString fullname; 769 770 v9fs_string_init(&fullname); 771 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 772 773 retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname, 774 credp->fc_mode, credp->fc_uid, credp->fc_gid); 775 v9fs_string_free(&fullname); 776 if (retval < 0) { 777 errno = -retval; 778 retval = -1; 779 } 780 return retval; 781 } 782 783 static int proxy_fstat(FsContext *fs_ctx, int fid_type, 784 V9fsFidOpenState *fs, struct stat *stbuf) 785 { 786 int fd; 787 788 if (fid_type == P9_FID_DIR) { 789 fd = dirfd(fs->dir.stream); 790 } else { 791 fd = fs->fd; 792 } 793 return fstat(fd, stbuf); 794 } 795 796 static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, 797 int flags, FsCred *credp, V9fsFidOpenState *fs) 798 { 799 V9fsString fullname; 800 801 v9fs_string_init(&fullname); 802 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 803 804 fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags, 805 credp->fc_mode, credp->fc_uid, credp->fc_gid); 806 v9fs_string_free(&fullname); 807 if (fs->fd < 0) { 808 errno = -fs->fd; 809 fs->fd = -1; 810 } 811 return fs->fd; 812 } 813 814 static int proxy_symlink(FsContext *fs_ctx, const char *oldpath, 815 V9fsPath *dir_path, const char *name, FsCred *credp) 816 { 817 int retval; 818 V9fsString fullname, target; 819 820 v9fs_string_init(&fullname); 821 v9fs_string_init(&target); 822 823 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 824 v9fs_string_sprintf(&target, "%s", oldpath); 825 826 retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname, 827 credp->fc_uid, credp->fc_gid); 828 v9fs_string_free(&fullname); 829 v9fs_string_free(&target); 830 if (retval < 0) { 831 errno = -retval; 832 retval = -1; 833 } 834 return retval; 835 } 836 837 static int proxy_link(FsContext *ctx, V9fsPath *oldpath, 838 V9fsPath *dirpath, const char *name) 839 { 840 int retval; 841 V9fsString newpath; 842 843 v9fs_string_init(&newpath); 844 v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); 845 846 retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath); 847 v9fs_string_free(&newpath); 848 if (retval < 0) { 849 errno = -retval; 850 retval = -1; 851 } 852 return retval; 853 } 854 855 static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) 856 { 857 int retval; 858 859 retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size); 860 if (retval < 0) { 861 errno = -retval; 862 return -1; 863 } 864 return 0; 865 } 866 867 static int proxy_rename(FsContext *ctx, const char *oldpath, 868 const char *newpath) 869 { 870 int retval; 871 V9fsString oldname, newname; 872 873 v9fs_string_init(&oldname); 874 v9fs_string_init(&newname); 875 876 v9fs_string_sprintf(&oldname, "%s", oldpath); 877 v9fs_string_sprintf(&newname, "%s", newpath); 878 retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname); 879 v9fs_string_free(&oldname); 880 v9fs_string_free(&newname); 881 if (retval < 0) { 882 errno = -retval; 883 } 884 return retval; 885 } 886 887 static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 888 { 889 int retval; 890 retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path, 891 credp->fc_uid, credp->fc_gid); 892 if (retval < 0) { 893 errno = -retval; 894 } 895 return retval; 896 } 897 898 static int proxy_utimensat(FsContext *s, V9fsPath *fs_path, 899 const struct timespec *buf) 900 { 901 int retval; 902 retval = v9fs_request(s->private, T_UTIME, NULL, fs_path, 903 buf[0].tv_sec, buf[0].tv_nsec, 904 buf[1].tv_sec, buf[1].tv_nsec); 905 if (retval < 0) { 906 errno = -retval; 907 } 908 return retval; 909 } 910 911 static int proxy_remove(FsContext *ctx, const char *path) 912 { 913 int retval; 914 V9fsString name; 915 v9fs_string_init(&name); 916 v9fs_string_sprintf(&name, "%s", path); 917 retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name); 918 v9fs_string_free(&name); 919 if (retval < 0) { 920 errno = -retval; 921 } 922 return retval; 923 } 924 925 static int proxy_fsync(FsContext *ctx, int fid_type, 926 V9fsFidOpenState *fs, int datasync) 927 { 928 int fd; 929 930 if (fid_type == P9_FID_DIR) { 931 fd = dirfd(fs->dir.stream); 932 } else { 933 fd = fs->fd; 934 } 935 936 if (datasync) { 937 return qemu_fdatasync(fd); 938 } else { 939 return fsync(fd); 940 } 941 } 942 943 static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) 944 { 945 int retval; 946 retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path); 947 if (retval < 0) { 948 errno = -retval; 949 return -1; 950 } 951 return retval; 952 } 953 954 static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path, 955 const char *name, void *value, size_t size) 956 { 957 int retval; 958 V9fsString xname; 959 960 v9fs_string_init(&xname); 961 v9fs_string_sprintf(&xname, "%s", name); 962 retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path, 963 &xname); 964 v9fs_string_free(&xname); 965 if (retval < 0) { 966 errno = -retval; 967 } 968 return retval; 969 } 970 971 static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path, 972 void *value, size_t size) 973 { 974 int retval; 975 retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path); 976 if (retval < 0) { 977 errno = -retval; 978 } 979 return retval; 980 } 981 982 static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, 983 void *value, size_t size, int flags) 984 { 985 int retval; 986 V9fsString xname, xvalue; 987 988 v9fs_string_init(&xname); 989 v9fs_string_sprintf(&xname, "%s", name); 990 991 v9fs_string_init(&xvalue); 992 xvalue.size = size; 993 xvalue.data = g_malloc(size); 994 memcpy(xvalue.data, value, size); 995 996 retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname, 997 &xvalue, size, flags); 998 v9fs_string_free(&xname); 999 v9fs_string_free(&xvalue); 1000 if (retval < 0) { 1001 errno = -retval; 1002 } 1003 return retval; 1004 } 1005 1006 static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path, 1007 const char *name) 1008 { 1009 int retval; 1010 V9fsString xname; 1011 1012 v9fs_string_init(&xname); 1013 v9fs_string_sprintf(&xname, "%s", name); 1014 retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname); 1015 v9fs_string_free(&xname); 1016 if (retval < 0) { 1017 errno = -retval; 1018 } 1019 return retval; 1020 } 1021 1022 static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path, 1023 const char *name, V9fsPath *target) 1024 { 1025 if (dir_path) { 1026 v9fs_path_sprintf(target, "%s/%s", dir_path->data, name); 1027 } else { 1028 v9fs_path_sprintf(target, "%s", name); 1029 } 1030 return 0; 1031 } 1032 1033 static int proxy_renameat(FsContext *ctx, V9fsPath *olddir, 1034 const char *old_name, V9fsPath *newdir, 1035 const char *new_name) 1036 { 1037 int ret; 1038 V9fsString old_full_name, new_full_name; 1039 1040 v9fs_string_init(&old_full_name); 1041 v9fs_string_init(&new_full_name); 1042 1043 v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); 1044 v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); 1045 1046 ret = proxy_rename(ctx, old_full_name.data, new_full_name.data); 1047 v9fs_string_free(&old_full_name); 1048 v9fs_string_free(&new_full_name); 1049 return ret; 1050 } 1051 1052 static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir, 1053 const char *name, int flags) 1054 { 1055 int ret; 1056 V9fsString fullname; 1057 v9fs_string_init(&fullname); 1058 1059 v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); 1060 ret = proxy_remove(ctx, fullname.data); 1061 v9fs_string_free(&fullname); 1062 1063 return ret; 1064 } 1065 1066 static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path, 1067 mode_t st_mode, uint64_t *st_gen) 1068 { 1069 int err; 1070 1071 /* Do not try to open special files like device nodes, fifos etc 1072 * we can get fd for regular files and directories only 1073 */ 1074 if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { 1075 errno = ENOTTY; 1076 return -1; 1077 } 1078 err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path); 1079 if (err < 0) { 1080 errno = -err; 1081 err = -1; 1082 } 1083 return err; 1084 } 1085 1086 static int connect_namedsocket(const char *path) 1087 { 1088 int sockfd, size; 1089 struct sockaddr_un helper; 1090 1091 if (strlen(path) >= sizeof(helper.sun_path)) { 1092 error_report("Socket name too long"); 1093 return -1; 1094 } 1095 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 1096 if (sockfd < 0) { 1097 error_report("Failed to create socket: %s", strerror(errno)); 1098 return -1; 1099 } 1100 strcpy(helper.sun_path, path); 1101 helper.sun_family = AF_UNIX; 1102 size = strlen(helper.sun_path) + sizeof(helper.sun_family); 1103 if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) { 1104 error_report("Failed to connect to %s: %s", path, strerror(errno)); 1105 close(sockfd); 1106 return -1; 1107 } 1108 1109 /* remove the socket for security reasons */ 1110 unlink(path); 1111 return sockfd; 1112 } 1113 1114 static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs) 1115 { 1116 const char *socket = qemu_opt_get(opts, "socket"); 1117 const char *sock_fd = qemu_opt_get(opts, "sock_fd"); 1118 1119 if (!socket && !sock_fd) { 1120 error_report("Must specify either socket or sock_fd"); 1121 return -1; 1122 } 1123 if (socket && sock_fd) { 1124 error_report("Both socket and sock_fd options specified"); 1125 return -1; 1126 } 1127 if (socket) { 1128 fs->path = g_strdup(socket); 1129 fs->export_flags = V9FS_PROXY_SOCK_NAME; 1130 } else { 1131 fs->path = g_strdup(sock_fd); 1132 fs->export_flags = V9FS_PROXY_SOCK_FD; 1133 } 1134 return 0; 1135 } 1136 1137 static int proxy_init(FsContext *ctx) 1138 { 1139 V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy)); 1140 int sock_id; 1141 1142 if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) { 1143 sock_id = connect_namedsocket(ctx->fs_root); 1144 } else { 1145 sock_id = atoi(ctx->fs_root); 1146 if (sock_id < 0) { 1147 error_report("Socket descriptor not initialized"); 1148 } 1149 } 1150 if (sock_id < 0) { 1151 g_free(proxy); 1152 return -1; 1153 } 1154 g_free(ctx->fs_root); 1155 ctx->fs_root = NULL; 1156 1157 proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 1158 proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 1159 proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 1160 proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 1161 1162 ctx->private = proxy; 1163 proxy->sockfd = sock_id; 1164 qemu_mutex_init(&proxy->mutex); 1165 1166 ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; 1167 ctx->exops.get_st_gen = proxy_ioc_getversion; 1168 return 0; 1169 } 1170 1171 static void proxy_cleanup(FsContext *ctx) 1172 { 1173 V9fsProxy *proxy = ctx->private; 1174 1175 g_free(proxy->out_iovec.iov_base); 1176 g_free(proxy->in_iovec.iov_base); 1177 if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) { 1178 close(proxy->sockfd); 1179 } 1180 g_free(proxy); 1181 } 1182 1183 FileOperations proxy_ops = { 1184 .parse_opts = proxy_parse_opts, 1185 .init = proxy_init, 1186 .cleanup = proxy_cleanup, 1187 .lstat = proxy_lstat, 1188 .readlink = proxy_readlink, 1189 .close = proxy_close, 1190 .closedir = proxy_closedir, 1191 .open = proxy_open, 1192 .opendir = proxy_opendir, 1193 .rewinddir = proxy_rewinddir, 1194 .telldir = proxy_telldir, 1195 .readdir = proxy_readdir, 1196 .seekdir = proxy_seekdir, 1197 .preadv = proxy_preadv, 1198 .pwritev = proxy_pwritev, 1199 .chmod = proxy_chmod, 1200 .mknod = proxy_mknod, 1201 .mkdir = proxy_mkdir, 1202 .fstat = proxy_fstat, 1203 .open2 = proxy_open2, 1204 .symlink = proxy_symlink, 1205 .link = proxy_link, 1206 .truncate = proxy_truncate, 1207 .rename = proxy_rename, 1208 .chown = proxy_chown, 1209 .utimensat = proxy_utimensat, 1210 .remove = proxy_remove, 1211 .fsync = proxy_fsync, 1212 .statfs = proxy_statfs, 1213 .lgetxattr = proxy_lgetxattr, 1214 .llistxattr = proxy_llistxattr, 1215 .lsetxattr = proxy_lsetxattr, 1216 .lremovexattr = proxy_lremovexattr, 1217 .name_to_path = proxy_name_to_path, 1218 .renameat = proxy_renameat, 1219 .unlinkat = proxy_unlinkat, 1220 }; 1221