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

cofs.c (9342B)


      1/*
      2 * 9p backend
      3 *
      4 * Copyright IBM, Corp. 2011
      5 *
      6 * Authors:
      7 *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.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/*
     15 * Not so fast! You might want to read the 9p developer docs first:
     16 * https://wiki.qemu.org/Documentation/9p
     17 */
     18
     19#include "qemu/osdep.h"
     20#include "fsdev/qemu-fsdev.h"
     21#include "qemu/thread.h"
     22#include "qemu/coroutine.h"
     23#include "qemu/main-loop.h"
     24#include "coth.h"
     25
     26static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
     27{
     28    ssize_t len, maxlen = PATH_MAX;
     29
     30    buf->data = g_malloc(PATH_MAX);
     31    for (;;) {
     32        len = s->ops->readlink(&s->ctx, path, buf->data, maxlen);
     33        if (len < 0) {
     34            g_free(buf->data);
     35            buf->data = NULL;
     36            buf->size = 0;
     37            break;
     38        } else if (len == maxlen) {
     39            /*
     40             * We dodn't have space to put the NULL or we have more
     41             * to read. Increase the size and try again
     42             */
     43            maxlen *= 2;
     44            g_free(buf->data);
     45            buf->data = g_malloc(maxlen);
     46            continue;
     47        }
     48        /*
     49         * Null terminate the readlink output
     50         */
     51        buf->data[len] = '\0';
     52        buf->size = len;
     53        break;
     54    }
     55    return len;
     56}
     57
     58int coroutine_fn v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
     59{
     60    int err;
     61    V9fsState *s = pdu->s;
     62
     63    if (v9fs_request_cancelled(pdu)) {
     64        return -EINTR;
     65    }
     66    v9fs_path_read_lock(s);
     67    v9fs_co_run_in_worker(
     68        {
     69            err = __readlink(s, path, buf);
     70            if (err < 0) {
     71                err = -errno;
     72            }
     73        });
     74    v9fs_path_unlock(s);
     75    return err;
     76}
     77
     78int coroutine_fn v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path,
     79                                struct statfs *stbuf)
     80{
     81    int err;
     82    V9fsState *s = pdu->s;
     83
     84    if (v9fs_request_cancelled(pdu)) {
     85        return -EINTR;
     86    }
     87    v9fs_path_read_lock(s);
     88    v9fs_co_run_in_worker(
     89        {
     90            err = s->ops->statfs(&s->ctx, path, stbuf);
     91            if (err < 0) {
     92                err = -errno;
     93            }
     94        });
     95    v9fs_path_unlock(s);
     96    return err;
     97}
     98
     99int coroutine_fn v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
    100{
    101    int err;
    102    FsCred cred;
    103    V9fsState *s = pdu->s;
    104
    105    if (v9fs_request_cancelled(pdu)) {
    106        return -EINTR;
    107    }
    108    cred_init(&cred);
    109    cred.fc_mode = mode;
    110    v9fs_path_read_lock(s);
    111    v9fs_co_run_in_worker(
    112        {
    113            err = s->ops->chmod(&s->ctx, path, &cred);
    114            if (err < 0) {
    115                err = -errno;
    116            }
    117        });
    118    v9fs_path_unlock(s);
    119    return err;
    120}
    121
    122int coroutine_fn v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
    123                                   struct timespec times[2])
    124{
    125    int err;
    126    V9fsState *s = pdu->s;
    127
    128    if (v9fs_request_cancelled(pdu)) {
    129        return -EINTR;
    130    }
    131    v9fs_path_read_lock(s);
    132    v9fs_co_run_in_worker(
    133        {
    134            err = s->ops->utimensat(&s->ctx, path, times);
    135            if (err < 0) {
    136                err = -errno;
    137            }
    138        });
    139    v9fs_path_unlock(s);
    140    return err;
    141}
    142
    143int coroutine_fn v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid,
    144                               gid_t gid)
    145{
    146    int err;
    147    FsCred cred;
    148    V9fsState *s = pdu->s;
    149
    150    if (v9fs_request_cancelled(pdu)) {
    151        return -EINTR;
    152    }
    153    cred_init(&cred);
    154    cred.fc_uid = uid;
    155    cred.fc_gid = gid;
    156    v9fs_path_read_lock(s);
    157    v9fs_co_run_in_worker(
    158        {
    159            err = s->ops->chown(&s->ctx, path, &cred);
    160            if (err < 0) {
    161                err = -errno;
    162            }
    163        });
    164    v9fs_path_unlock(s);
    165    return err;
    166}
    167
    168int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
    169{
    170    int err;
    171    V9fsState *s = pdu->s;
    172
    173    if (v9fs_request_cancelled(pdu)) {
    174        return -EINTR;
    175    }
    176    v9fs_path_read_lock(s);
    177    v9fs_co_run_in_worker(
    178        {
    179            err = s->ops->truncate(&s->ctx, path, size);
    180            if (err < 0) {
    181                err = -errno;
    182            }
    183        });
    184    v9fs_path_unlock(s);
    185    return err;
    186}
    187
    188int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp,
    189                               V9fsString *name, uid_t uid, gid_t gid,
    190                               dev_t dev, mode_t mode, struct stat *stbuf)
    191{
    192    int err;
    193    V9fsPath path;
    194    FsCred cred;
    195    V9fsState *s = pdu->s;
    196
    197    if (v9fs_request_cancelled(pdu)) {
    198        return -EINTR;
    199    }
    200    cred_init(&cred);
    201    cred.fc_uid  = uid;
    202    cred.fc_gid  = gid;
    203    cred.fc_mode = mode;
    204    cred.fc_rdev = dev;
    205    v9fs_path_read_lock(s);
    206    v9fs_co_run_in_worker(
    207        {
    208            err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
    209            if (err < 0) {
    210                err = -errno;
    211            } else {
    212                v9fs_path_init(&path);
    213                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
    214                if (!err) {
    215                    err = s->ops->lstat(&s->ctx, &path, stbuf);
    216                    if (err < 0) {
    217                        err = -errno;
    218                    }
    219                }
    220                v9fs_path_free(&path);
    221            }
    222        });
    223    v9fs_path_unlock(s);
    224    return err;
    225}
    226
    227/* Only works with path name based fid */
    228int coroutine_fn v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
    229{
    230    int err;
    231    V9fsState *s = pdu->s;
    232
    233    if (v9fs_request_cancelled(pdu)) {
    234        return -EINTR;
    235    }
    236    v9fs_path_read_lock(s);
    237    v9fs_co_run_in_worker(
    238        {
    239            err = s->ops->remove(&s->ctx, path->data);
    240            if (err < 0) {
    241                err = -errno;
    242            }
    243        });
    244    v9fs_path_unlock(s);
    245    return err;
    246}
    247
    248int coroutine_fn v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path,
    249                                  V9fsString *name, int flags)
    250{
    251    int err;
    252    V9fsState *s = pdu->s;
    253
    254    if (v9fs_request_cancelled(pdu)) {
    255        return -EINTR;
    256    }
    257    v9fs_path_read_lock(s);
    258    v9fs_co_run_in_worker(
    259        {
    260            err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
    261            if (err < 0) {
    262                err = -errno;
    263            }
    264        });
    265    v9fs_path_unlock(s);
    266    return err;
    267}
    268
    269/* Only work with path name based fid */
    270int coroutine_fn v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath,
    271                                V9fsPath *newpath)
    272{
    273    int err;
    274    V9fsState *s = pdu->s;
    275
    276    if (v9fs_request_cancelled(pdu)) {
    277        return -EINTR;
    278    }
    279    v9fs_co_run_in_worker(
    280        {
    281            err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
    282            if (err < 0) {
    283                err = -errno;
    284            }
    285        });
    286    return err;
    287}
    288
    289int coroutine_fn v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath,
    290                                  V9fsString *oldname, V9fsPath *newdirpath,
    291                                  V9fsString *newname)
    292{
    293    int err;
    294    V9fsState *s = pdu->s;
    295
    296    if (v9fs_request_cancelled(pdu)) {
    297        return -EINTR;
    298    }
    299    v9fs_co_run_in_worker(
    300        {
    301            err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
    302                                   newdirpath, newname->data);
    303            if (err < 0) {
    304                err = -errno;
    305            }
    306        });
    307    return err;
    308}
    309
    310int coroutine_fn v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp,
    311                                 V9fsString *name, const char *oldpath,
    312                                 gid_t gid, struct stat *stbuf)
    313{
    314    int err;
    315    FsCred cred;
    316    V9fsPath path;
    317    V9fsState *s = pdu->s;
    318
    319    if (v9fs_request_cancelled(pdu)) {
    320        return -EINTR;
    321    }
    322    cred_init(&cred);
    323    cred.fc_uid = dfidp->uid;
    324    cred.fc_gid = gid;
    325    cred.fc_mode = 0777;
    326    v9fs_path_read_lock(s);
    327    v9fs_co_run_in_worker(
    328        {
    329            err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
    330                                  name->data, &cred);
    331            if (err < 0) {
    332                err = -errno;
    333            } else {
    334                v9fs_path_init(&path);
    335                err = v9fs_name_to_path(s, &dfidp->path, name->data, &path);
    336                if (!err) {
    337                    err = s->ops->lstat(&s->ctx, &path, stbuf);
    338                    if (err < 0) {
    339                        err = -errno;
    340                    }
    341                }
    342                v9fs_path_free(&path);
    343            }
    344        });
    345    v9fs_path_unlock(s);
    346    return err;
    347}
    348
    349/*
    350 * For path name based fid we don't block. So we can
    351 * directly call the fs driver ops.
    352 */
    353int coroutine_fn v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
    354                                      const char *name, V9fsPath *path)
    355{
    356    int err;
    357    V9fsState *s = pdu->s;
    358
    359    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
    360        err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
    361        if (err < 0) {
    362            err = -errno;
    363        }
    364    } else {
    365        if (v9fs_request_cancelled(pdu)) {
    366            return -EINTR;
    367        }
    368        v9fs_co_run_in_worker(
    369            {
    370                err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
    371                if (err < 0) {
    372                    err = -errno;
    373                }
    374            });
    375    }
    376    return err;
    377}