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