cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

9p-proxy.c (35621B)


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