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