qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

9p-synth.c (17850B)


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