diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2011-10-31 11:06:02 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2011-10-31 11:06:02 -0500 |
commit | d439b79d730bf219e47c14ab94f1546bcc5045ab (patch) | |
tree | c8d0ae00ff1e86e7ecdaac028d2b2db30305f0c3 /hw | |
parent | 96b3d73f5ad5838690d42666c566a48be9d173dc (diff) | |
parent | 2583e443676e6b9259425f7d5ccaccbfa9bf7886 (diff) | |
download | qemu-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.c | 16 | ||||
-rw-r--r-- | hw/9pfs/cofile.c | 37 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-coth.h | 6 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-handle.c | 96 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-local.c | 113 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-synth.c | 571 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-synth.h | 50 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p.c | 62 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p.h | 27 |
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; |