qemu/hw/9pfs/9p-synth.c
<<
>>
Prefs
   1/*
   2 * 9p synthetic file system support
   3 *
   4 * Copyright IBM, Corp. 2011
   5 *
   6 * Authors:
   7 *  Malahal Naineni <malahal@us.ibm.com>
   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 "9p.h"
  17#include "fsdev/qemu-fsdev.h"
  18#include "9p-synth.h"
  19#include "qemu/rcu.h"
  20#include "qemu/rcu_queue.h"
  21#include "qemu/cutils.h"
  22
  23/* Root node for synth file system */
  24static V9fsSynthNode synth_root = {
  25    .name = "/",
  26    .actual_attr = {
  27        .mode = 0555 | S_IFDIR,
  28        .nlink = 1,
  29    },
  30    .attr = &synth_root.actual_attr,
  31};
  32
  33static QemuMutex  synth_mutex;
  34static int synth_node_count;
  35/* set to 1 when the synth fs is ready */
  36static int synth_fs;
  37
  38static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
  39                                        const char *name,
  40                                        V9fsSynthNodeAttr *attr, int inode)
  41{
  42    V9fsSynthNode *node;
  43
  44    /* Add directory type and remove write bits */
  45    mode = ((mode & 0777) | S_IFDIR) & ~(S_IWUSR | S_IWGRP | S_IWOTH);
  46    node = g_malloc0(sizeof(V9fsSynthNode));
  47    if (attr) {
  48        /* We are adding .. or . entries */
  49        node->attr = attr;
  50        node->attr->nlink++;
  51    } else {
  52        node->attr = &node->actual_attr;
  53        node->attr->inode = inode;
  54        node->attr->nlink = 1;
  55        /* We don't allow write to directories */
  56        node->attr->mode   = mode;
  57        node->attr->write = NULL;
  58        node->attr->read  = NULL;
  59    }
  60    node->private = node;
  61    pstrcpy(node->name, sizeof(node->name), name);
  62    QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
  63    return node;
  64}
  65
  66int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
  67                          const char *name, V9fsSynthNode **result)
  68{
  69    int ret;
  70    V9fsSynthNode *node, *tmp;
  71
  72    if (!synth_fs) {
  73        return EAGAIN;
  74    }
  75    if (!name || (strlen(name) >= NAME_MAX)) {
  76        return EINVAL;
  77    }
  78    if (!parent) {
  79        parent = &synth_root;
  80    }
  81    qemu_mutex_lock(&synth_mutex);
  82    QLIST_FOREACH(tmp, &parent->child, sibling) {
  83        if (!strcmp(tmp->name, name)) {
  84            ret = EEXIST;
  85            goto err_out;
  86        }
  87    }
  88    /* Add the name */
  89    node = v9fs_add_dir_node(parent, mode, name, NULL, synth_node_count++);
  90    v9fs_add_dir_node(node, parent->attr->mode, "..",
  91                      parent->attr, parent->attr->inode);
  92    v9fs_add_dir_node(node, node->attr->mode, ".",
  93                      node->attr, node->attr->inode);
  94    *result = node;
  95    ret = 0;
  96err_out:
  97    qemu_mutex_unlock(&synth_mutex);
  98    return ret;
  99}
 100
 101int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
 102                             const char *name, v9fs_synth_read read,
 103                             v9fs_synth_write write, void *arg)
 104{
 105    int ret;
 106    V9fsSynthNode *node, *tmp;
 107
 108    if (!synth_fs) {
 109        return EAGAIN;
 110    }
 111    if (!name || (strlen(name) >= NAME_MAX)) {
 112        return EINVAL;
 113    }
 114    if (!parent) {
 115        parent = &synth_root;
 116    }
 117
 118    qemu_mutex_lock(&synth_mutex);
 119    QLIST_FOREACH(tmp, &parent->child, sibling) {
 120        if (!strcmp(tmp->name, name)) {
 121            ret = EEXIST;
 122            goto err_out;
 123        }
 124    }
 125    /* Add file type and remove write bits */
 126    mode = ((mode & 0777) | S_IFREG);
 127    node = g_malloc0(sizeof(V9fsSynthNode));
 128    node->attr         = &node->actual_attr;
 129    node->attr->inode  = synth_node_count++;
 130    node->attr->nlink  = 1;
 131    node->attr->read   = read;
 132    node->attr->write  = write;
 133    node->attr->mode   = mode;
 134    node->private      = arg;
 135    pstrcpy(node->name, sizeof(node->name), name);
 136    QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
 137    ret = 0;
 138err_out:
 139    qemu_mutex_unlock(&synth_mutex);
 140    return ret;
 141}
 142
 143static void synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
 144{
 145    stbuf->st_dev = 0;
 146    stbuf->st_ino = node->attr->inode;
 147    stbuf->st_mode = node->attr->mode;
 148    stbuf->st_nlink = node->attr->nlink;
 149    stbuf->st_uid = 0;
 150    stbuf->st_gid = 0;
 151    stbuf->st_rdev = 0;
 152    stbuf->st_size = 0;
 153    stbuf->st_blksize = 0;
 154    stbuf->st_blocks = 0;
 155    stbuf->st_atime = 0;
 156    stbuf->st_mtime = 0;
 157    stbuf->st_ctime = 0;
 158}
 159
 160static int synth_lstat(FsContext *fs_ctx,
 161                            V9fsPath *fs_path, struct stat *stbuf)
 162{
 163    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
 164
 165    synth_fill_statbuf(node, stbuf);
 166    return 0;
 167}
 168
 169static int synth_fstat(FsContext *fs_ctx, int fid_type,
 170                            V9fsFidOpenState *fs, struct stat *stbuf)
 171{
 172    V9fsSynthOpenState *synth_open = fs->private;
 173    synth_fill_statbuf(synth_open->node, stbuf);
 174    return 0;
 175}
 176
 177static int synth_opendir(FsContext *ctx,
 178                             V9fsPath *fs_path, V9fsFidOpenState *fs)
 179{
 180    V9fsSynthOpenState *synth_open;
 181    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
 182
 183    synth_open = g_malloc(sizeof(*synth_open));
 184    synth_open->node = node;
 185    node->open_count++;
 186    fs->private = synth_open;
 187    return 0;
 188}
 189
 190static int synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
 191{
 192    V9fsSynthOpenState *synth_open = fs->private;
 193    V9fsSynthNode *node = synth_open->node;
 194
 195    node->open_count--;
 196    g_free(synth_open);
 197    fs->private = NULL;
 198    return 0;
 199}
 200
 201static off_t synth_telldir(FsContext *ctx, V9fsFidOpenState *fs)
 202{
 203    V9fsSynthOpenState *synth_open = fs->private;
 204    return synth_open->offset;
 205}
 206
 207static void synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
 208{
 209    V9fsSynthOpenState *synth_open = fs->private;
 210    synth_open->offset = off;
 211}
 212
 213static void synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
 214{
 215    synth_seekdir(ctx, fs, 0);
 216}
 217
 218static void synth_direntry(V9fsSynthNode *node,
 219                                struct dirent *entry, off_t off)
 220{
 221    strcpy(entry->d_name, node->name);
 222    entry->d_ino = node->attr->inode;
 223    entry->d_off = off + 1;
 224}
 225
 226static struct dirent *synth_get_dentry(V9fsSynthNode *dir,
 227                                            struct dirent *entry, off_t off)
 228{
 229    int i = 0;
 230    V9fsSynthNode *node;
 231
 232    rcu_read_lock();
 233    QLIST_FOREACH(node, &dir->child, sibling) {
 234        /* This is the off child of the directory */
 235        if (i == off) {
 236            break;
 237        }
 238        i++;
 239    }
 240    rcu_read_unlock();
 241    if (!node) {
 242        /* end of directory */
 243        return NULL;
 244    }
 245    synth_direntry(node, entry, off);
 246    return entry;
 247}
 248
 249static struct dirent *synth_readdir(FsContext *ctx, V9fsFidOpenState *fs)
 250{
 251    struct dirent *entry;
 252    V9fsSynthOpenState *synth_open = fs->private;
 253    V9fsSynthNode *node = synth_open->node;
 254    entry = synth_get_dentry(node, &synth_open->dent, synth_open->offset);
 255    if (entry) {
 256        synth_open->offset++;
 257    }
 258    return entry;
 259}
 260
 261static int synth_open(FsContext *ctx, V9fsPath *fs_path,
 262                           int flags, V9fsFidOpenState *fs)
 263{
 264    V9fsSynthOpenState *synth_open;
 265    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
 266
 267    synth_open = g_malloc(sizeof(*synth_open));
 268    synth_open->node = node;
 269    node->open_count++;
 270    fs->private = synth_open;
 271    return 0;
 272}
 273
 274static int synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
 275                            const char *name, int flags,
 276                            FsCred *credp, V9fsFidOpenState *fs)
 277{
 278    errno = ENOSYS;
 279    return -1;
 280}
 281
 282static int synth_close(FsContext *ctx, V9fsFidOpenState *fs)
 283{
 284    V9fsSynthOpenState *synth_open = fs->private;
 285    V9fsSynthNode *node = synth_open->node;
 286
 287    node->open_count--;
 288    g_free(synth_open);
 289    fs->private = NULL;
 290    return 0;
 291}
 292
 293static ssize_t synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
 294                                  const struct iovec *iov,
 295                                  int iovcnt, off_t offset)
 296{
 297    int i, count = 0, wcount;
 298    V9fsSynthOpenState *synth_open = fs->private;
 299    V9fsSynthNode *node = synth_open->node;
 300    if (!node->attr->write) {
 301        errno = EPERM;
 302        return -1;
 303    }
 304    for (i = 0; i < iovcnt; i++) {
 305        wcount = node->attr->write(iov[i].iov_base, iov[i].iov_len,
 306                                   offset, node->private);
 307        offset += wcount;
 308        count  += wcount;
 309        /* If we wrote less than requested. we are done */
 310        if (wcount < iov[i].iov_len) {
 311            break;
 312        }
 313    }
 314    return count;
 315}
 316
 317static ssize_t synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
 318                                 const struct iovec *iov,
 319                                 int iovcnt, off_t offset)
 320{
 321    int i, count = 0, rcount;
 322    V9fsSynthOpenState *synth_open = fs->private;
 323    V9fsSynthNode *node = synth_open->node;
 324    if (!node->attr->read) {
 325        errno = EPERM;
 326        return -1;
 327    }
 328    for (i = 0; i < iovcnt; i++) {
 329        rcount = node->attr->read(iov[i].iov_base, iov[i].iov_len,
 330                                  offset, node->private);
 331        offset += rcount;
 332        count  += rcount;
 333        /* If we read less than requested. we are done */
 334        if (rcount < iov[i].iov_len) {
 335            break;
 336        }
 337    }
 338    return count;
 339}
 340
 341static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
 342{
 343    errno = ENOSYS;
 344    return -1;
 345}
 346
 347static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
 348{
 349    errno = EPERM;
 350    return -1;
 351}
 352
 353static int synth_mknod(FsContext *fs_ctx, V9fsPath *path,
 354                       const char *buf, FsCred *credp)
 355{
 356    errno = EPERM;
 357    return -1;
 358}
 359
 360static int synth_mkdir(FsContext *fs_ctx, V9fsPath *path,
 361                       const char *buf, FsCred *credp)
 362{
 363    errno = EPERM;
 364    return -1;
 365}
 366
 367static ssize_t synth_readlink(FsContext *fs_ctx, V9fsPath *path,
 368                                   char *buf, size_t bufsz)
 369{
 370    errno = ENOSYS;
 371    return -1;
 372}
 373
 374static int synth_symlink(FsContext *fs_ctx, const char *oldpath,
 375                              V9fsPath *newpath, const char *buf, FsCred *credp)
 376{
 377    errno = EPERM;
 378    return -1;
 379}
 380
 381static int synth_link(FsContext *fs_ctx, V9fsPath *oldpath,
 382                           V9fsPath *newpath, const char *buf)
 383{
 384    errno = EPERM;
 385    return -1;
 386}
 387
 388static int synth_rename(FsContext *ctx, const char *oldpath,
 389                             const char *newpath)
 390{
 391    errno = EPERM;
 392    return -1;
 393}
 394
 395static int synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
 396{
 397    errno = EPERM;
 398    return -1;
 399}
 400
 401static int synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
 402                                const struct timespec *buf)
 403{
 404    errno = EPERM;
 405    return 0;
 406}
 407
 408static int synth_remove(FsContext *ctx, const char *path)
 409{
 410    errno = EPERM;
 411    return -1;
 412}
 413
 414static int synth_fsync(FsContext *ctx, int fid_type,
 415                            V9fsFidOpenState *fs, int datasync)
 416{
 417    errno = ENOSYS;
 418    return 0;
 419}
 420
 421static int synth_statfs(FsContext *s, V9fsPath *fs_path,
 422                             struct statfs *stbuf)
 423{
 424    stbuf->f_type = 0xABCD;
 425    stbuf->f_bsize = 512;
 426    stbuf->f_blocks = 0;
 427    stbuf->f_files = synth_node_count;
 428    stbuf->f_namelen = NAME_MAX;
 429    return 0;
 430}
 431
 432static ssize_t synth_lgetxattr(FsContext *ctx, V9fsPath *path,
 433                                    const char *name, void *value, size_t size)
 434{
 435    errno = ENOTSUP;
 436    return -1;
 437}
 438
 439static ssize_t synth_llistxattr(FsContext *ctx, V9fsPath *path,
 440                                     void *value, size_t size)
 441{
 442    errno = ENOTSUP;
 443    return -1;
 444}
 445
 446static int synth_lsetxattr(FsContext *ctx, V9fsPath *path,
 447                                const char *name, void *value,
 448                                size_t size, int flags)
 449{
 450    errno = ENOTSUP;
 451    return -1;
 452}
 453
 454static int synth_lremovexattr(FsContext *ctx,
 455                                   V9fsPath *path, const char *name)
 456{
 457    errno = ENOTSUP;
 458    return -1;
 459}
 460
 461static int synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
 462                                   const char *name, V9fsPath *target)
 463{
 464    V9fsSynthNode *node;
 465    V9fsSynthNode *dir_node;
 466
 467    /* "." and ".." are not allowed */
 468    if (!strcmp(name, ".") || !strcmp(name, "..")) {
 469        errno = EINVAL;
 470        return -1;
 471
 472    }
 473    if (!dir_path) {
 474        dir_node = &synth_root;
 475    } else {
 476        dir_node = *(V9fsSynthNode **)dir_path->data;
 477    }
 478    if (!strcmp(name, "/")) {
 479        node = dir_node;
 480        goto out;
 481    }
 482    /* search for the name in the childern */
 483    rcu_read_lock();
 484    QLIST_FOREACH(node, &dir_node->child, sibling) {
 485        if (!strcmp(node->name, name)) {
 486            break;
 487        }
 488    }
 489    rcu_read_unlock();
 490
 491    if (!node) {
 492        errno = ENOENT;
 493        return -1;
 494    }
 495out:
 496    /* Copy the node pointer to fid */
 497    target->data = g_malloc(sizeof(void *));
 498    memcpy(target->data, &node, sizeof(void *));
 499    target->size = sizeof(void *);
 500    return 0;
 501}
 502
 503static int synth_renameat(FsContext *ctx, V9fsPath *olddir,
 504                               const char *old_name, V9fsPath *newdir,
 505                               const char *new_name)
 506{
 507    errno = EPERM;
 508    return -1;
 509}
 510
 511static int synth_unlinkat(FsContext *ctx, V9fsPath *dir,
 512                               const char *name, int flags)
 513{
 514    errno = EPERM;
 515    return -1;
 516}
 517
 518static int synth_init(FsContext *ctx)
 519{
 520    QLIST_INIT(&synth_root.child);
 521    qemu_mutex_init(&synth_mutex);
 522
 523    /* Add "." and ".." entries for root */
 524    v9fs_add_dir_node(&synth_root, synth_root.attr->mode,
 525                      "..", synth_root.attr, synth_root.attr->inode);
 526    v9fs_add_dir_node(&synth_root, synth_root.attr->mode,
 527                      ".", synth_root.attr, synth_root.attr->inode);
 528
 529    /* Mark the subsystem is ready for use */
 530    synth_fs = 1;
 531    return 0;
 532}
 533
 534FileOperations synth_ops = {
 535    .init         = synth_init,
 536    .lstat        = synth_lstat,
 537    .readlink     = synth_readlink,
 538    .close        = synth_close,
 539    .closedir     = synth_closedir,
 540    .open         = synth_open,
 541    .opendir      = synth_opendir,
 542    .rewinddir    = synth_rewinddir,
 543    .telldir      = synth_telldir,
 544    .readdir      = synth_readdir,
 545    .seekdir      = synth_seekdir,
 546    .preadv       = synth_preadv,
 547    .pwritev      = synth_pwritev,
 548    .chmod        = synth_chmod,
 549    .mknod        = synth_mknod,
 550    .mkdir        = synth_mkdir,
 551    .fstat        = synth_fstat,
 552    .open2        = synth_open2,
 553    .symlink      = synth_symlink,
 554    .link         = synth_link,
 555    .truncate     = synth_truncate,
 556    .rename       = synth_rename,
 557    .chown        = synth_chown,
 558    .utimensat    = synth_utimensat,
 559    .remove       = synth_remove,
 560    .fsync        = synth_fsync,
 561    .statfs       = synth_statfs,
 562    .lgetxattr    = synth_lgetxattr,
 563    .llistxattr   = synth_llistxattr,
 564    .lsetxattr    = synth_lsetxattr,
 565    .lremovexattr = synth_lremovexattr,
 566    .name_to_path = synth_name_to_path,
 567    .renameat     = synth_renameat,
 568    .unlinkat     = synth_unlinkat,
 569};
 570