2 * Virtio 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"
16 #include "hw/virtio/virtio.h"
19 #include "fsdev/qemu-fsdev.h"
22 #include "qemu/rcu_queue.h"
23 #include "qemu/cutils.h"
25 /* Root node for synth file system */
26 static V9fsSynthNode v9fs_synth_root
= {
29 .mode
= 0555 | S_IFDIR
,
32 .attr
= &v9fs_synth_root
.actual_attr
,
35 static QemuMutex v9fs_synth_mutex
;
36 static int v9fs_synth_node_count
;
37 /* set to 1 when the synth fs is ready */
38 static int v9fs_synth_fs
;
40 static V9fsSynthNode
*v9fs_add_dir_node(V9fsSynthNode
*parent
, int mode
,
42 V9fsSynthNodeAttr
*attr
, int inode
)
46 /* Add directory type and remove write bits */
47 mode
= ((mode
& 0777) | S_IFDIR
) & ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
48 node
= g_malloc0(sizeof(V9fsSynthNode
));
50 /* We are adding .. or . entries */
54 node
->attr
= &node
->actual_attr
;
55 node
->attr
->inode
= inode
;
56 node
->attr
->nlink
= 1;
57 /* We don't allow write to directories */
58 node
->attr
->mode
= mode
;
59 node
->attr
->write
= NULL
;
60 node
->attr
->read
= NULL
;
63 pstrcpy(node
->name
, sizeof(node
->name
), name
);
64 QLIST_INSERT_HEAD_RCU(&parent
->child
, node
, sibling
);
68 int qemu_v9fs_synth_mkdir(V9fsSynthNode
*parent
, int mode
,
69 const char *name
, V9fsSynthNode
**result
)
72 V9fsSynthNode
*node
, *tmp
;
77 if (!name
|| (strlen(name
) >= NAME_MAX
)) {
81 parent
= &v9fs_synth_root
;
83 qemu_mutex_lock(&v9fs_synth_mutex
);
84 QLIST_FOREACH(tmp
, &parent
->child
, sibling
) {
85 if (!strcmp(tmp
->name
, name
)) {
91 node
= v9fs_add_dir_node(parent
, mode
, name
, NULL
, v9fs_synth_node_count
++);
92 v9fs_add_dir_node(node
, parent
->attr
->mode
, "..",
93 parent
->attr
, parent
->attr
->inode
);
94 v9fs_add_dir_node(node
, node
->attr
->mode
, ".",
95 node
->attr
, node
->attr
->inode
);
99 qemu_mutex_unlock(&v9fs_synth_mutex
);
103 int qemu_v9fs_synth_add_file(V9fsSynthNode
*parent
, int mode
,
104 const char *name
, v9fs_synth_read read
,
105 v9fs_synth_write write
, void *arg
)
108 V9fsSynthNode
*node
, *tmp
;
110 if (!v9fs_synth_fs
) {
113 if (!name
|| (strlen(name
) >= NAME_MAX
)) {
117 parent
= &v9fs_synth_root
;
120 qemu_mutex_lock(&v9fs_synth_mutex
);
121 QLIST_FOREACH(tmp
, &parent
->child
, sibling
) {
122 if (!strcmp(tmp
->name
, name
)) {
127 /* Add file type and remove write bits */
128 mode
= ((mode
& 0777) | S_IFREG
);
129 node
= g_malloc0(sizeof(V9fsSynthNode
));
130 node
->attr
= &node
->actual_attr
;
131 node
->attr
->inode
= v9fs_synth_node_count
++;
132 node
->attr
->nlink
= 1;
133 node
->attr
->read
= read
;
134 node
->attr
->write
= write
;
135 node
->attr
->mode
= mode
;
137 pstrcpy(node
->name
, sizeof(node
->name
), name
);
138 QLIST_INSERT_HEAD_RCU(&parent
->child
, node
, sibling
);
141 qemu_mutex_unlock(&v9fs_synth_mutex
);
145 static void v9fs_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 v9fs_synth_lstat(FsContext
*fs_ctx
,
163 V9fsPath
*fs_path
, struct stat
*stbuf
)
165 V9fsSynthNode
*node
= *(V9fsSynthNode
**)fs_path
->data
;
167 v9fs_synth_fill_statbuf(node
, stbuf
);
171 static int v9fs_synth_fstat(FsContext
*fs_ctx
, int fid_type
,
172 V9fsFidOpenState
*fs
, struct stat
*stbuf
)
174 V9fsSynthOpenState
*synth_open
= fs
->private;
175 v9fs_synth_fill_statbuf(synth_open
->node
, stbuf
);
179 static int v9fs_synth_opendir(FsContext
*ctx
,
180 V9fsPath
*fs_path
, V9fsFidOpenState
*fs
)
182 V9fsSynthOpenState
*synth_open
;
183 V9fsSynthNode
*node
= *(V9fsSynthNode
**)fs_path
->data
;
185 synth_open
= g_malloc(sizeof(*synth_open
));
186 synth_open
->node
= node
;
188 fs
->private = synth_open
;
192 static int v9fs_synth_closedir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
194 V9fsSynthOpenState
*synth_open
= fs
->private;
195 V9fsSynthNode
*node
= synth_open
->node
;
203 static off_t
v9fs_synth_telldir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
205 V9fsSynthOpenState
*synth_open
= fs
->private;
206 return synth_open
->offset
;
209 static void v9fs_synth_seekdir(FsContext
*ctx
, V9fsFidOpenState
*fs
, off_t off
)
211 V9fsSynthOpenState
*synth_open
= fs
->private;
212 synth_open
->offset
= off
;
215 static void v9fs_synth_rewinddir(FsContext
*ctx
, V9fsFidOpenState
*fs
)
217 v9fs_synth_seekdir(ctx
, fs
, 0);
220 static void v9fs_synth_direntry(V9fsSynthNode
*node
,
221 struct dirent
*entry
, off_t off
)
223 strcpy(entry
->d_name
, node
->name
);
224 entry
->d_ino
= node
->attr
->inode
;
225 entry
->d_off
= off
+ 1;
228 static int v9fs_synth_get_dentry(V9fsSynthNode
*dir
, struct dirent
*entry
,
229 struct dirent
**result
, off_t off
)
235 QLIST_FOREACH(node
, &dir
->child
, sibling
) {
236 /* This is the off child of the directory */
244 /* end of directory */
248 v9fs_synth_direntry(node
, entry
, off
);
253 static int v9fs_synth_readdir_r(FsContext
*ctx
, V9fsFidOpenState
*fs
,
254 struct dirent
*entry
, struct dirent
**result
)
257 V9fsSynthOpenState
*synth_open
= fs
->private;
258 V9fsSynthNode
*node
= synth_open
->node
;
259 ret
= v9fs_synth_get_dentry(node
, entry
, result
, synth_open
->offset
);
260 if (!ret
&& *result
!= NULL
) {
261 synth_open
->offset
++;
266 static int v9fs_synth_open(FsContext
*ctx
, V9fsPath
*fs_path
,
267 int flags
, V9fsFidOpenState
*fs
)
269 V9fsSynthOpenState
*synth_open
;
270 V9fsSynthNode
*node
= *(V9fsSynthNode
**)fs_path
->data
;
272 synth_open
= g_malloc(sizeof(*synth_open
));
273 synth_open
->node
= node
;
275 fs
->private = synth_open
;
279 static int v9fs_synth_open2(FsContext
*fs_ctx
, V9fsPath
*dir_path
,
280 const char *name
, int flags
,
281 FsCred
*credp
, V9fsFidOpenState
*fs
)
287 static int v9fs_synth_close(FsContext
*ctx
, V9fsFidOpenState
*fs
)
289 V9fsSynthOpenState
*synth_open
= fs
->private;
290 V9fsSynthNode
*node
= synth_open
->node
;
298 static ssize_t
v9fs_synth_pwritev(FsContext
*ctx
, V9fsFidOpenState
*fs
,
299 const struct iovec
*iov
,
300 int iovcnt
, off_t offset
)
302 int i
, count
= 0, wcount
;
303 V9fsSynthOpenState
*synth_open
= fs
->private;
304 V9fsSynthNode
*node
= synth_open
->node
;
305 if (!node
->attr
->write
) {
309 for (i
= 0; i
< iovcnt
; i
++) {
310 wcount
= node
->attr
->write(iov
[i
].iov_base
, iov
[i
].iov_len
,
311 offset
, node
->private);
314 /* If we wrote less than requested. we are done */
315 if (wcount
< iov
[i
].iov_len
) {
322 static ssize_t
v9fs_synth_preadv(FsContext
*ctx
, V9fsFidOpenState
*fs
,
323 const struct iovec
*iov
,
324 int iovcnt
, off_t offset
)
326 int i
, count
= 0, rcount
;
327 V9fsSynthOpenState
*synth_open
= fs
->private;
328 V9fsSynthNode
*node
= synth_open
->node
;
329 if (!node
->attr
->read
) {
333 for (i
= 0; i
< iovcnt
; i
++) {
334 rcount
= node
->attr
->read(iov
[i
].iov_base
, iov
[i
].iov_len
,
335 offset
, node
->private);
338 /* If we read less than requested. we are done */
339 if (rcount
< iov
[i
].iov_len
) {
346 static int v9fs_synth_truncate(FsContext
*ctx
, V9fsPath
*path
, off_t offset
)
352 static int v9fs_synth_chmod(FsContext
*fs_ctx
, V9fsPath
*path
, FsCred
*credp
)
358 static int v9fs_synth_mknod(FsContext
*fs_ctx
, V9fsPath
*path
,
359 const char *buf
, FsCred
*credp
)
365 static int v9fs_synth_mkdir(FsContext
*fs_ctx
, V9fsPath
*path
,
366 const char *buf
, FsCred
*credp
)
372 static ssize_t
v9fs_synth_readlink(FsContext
*fs_ctx
, V9fsPath
*path
,
373 char *buf
, size_t bufsz
)
379 static int v9fs_synth_symlink(FsContext
*fs_ctx
, const char *oldpath
,
380 V9fsPath
*newpath
, const char *buf
, FsCred
*credp
)
386 static int v9fs_synth_link(FsContext
*fs_ctx
, V9fsPath
*oldpath
,
387 V9fsPath
*newpath
, const char *buf
)
393 static int v9fs_synth_rename(FsContext
*ctx
, const char *oldpath
,
400 static int v9fs_synth_chown(FsContext
*fs_ctx
, V9fsPath
*path
, FsCred
*credp
)
406 static int v9fs_synth_utimensat(FsContext
*fs_ctx
, V9fsPath
*path
,
407 const struct timespec
*buf
)
413 static int v9fs_synth_remove(FsContext
*ctx
, const char *path
)
419 static int v9fs_synth_fsync(FsContext
*ctx
, int fid_type
,
420 V9fsFidOpenState
*fs
, int datasync
)
426 static int v9fs_synth_statfs(FsContext
*s
, V9fsPath
*fs_path
,
427 struct statfs
*stbuf
)
429 stbuf
->f_type
= 0xABCD;
430 stbuf
->f_bsize
= 512;
432 stbuf
->f_files
= v9fs_synth_node_count
;
433 stbuf
->f_namelen
= NAME_MAX
;
437 static ssize_t
v9fs_synth_lgetxattr(FsContext
*ctx
, V9fsPath
*path
,
438 const char *name
, void *value
, size_t size
)
444 static ssize_t
v9fs_synth_llistxattr(FsContext
*ctx
, V9fsPath
*path
,
445 void *value
, size_t size
)
451 static int v9fs_synth_lsetxattr(FsContext
*ctx
, V9fsPath
*path
,
452 const char *name
, void *value
,
453 size_t size
, int flags
)
459 static int v9fs_synth_lremovexattr(FsContext
*ctx
,
460 V9fsPath
*path
, const char *name
)
466 static int v9fs_synth_name_to_path(FsContext
*ctx
, V9fsPath
*dir_path
,
467 const char *name
, V9fsPath
*target
)
470 V9fsSynthNode
*dir_node
;
472 /* "." and ".." are not allowed */
473 if (!strcmp(name
, ".") || !strcmp(name
, "..")) {
479 dir_node
= &v9fs_synth_root
;
481 dir_node
= *(V9fsSynthNode
**)dir_path
->data
;
483 if (!strcmp(name
, "/")) {
487 /* search for the name in the childern */
489 QLIST_FOREACH(node
, &dir_node
->child
, sibling
) {
490 if (!strcmp(node
->name
, name
)) {
501 /* Copy the node pointer to fid */
502 target
->data
= g_malloc(sizeof(void *));
503 memcpy(target
->data
, &node
, sizeof(void *));
504 target
->size
= sizeof(void *);
508 static int v9fs_synth_renameat(FsContext
*ctx
, V9fsPath
*olddir
,
509 const char *old_name
, V9fsPath
*newdir
,
510 const char *new_name
)
516 static int v9fs_synth_unlinkat(FsContext
*ctx
, V9fsPath
*dir
,
517 const char *name
, int flags
)
523 static int v9fs_synth_init(FsContext
*ctx
)
525 QLIST_INIT(&v9fs_synth_root
.child
);
526 qemu_mutex_init(&v9fs_synth_mutex
);
528 /* Add "." and ".." entries for root */
529 v9fs_add_dir_node(&v9fs_synth_root
, v9fs_synth_root
.attr
->mode
,
530 "..", v9fs_synth_root
.attr
, v9fs_synth_root
.attr
->inode
);
531 v9fs_add_dir_node(&v9fs_synth_root
, v9fs_synth_root
.attr
->mode
,
532 ".", v9fs_synth_root
.attr
, v9fs_synth_root
.attr
->inode
);
534 /* Mark the subsystem is ready for use */
539 FileOperations synth_ops
= {
540 .init
= v9fs_synth_init
,
541 .lstat
= v9fs_synth_lstat
,
542 .readlink
= v9fs_synth_readlink
,
543 .close
= v9fs_synth_close
,
544 .closedir
= v9fs_synth_closedir
,
545 .open
= v9fs_synth_open
,
546 .opendir
= v9fs_synth_opendir
,
547 .rewinddir
= v9fs_synth_rewinddir
,
548 .telldir
= v9fs_synth_telldir
,
549 .readdir_r
= v9fs_synth_readdir_r
,
550 .seekdir
= v9fs_synth_seekdir
,
551 .preadv
= v9fs_synth_preadv
,
552 .pwritev
= v9fs_synth_pwritev
,
553 .chmod
= v9fs_synth_chmod
,
554 .mknod
= v9fs_synth_mknod
,
555 .mkdir
= v9fs_synth_mkdir
,
556 .fstat
= v9fs_synth_fstat
,
557 .open2
= v9fs_synth_open2
,
558 .symlink
= v9fs_synth_symlink
,
559 .link
= v9fs_synth_link
,
560 .truncate
= v9fs_synth_truncate
,
561 .rename
= v9fs_synth_rename
,
562 .chown
= v9fs_synth_chown
,
563 .utimensat
= v9fs_synth_utimensat
,
564 .remove
= v9fs_synth_remove
,
565 .fsync
= v9fs_synth_fsync
,
566 .statfs
= v9fs_synth_statfs
,
567 .lgetxattr
= v9fs_synth_lgetxattr
,
568 .llistxattr
= v9fs_synth_llistxattr
,
569 .lsetxattr
= v9fs_synth_lsetxattr
,
570 .lremovexattr
= v9fs_synth_lremovexattr
,
571 .name_to_path
= v9fs_synth_name_to_path
,
572 .renameat
= v9fs_synth_renameat
,
573 .unlinkat
= v9fs_synth_unlinkat
,