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