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