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