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 "block/coroutine.h"
  18#include "virtio-9p-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 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 v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf)
  73{
  74    int err;
  75    V9fsState *s = pdu->s;
  76
  77    if (v9fs_request_cancelled(pdu)) {
  78        return -EINTR;
  79    }
  80    v9fs_path_read_lock(s);
  81    v9fs_co_run_in_worker(
  82        {
  83            err = s->ops->statfs(&s->ctx, path, stbuf);
  84            if (err < 0) {
  85                err = -errno;
  86            }
  87        });
  88    v9fs_path_unlock(s);
  89    return err;
  90}
  91
  92int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
  93{
  94    int err;
  95    FsCred cred;
  96    V9fsState *s = pdu->s;
  97
  98    if (v9fs_request_cancelled(pdu)) {
  99        return -EINTR;
 100    }
 101    cred_init(&cred);
 102    cred.fc_mode = mode;
 103    v9fs_path_read_lock(s);
 104    v9fs_co_run_in_worker(
 105        {
 106            err = s->ops->chmod(&s->ctx, path, &cred);
 107            if (err < 0) {
 108                err = -errno;
 109            }
 110        });
 111    v9fs_path_unlock(s);
 112    return err;
 113}
 114
 115int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
 116                      struct timespec times[2])
 117{
 118    int err;
 119    V9fsState *s = pdu->s;
 120
 121    if (v9fs_request_cancelled(pdu)) {
 122        return -EINTR;
 123    }
 124    v9fs_path_read_lock(s);
 125    v9fs_co_run_in_worker(
 126        {
 127            err = s->ops->utimensat(&s->ctx, path, times);
 128            if (err < 0) {
 129                err = -errno;
 130            }
 131        });
 132    v9fs_path_unlock(s);
 133    return err;
 134}
 135
 136int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid)
 137{
 138    int err;
 139    FsCred cred;
 140    V9fsState *s = pdu->s;
 141
 142    if (v9fs_request_cancelled(pdu)) {
 143        return -EINTR;
 144    }
 145    cred_init(&cred);
 146    cred.fc_uid = uid;
 147    cred.fc_gid = gid;
 148    v9fs_path_read_lock(s);
 149    v9fs_co_run_in_worker(
 150        {
 151            err = s->ops->chown(&s->ctx, path, &cred);
 152            if (err < 0) {
 153                err = -errno;
 154            }
 155        });
 156    v9fs_path_unlock(s);
 157    return err;
 158}
 159
 160int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
 161{
 162    int err;
 163    V9fsState *s = pdu->s;
 164
 165    if (v9fs_request_cancelled(pdu)) {
 166        return -EINTR;
 167    }
 168    v9fs_path_read_lock(s);
 169    v9fs_co_run_in_worker(
 170        {
 171            err = s->ops->truncate(&s->ctx, path, size);
 172            if (err < 0) {
 173                err = -errno;
 174            }
 175        });
 176    v9fs_path_unlock(s);
 177    return err;
 178}
 179
 180int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid,
 181                  gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
 182{
 183    int err;
 184    V9fsPath path;
 185    FsCred cred;
 186    V9fsState *s = pdu->s;
 187
 188    if (v9fs_request_cancelled(pdu)) {
 189        return -EINTR;
 190    }
 191    cred_init(&cred);
 192    cred.fc_uid  = uid;
 193    cred.fc_gid  = gid;
 194    cred.fc_mode = mode;
 195    cred.fc_rdev = dev;
 196    v9fs_path_read_lock(s);
 197    v9fs_co_run_in_worker(
 198        {
 199            err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
 200            if (err < 0) {
 201                err = -errno;
 202            } else {
 203                v9fs_path_init(&path);
 204                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
 205                if (!err) {
 206                    err = s->ops->lstat(&s->ctx, &path, stbuf);
 207                    if (err < 0) {
 208                        err = -errno;
 209                    }
 210                }
 211                v9fs_path_free(&path);
 212            }
 213        });
 214    v9fs_path_unlock(s);
 215    return err;
 216}
 217
 218/* Only works with path name based fid */
 219int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
 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->remove(&s->ctx, path->data);
 231            if (err < 0) {
 232                err = -errno;
 233            }
 234        });
 235    v9fs_path_unlock(s);
 236    return err;
 237}
 238
 239int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags)
 240{
 241    int err;
 242    V9fsState *s = pdu->s;
 243
 244    if (v9fs_request_cancelled(pdu)) {
 245        return -EINTR;
 246    }
 247    v9fs_path_read_lock(s);
 248    v9fs_co_run_in_worker(
 249        {
 250            err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
 251            if (err < 0) {
 252                err = -errno;
 253            }
 254        });
 255    v9fs_path_unlock(s);
 256    return err;
 257}
 258
 259/* Only work with path name based fid */
 260int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath)
 261{
 262    int err;
 263    V9fsState *s = pdu->s;
 264
 265    if (v9fs_request_cancelled(pdu)) {
 266        return -EINTR;
 267    }
 268    v9fs_co_run_in_worker(
 269        {
 270            err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
 271            if (err < 0) {
 272                err = -errno;
 273            }
 274        });
 275    return err;
 276}
 277
 278int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname,
 279                     V9fsPath *newdirpath, V9fsString *newname)
 280{
 281    int err;
 282    V9fsState *s = pdu->s;
 283
 284    if (v9fs_request_cancelled(pdu)) {
 285        return -EINTR;
 286    }
 287    v9fs_co_run_in_worker(
 288        {
 289            err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
 290                                   newdirpath, newname->data);
 291            if (err < 0) {
 292                err = -errno;
 293            }
 294        });
 295    return err;
 296}
 297
 298int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name,
 299                    const char *oldpath, gid_t gid, struct stat *stbuf)
 300{
 301    int err;
 302    FsCred cred;
 303    V9fsPath path;
 304    V9fsState *s = pdu->s;
 305
 306    if (v9fs_request_cancelled(pdu)) {
 307        return -EINTR;
 308    }
 309    cred_init(&cred);
 310    cred.fc_uid = dfidp->uid;
 311    cred.fc_gid = gid;
 312    cred.fc_mode = 0777;
 313    v9fs_path_read_lock(s);
 314    v9fs_co_run_in_worker(
 315        {
 316            err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
 317                                  name->data, &cred);
 318            if (err < 0) {
 319                err = -errno;
 320            } else {
 321                v9fs_path_init(&path);
 322                err = v9fs_name_to_path(s, &dfidp->path, name->data, &path);
 323                if (!err) {
 324                    err = s->ops->lstat(&s->ctx, &path, stbuf);
 325                    if (err < 0) {
 326                        err = -errno;
 327                    }
 328                }
 329                v9fs_path_free(&path);
 330            }
 331        });
 332    v9fs_path_unlock(s);
 333    return err;
 334}
 335
 336/*
 337 * For path name based fid we don't block. So we can
 338 * directly call the fs driver ops.
 339 */
 340int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
 341                         const char *name, V9fsPath *path)
 342{
 343    int err;
 344    V9fsState *s = pdu->s;
 345
 346    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
 347        err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
 348        if (err < 0) {
 349            err = -errno;
 350        }
 351    } else {
 352        if (v9fs_request_cancelled(pdu)) {
 353            return -EINTR;
 354        }
 355        v9fs_co_run_in_worker(
 356            {
 357                err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
 358                if (err < 0) {
 359                    err = -errno;
 360                }
 361            });
 362    }
 363    return err;
 364}
 365