2 * 9p synthetic file system support
4 * Copyright IBM, Corp. 2011
7 * Malahal Naineni <malahal@us.ibm.com>
8 * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
10 * This work is licensed under the terms of the GNU GPL, version 2. See
11 * the COPYING file in the top-level directory.
16 * Not so fast! You might want to read the 9p developer docs first:
17 * https://wiki.qemu.org/Documentation/9p
20 #include "qemu/osdep.h"
22 #include "fsdev/qemu-fsdev.h"
25 #include "qemu/rcu_queue.h"
26 #include "qemu/cutils.h"
27 #include "sysemu/qtest.h"
29 /* Root node for synth file system */
30 static V9fsSynthNode synth_root
= {
33 .mode
= 0555 | S_IFDIR
,
36 .attr
= &synth_root
.actual_attr
,
39 static QemuMutex synth_mutex
;
40 static int synth_node_count
;
41 /* set to 1 when the synth fs is ready */
44 static V9fsSynthNode
*v9fs_add_dir_node(V9fsSynthNode
*parent
, int mode
,
46 V9fsSynthNodeAttr
*attr
, int inode
)
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);
54 /* We are adding .. or . entries */
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
;
67 pstrcpy(node
->name
, sizeof(node
->name
), name
);
68 QLIST_INSERT_HEAD_RCU(&parent
->child
, node
, sibling
);
72 int qemu_v9fs_synth_mkdir(V9fsSynthNode
*parent
, int mode
,
73 const char *name
, V9fsSynthNode
**result
)
76 V9fsSynthNode
*node
, *tmp
;
81 if (!name
|| (strlen(name
) >= NAME_MAX
)) {
87 QEMU_LOCK_GUARD(&synth_mutex
);
88 QLIST_FOREACH(tmp
, &parent
->child
, sibling
) {
89 if (!strcmp(tmp
->name
, 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
);
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
)
110 V9fsSynthNode
*node
, *tmp
;
115 if (!name
|| (strlen(name
) >= NAME_MAX
)) {
119 parent
= &synth_root
;
122 QEMU_LOCK_GUARD(&synth_mutex
);
123 QLIST_FOREACH(tmp
, &parent
->child
, sibling
) {
124 if (!strcmp(tmp
->name
, name
)) {
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
;
139 pstrcpy(node
->name
, sizeof(node
->name
), name
);
140 QLIST_INSERT_HEAD_RCU(&parent
->child
, node
, sibling
);
145 static void synth_fill_statbuf(V9fsSynthNode
*node
, struct stat
*stbuf
)
148 stbuf
->st_ino
= node
->attr
->inode
;
149 stbuf
->st_mode
= node
->attr
->mode
;
150 stbuf
->st_nlink
= node
->attr
->nlink
;
155 stbuf
->st_blksize
= 0;
156 stbuf
->st_blocks
= 0;
162 static int synth_lstat(FsContext
*fs_ctx
,
163 V9fsPath
*fs_path
, struct stat
*stbuf
)
165 V9fsSynthNode
*node
= *(V9fsSynthNode
**)fs_path
->data
;
167 synth_fill_statbuf(node
, stbuf
);
171 static int synth_fstat(FsContext
*fs_ctx
, int fid_type
,
172 V9fsFidOpenState
*fs
, struct stat
*stbuf
)
174 V9fsSynthOpenState
*synth_open
= fs
->private;
175 synth_fill_statbuf(synth_open
->node
, stbuf
);
179 static int synth_opendir(FsContext
*ctx
,
180 V9fsPath
*fs_path
, V9fsFidOpenState
*fs
)
182 V9fsSynthOpenState
*synth_open
;
183 V9fsSynthNode
*node
= *(V9fsSynthNode
**)fs_path
->data
;
186 * V9fsSynthOpenState contains 'struct dirent' which have OS-specific
187 * properties, thus it's zero cleared on allocation here and below
190 synth_open
= g_new0(V9fsSynthOpenState
, 1);
191 synth_open
->node
= node
;
193 fs
->private = synth_open
;
197 static int synth_closedir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
199 V9fsSynthOpenState
*synth_open
= fs
->private;
200 V9fsSynthNode
*node
= synth_open
->node
;
208 static off_t
synth_telldir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
210 V9fsSynthOpenState
*synth_open
= fs
->private;
211 return synth_open
->offset
;
214 static void synth_seekdir(FsContext
*ctx
, V9fsFidOpenState
*fs
, off_t off
)
216 V9fsSynthOpenState
*synth_open
= fs
->private;
217 synth_open
->offset
= off
;
220 static void synth_rewinddir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
222 synth_seekdir(ctx
, fs
, 0);
225 static void synth_direntry(V9fsSynthNode
*node
,
226 struct dirent
*entry
, off_t off
)
228 size_t sz
= strlen(node
->name
) + 1;
230 * 'entry' is always inside of V9fsSynthOpenState which have NAME_MAX
231 * back padding. Ensure we do not overflow it.
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
;
238 entry
->d_seekoff
= off
+ 1;
240 entry
->d_off
= off
+ 1;
244 static struct dirent
*synth_get_dentry(V9fsSynthNode
*dir
,
245 struct dirent
*entry
, off_t off
)
251 QLIST_FOREACH(node
, &dir
->child
, sibling
) {
252 /* This is the off child of the directory */
260 /* end of directory */
263 synth_direntry(node
, entry
, off
);
267 static struct dirent
*synth_readdir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
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
);
274 synth_open
->offset
++;
279 static int synth_open(FsContext
*ctx
, V9fsPath
*fs_path
,
280 int flags
, V9fsFidOpenState
*fs
)
282 V9fsSynthOpenState
*synth_open
;
283 V9fsSynthNode
*node
= *(V9fsSynthNode
**)fs_path
->data
;
285 synth_open
= g_new0(V9fsSynthOpenState
, 1);
286 synth_open
->node
= node
;
288 fs
->private = synth_open
;
292 static int synth_open2(FsContext
*fs_ctx
, V9fsPath
*dir_path
,
293 const char *name
, int flags
,
294 FsCred
*credp
, V9fsFidOpenState
*fs
)
300 static int synth_close(FsContext
*ctx
, V9fsFidOpenState
*fs
)
302 V9fsSynthOpenState
*synth_open
= fs
->private;
303 V9fsSynthNode
*node
= synth_open
->node
;
311 static ssize_t
synth_pwritev(FsContext
*ctx
, V9fsFidOpenState
*fs
,
312 const struct iovec
*iov
,
313 int iovcnt
, off_t offset
)
315 int i
, count
= 0, wcount
;
316 V9fsSynthOpenState
*synth_open
= fs
->private;
317 V9fsSynthNode
*node
= synth_open
->node
;
318 if (!node
->attr
->write
) {
322 for (i
= 0; i
< iovcnt
; i
++) {
323 wcount
= node
->attr
->write(iov
[i
].iov_base
, iov
[i
].iov_len
,
324 offset
, node
->private);
327 /* If we wrote less than requested. we are done */
328 if (wcount
< iov
[i
].iov_len
) {
335 static ssize_t
synth_preadv(FsContext
*ctx
, V9fsFidOpenState
*fs
,
336 const struct iovec
*iov
,
337 int iovcnt
, off_t offset
)
339 int i
, count
= 0, rcount
;
340 V9fsSynthOpenState
*synth_open
= fs
->private;
341 V9fsSynthNode
*node
= synth_open
->node
;
342 if (!node
->attr
->read
) {
346 for (i
= 0; i
< iovcnt
; i
++) {
347 rcount
= node
->attr
->read(iov
[i
].iov_base
, iov
[i
].iov_len
,
348 offset
, node
->private);
351 /* If we read less than requested. we are done */
352 if (rcount
< iov
[i
].iov_len
) {
359 static int synth_truncate(FsContext
*ctx
, V9fsPath
*path
, off_t offset
)
365 static int synth_chmod(FsContext
*fs_ctx
, V9fsPath
*path
, FsCred
*credp
)
371 static int synth_mknod(FsContext
*fs_ctx
, V9fsPath
*path
,
372 const char *buf
, FsCred
*credp
)
378 static int synth_mkdir(FsContext
*fs_ctx
, V9fsPath
*path
,
379 const char *buf
, FsCred
*credp
)
385 static ssize_t
synth_readlink(FsContext
*fs_ctx
, V9fsPath
*path
,
386 char *buf
, size_t bufsz
)
392 static int synth_symlink(FsContext
*fs_ctx
, const char *oldpath
,
393 V9fsPath
*newpath
, const char *buf
, FsCred
*credp
)
399 static int synth_link(FsContext
*fs_ctx
, V9fsPath
*oldpath
,
400 V9fsPath
*newpath
, const char *buf
)
406 static int synth_rename(FsContext
*ctx
, const char *oldpath
,
413 static int synth_chown(FsContext
*fs_ctx
, V9fsPath
*path
, FsCred
*credp
)
419 static int synth_utimensat(FsContext
*fs_ctx
, V9fsPath
*path
,
420 const struct timespec
*buf
)
426 static int synth_remove(FsContext
*ctx
, const char *path
)
432 static int synth_fsync(FsContext
*ctx
, int fid_type
,
433 V9fsFidOpenState
*fs
, int datasync
)
439 static int synth_statfs(FsContext
*s
, V9fsPath
*fs_path
,
440 struct statfs
*stbuf
)
442 stbuf
->f_type
= 0xABCD;
443 stbuf
->f_bsize
= 512;
445 stbuf
->f_files
= synth_node_count
;
446 #ifndef CONFIG_DARWIN
447 stbuf
->f_namelen
= NAME_MAX
;
452 static ssize_t
synth_lgetxattr(FsContext
*ctx
, V9fsPath
*path
,
453 const char *name
, void *value
, size_t size
)
459 static ssize_t
synth_llistxattr(FsContext
*ctx
, V9fsPath
*path
,
460 void *value
, size_t size
)
466 static int synth_lsetxattr(FsContext
*ctx
, V9fsPath
*path
,
467 const char *name
, void *value
,
468 size_t size
, int flags
)
474 static int synth_lremovexattr(FsContext
*ctx
,
475 V9fsPath
*path
, const char *name
)
481 static int synth_name_to_path(FsContext
*ctx
, V9fsPath
*dir_path
,
482 const char *name
, V9fsPath
*target
)
485 V9fsSynthNode
*dir_node
;
487 /* "." and ".." are not allowed */
488 if (!strcmp(name
, ".") || !strcmp(name
, "..")) {
494 dir_node
= &synth_root
;
496 dir_node
= *(V9fsSynthNode
**)dir_path
->data
;
498 if (!strcmp(name
, "/")) {
502 /* search for the name in the childern */
504 QLIST_FOREACH(node
, &dir_node
->child
, sibling
) {
505 if (!strcmp(node
->name
, name
)) {
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 *);
523 static int synth_renameat(FsContext
*ctx
, V9fsPath
*olddir
,
524 const char *old_name
, V9fsPath
*newdir
,
525 const char *new_name
)
531 static int synth_unlinkat(FsContext
*ctx
, V9fsPath
*dir
,
532 const char *name
, int flags
)
538 static ssize_t
v9fs_synth_qtest_write(void *buf
, int len
, off_t offset
,
544 static ssize_t
v9fs_synth_qtest_flush_write(void *buf
, int len
, off_t offset
,
547 bool should_block
= !!*(uint8_t *)buf
;
550 /* This will cause the server to call us again until we're cancelled */
558 static int synth_init(FsContext
*ctx
, Error
**errp
)
560 QLIST_INIT(&synth_root
.child
);
561 qemu_mutex_init(&synth_mutex
);
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
);
569 /* Mark the subsystem is ready for use */
572 if (qtest_enabled()) {
573 V9fsSynthNode
*node
= NULL
;
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
);
580 ret
= qemu_v9fs_synth_mkdir(node
, 0700, name
, &node
);
585 /* File for LOPEN test */
586 ret
= qemu_v9fs_synth_add_file(NULL
, 0, QTEST_V9FS_SYNTH_LOPEN_FILE
,
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
);
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
,
601 /* Directory for READDIR test */
603 V9fsSynthNode
*dir
= NULL
;
604 ret
= qemu_v9fs_synth_mkdir(
605 NULL
, 0700, QTEST_V9FS_SYNTH_READDIR_DIR
, &dir
608 for (i
= 0; i
< QTEST_V9FS_SYNTH_READDIR_NFILES
; ++i
) {
609 char *name
= g_strdup_printf(
610 QTEST_V9FS_SYNTH_READDIR_FILE
, i
612 ret
= qemu_v9fs_synth_add_file(
613 dir
, 0, name
, NULL
, NULL
, ctx
624 FileOperations synth_ops
= {
626 .lstat
= synth_lstat
,
627 .readlink
= synth_readlink
,
628 .close
= synth_close
,
629 .closedir
= synth_closedir
,
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
,
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
,