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