aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-10-31 11:06:02 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2011-10-31 11:06:02 -0500
commitd439b79d730bf219e47c14ab94f1546bcc5045ab (patch)
treec8d0ae00ff1e86e7ecdaac028d2b2db30305f0c3 /hw
parent96b3d73f5ad5838690d42666c566a48be9d173dc (diff)
parent2583e443676e6b9259425f7d5ccaccbfa9bf7886 (diff)
downloadqemu-d439b79d730bf219e47c14ab94f1546bcc5045ab.zip
qemu-d439b79d730bf219e47c14ab94f1546bcc5045ab.tar.gz
qemu-d439b79d730bf219e47c14ab94f1546bcc5045ab.tar.bz2
Merge remote-tracking branch 'aneesh/for-upstream-7' into staging
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/codir.c16
-rw-r--r--hw/9pfs/cofile.c37
-rw-r--r--hw/9pfs/virtio-9p-coth.h6
-rw-r--r--hw/9pfs/virtio-9p-handle.c96
-rw-r--r--hw/9pfs/virtio-9p-local.c113
-rw-r--r--hw/9pfs/virtio-9p-synth.c571
-rw-r--r--hw/9pfs/virtio-9p-synth.h50
-rw-r--r--hw/9pfs/virtio-9p.c62
-rw-r--r--hw/9pfs/virtio-9p.h27
9 files changed, 842 insertions, 136 deletions
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 72732e7..9b6d47d 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -29,7 +29,7 @@ int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent,
v9fs_co_run_in_worker(
{
errno = 0;
- err = s->ops->readdir_r(&s->ctx, fidp->fs.dir, dent, result);
+ err = s->ops->readdir_r(&s->ctx, &fidp->fs, dent, result);
if (!*result && errno) {
err = -errno;
} else {
@@ -49,7 +49,7 @@ off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
}
v9fs_co_run_in_worker(
{
- err = s->ops->telldir(&s->ctx, fidp->fs.dir);
+ err = s->ops->telldir(&s->ctx, &fidp->fs);
if (err < 0) {
err = -errno;
}
@@ -65,7 +65,7 @@ void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset)
}
v9fs_co_run_in_worker(
{
- s->ops->seekdir(&s->ctx, fidp->fs.dir, offset);
+ s->ops->seekdir(&s->ctx, &fidp->fs, offset);
});
}
@@ -77,7 +77,7 @@ void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
}
v9fs_co_run_in_worker(
{
- s->ops->rewinddir(&s->ctx, fidp->fs.dir);
+ s->ops->rewinddir(&s->ctx, &fidp->fs);
});
}
@@ -129,8 +129,8 @@ int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- fidp->fs.dir = s->ops->opendir(&s->ctx, &fidp->path);
- if (!fidp->fs.dir) {
+ err = s->ops->opendir(&s->ctx, &fidp->path, &fidp->fs);
+ if (err < 0) {
err = -errno;
} else {
err = 0;
@@ -146,7 +146,7 @@ int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
return err;
}
-int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir)
+int v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs)
{
int err;
V9fsState *s = pdu->s;
@@ -156,7 +156,7 @@ int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir)
}
v9fs_co_run_in_worker(
{
- err = s->ops->closedir(&s->ctx, dir);
+ err = s->ops->closedir(&s->ctx, fs);
if (err < 0) {
err = -errno;
}
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 692811e..586b038 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -61,7 +61,7 @@ int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
return err;
}
-int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
+int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
{
int err;
V9fsState *s = pdu->s;
@@ -71,7 +71,7 @@ int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
}
v9fs_co_run_in_worker(
{
- err = s->ops->fstat(&s->ctx, fd, stbuf);
+ err = s->ops->fstat(&s->ctx, &fidp->fs, stbuf);
if (err < 0) {
err = -errno;
}
@@ -90,8 +90,8 @@ int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags);
- if (fidp->fs.fd == -1) {
+ err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs);
+ if (err == -1) {
err = -errno;
} else {
err = 0;
@@ -130,9 +130,9 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path,
- name->data, flags, &cred);
- if (fidp->fs.fd == -1) {
+ err = s->ops->open2(&s->ctx, &fidp->path,
+ name->data, flags, &cred, &fidp->fs);
+ if (err < 0) {
err = -errno;
} else {
v9fs_path_init(&path);
@@ -141,12 +141,12 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
err = s->ops->lstat(&s->ctx, &path, stbuf);
if (err < 0) {
err = -errno;
- s->ops->close(&s->ctx, fidp->fs.fd);
+ s->ops->close(&s->ctx, &fidp->fs);
} else {
v9fs_path_copy(&fidp->path, &path);
}
} else {
- s->ops->close(&s->ctx, fidp->fs.fd);
+ s->ops->close(&s->ctx, &fidp->fs);
}
v9fs_path_free(&path);
}
@@ -161,7 +161,7 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
return err;
}
-int v9fs_co_close(V9fsPDU *pdu, int fd)
+int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
{
int err;
V9fsState *s = pdu->s;
@@ -171,7 +171,7 @@ int v9fs_co_close(V9fsPDU *pdu, int fd)
}
v9fs_co_run_in_worker(
{
- err = s->ops->close(&s->ctx, fd);
+ err = s->ops->close(&s->ctx, fs);
if (err < 0) {
err = -errno;
}
@@ -184,16 +184,15 @@ int v9fs_co_close(V9fsPDU *pdu, int fd)
int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
{
- int fd, err;
+ int err;
V9fsState *s = pdu->s;
if (v9fs_request_cancelled(pdu)) {
return -EINTR;
}
- fd = fidp->fs.fd;
v9fs_co_run_in_worker(
{
- err = s->ops->fsync(&s->ctx, fd, datasync);
+ err = s->ops->fsync(&s->ctx, &fidp->fs, datasync);
if (err < 0) {
err = -errno;
}
@@ -226,16 +225,15 @@ int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
struct iovec *iov, int iovcnt, int64_t offset)
{
- int fd, err;
+ int err;
V9fsState *s = pdu->s;
if (v9fs_request_cancelled(pdu)) {
return -EINTR;
}
- fd = fidp->fs.fd;
v9fs_co_run_in_worker(
{
- err = s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
+ err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
if (err < 0) {
err = -errno;
}
@@ -246,16 +244,15 @@ int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
struct iovec *iov, int iovcnt, int64_t offset)
{
- int fd, err;
+ int err;
V9fsState *s = pdu->s;
if (v9fs_request_cancelled(pdu)) {
return -EINTR;
}
- fd = fidp->fs.fd;
v9fs_co_run_in_worker(
{
- err = s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
+ err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
if (err < 0) {
err = -errno;
}
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index ca96b9c..c4b74b0 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -80,7 +80,7 @@ extern int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *);
extern int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags);
extern int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *,
V9fsPath *, V9fsString *);
-extern int v9fs_co_fstat(V9fsPDU *, int, struct stat *);
+extern int v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *);
extern int v9fs_co_opendir(V9fsPDU *, V9fsFidState *);
extern int v9fs_co_open(V9fsPDU *, V9fsFidState *, int);
extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
@@ -88,8 +88,8 @@ extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *,
void *, size_t, int);
extern int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *);
-extern int v9fs_co_closedir(V9fsPDU *, DIR *);
-extern int v9fs_co_close(V9fsPDU *, int);
+extern int v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *);
+extern int v9fs_co_close(V9fsPDU *, V9fsFidOpenState *);
extern int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int);
extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *,
const char *, gid_t, struct stat *);
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
index 98809f1..c38e0e7 100644
--- a/hw/9pfs/virtio-9p-handle.c
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -133,81 +133,91 @@ static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
return ret;
}
-static int handle_close(FsContext *ctx, int fd)
+static int handle_close(FsContext *ctx, V9fsFidOpenState *fs)
{
- return close(fd);
+ return close(fs->fd);
}
-static int handle_closedir(FsContext *ctx, DIR *dir)
+static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs)
{
- return closedir(dir);
+ return closedir(fs->dir);
}
-static int handle_open(FsContext *ctx, V9fsPath *fs_path, int flags)
+static int handle_open(FsContext *ctx, V9fsPath *fs_path,
+ int flags, V9fsFidOpenState *fs)
{
struct handle_data *data = (struct handle_data *)ctx->private;
- return open_by_handle(data->mountfd, fs_path->data, flags);
+ fs->fd = open_by_handle(data->mountfd, fs_path->data, flags);
+ return fs->fd;
}
-static DIR *handle_opendir(FsContext *ctx, V9fsPath *fs_path)
+static int handle_opendir(FsContext *ctx,
+ V9fsPath *fs_path, V9fsFidOpenState *fs)
{
- int fd;
- fd = handle_open(ctx, fs_path, O_DIRECTORY);
- if (fd < 0) {
- return NULL;
+ int ret;
+ ret = handle_open(ctx, fs_path, O_DIRECTORY, fs);
+ if (ret < 0) {
+ return -1;
}
- return fdopendir(fd);
+ fs->dir = fdopendir(ret);
+ if (!fs->dir) {
+ return -1;
+ }
+ return 0;
}
-static void handle_rewinddir(FsContext *ctx, DIR *dir)
+static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
{
- return rewinddir(dir);
+ return rewinddir(fs->dir);
}
-static off_t handle_telldir(FsContext *ctx, DIR *dir)
+static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs)
{
- return telldir(dir);
+ return telldir(fs->dir);
}
-static int handle_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+ struct dirent *entry,
struct dirent **result)
{
- return readdir_r(dir, entry, result);
+ return readdir_r(fs->dir, entry, result);
}
-static void handle_seekdir(FsContext *ctx, DIR *dir, off_t off)
+static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
{
- return seekdir(dir, off);
+ return seekdir(fs->dir, off);
}
-static ssize_t handle_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+ const struct iovec *iov,
int iovcnt, off_t offset)
{
#ifdef CONFIG_PREADV
- return preadv(fd, iov, iovcnt, offset);
+ return preadv(fs->fd, iov, iovcnt, offset);
#else
- int err = lseek(fd, offset, SEEK_SET);
+ int err = lseek(fs->fd, offset, SEEK_SET);
if (err == -1) {
return err;
} else {
- return readv(fd, iov, iovcnt);
+ return readv(fs->fd, iov, iovcnt);
}
#endif
}
-static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+ const struct iovec *iov,
int iovcnt, off_t offset)
{
ssize_t ret;
#ifdef CONFIG_PREADV
- ret = pwritev(fd, iov, iovcnt, offset);
+ ret = pwritev(fs->fd, iov, iovcnt, offset);
#else
- int err = lseek(fd, offset, SEEK_SET);
+ int err = lseek(fs->fd, offset, SEEK_SET);
if (err == -1) {
return err;
} else {
- ret = writev(fd, iov, iovcnt);
+ ret = writev(fs->fd, iov, iovcnt);
}
#endif
#ifdef CONFIG_SYNC_FILE_RANGE
@@ -217,7 +227,7 @@ static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
* We want to ensure that we don't leave dirty pages in the cache
* after write when writeout=immediate is sepcified.
*/
- sync_file_range(fd, offset, ret,
+ sync_file_range(fs->fd, offset, ret,
SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
}
#endif
@@ -274,13 +284,14 @@ static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
return ret;
}
-static int handle_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+static int handle_fstat(FsContext *fs_ctx, V9fsFidOpenState *fs,
+ struct stat *stbuf)
{
- return fstat(fd, stbuf);
+ return fstat(fs->fd, stbuf);
}
static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
- int flags, FsCred *credp)
+ int flags, FsCred *credp, V9fsFidOpenState *fs)
{
int ret;
int dirfd, fd;
@@ -296,6 +307,8 @@ static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
if (ret < 0) {
close(fd);
fd = ret;
+ } else {
+ fs->fd = fd;
}
}
close(dirfd);
@@ -411,12 +424,12 @@ static int handle_remove(FsContext *ctx, const char *path)
return -1;
}
-static int handle_fsync(FsContext *ctx, int fd, int datasync)
+static int handle_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
{
if (datasync) {
- return qemu_fdatasync(fd);
+ return qemu_fdatasync(fs->fd);
} else {
- return fsync(fd);
+ return fsync(fs->fd);
}
}
@@ -575,7 +588,8 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
mode_t st_mode, uint64_t *st_gen)
{
- int err, fd;
+ int err;
+ V9fsFidOpenState fid_open;
/*
* Do not try to open special files like device nodes, fifos etc
@@ -584,12 +598,12 @@ static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
return 0;
}
- fd = handle_open(ctx, path, O_RDONLY);
- if (fd < 0) {
- return fd;
+ err = handle_open(ctx, path, O_RDONLY, &fid_open);
+ if (err < 0) {
+ return err;
}
- err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
- handle_close(ctx, fd);
+ err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
+ handle_close(ctx, &fid_open);
return err;
}
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index d561de8..782dc0a 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -156,81 +156,91 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
return tsize;
}
-static int local_close(FsContext *ctx, int fd)
+static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
{
- return close(fd);
+ return close(fs->fd);
}
-static int local_closedir(FsContext *ctx, DIR *dir)
+static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
{
- return closedir(dir);
+ return closedir(fs->dir);
}
-static int local_open(FsContext *ctx, V9fsPath *fs_path, int flags)
+static int local_open(FsContext *ctx, V9fsPath *fs_path,
+ int flags, V9fsFidOpenState *fs)
{
char buffer[PATH_MAX];
char *path = fs_path->data;
- return open(rpath(ctx, path, buffer), flags);
+ fs->fd = open(rpath(ctx, path, buffer), flags);
+ return fs->fd;
}
-static DIR *local_opendir(FsContext *ctx, V9fsPath *fs_path)
+static int local_opendir(FsContext *ctx,
+ V9fsPath *fs_path, V9fsFidOpenState *fs)
{
char buffer[PATH_MAX];
char *path = fs_path->data;
- return opendir(rpath(ctx, path, buffer));
+ fs->dir = opendir(rpath(ctx, path, buffer));
+ if (!fs->dir) {
+ return -1;
+ }
+ return 0;
}
-static void local_rewinddir(FsContext *ctx, DIR *dir)
+static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
{
- return rewinddir(dir);
+ return rewinddir(fs->dir);
}
-static off_t local_telldir(FsContext *ctx, DIR *dir)
+static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
{
- return telldir(dir);
+ return telldir(fs->dir);
}
-static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+ struct dirent *entry,
struct dirent **result)
{
- return readdir_r(dir, entry, result);
+ return readdir_r(fs->dir, entry, result);
}
-static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
+static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
{
- return seekdir(dir, off);
+ return seekdir(fs->dir, off);
}
-static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+ const struct iovec *iov,
int iovcnt, off_t offset)
{
#ifdef CONFIG_PREADV
- return preadv(fd, iov, iovcnt, offset);
+ return preadv(fs->fd, iov, iovcnt, offset);
#else
- int err = lseek(fd, offset, SEEK_SET);
+ int err = lseek(fs->fd, offset, SEEK_SET);
if (err == -1) {
return err;
} else {
- return readv(fd, iov, iovcnt);
+ return readv(fs->fd, iov, iovcnt);
}
#endif
}
-static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+ const struct iovec *iov,
int iovcnt, off_t offset)
{
ssize_t ret
;
#ifdef CONFIG_PREADV
- ret = pwritev(fd, iov, iovcnt, offset);
+ ret = pwritev(fs->fd, iov, iovcnt, offset);
#else
- int err = lseek(fd, offset, SEEK_SET);
+ int err = lseek(fs->fd, offset, SEEK_SET);
if (err == -1) {
return err;
} else {
- ret = writev(fd, iov, iovcnt);
+ ret = writev(fs->fd, iov, iovcnt);
}
#endif
#ifdef CONFIG_SYNC_FILE_RANGE
@@ -240,7 +250,7 @@ static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
* We want to ensure that we don't leave dirty pages in the cache
* after write when writeout=immediate is sepcified.
*/
- sync_file_range(fd, offset, ret,
+ sync_file_range(fs->fd, offset, ret,
SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
}
#endif
@@ -281,7 +291,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
if (err == -1) {
goto out;
}
- local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
if (err == -1) {
serrno = errno;
goto err_end;
@@ -356,10 +366,11 @@ out:
return err;
}
-static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+static int local_fstat(FsContext *fs_ctx,
+ V9fsFidOpenState *fs, struct stat *stbuf)
{
int err;
- err = fstat(fd, stbuf);
+ err = fstat(fs->fd, stbuf);
if (err) {
return err;
}
@@ -370,16 +381,20 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
mode_t tmp_mode;
dev_t tmp_dev;
- if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
+ if (fgetxattr(fs->fd, "user.virtfs.uid",
+ &tmp_uid, sizeof(uid_t)) > 0) {
stbuf->st_uid = tmp_uid;
}
- if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
+ if (fgetxattr(fs->fd, "user.virtfs.gid",
+ &tmp_gid, sizeof(gid_t)) > 0) {
stbuf->st_gid = tmp_gid;
}
- if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
+ if (fgetxattr(fs->fd, "user.virtfs.mode",
+ &tmp_mode, sizeof(mode_t)) > 0) {
stbuf->st_mode = tmp_mode;
}
- if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
+ if (fgetxattr(fs->fd, "user.virtfs.rdev",
+ &tmp_dev, sizeof(dev_t)) > 0) {
stbuf->st_rdev = tmp_dev;
}
}
@@ -387,7 +402,7 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
}
static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
- int flags, FsCred *credp)
+ int flags, FsCred *credp, V9fsFidOpenState *fs)
{
char *path;
int fd = -1;
@@ -428,6 +443,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
}
}
err = fd;
+ fs->fd = fd;
goto out;
err_end:
@@ -551,15 +567,12 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
char *path = fs_path->data;
if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
- (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH)) {
- return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
- credp->fc_gid);
+ (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
+ (fs_ctx->export_flags & V9FS_SM_NONE)) {
+ return lchown(rpath(fs_ctx, path, buffer),
+ credp->fc_uid, credp->fc_gid);
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
- } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
- (fs_ctx->export_flags & V9FS_SM_NONE)) {
- return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
- credp->fc_gid);
}
return -1;
}
@@ -580,12 +593,12 @@ static int local_remove(FsContext *ctx, const char *path)
return remove(rpath(ctx, path, buffer));
}
-static int local_fsync(FsContext *ctx, int fd, int datasync)
+static int local_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
{
if (datasync) {
- return qemu_fdatasync(fd);
+ return qemu_fdatasync(fs->fd);
} else {
- return fsync(fd);
+ return fsync(fs->fd);
}
}
@@ -680,7 +693,9 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
mode_t st_mode, uint64_t *st_gen)
{
- int err, fd;
+ int err;
+ V9fsFidOpenState fid_open;
+
/*
* Do not try to open special files like device nodes, fifos etc
* We can get fd for regular files and directories only
@@ -688,12 +703,12 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
return 0;
}
- fd = local_open(ctx, path, O_RDONLY);
- if (fd < 0) {
- return fd;
+ err = local_open(ctx, path, O_RDONLY, &fid_open);
+ if (err < 0) {
+ return err;
}
- err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
- local_close(ctx, fd);
+ err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
+ local_close(ctx, &fid_open);
return err;
}
diff --git a/hw/9pfs/virtio-9p-synth.c b/hw/9pfs/virtio-9p-synth.c
new file mode 100644
index 0000000..f573616
--- /dev/null
+++ b/hw/9pfs/virtio-9p-synth.c
@@ -0,0 +1,571 @@
+/*
+ * Virtio 9p synthetic file system support
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Malahal Naineni <malahal@us.ibm.com>
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-synth.h"
+
+#include <sys/stat.h>
+
+/* Root node for synth file system */
+V9fsSynthNode v9fs_synth_root = {
+ .name = "/",
+ .actual_attr = {
+ .mode = 0555 | S_IFDIR,
+ .nlink = 1,
+ },
+ .attr = &v9fs_synth_root.actual_attr,
+};
+
+static QemuMutex v9fs_synth_mutex;
+static int v9fs_synth_node_count;
+/* set to 1 when the synth fs is ready */
+static int v9fs_synth_fs;
+
+static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
+ const char *name,
+ V9fsSynthNodeAttr *attr, int inode)
+{
+ V9fsSynthNode *node;
+
+ /* Add directory type and remove write bits */
+ mode = ((mode & 0777) | S_IFDIR) & ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ node = g_malloc0(sizeof(V9fsSynthNode));
+ if (attr) {
+ /* We are adding .. or . entries */
+ node->attr = attr;
+ node->attr->nlink++;
+ } else {
+ node->attr = &node->actual_attr;
+ node->attr->inode = inode;
+ node->attr->nlink = 1;
+ /* We don't allow write to directories */
+ node->attr->mode = mode;
+ node->attr->write = NULL;
+ node->attr->read = NULL;
+ }
+ node->private = node;
+ strncpy(node->name, name, sizeof(node->name));
+ QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
+ return node;
+}
+
+int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
+ const char *name, V9fsSynthNode **result)
+{
+ int ret;
+ V9fsSynthNode *node, *tmp;
+
+ if (!v9fs_synth_fs) {
+ return EAGAIN;
+ }
+ if (!name || (strlen(name) >= NAME_MAX)) {
+ return EINVAL;
+ }
+ if (!parent) {
+ parent = &v9fs_synth_root;
+ }
+ qemu_mutex_lock(&v9fs_synth_mutex);
+ QLIST_FOREACH(tmp, &parent->child, sibling) {
+ if (!strcmp(tmp->name, name)) {
+ ret = EEXIST;
+ goto err_out;
+ }
+ }
+ /* Add the name */
+ node = v9fs_add_dir_node(parent, mode, name, NULL, v9fs_synth_node_count++);
+ v9fs_add_dir_node(node, parent->attr->mode, "..",
+ parent->attr, parent->attr->inode);
+ v9fs_add_dir_node(node, node->attr->mode, ".",
+ node->attr, node->attr->inode);
+ *result = node;
+ ret = 0;
+err_out:
+ qemu_mutex_unlock(&v9fs_synth_mutex);
+ return ret;
+}
+
+int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
+ const char *name, v9fs_synth_read read,
+ v9fs_synth_write write, void *arg)
+{
+ int ret;
+ V9fsSynthNode *node, *tmp;
+
+ if (!v9fs_synth_fs) {
+ return EAGAIN;
+ }
+ if (!name || (strlen(name) >= NAME_MAX)) {
+ return EINVAL;
+ }
+ if (!parent) {
+ parent = &v9fs_synth_root;
+ }
+
+ qemu_mutex_lock(&v9fs_synth_mutex);
+ QLIST_FOREACH(tmp, &parent->child, sibling) {
+ if (!strcmp(tmp->name, name)) {
+ ret = EEXIST;
+ goto err_out;
+ }
+ }
+ /* Add file type and remove write bits */
+ mode = ((mode & 0777) | S_IFREG);
+ node = g_malloc0(sizeof(V9fsSynthNode));
+ node->attr = &node->actual_attr;
+ node->attr->inode = v9fs_synth_node_count++;
+ node->attr->nlink = 1;
+ node->attr->read = read;
+ node->attr->write = write;
+ node->attr->mode = mode;
+ node->private = arg;
+ strncpy(node->name, name, sizeof(node->name));
+ QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
+ ret = 0;
+err_out:
+ qemu_mutex_unlock(&v9fs_synth_mutex);
+ return ret;
+}
+
+static void v9fs_synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
+{
+ stbuf->st_dev = 0;
+ stbuf->st_ino = node->attr->inode;
+ stbuf->st_mode = node->attr->mode;
+ stbuf->st_nlink = node->attr->nlink;
+ stbuf->st_uid = 0;
+ stbuf->st_gid = 0;
+ stbuf->st_rdev = 0;
+ stbuf->st_size = 0;
+ stbuf->st_blksize = 0;
+ stbuf->st_blocks = 0;
+ stbuf->st_atime = 0;
+ stbuf->st_mtime = 0;
+ stbuf->st_ctime = 0;
+}
+
+static int v9fs_synth_lstat(FsContext *fs_ctx,
+ V9fsPath *fs_path, struct stat *stbuf)
+{
+ V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
+
+ v9fs_synth_fill_statbuf(node, stbuf);
+ return 0;
+}
+
+static int v9fs_synth_fstat(FsContext *fs_ctx,
+ V9fsFidOpenState *fs, struct stat *stbuf)
+{
+ V9fsSynthOpenState *synth_open = fs->private;
+ v9fs_synth_fill_statbuf(synth_open->node, stbuf);
+ return 0;
+}
+
+static int v9fs_synth_opendir(FsContext *ctx,
+ V9fsPath *fs_path, V9fsFidOpenState *fs)
+{
+ V9fsSynthOpenState *synth_open;
+ V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
+
+ synth_open = g_malloc(sizeof(*synth_open));
+ synth_open->node = node;
+ node->open_count++;
+ fs->private = synth_open;
+ return 0;
+}
+
+static int v9fs_synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+ V9fsSynthOpenState *synth_open = fs->private;
+ V9fsSynthNode *node = synth_open->node;
+
+ node->open_count--;
+ g_free(synth_open);
+ fs->private = NULL;
+ return 0;
+}
+
+static off_t v9fs_synth_telldir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+ V9fsSynthOpenState *synth_open = fs->private;
+ return synth_open->offset;
+}
+
+static void v9fs_synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
+{
+ V9fsSynthOpenState *synth_open = fs->private;
+ synth_open->offset = off;
+}
+
+static void v9fs_synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+ v9fs_synth_seekdir(ctx, fs, 0);
+}
+
+static void v9fs_synth_direntry(V9fsSynthNode *node,
+ struct dirent *entry, off_t off)
+{
+ strcpy(entry->d_name, node->name);
+ entry->d_ino = node->attr->inode;
+ entry->d_off = off + 1;
+}
+
+static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent *entry,
+ struct dirent **result, off_t off)
+{
+ int i = 0;
+ V9fsSynthNode *node;
+
+ rcu_read_lock();
+ QLIST_FOREACH(node, &dir->child, sibling) {
+ /* This is the off child of the directory */
+ if (i == off) {
+ break;
+ }
+ i++;
+ }
+ rcu_read_unlock();
+ if (!node) {
+ /* end of directory */
+ *result = NULL;
+ return 0;
+ }
+ v9fs_synth_direntry(node, entry, off);
+ *result = entry;
+ return 0;
+}
+
+static int v9fs_synth_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+ struct dirent *entry, struct dirent **result)
+{
+ int ret;
+ V9fsSynthOpenState *synth_open = fs->private;
+ V9fsSynthNode *node = synth_open->node;
+ ret = v9fs_synth_get_dentry(node, entry, result, synth_open->offset);
+ if (!ret && *result != NULL) {
+ synth_open->offset++;
+ }
+ return ret;
+}
+
+static int v9fs_synth_open(FsContext *ctx, V9fsPath *fs_path,
+ int flags, V9fsFidOpenState *fs)
+{
+ V9fsSynthOpenState *synth_open;
+ V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
+
+ synth_open = g_malloc(sizeof(*synth_open));
+ synth_open->node = node;
+ node->open_count++;
+ fs->private = synth_open;
+ return 0;
+}
+
+static int v9fs_synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
+ const char *name, int flags,
+ FsCred *credp, V9fsFidOpenState *fs)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int v9fs_synth_close(FsContext *ctx, V9fsFidOpenState *fs)
+{
+ V9fsSynthOpenState *synth_open = fs->private;
+ V9fsSynthNode *node = synth_open->node;
+
+ node->open_count--;
+ g_free(synth_open);
+ fs->private = NULL;
+ return 0;
+}
+
+static ssize_t v9fs_synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+ const struct iovec *iov,
+ int iovcnt, off_t offset)
+{
+ int i, count = 0, wcount;
+ V9fsSynthOpenState *synth_open = fs->private;
+ V9fsSynthNode *node = synth_open->node;
+ if (!node->attr->write) {
+ errno = EPERM;
+ return -1;
+ }
+ for (i = 0; i < iovcnt; i++) {
+ wcount = node->attr->write(iov[i].iov_base, iov[i].iov_len,
+ offset, node->private);
+ offset += wcount;
+ count += wcount;
+ /* If we wrote less than requested. we are done */
+ if (wcount < iov[i].iov_len) {
+ break;
+ }
+ }
+ return count;
+}
+
+static ssize_t v9fs_synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+ const struct iovec *iov,
+ int iovcnt, off_t offset)
+{
+ int i, count = 0, rcount;
+ V9fsSynthOpenState *synth_open = fs->private;
+ V9fsSynthNode *node = synth_open->node;
+ if (!node->attr->read) {
+ errno = EPERM;
+ return -1;
+ }
+ for (i = 0; i < iovcnt; i++) {
+ rcount = node->attr->read(iov[i].iov_base, iov[i].iov_len,
+ offset, node->private);
+ offset += rcount;
+ count += rcount;
+ /* If we read less than requested. we are done */
+ if (rcount < iov[i].iov_len) {
+ break;
+ }
+ }
+ return count;
+}
+
+static int v9fs_synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int v9fs_synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static int v9fs_synth_mknod(FsContext *fs_ctx, V9fsPath *path,
+ const char *buf, FsCred *credp)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static int v9fs_synth_mkdir(FsContext *fs_ctx, V9fsPath *path,
+ const char *buf, FsCred *credp)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static ssize_t v9fs_synth_readlink(FsContext *fs_ctx, V9fsPath *path,
+ char *buf, size_t bufsz)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int v9fs_synth_symlink(FsContext *fs_ctx, const char *oldpath,
+ V9fsPath *newpath, const char *buf, FsCred *credp)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static int v9fs_synth_link(FsContext *fs_ctx, V9fsPath *oldpath,
+ V9fsPath *newpath, const char *buf)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static int v9fs_synth_rename(FsContext *ctx, const char *oldpath,
+ const char *newpath)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static int v9fs_synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static int v9fs_synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
+ const struct timespec *buf)
+{
+ errno = EPERM;
+ return 0;
+}
+
+static int v9fs_synth_remove(FsContext *ctx, const char *path)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static int v9fs_synth_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
+{
+ errno = ENOSYS;
+ return 0;
+}
+
+static int v9fs_synth_statfs(FsContext *s, V9fsPath *fs_path,
+ struct statfs *stbuf)
+{
+ stbuf->f_type = 0xABCD;
+ stbuf->f_bsize = 512;
+ stbuf->f_blocks = 0;
+ stbuf->f_files = v9fs_synth_node_count;
+ stbuf->f_namelen = NAME_MAX;
+ return 0;
+}
+
+static ssize_t v9fs_synth_lgetxattr(FsContext *ctx, V9fsPath *path,
+ const char *name, void *value, size_t size)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static ssize_t v9fs_synth_llistxattr(FsContext *ctx, V9fsPath *path,
+ void *value, size_t size)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static int v9fs_synth_lsetxattr(FsContext *ctx, V9fsPath *path,
+ const char *name, void *value,
+ size_t size, int flags)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static int v9fs_synth_lremovexattr(FsContext *ctx,
+ V9fsPath *path, const char *name)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+ const char *name, V9fsPath *target)
+{
+ V9fsSynthNode *node;
+ V9fsSynthNode *dir_node;
+
+ /* "." and ".." are not allowed */
+ if (!strcmp(name, ".") || !strcmp(name, "..")) {
+ errno = EINVAL;
+ return -1;
+
+ }
+ if (!dir_path) {
+ dir_node = &v9fs_synth_root;
+ } else {
+ dir_node = *(V9fsSynthNode **)dir_path->data;
+ }
+ if (!strcmp(name, "/")) {
+ node = dir_node;
+ goto out;
+ }
+ /* search for the name in the childern */
+ rcu_read_lock();
+ QLIST_FOREACH(node, &dir_node->child, sibling) {
+ if (!strcmp(node->name, name)) {
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ if (!node) {
+ errno = ENOENT;
+ return -1;
+ }
+out:
+ /* Copy the node pointer to fid */
+ target->data = g_malloc(sizeof(void *));
+ memcpy(target->data, &node, sizeof(void *));
+ target->size = sizeof(void *);
+ return 0;
+}
+
+static int v9fs_synth_renameat(FsContext *ctx, V9fsPath *olddir,
+ const char *old_name, V9fsPath *newdir,
+ const char *new_name)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static int v9fs_synth_unlinkat(FsContext *ctx, V9fsPath *dir,
+ const char *name, int flags)
+{
+ errno = EPERM;
+ return -1;
+}
+
+static int v9fs_synth_init(FsContext *ctx)
+{
+ QLIST_INIT(&v9fs_synth_root.child);
+ qemu_mutex_init(&v9fs_synth_mutex);
+
+ /* Add "." and ".." entries for root */
+ v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
+ "..", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
+ v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
+ ".", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
+
+ /* Mark the subsystem is ready for use */
+ v9fs_synth_fs = 1;
+ return 0;
+}
+
+FileOperations synth_ops = {
+ .init = v9fs_synth_init,
+ .lstat = v9fs_synth_lstat,
+ .readlink = v9fs_synth_readlink,
+ .close = v9fs_synth_close,
+ .closedir = v9fs_synth_closedir,
+ .open = v9fs_synth_open,
+ .opendir = v9fs_synth_opendir,
+ .rewinddir = v9fs_synth_rewinddir,
+ .telldir = v9fs_synth_telldir,
+ .readdir_r = v9fs_synth_readdir_r,
+ .seekdir = v9fs_synth_seekdir,
+ .preadv = v9fs_synth_preadv,
+ .pwritev = v9fs_synth_pwritev,
+ .chmod = v9fs_synth_chmod,
+ .mknod = v9fs_synth_mknod,
+ .mkdir = v9fs_synth_mkdir,
+ .fstat = v9fs_synth_fstat,
+ .open2 = v9fs_synth_open2,
+ .symlink = v9fs_synth_symlink,
+ .link = v9fs_synth_link,
+ .truncate = v9fs_synth_truncate,
+ .rename = v9fs_synth_rename,
+ .chown = v9fs_synth_chown,
+ .utimensat = v9fs_synth_utimensat,
+ .remove = v9fs_synth_remove,
+ .fsync = v9fs_synth_fsync,
+ .statfs = v9fs_synth_statfs,
+ .lgetxattr = v9fs_synth_lgetxattr,
+ .llistxattr = v9fs_synth_llistxattr,
+ .lsetxattr = v9fs_synth_lsetxattr,
+ .lremovexattr = v9fs_synth_lremovexattr,
+ .name_to_path = v9fs_synth_name_to_path,
+ .renameat = v9fs_synth_renameat,
+ .unlinkat = v9fs_synth_unlinkat,
+};
diff --git a/hw/9pfs/virtio-9p-synth.h b/hw/9pfs/virtio-9p-synth.h
new file mode 100644
index 0000000..e03f434
--- /dev/null
+++ b/hw/9pfs/virtio-9p-synth.h
@@ -0,0 +1,50 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+
+typedef struct V9fsSynthNode V9fsSynthNode;
+typedef ssize_t (*v9fs_synth_read)(void *buf, int len, off_t offset,
+ void *arg);
+typedef ssize_t (*v9fs_synth_write)(void *buf, int len, off_t offset,
+ void *arg);
+typedef struct V9fsSynthNodeAttr {
+ int mode;
+ int inode;
+ int nlink;
+ v9fs_synth_read read;
+ v9fs_synth_write write;
+} V9fsSynthNodeAttr;
+
+struct V9fsSynthNode {
+ QLIST_HEAD(, V9fsSynthNode) child;
+ QLIST_ENTRY(V9fsSynthNode) sibling;
+ char name[NAME_MAX];
+ V9fsSynthNodeAttr *attr;
+ V9fsSynthNodeAttr actual_attr;
+ void *private;
+ int open_count;
+};
+
+typedef struct V9fsSynthOpenState {
+ off_t offset;
+ V9fsSynthNode *node;
+} V9fsSynthOpenState;
+
+extern int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
+ const char *name, V9fsSynthNode **result);
+extern int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
+ const char *name, v9fs_synth_read read,
+ v9fs_synth_write write, void *arg);
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 8b6813f..0777ece 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -455,11 +455,11 @@ static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
if (fidp->fid_type == P9_FID_FILE) {
/* If we reclaimed the fd no need to close */
if (fidp->fs.fd != -1) {
- retval = v9fs_co_close(pdu, fidp->fs.fd);
+ retval = v9fs_co_close(pdu, &fidp->fs);
}
} else if (fidp->fid_type == P9_FID_DIR) {
if (fidp->fs.dir != NULL) {
- retval = v9fs_co_closedir(pdu, fidp->fs.dir);
+ retval = v9fs_co_closedir(pdu, &fidp->fs);
}
} else if (fidp->fid_type == P9_FID_XATTR) {
retval = v9fs_xattr_fid_clunk(pdu, fidp);
@@ -567,9 +567,9 @@ void v9fs_reclaim_fd(V9fsPDU *pdu)
f = reclaim_list;
reclaim_list = f->rclm_lst;
if (f->fid_type == P9_FID_FILE) {
- v9fs_co_close(pdu, f->fs_reclaim.fd);
+ v9fs_co_close(pdu, &f->fs_reclaim);
} else if (f->fid_type == P9_FID_DIR) {
- v9fs_co_closedir(pdu, f->fs_reclaim.dir);
+ v9fs_co_closedir(pdu, &f->fs_reclaim);
}
f->rclm_lst = NULL;
/*
@@ -1271,6 +1271,11 @@ static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
dst->size++;
}
+static inline bool is_ro_export(FsContext *ctx)
+{
+ return ctx->export_flags & V9FS_RDONLY;
+}
+
static void v9fs_version(void *opaque)
{
V9fsPDU *pdu = opaque;
@@ -1690,6 +1695,14 @@ static void v9fs_open(void *opaque)
} else {
flags = omode_to_uflags(mode);
}
+ if (is_ro_export(&s->ctx)) {
+ if (mode & O_WRONLY || mode & O_RDWR ||
+ mode & O_APPEND || mode & O_TRUNC) {
+ err = -EROFS;
+ goto out;
+ }
+ flags |= O_NOATIME;
+ }
err = v9fs_co_open(pdu, fidp, flags);
if (err < 0) {
goto out;
@@ -2996,7 +3009,7 @@ static void v9fs_lock(void *opaque)
err = -ENOENT;
goto out_nofid;
}
- err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
+ err = v9fs_co_fstat(pdu, fidp, &stbuf);
if (err < 0) {
goto out;
}
@@ -3039,7 +3052,7 @@ static void v9fs_getlock(void *opaque)
err = -ENOENT;
goto out_nofid;
}
- err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
+ err = v9fs_co_fstat(pdu, fidp, &stbuf);
if (err < 0) {
goto out;
}
@@ -3309,6 +3322,39 @@ static void v9fs_op_not_supp(void *opaque)
complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
}
+static void v9fs_fs_ro(void *opaque)
+{
+ V9fsPDU *pdu = opaque;
+ complete_pdu(pdu->s, pdu, -EROFS);
+}
+
+static inline bool is_read_only_op(V9fsPDU *pdu)
+{
+ switch (pdu->id) {
+ case P9_TREADDIR:
+ case P9_TSTATFS:
+ case P9_TGETATTR:
+ case P9_TXATTRWALK:
+ case P9_TLOCK:
+ case P9_TGETLOCK:
+ case P9_TREADLINK:
+ case P9_TVERSION:
+ case P9_TLOPEN:
+ case P9_TATTACH:
+ case P9_TSTAT:
+ case P9_TWALK:
+ case P9_TCLUNK:
+ case P9_TFSYNC:
+ case P9_TOPEN:
+ case P9_TREAD:
+ case P9_TAUTH:
+ case P9_TFLUSH:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
{
Coroutine *co;
@@ -3320,6 +3366,10 @@ static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
} else {
handler = pdu_co_handlers[pdu->id];
}
+
+ if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
+ handler = v9fs_fs_ro;
+ }
co = qemu_coroutine_create(handler);
qemu_coroutine_enter(co, pdu);
}
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 802f580..7f88356 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -204,20 +204,29 @@ typedef struct V9fsXattr
int flags;
} V9fsXattr;
+/*
+ * Filled by fs driver on open and other
+ * calls.
+ */
+union V9fsFidOpenState {
+ int fd;
+ DIR *dir;
+ V9fsXattr xattr;
+ /*
+ * private pointer for fs drivers, that
+ * have its own internal representation of
+ * open files.
+ */
+ void *private;
+};
+
struct V9fsFidState
{
int fid_type;
int32_t fid;
V9fsPath path;
- union {
- int fd;
- DIR *dir;
- V9fsXattr xattr;
- } fs;
- union {
- int fd;
- DIR *dir;
- } fs_reclaim;
+ V9fsFidOpenState fs;
+ V9fsFidOpenState fs_reclaim;
int flags;
int open_flags;
uid_t uid;