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/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}
 378