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

buffer.c (8129B)


      1/*
      2 * FUSE: Filesystem in Userspace
      3 * Copyright (C) 2010  Miklos Szeredi <miklos@szeredi.hu>
      4 *
      5 * Functions for dealing with `struct fuse_buf` and `struct
      6 * fuse_bufvec`.
      7 *
      8 * This program can be distributed under the terms of the GNU LGPLv2.
      9 * See the file COPYING.LIB
     10 */
     11
     12#include "qemu/osdep.h"
     13#include "fuse_i.h"
     14#include "fuse_lowlevel.h"
     15
     16size_t fuse_buf_size(const struct fuse_bufvec *bufv)
     17{
     18    size_t i;
     19    size_t size = 0;
     20
     21    for (i = 0; i < bufv->count; i++) {
     22        if (bufv->buf[i].size == SIZE_MAX) {
     23            size = SIZE_MAX;
     24        } else {
     25            size += bufv->buf[i].size;
     26        }
     27    }
     28
     29    return size;
     30}
     31
     32static ssize_t fuse_buf_writev(struct fuse_buf *out_buf,
     33                               struct fuse_bufvec *in_buf)
     34{
     35    ssize_t res, i, j;
     36    size_t iovcnt = in_buf->count;
     37    struct iovec *iov;
     38    int fd = out_buf->fd;
     39
     40    iov = g_try_new0(struct iovec, iovcnt);
     41    if (!iov) {
     42        return -ENOMEM;
     43    }
     44
     45    for (i = 0, j = 0; i < iovcnt; i++) {
     46        /* Skip the buf with 0 size */
     47        if (in_buf->buf[i].size) {
     48            iov[j].iov_base = in_buf->buf[i].mem;
     49            iov[j].iov_len = in_buf->buf[i].size;
     50            j++;
     51        }
     52    }
     53
     54    if (out_buf->flags & FUSE_BUF_FD_SEEK) {
     55        res = pwritev(fd, iov, iovcnt, out_buf->pos);
     56    } else {
     57        res = writev(fd, iov, iovcnt);
     58    }
     59
     60    if (res == -1) {
     61        res = -errno;
     62    }
     63
     64    g_free(iov);
     65    return res;
     66}
     67
     68static size_t min_size(size_t s1, size_t s2)
     69{
     70    return s1 < s2 ? s1 : s2;
     71}
     72
     73static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
     74                              const struct fuse_buf *src, size_t src_off,
     75                              size_t len)
     76{
     77    ssize_t res = 0;
     78    size_t copied = 0;
     79
     80    while (len) {
     81        if (dst->flags & FUSE_BUF_FD_SEEK) {
     82            res = pwrite(dst->fd, (char *)src->mem + src_off, len,
     83                         dst->pos + dst_off);
     84        } else {
     85            res = write(dst->fd, (char *)src->mem + src_off, len);
     86        }
     87        if (res == -1) {
     88            if (!copied) {
     89                return -errno;
     90            }
     91            break;
     92        }
     93        if (res == 0) {
     94            break;
     95        }
     96
     97        copied += res;
     98        if (!(dst->flags & FUSE_BUF_FD_RETRY)) {
     99            break;
    100        }
    101
    102        src_off += res;
    103        dst_off += res;
    104        len -= res;
    105    }
    106
    107    return copied;
    108}
    109
    110static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
    111                             const struct fuse_buf *src, size_t src_off,
    112                             size_t len)
    113{
    114    ssize_t res = 0;
    115    size_t copied = 0;
    116
    117    while (len) {
    118        if (src->flags & FUSE_BUF_FD_SEEK) {
    119            res = pread(src->fd, (char *)dst->mem + dst_off, len,
    120                        src->pos + src_off);
    121        } else {
    122            res = read(src->fd, (char *)dst->mem + dst_off, len);
    123        }
    124        if (res == -1) {
    125            if (!copied) {
    126                return -errno;
    127            }
    128            break;
    129        }
    130        if (res == 0) {
    131            break;
    132        }
    133
    134        copied += res;
    135        if (!(src->flags & FUSE_BUF_FD_RETRY)) {
    136            break;
    137        }
    138
    139        dst_off += res;
    140        src_off += res;
    141        len -= res;
    142    }
    143
    144    return copied;
    145}
    146
    147static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
    148                                 const struct fuse_buf *src, size_t src_off,
    149                                 size_t len)
    150{
    151    char buf[4096];
    152    struct fuse_buf tmp = {
    153        .size = sizeof(buf),
    154        .flags = 0,
    155    };
    156    ssize_t res;
    157    size_t copied = 0;
    158
    159    tmp.mem = buf;
    160
    161    while (len) {
    162        size_t this_len = min_size(tmp.size, len);
    163        size_t read_len;
    164
    165        res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
    166        if (res < 0) {
    167            if (!copied) {
    168                return res;
    169            }
    170            break;
    171        }
    172        if (res == 0) {
    173            break;
    174        }
    175
    176        read_len = res;
    177        res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
    178        if (res < 0) {
    179            if (!copied) {
    180                return res;
    181            }
    182            break;
    183        }
    184        if (res == 0) {
    185            break;
    186        }
    187
    188        copied += res;
    189
    190        if (res < this_len) {
    191            break;
    192        }
    193
    194        dst_off += res;
    195        src_off += res;
    196        len -= res;
    197    }
    198
    199    return copied;
    200}
    201
    202static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
    203                                 const struct fuse_buf *src, size_t src_off,
    204                                 size_t len)
    205{
    206    int src_is_fd = src->flags & FUSE_BUF_IS_FD;
    207    int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
    208
    209    if (!src_is_fd && !dst_is_fd) {
    210        char *dstmem = (char *)dst->mem + dst_off;
    211        char *srcmem = (char *)src->mem + src_off;
    212
    213        if (dstmem != srcmem) {
    214            if (dstmem + len <= srcmem || srcmem + len <= dstmem) {
    215                memcpy(dstmem, srcmem, len);
    216            } else {
    217                memmove(dstmem, srcmem, len);
    218            }
    219        }
    220
    221        return len;
    222    } else if (!src_is_fd) {
    223        return fuse_buf_write(dst, dst_off, src, src_off, len);
    224    } else if (!dst_is_fd) {
    225        return fuse_buf_read(dst, dst_off, src, src_off, len);
    226    } else {
    227        return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
    228    }
    229}
    230
    231static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
    232{
    233    if (bufv->idx < bufv->count) {
    234        return &bufv->buf[bufv->idx];
    235    } else {
    236        return NULL;
    237    }
    238}
    239
    240static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
    241{
    242    const struct fuse_buf *buf = fuse_bufvec_current(bufv);
    243
    244    if (!buf) {
    245        return 0;
    246    }
    247
    248    bufv->off += len;
    249    assert(bufv->off <= buf->size);
    250    if (bufv->off == buf->size) {
    251        assert(bufv->idx < bufv->count);
    252        bufv->idx++;
    253        if (bufv->idx == bufv->count) {
    254            return 0;
    255        }
    256        bufv->off = 0;
    257    }
    258    return 1;
    259}
    260
    261ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv)
    262{
    263    size_t copied = 0, i;
    264
    265    if (dstv == srcv) {
    266        return fuse_buf_size(dstv);
    267    }
    268
    269    /*
    270     * use writev to improve bandwidth when all the
    271     * src buffers already mapped by the daemon
    272     * process
    273     */
    274    for (i = 0; i < srcv->count; i++) {
    275        if (srcv->buf[i].flags & FUSE_BUF_IS_FD) {
    276            break;
    277        }
    278    }
    279    if ((i == srcv->count) && (dstv->count == 1) &&
    280        (dstv->idx == 0) &&
    281        (dstv->buf[0].flags & FUSE_BUF_IS_FD)) {
    282        dstv->buf[0].pos += dstv->off;
    283        return fuse_buf_writev(&dstv->buf[0], srcv);
    284    }
    285
    286    for (;;) {
    287        const struct fuse_buf *src = fuse_bufvec_current(srcv);
    288        const struct fuse_buf *dst = fuse_bufvec_current(dstv);
    289        size_t src_len;
    290        size_t dst_len;
    291        size_t len;
    292        ssize_t res;
    293
    294        if (src == NULL || dst == NULL) {
    295            break;
    296        }
    297
    298        src_len = src->size - srcv->off;
    299        dst_len = dst->size - dstv->off;
    300        len = min_size(src_len, dst_len);
    301
    302        res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len);
    303        if (res < 0) {
    304            if (!copied) {
    305                return res;
    306            }
    307            break;
    308        }
    309        copied += res;
    310
    311        if (!fuse_bufvec_advance(srcv, res) ||
    312            !fuse_bufvec_advance(dstv, res)) {
    313            break;
    314        }
    315
    316        if (res < len) {
    317            break;
    318        }
    319    }
    320
    321    return copied;
    322}
    323
    324void *fuse_mbuf_iter_advance(struct fuse_mbuf_iter *iter, size_t len)
    325{
    326    void *ptr;
    327
    328    if (len > iter->size - iter->pos) {
    329        return NULL;
    330    }
    331
    332    ptr = iter->mem + iter->pos;
    333    iter->pos += len;
    334    return ptr;
    335}
    336
    337const char *fuse_mbuf_iter_advance_str(struct fuse_mbuf_iter *iter)
    338{
    339    const char *str = iter->mem + iter->pos;
    340    size_t remaining = iter->size - iter->pos;
    341    size_t i;
    342
    343    for (i = 0; i < remaining; i++) {
    344        if (str[i] == '\0') {
    345            iter->pos += i + 1;
    346            return str;
    347        }
    348    }
    349    return NULL;
    350}