qemu/hw/9pfs/cofile.c
<<
>>
Prefs
   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
  26int coroutine_fn v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
  27                                V9fsStatDotl *v9stat)
  28{
  29    int err = 0;
  30    V9fsState *s = pdu->s;
  31
  32    if (v9fs_request_cancelled(pdu)) {
  33        return -EINTR;
  34    }
  35    if (s->ctx.exops.get_st_gen) {
  36        v9fs_path_read_lock(s);
  37        v9fs_co_run_in_worker(
  38            {
  39                err = s->ctx.exops.get_st_gen(&s->ctx, path, st_mode,
  40                                              &v9stat->st_gen);
  41                if (err < 0) {
  42                    err = -errno;
  43                }
  44            });
  45        v9fs_path_unlock(s);
  46    }
  47    return err;
  48}
  49
  50int coroutine_fn v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
  51{
  52    int err;
  53    V9fsState *s = pdu->s;
  54
  55    if (v9fs_request_cancelled(pdu)) {
  56        return -EINTR;
  57    }
  58    v9fs_path_read_lock(s);
  59    v9fs_co_run_in_worker(
  60        {
  61            err = s->ops->lstat(&s->ctx, path, stbuf);
  62            if (err < 0) {
  63                err = -errno;
  64            }
  65        });
  66    v9fs_path_unlock(s);
  67    return err;
  68}
  69
  70int coroutine_fn v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp,
  71                               struct stat *stbuf)
  72{
  73    int err;
  74    V9fsState *s = pdu->s;
  75
  76    if (v9fs_request_cancelled(pdu)) {
  77        return -EINTR;
  78    }
  79    v9fs_co_run_in_worker(
  80        {
  81            err = s->ops->fstat(&s->ctx, fidp->fid_type, &fidp->fs, stbuf);
  82            if (err < 0) {
  83                err = -errno;
  84            }
  85        });
  86    /*
  87     * Some FS driver (local:mapped-file) can't support fetching attributes
  88     * using file descriptor. Use Path name in that case.
  89     */
  90    if (err == -EOPNOTSUPP) {
  91        err = v9fs_co_lstat(pdu, &fidp->path, stbuf);
  92        if (err == -ENOENT) {
  93            /*
  94             * fstat on an unlinked file. Work with partial results
  95             * returned from s->ops->fstat
  96             */
  97            err = 0;
  98        }
  99    }
 100    return err;
 101}
 102
 103int coroutine_fn v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
 104{
 105    int err;
 106    V9fsState *s = pdu->s;
 107
 108    if (v9fs_request_cancelled(pdu)) {
 109        return -EINTR;
 110    }
 111    v9fs_path_read_lock(s);
 112    v9fs_co_run_in_worker(
 113        {
 114            err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs);
 115            if (err == -1) {
 116                err = -errno;
 117            } else {
 118                err = 0;
 119            }
 120        });
 121    v9fs_path_unlock(s);
 122    if (!err) {
 123        total_open_fd++;
 124        if (total_open_fd > open_fd_hw) {
 125            v9fs_reclaim_fd(pdu);
 126        }
 127    }
 128    return err;
 129}
 130
 131int coroutine_fn v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp,
 132                               V9fsString *name, gid_t gid, int flags, int mode,
 133                               struct stat *stbuf)
 134{
 135    int err;
 136    FsCred cred;
 137    V9fsPath path;
 138    V9fsState *s = pdu->s;
 139
 140    if (v9fs_request_cancelled(pdu)) {
 141        return -EINTR;
 142    }
 143    cred_init(&cred);
 144    cred.fc_mode = mode & 07777;
 145    cred.fc_uid = fidp->uid;
 146    cred.fc_gid = gid;
 147    /*
 148     * Hold the directory fid lock so that directory path name
 149     * don't change. Take the write lock to be sure this fid
 150     * cannot be used by another operation.
 151     */
 152    v9fs_path_write_lock(s);
 153    v9fs_co_run_in_worker(
 154        {
 155            err = s->ops->open2(&s->ctx, &fidp->path,
 156                                name->data, flags, &cred, &fidp->fs);
 157            if (err < 0) {
 158                err = -errno;
 159            } else {
 160                v9fs_path_init(&path);
 161                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
 162                if (!err) {
 163                    err = s->ops->lstat(&s->ctx, &path, stbuf);
 164                    if (err < 0) {
 165                        err = -errno;
 166                        s->ops->close(&s->ctx, &fidp->fs);
 167                    } else {
 168                        v9fs_path_copy(&fidp->path, &path);
 169                    }
 170                } else {
 171                    s->ops->close(&s->ctx, &fidp->fs);
 172                }
 173                v9fs_path_free(&path);
 174            }
 175        });
 176    v9fs_path_unlock(s);
 177    if (!err) {
 178        total_open_fd++;
 179        if (total_open_fd > open_fd_hw) {
 180            v9fs_reclaim_fd(pdu);
 181        }
 182    }
 183    return err;
 184}
 185
 186int coroutine_fn v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
 187{
 188    int err;
 189    V9fsState *s = pdu->s;
 190
 191    if (v9fs_request_cancelled(pdu)) {
 192        return -EINTR;
 193    }
 194    v9fs_co_run_in_worker(
 195        {
 196            err = s->ops->close(&s->ctx, fs);
 197            if (err < 0) {
 198                err = -errno;
 199            }
 200        });
 201    if (!err) {
 202        total_open_fd--;
 203    }
 204    return err;
 205}
 206
 207int coroutine_fn v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
 208{
 209    int err;
 210    V9fsState *s = pdu->s;
 211
 212    if (v9fs_request_cancelled(pdu)) {
 213        return -EINTR;
 214    }
 215    v9fs_co_run_in_worker(
 216        {
 217            err = s->ops->fsync(&s->ctx, fidp->fid_type, &fidp->fs, datasync);
 218            if (err < 0) {
 219                err = -errno;
 220            }
 221        });
 222    return err;
 223}
 224
 225int coroutine_fn v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
 226                              V9fsFidState *newdirfid, V9fsString *name)
 227{
 228    int err;
 229    V9fsState *s = pdu->s;
 230
 231    if (v9fs_request_cancelled(pdu)) {
 232        return -EINTR;
 233    }
 234    v9fs_path_read_lock(s);
 235    v9fs_co_run_in_worker(
 236        {
 237            err = s->ops->link(&s->ctx, &oldfid->path,
 238                               &newdirfid->path, name->data);
 239            if (err < 0) {
 240                err = -errno;
 241            }
 242        });
 243    v9fs_path_unlock(s);
 244    return err;
 245}
 246
 247int coroutine_fn v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
 248                                 struct iovec *iov, int iovcnt, int64_t offset)
 249{
 250    int err;
 251    V9fsState *s = pdu->s;
 252
 253    if (v9fs_request_cancelled(pdu)) {
 254        return -EINTR;
 255    }
 256    fsdev_co_throttle_request(s->ctx.fst, true, iov, iovcnt);
 257    v9fs_co_run_in_worker(
 258        {
 259            err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
 260            if (err < 0) {
 261                err = -errno;
 262            }
 263        });
 264    return err;
 265}
 266
 267int coroutine_fn v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
 268                                struct iovec *iov, int iovcnt, int64_t offset)
 269{
 270    int err;
 271    V9fsState *s = pdu->s;
 272
 273    if (v9fs_request_cancelled(pdu)) {
 274        return -EINTR;
 275    }
 276    fsdev_co_throttle_request(s->ctx.fst, false, iov, iovcnt);
 277    v9fs_co_run_in_worker(
 278        {
 279            err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
 280            if (err < 0) {
 281                err = -errno;
 282            }
 283        });
 284    return err;
 285}
 286