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.
15 #include "qemu/osdep.h"
17 #include "fsdev/qemu-fsdev.h"
20 #include "qemu/rcu_queue.h"
21 #include "qemu/cutils.h"
23 /* Root node for synth file system */
24 static V9fsSynthNode synth_root
= {
27 .mode
= 0555 | S_IFDIR
,
30 .attr
= &synth_root
.actual_attr
,
33 static QemuMutex synth_mutex
;
34 static int synth_node_count
;
35 /* set to 1 when the synth fs is ready */
38 static V9fsSynthNode
*v9fs_add_dir_node(V9fsSynthNode
*parent
, int mode
,
40 V9fsSynthNodeAttr
*attr
, int inode
)
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
));
48 /* We are adding .. or . entries */
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
;
61 pstrcpy(node
->name
, sizeof(node
->name
), name
);
62 QLIST_INSERT_HEAD_RCU(&parent
->child
, node
, sibling
);
66 int qemu_v9fs_synth_mkdir(V9fsSynthNode
*parent
, int mode
,
67 const char *name
, V9fsSynthNode
**result
)
70 V9fsSynthNode
*node
, *tmp
;
75 if (!name
|| (strlen(name
) >= NAME_MAX
)) {
81 qemu_mutex_lock(&synth_mutex
);
82 QLIST_FOREACH(tmp
, &parent
->child
, sibling
) {
83 if (!strcmp(tmp
->name
, 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
);
97 qemu_mutex_unlock(&synth_mutex
);
101 int qemu_v9fs_synth_add_file(V9fsSynthNode
*parent
, int mode
,
102 const char *name
, v9fs_synth_read read
,
103 v9fs_synth_write write
, void *arg
)
106 V9fsSynthNode
*node
, *tmp
;
111 if (!name
|| (strlen(name
) >= NAME_MAX
)) {
115 parent
= &synth_root
;
118 qemu_mutex_lock(&synth_mutex
);
119 QLIST_FOREACH(tmp
, &parent
->child
, sibling
) {
120 if (!strcmp(tmp
->name
, name
)) {
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
;
135 pstrcpy(node
->name
, sizeof(node
->name
), name
);
136 QLIST_INSERT_HEAD_RCU(&parent
->child
, node
, sibling
);
139 qemu_mutex_unlock(&synth_mutex
);
143 static void synth_fill_statbuf(V9fsSynthNode
*node
, struct stat
*stbuf
)
146 stbuf
->st_ino
= node
->attr
->inode
;
147 stbuf
->st_mode
= node
->attr
->mode
;
148 stbuf
->st_nlink
= node
->attr
->nlink
;
153 stbuf
->st_blksize
= 0;
154 stbuf
->st_blocks
= 0;
160 static int synth_lstat(FsContext
*fs_ctx
,
161 V9fsPath
*fs_path
, struct stat
*stbuf
)
163 V9fsSynthNode
*node
= *(V9fsSynthNode
**)fs_path
->data
;
165 synth_fill_statbuf(node
, stbuf
);
169 static int synth_fstat(FsContext
*fs_ctx
, int fid_type
,
170 V9fsFidOpenState
*fs
, struct stat
*stbuf
)
172 V9fsSynthOpenState
*synth_open
= fs
->private;
173 synth_fill_statbuf(synth_open
->node
, stbuf
);
177 static int synth_opendir(FsContext
*ctx
,
178 V9fsPath
*fs_path
, V9fsFidOpenState
*fs
)
180 V9fsSynthOpenState
*synth_open
;
181 V9fsSynthNode
*node
= *(V9fsSynthNode
**)fs_path
->data
;
183 synth_open
= g_malloc(sizeof(*synth_open
));
184 synth_open
->node
= node
;
186 fs
->private = synth_open
;
190 static int synth_closedir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
192 V9fsSynthOpenState
*synth_open
= fs
->private;
193 V9fsSynthNode
*node
= synth_open
->node
;
201 static off_t
synth_telldir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
203 V9fsSynthOpenState
*synth_open
= fs
->private;
204 return synth_open
->offset
;
207 static void synth_seekdir(FsContext
*ctx
, V9fsFidOpenState
*fs
, off_t off
)
209 V9fsSynthOpenState
*synth_open
= fs
->private;
210 synth_open
->offset
= off
;
213 static void synth_rewinddir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
215 synth_seekdir(ctx
, fs
, 0);
218 static void synth_direntry(V9fsSynthNode
*node
,
219 struct dirent
*entry
, off_t off
)
221 strcpy(entry
->d_name
, node
->name
);
222 entry
->d_ino
= node
->attr
->inode
;
223 entry
->d_off
= off
+ 1;
226 static struct dirent
*synth_get_dentry(V9fsSynthNode
*dir
,
227 struct dirent
*entry
, off_t off
)
233 QLIST_FOREACH(node
, &dir
->child
, sibling
) {
234 /* This is the off child of the directory */
242 /* end of directory */
245 synth_direntry(node
, entry
, off
);
249 static struct dirent
*synth_readdir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
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
);
256 synth_open
->offset
++;
261 static int synth_open(FsContext
*ctx
, V9fsPath
*fs_path
,
262 int flags
, V9fsFidOpenState
*fs
)
264 V9fsSynthOpenState
*synth_open
;
265 V9fsSynthNode
*node
= *(V9fsSynthNode
**)fs_path
->data
;
267 synth_open
= g_malloc(sizeof(*synth_open
));
268 synth_open
->node
= node
;
270 fs
->private = synth_open
;
274 static int synth_open2(FsContext
*fs_ctx
, V9fsPath
*dir_path
,
275 const char *name
, int flags
,
276 FsCred
*credp
, V9fsFidOpenState
*fs
)
282 static int synth_close(FsContext
*ctx
, V9fsFidOpenState
*fs
)
284 V9fsSynthOpenState
*synth_open
= fs
->private;
285 V9fsSynthNode
*node
= synth_open
->node
;
293 static ssize_t
synth_pwritev(FsContext
*ctx
, V9fsFidOpenState
*fs
,
294 const struct iovec
*iov
,
295 int iovcnt
, off_t offset
)
297 int i
, count
= 0, wcount
;
298 V9fsSynthOpenState
*synth_open
= fs
->private;
299 V9fsSynthNode
*node
= synth_open
->node
;
300 if (!node
->attr
->write
) {
304 for (i
= 0; i
< iovcnt
; i
++) {
305 wcount
= node
->attr
->write(iov
[i
].iov_base
, iov
[i
].iov_len
,
306 offset
, node
->private);
309 /* If we wrote less than requested. we are done */
310 if (wcount
< iov
[i
].iov_len
) {
317 static ssize_t
synth_preadv(FsContext
*ctx
, V9fsFidOpenState
*fs
,
318 const struct iovec
*iov
,
319 int iovcnt
, off_t offset
)
321 int i
, count
= 0, rcount
;
322 V9fsSynthOpenState
*synth_open
= fs
->private;
323 V9fsSynthNode
*node
= synth_open
->node
;
324 if (!node
->attr
->read
) {
328 for (i
= 0; i
< iovcnt
; i
++) {
329 rcount
= node
->attr
->read(iov
[i
].iov_base
, iov
[i
].iov_len
,
330 offset
, node
->private);
333 /* If we read less than requested. we are done */
334 if (rcount
< iov
[i
].iov_len
) {
341 static int synth_truncate(FsContext
*ctx
, V9fsPath
*path
, off_t offset
)
347 static int synth_chmod(FsContext
*fs_ctx
, V9fsPath
*path
, FsCred
*credp
)
353 static int synth_mknod(FsContext
*fs_ctx
, V9fsPath
*path
,
354 const char *buf
, FsCred
*credp
)
360 static int synth_mkdir(FsContext
*fs_ctx
, V9fsPath
*path
,
361 const char *buf
, FsCred
*credp
)
367 static ssize_t
synth_readlink(FsContext
*fs_ctx
, V9fsPath
*path
,
368 char *buf
, size_t bufsz
)
374 static int synth_symlink(FsContext
*fs_ctx
, const char *oldpath
,
375 V9fsPath
*newpath
, const char *buf
, FsCred
*credp
)
381 static int synth_link(FsContext
*fs_ctx
, V9fsPath
*oldpath
,
382 V9fsPath
*newpath
, const char *buf
)
388 static int synth_rename(FsContext
*ctx
, const char *oldpath
,
395 static int synth_chown(FsContext
*fs_ctx
, V9fsPath
*path
, FsCred
*credp
)
401 static int synth_utimensat(FsContext
*fs_ctx
, V9fsPath
*path
,
402 const struct timespec
*buf
)
408 static int synth_remove(FsContext
*ctx
, const char *path
)
414 static int synth_fsync(FsContext
*ctx
, int fid_type
,
415 V9fsFidOpenState
*fs
, int datasync
)
421 static int synth_statfs(FsContext
*s
, V9fsPath
*fs_path
,
422 struct statfs
*stbuf
)
424 stbuf
->f_type
= 0xABCD;
425 stbuf
->f_bsize
= 512;
427 stbuf
->f_files
= synth_node_count
;
428 stbuf
->f_namelen
= NAME_MAX
;
432 static ssize_t
synth_lgetxattr(FsContext
*ctx
, V9fsPath
*path
,
433 const char *name
, void *value
, size_t size
)
439 static ssize_t
synth_llistxattr(FsContext
*ctx
, V9fsPath
*path
,
440 void *value
, size_t size
)
446 static int synth_lsetxattr(FsContext
*ctx
, V9fsPath
*path
,
447 const char *name
, void *value
,
448 size_t size
, int flags
)
454 static int synth_lremovexattr(FsContext
*ctx
,
455 V9fsPath
*path
, const char *name
)
461 static int synth_name_to_path(FsContext
*ctx
, V9fsPath
*dir_path
,
462 const char *name
, V9fsPath
*target
)
465 V9fsSynthNode
*dir_node
;
467 /* "." and ".." are not allowed */
468 if (!strcmp(name
, ".") || !strcmp(name
, "..")) {
474 dir_node
= &synth_root
;
476 dir_node
= *(V9fsSynthNode
**)dir_path
->data
;
478 if (!strcmp(name
, "/")) {
482 /* search for the name in the childern */
484 QLIST_FOREACH(node
, &dir_node
->child
, sibling
) {
485 if (!strcmp(node
->name
, name
)) {
496 /* Copy the node pointer to fid */
497 target
->data
= g_memdup(&node
, sizeof(void *));
498 target
->size
= sizeof(void *);
502 static int synth_renameat(FsContext
*ctx
, V9fsPath
*olddir
,
503 const char *old_name
, V9fsPath
*newdir
,
504 const char *new_name
)
510 static int synth_unlinkat(FsContext
*ctx
, V9fsPath
*dir
,
511 const char *name
, int flags
)
517 static int synth_init(FsContext
*ctx
)
519 QLIST_INIT(&synth_root
.child
);
520 qemu_mutex_init(&synth_mutex
);
522 /* Add "." and ".." entries for root */
523 v9fs_add_dir_node(&synth_root
, synth_root
.attr
->mode
,
524 "..", synth_root
.attr
, synth_root
.attr
->inode
);
525 v9fs_add_dir_node(&synth_root
, synth_root
.attr
->mode
,
526 ".", synth_root
.attr
, synth_root
.attr
->inode
);
528 /* Mark the subsystem is ready for use */
533 FileOperations synth_ops
= {
535 .lstat
= synth_lstat
,
536 .readlink
= synth_readlink
,
537 .close
= synth_close
,
538 .closedir
= synth_closedir
,
540 .opendir
= synth_opendir
,
541 .rewinddir
= synth_rewinddir
,
542 .telldir
= synth_telldir
,
543 .readdir
= synth_readdir
,
544 .seekdir
= synth_seekdir
,
545 .preadv
= synth_preadv
,
546 .pwritev
= synth_pwritev
,
547 .chmod
= synth_chmod
,
548 .mknod
= synth_mknod
,
549 .mkdir
= synth_mkdir
,
550 .fstat
= synth_fstat
,
551 .open2
= synth_open2
,
552 .symlink
= synth_symlink
,
554 .truncate
= synth_truncate
,
555 .rename
= synth_rename
,
556 .chown
= synth_chown
,
557 .utimensat
= synth_utimensat
,
558 .remove
= synth_remove
,
559 .fsync
= synth_fsync
,
560 .statfs
= synth_statfs
,
561 .lgetxattr
= synth_lgetxattr
,
562 .llistxattr
= synth_llistxattr
,
563 .lsetxattr
= synth_lsetxattr
,
564 .lremovexattr
= synth_lremovexattr
,
565 .name_to_path
= synth_name_to_path
,
566 .renameat
= synth_renameat
,
567 .unlinkat
= synth_unlinkat
,