aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-09-29 13:32:05 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2011-09-29 13:32:05 -0500
commit62ec6073cd07b847c296b3a1fa19894293f8155d (patch)
tree19fc1772d9cabd7f5590e33374d58a3f4b38d0ba /hw
parent0bce98df2639aef1e8af90b271aa91e16d695408 (diff)
parent5f5422258e1f50f871bafcc5bfb2b498f414a310 (diff)
Merge remote-tracking branch 'aneesh/for-upstream-5' into staging
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/codir.c64
-rw-r--r--hw/9pfs/cofile.c110
-rw-r--r--hw/9pfs/cofs.c195
-rw-r--r--hw/9pfs/coxattr.c41
-rw-r--r--hw/9pfs/virtio-9p-coth.h72
-rw-r--r--hw/9pfs/virtio-9p-device.c10
-rw-r--r--hw/9pfs/virtio-9p-handle.c611
-rw-r--r--hw/9pfs/virtio-9p-local.c213
-rw-r--r--hw/9pfs/virtio-9p.c820
-rw-r--r--hw/9pfs/virtio-9p.h50
10 files changed, 1670 insertions, 516 deletions
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index f17f927c10..72732e7c53 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -17,11 +17,15 @@
#include "qemu-coroutine.h"
#include "virtio-9p-coth.h"
-int v9fs_co_readdir_r(V9fsState *s, V9fsFidState *fidp, struct dirent *dent,
+int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent,
struct dirent **result)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
v9fs_co_run_in_worker(
{
errno = 0;
@@ -35,10 +39,14 @@ int v9fs_co_readdir_r(V9fsState *s, V9fsFidState *fidp, struct dirent *dent,
return err;
}
-off_t v9fs_co_telldir(V9fsState *s, V9fsFidState *fidp)
+off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
{
off_t err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
v9fs_co_run_in_worker(
{
err = s->ops->telldir(&s->ctx, fidp->fs.dir);
@@ -49,67 +57,103 @@ off_t v9fs_co_telldir(V9fsState *s, V9fsFidState *fidp)
return err;
}
-void v9fs_co_seekdir(V9fsState *s, V9fsFidState *fidp, off_t offset)
+void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset)
{
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return;
+ }
v9fs_co_run_in_worker(
{
s->ops->seekdir(&s->ctx, fidp->fs.dir, offset);
});
}
-void v9fs_co_rewinddir(V9fsState *s, V9fsFidState *fidp)
+void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
{
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return;
+ }
v9fs_co_run_in_worker(
{
s->ops->rewinddir(&s->ctx, fidp->fs.dir);
});
}
-int v9fs_co_mkdir(V9fsState *s, char *name, mode_t mode, uid_t uid, gid_t gid)
+int v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name,
+ mode_t mode, uid_t uid, gid_t gid, struct stat *stbuf)
{
int err;
FsCred cred;
+ V9fsPath path;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;;
+ }
cred_init(&cred);
cred.fc_mode = mode;
cred.fc_uid = uid;
cred.fc_gid = gid;
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->mkdir(&s->ctx, name, &cred);
+ err = s->ops->mkdir(&s->ctx, &fidp->path, name->data, &cred);
if (err < 0) {
err = -errno;
+ } else {
+ v9fs_path_init(&path);
+ err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+ if (!err) {
+ err = s->ops->lstat(&s->ctx, &path, stbuf);
+ if (err < 0) {
+ err = -errno;
+ }
+ }
+ v9fs_path_free(&path);
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
+int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- fidp->fs.dir = s->ops->opendir(&s->ctx, fidp->path.data);
+ fidp->fs.dir = s->ops->opendir(&s->ctx, &fidp->path);
if (!fidp->fs.dir) {
err = -errno;
} else {
err = 0;
}
});
+ v9fs_path_unlock(s);
if (!err) {
total_open_fd++;
if (total_open_fd > open_fd_hw) {
- v9fs_reclaim_fd(s);
+ v9fs_reclaim_fd(pdu);
}
}
return err;
}
-int v9fs_co_closedir(V9fsState *s, DIR *dir)
+int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;;
+ }
v9fs_co_run_in_worker(
{
err = s->ops->closedir(&s->ctx, dir);
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 0caf1e3cee..7ad4bec005 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -17,24 +17,34 @@
#include "qemu-coroutine.h"
#include "virtio-9p-coth.h"
-int v9fs_co_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
+int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->lstat(&s->ctx, path->data, stbuf);
+ err = s->ops->lstat(&s->ctx, path, stbuf);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_fstat(V9fsState *s, int fd, struct stat *stbuf)
+int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
v9fs_co_run_in_worker(
{
err = s->ops->fstat(&s->ctx, fd, stbuf);
@@ -45,59 +55,96 @@ int v9fs_co_fstat(V9fsState *s, int fd, struct stat *stbuf)
return err;
}
-int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
+int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- fidp->fs.fd = s->ops->open(&s->ctx, fidp->path.data, flags);
+ fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags);
if (fidp->fs.fd == -1) {
err = -errno;
} else {
err = 0;
}
});
+ v9fs_path_unlock(s);
if (!err) {
total_open_fd++;
if (total_open_fd > open_fd_hw) {
- v9fs_reclaim_fd(s);
+ v9fs_reclaim_fd(pdu);
}
}
return err;
}
-int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, char *fullname, gid_t gid,
- int flags, int mode)
+int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
+ int flags, int mode, struct stat *stbuf)
{
int err;
FsCred cred;
+ V9fsPath path;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
cred_init(&cred);
cred.fc_mode = mode & 07777;
cred.fc_uid = fidp->uid;
cred.fc_gid = gid;
+ /*
+ * Hold the directory fid lock so that directory path name
+ * don't change. Read lock is fine because this fid cannot
+ * be used by any other operation.
+ */
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- fidp->fs.fd = s->ops->open2(&s->ctx, fullname, flags, &cred);
- err = 0;
+ fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path,
+ name->data, flags, &cred);
if (fidp->fs.fd == -1) {
err = -errno;
+ } else {
+ v9fs_path_init(&path);
+ err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+ if (!err) {
+ err = s->ops->lstat(&s->ctx, &path, stbuf);
+ if (err < 0) {
+ err = -errno;
+ s->ops->close(&s->ctx, fidp->fs.fd);
+ } else {
+ v9fs_path_copy(&fidp->path, &path);
+ }
+ } else {
+ s->ops->close(&s->ctx, fidp->fs.fd);
+ }
+ v9fs_path_free(&path);
}
});
+ v9fs_path_unlock(s);
if (!err) {
total_open_fd++;
if (total_open_fd > open_fd_hw) {
- v9fs_reclaim_fd(s);
+ v9fs_reclaim_fd(pdu);
}
}
return err;
}
-int v9fs_co_close(V9fsState *s, int fd)
+int v9fs_co_close(V9fsPDU *pdu, int fd)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
v9fs_co_run_in_worker(
{
err = s->ops->close(&s->ctx, fd);
@@ -111,11 +158,14 @@ int v9fs_co_close(V9fsState *s, int fd)
return err;
}
-int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync)
+int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
{
- int fd;
- int err;
+ int fd, err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
fd = fidp->fs.fd;
v9fs_co_run_in_worker(
{
@@ -127,26 +177,37 @@ int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync)
return err;
}
-int v9fs_co_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
+int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
+ V9fsFidState *newdirfid, V9fsString *name)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->link(&s->ctx, oldpath->data, newpath->data);
+ err = s->ops->link(&s->ctx, &oldfid->path,
+ &newdirfid->path, name->data);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_pwritev(V9fsState *s, V9fsFidState *fidp,
+int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
struct iovec *iov, int iovcnt, int64_t offset)
{
- int fd;
- int err;
+ int fd, err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
fd = fidp->fs.fd;
v9fs_co_run_in_worker(
{
@@ -158,12 +219,15 @@ int v9fs_co_pwritev(V9fsState *s, V9fsFidState *fidp,
return err;
}
-int v9fs_co_preadv(V9fsState *s, V9fsFidState *fidp,
+int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
struct iovec *iov, int iovcnt, int64_t offset)
{
- int fd;
- int err;
+ int fd, err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
fd = fidp->fs.fd;
v9fs_co_run_in_worker(
{
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index a78fccbe23..68745add1e 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -17,15 +17,20 @@
#include "qemu-coroutine.h"
#include "virtio-9p-coth.h"
-int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
+int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
{
int err;
ssize_t len;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
buf->data = g_malloc(PATH_MAX);
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- len = s->ops->readlink(&s->ctx, path->data,
+ len = s->ops->readlink(&s->ctx, path,
buf->data, PATH_MAX - 1);
if (len > -1) {
buf->size = len;
@@ -35,6 +40,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
err = -errno;
}
});
+ v9fs_path_unlock(s);
if (err) {
g_free(buf->data);
buf->data = NULL;
@@ -43,109 +49,162 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
return err;
}
-int v9fs_co_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
+int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->statfs(&s->ctx, path->data, stbuf);
+ err = s->ops->statfs(&s->ctx, path, stbuf);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
+int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
{
int err;
FsCred cred;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
cred_init(&cred);
cred.fc_mode = mode;
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->chmod(&s->ctx, path->data, &cred);
+ err = s->ops->chmod(&s->ctx, path, &cred);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
+int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
struct timespec times[2])
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->utimensat(&s->ctx, path->data, times);
+ err = s->ops->utimensat(&s->ctx, path, times);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
+int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid)
{
int err;
FsCred cred;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
cred_init(&cred);
cred.fc_uid = uid;
cred.fc_gid = gid;
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->chown(&s->ctx, path->data, &cred);
+ err = s->ops->chown(&s->ctx, path, &cred);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_truncate(V9fsState *s, V9fsString *path, off_t size)
+int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->truncate(&s->ctx, path->data, size);
+ err = s->ops->truncate(&s->ctx, path, size);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_mknod(V9fsState *s, V9fsString *path, uid_t uid,
- gid_t gid, dev_t dev, mode_t mode)
+int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid,
+ gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
{
int err;
+ V9fsPath path;
FsCred cred;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
cred_init(&cred);
cred.fc_uid = uid;
cred.fc_gid = gid;
cred.fc_mode = mode;
cred.fc_rdev = dev;
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->mknod(&s->ctx, path->data, &cred);
+ err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
if (err < 0) {
err = -errno;
+ } else {
+ v9fs_path_init(&path);
+ err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+ if (!err) {
+ err = s->ops->lstat(&s->ctx, &path, stbuf);
+ if (err < 0) {
+ err = -errno;
+ }
+ }
+ v9fs_path_free(&path);
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_remove(V9fsState *s, V9fsString *path)
+/* Only works with path name based fid */
+int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
err = s->ops->remove(&s->ctx, path->data);
@@ -153,13 +212,39 @@ int v9fs_co_remove(V9fsState *s, V9fsString *path)
err = -errno;
}
});
+ v9fs_path_unlock(s);
+ return err;
+}
+
+int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags)
+{
+ int err;
+ V9fsState *s = pdu->s;
+
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
+ v9fs_co_run_in_worker(
+ {
+ err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
+ if (err < 0) {
+ err = -errno;
+ }
+ });
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_rename(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
+/* Only work with path name based fid */
+int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
v9fs_co_run_in_worker(
{
err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
@@ -170,22 +255,90 @@ int v9fs_co_rename(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
return err;
}
-int v9fs_co_symlink(V9fsState *s, V9fsFidState *fidp,
- const char *oldpath, const char *newpath, gid_t gid)
+int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname,
+ V9fsPath *newdirpath, V9fsString *newname)
+{
+ int err;
+ V9fsState *s = pdu->s;
+
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_co_run_in_worker(
+ {
+ err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
+ newdirpath, newname->data);
+ if (err < 0) {
+ err = -errno;
+ }
+ });
+ return err;
+}
+
+int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name,
+ const char *oldpath, gid_t gid, struct stat *stbuf)
{
int err;
FsCred cred;
+ V9fsPath path;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
cred_init(&cred);
- cred.fc_uid = fidp->uid;
+ cred.fc_uid = dfidp->uid;
cred.fc_gid = gid;
cred.fc_mode = 0777;
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
+ err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
+ name->data, &cred);
if (err < 0) {
err = -errno;
+ } else {
+ v9fs_path_init(&path);
+ err = v9fs_name_to_path(s, &dfidp->path, name->data, &path);
+ if (!err) {
+ err = s->ops->lstat(&s->ctx, &path, stbuf);
+ if (err < 0) {
+ err = -errno;
+ }
+ }
+ v9fs_path_free(&path);
}
});
+ v9fs_path_unlock(s);
+ return err;
+}
+
+/*
+ * For path name based fid we don't block. So we can
+ * directly call the fs driver ops.
+ */
+int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
+ const char *name, V9fsPath *path)
+{
+ int err;
+ V9fsState *s = pdu->s;
+
+ if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+ err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+ if (err < 0) {
+ err = -errno;
+ }
+ } else {
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_co_run_in_worker(
+ {
+ err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+ if (err < 0) {
+ err = -errno;
+ }
+ });
+ }
return err;
}
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index a289389e49..8a48228702 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -17,68 +17,91 @@
#include "qemu-coroutine.h"
#include "virtio-9p-coth.h"
-int v9fs_co_llistxattr(V9fsState *s, V9fsString *path, void *value, size_t size)
+int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->llistxattr(&s->ctx, path->data, value, size);
+ err = s->ops->llistxattr(&s->ctx, path, value, size);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
+int v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path,
V9fsString *xattr_name,
void *value, size_t size)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->lgetxattr(&s->ctx, path->data,
+ err = s->ops->lgetxattr(&s->ctx, path,
xattr_name->data,
value, size);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
+int v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path,
V9fsString *xattr_name, void *value,
size_t size, int flags)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->lsetxattr(&s->ctx, path->data,
+ err = s->ops->lsetxattr(&s->ctx, path,
xattr_name->data, value,
size, flags);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
-int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
+int v9fs_co_lremovexattr(V9fsPDU *pdu, V9fsPath *path,
V9fsString *xattr_name)
{
int err;
+ V9fsState *s = pdu->s;
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- err = s->ops->lremovexattr(&s->ctx, path->data,
- xattr_name->data);
+ err = s->ops->lremovexattr(&s->ctx, path, xattr_name->data);
if (err < 0) {
err = -errno;
}
});
+ v9fs_path_unlock(s);
return err;
}
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index b7be9b5f1f..4630080e53 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -56,41 +56,49 @@ typedef struct V9fsThPool {
extern void co_run_in_worker_bh(void *);
extern int v9fs_init_worker_threads(void);
-extern int v9fs_co_readlink(V9fsState *, V9fsString *, V9fsString *);
-extern int v9fs_co_readdir_r(V9fsState *, V9fsFidState *,
+extern int v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *);
+extern int v9fs_co_readdir_r(V9fsPDU *, V9fsFidState *,
struct dirent *, struct dirent **result);
-extern off_t v9fs_co_telldir(V9fsState *, V9fsFidState *);
-extern void v9fs_co_seekdir(V9fsState *, V9fsFidState *, off_t);
-extern void v9fs_co_rewinddir(V9fsState *, V9fsFidState *);
-extern int v9fs_co_statfs(V9fsState *, V9fsString *, struct statfs *);
-extern int v9fs_co_lstat(V9fsState *, V9fsString *, struct stat *);
-extern int v9fs_co_chmod(V9fsState *, V9fsString *, mode_t);
-extern int v9fs_co_utimensat(V9fsState *, V9fsString *, struct timespec [2]);
-extern int v9fs_co_chown(V9fsState *, V9fsString *, uid_t, gid_t);
-extern int v9fs_co_truncate(V9fsState *, V9fsString *, off_t);
-extern int v9fs_co_llistxattr(V9fsState *, V9fsString *, void *, size_t);
-extern int v9fs_co_lgetxattr(V9fsState *, V9fsString *,
+extern off_t v9fs_co_telldir(V9fsPDU *, V9fsFidState *);
+extern void v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t);
+extern void v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *);
+extern int v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *);
+extern int v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *);
+extern int v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t);
+extern int v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]);
+extern int v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t);
+extern int v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t);
+extern int v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t);
+extern int v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *,
V9fsString *, void *, size_t);
-extern int v9fs_co_mknod(V9fsState *, V9fsString *, uid_t,
- gid_t, dev_t, mode_t);
-extern int v9fs_co_mkdir(V9fsState *, char *, mode_t, uid_t, gid_t);
-extern int v9fs_co_remove(V9fsState *, V9fsString *);
-extern int v9fs_co_rename(V9fsState *, V9fsString *, V9fsString *);
-extern int v9fs_co_fstat(V9fsState *, int, struct stat *);
-extern int v9fs_co_opendir(V9fsState *, V9fsFidState *);
-extern int v9fs_co_open(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_open2(V9fsState *, V9fsFidState *, char *, gid_t, int, int);
-extern int v9fs_co_lsetxattr(V9fsState *, V9fsString *, V9fsString *,
+extern int v9fs_co_mknod(V9fsPDU *, V9fsFidState *, V9fsString *, uid_t,
+ gid_t, dev_t, mode_t, struct stat *);
+extern int v9fs_co_mkdir(V9fsPDU *, V9fsFidState *, V9fsString *,
+ mode_t, uid_t, gid_t, struct stat *);
+extern int v9fs_co_remove(V9fsPDU *, V9fsPath *);
+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_opendir(V9fsPDU *, V9fsFidState *);
+extern int v9fs_co_open(V9fsPDU *, V9fsFidState *, int);
+extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
+ gid_t, int, int, struct stat *);
+extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *,
void *, size_t, int);
-extern int v9fs_co_lremovexattr(V9fsState *, V9fsString *, V9fsString *);
-extern int v9fs_co_closedir(V9fsState *, DIR *);
-extern int v9fs_co_close(V9fsState *, int);
-extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, const char *,
- const char *, gid_t);
-extern int v9fs_co_link(V9fsState *, V9fsString *, V9fsString *);
-extern int v9fs_co_pwritev(V9fsState *, V9fsFidState *,
+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_fsync(V9fsPDU *, V9fsFidState *, int);
+extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *,
+ const char *, gid_t, struct stat *);
+extern int v9fs_co_link(V9fsPDU *, V9fsFidState *,
+ V9fsFidState *, V9fsString *);
+extern int v9fs_co_pwritev(V9fsPDU *, V9fsFidState *,
struct iovec *, int, int64_t);
-extern int v9fs_co_preadv(V9fsState *, V9fsFidState *,
+extern int v9fs_co_preadv(V9fsPDU *, V9fsFidState *,
struct iovec *, int, int64_t);
+extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *,
+ const char *, V9fsPath *);
#endif
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 97f2da5f0e..513e181c82 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -45,7 +45,7 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
}
VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
- {
+{
V9fsState *s;
int i, len;
struct stat stat;
@@ -58,6 +58,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
sizeof(V9fsState));
/* initialize pdu allocator */
QLIST_INIT(&s->free_list);
+ QLIST_INIT(&s->active_list);
for (i = 0; i < (MAX_REQ - 1); i++) {
QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
}
@@ -124,6 +125,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
memcpy(s->tag, conf->tag, len);
s->tag_len = len;
s->ctx.uid = -1;
+ s->ctx.flags = 0;
s->ops = fse->ops;
s->vdev.get_features = virtio_9p_get_features;
@@ -131,7 +133,13 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
s->tag_len;
s->vdev.get_config = virtio_9p_get_config;
s->fid_list = NULL;
+ qemu_co_rwlock_init(&s->rename_lock);
+ if (s->ops->init(&s->ctx) < 0) {
+ fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s"
+ " and export path:%s\n", conf->fsdev_id, s->ctx.fs_root);
+ exit(1);
+ }
if (v9fs_init_worker_threads() < 0) {
fprintf(stderr, "worker thread initialization failed\n");
exit(1);
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
new file mode 100644
index 0000000000..5c8b5ed471
--- /dev/null
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -0,0 +1,611 @@
+/*
+ * Virtio 9p handle callback
+ *
+ * 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 "hw/virtio.h"
+#include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <attr/xattr.h>
+#include <unistd.h>
+
+struct handle_data {
+ int mountfd;
+ int handle_bytes;
+};
+
+#if __GLIBC__ <= 2 && __GLIBC_MINOR__ < 14
+struct file_handle {
+ unsigned int handle_bytes;
+ int handle_type;
+ unsigned char handle[0];
+};
+#endif
+
+#ifndef AT_EMPTY_PATH
+#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
+#endif
+#ifndef O_PATH
+#define O_PATH 010000000
+#endif
+
+#ifndef __NR_name_to_handle_at
+#if defined(__i386__)
+#define __NR_name_to_handle_at 341
+#define __NR_open_by_handle_at 342
+#elif defined(__x86_64__)
+#define __NR_name_to_handle_at 303
+#define __NR_open_by_handle_at 304
+#endif
+#endif
+
+#ifdef __NR_name_to_handle_at
+static inline int name_to_handle(int dirfd, const char *name,
+ struct file_handle *fh, int *mnt_id, int flags)
+{
+ return syscall(__NR_name_to_handle_at, dirfd, name, fh, mnt_id, flags);
+}
+
+static inline int open_by_handle(int mountfd, const char *fh, int flags)
+{
+ return syscall(__NR_open_by_handle_at, mountfd, fh, flags);
+}
+#else
+static inline int name_to_handle(int dirfd, const char *name,
+ struct file_handle *fh, int *mnt_id, int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static inline int open_by_handle(int mountfd, const char *fh, int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
+{
+ int fd, ret;
+ fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);;
+ if (fd < 0) {
+ return fd;
+ }
+ ret = fchmod(fd, credp->fc_mode & 07777);
+ if (ret < 0) {
+ goto err_out;
+ }
+ ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+err_out:
+ close(fd);
+ return ret;
+}
+
+
+static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path,
+ struct stat *stbuf)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH);
+ close(fd);
+ return ret;
+}
+
+static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
+ char *buf, size_t bufsz)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = readlinkat(fd, "", buf, bufsz);
+ close(fd);
+ return ret;
+}
+
+static int handle_close(FsContext *ctx, int fd)
+{
+ return close(fd);
+}
+
+static int handle_closedir(FsContext *ctx, DIR *dir)
+{
+ return closedir(dir);
+}
+
+static int handle_open(FsContext *ctx, V9fsPath *fs_path, int flags)
+{
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ return open_by_handle(data->mountfd, fs_path->data, flags);
+}
+
+static DIR *handle_opendir(FsContext *ctx, V9fsPath *fs_path)
+{
+ int fd;
+ fd = handle_open(ctx, fs_path, O_DIRECTORY);
+ if (fd < 0) {
+ return NULL;
+ }
+ return fdopendir(fd);
+}
+
+static void handle_rewinddir(FsContext *ctx, DIR *dir)
+{
+ return rewinddir(dir);
+}
+
+static off_t handle_telldir(FsContext *ctx, DIR *dir)
+{
+ return telldir(dir);
+}
+
+static int handle_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+ struct dirent **result)
+{
+ return readdir_r(dir, entry, result);
+}
+
+static void handle_seekdir(FsContext *ctx, DIR *dir, off_t off)
+{
+ return seekdir(dir, off);
+}
+
+static ssize_t handle_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+ int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+ return preadv(fd, iov, iovcnt, offset);
+#else
+ int err = lseek(fd, offset, SEEK_SET);
+ if (err == -1) {
+ return err;
+ } else {
+ return readv(fd, iov, iovcnt);
+ }
+#endif
+}
+
+static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+ int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+ return pwritev(fd, iov, iovcnt, offset);
+#else
+ int err = lseek(fd, offset, SEEK_SET);
+ if (err == -1) {
+ return err;
+ } else {
+ return writev(fd, iov, iovcnt);
+ }
+#endif
+}
+
+static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = fchmod(fd, credp->fc_mode);
+ close(fd);
+ return ret;
+}
+
+static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+ const char *name, FsCred *credp)
+{
+ int dirfd, ret;
+ struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+ dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+ if (dirfd < 0) {
+ return dirfd;
+ }
+ ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
+ if (!ret) {
+ ret = handle_update_file_cred(dirfd, name, credp);
+ }
+ close(dirfd);
+ return ret;
+}
+
+static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+ const char *name, FsCred *credp)
+{
+ int dirfd, ret;
+ struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+ dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+ if (dirfd < 0) {
+ return dirfd;
+ }
+ ret = mkdirat(dirfd, name, credp->fc_mode);
+ if (!ret) {
+ ret = handle_update_file_cred(dirfd, name, credp);
+ }
+ close(dirfd);
+ return ret;
+}
+
+static int handle_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+{
+ return fstat(fd, stbuf);
+}
+
+static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
+ int flags, FsCred *credp)
+{
+ int ret;
+ int dirfd, fd;
+ struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+ dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+ if (dirfd < 0) {
+ return dirfd;
+ }
+ fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode);
+ if (fd >= 0) {
+ ret = handle_update_file_cred(dirfd, name, credp);
+ if (ret < 0) {
+ close(fd);
+ fd = ret;
+ }
+ }
+ close(dirfd);
+ return fd;
+}
+
+
+static int handle_symlink(FsContext *fs_ctx, const char *oldpath,
+ V9fsPath *dir_path, const char *name, FsCred *credp)
+{
+ int fd, dirfd, ret;
+ struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+ dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+ if (dirfd < 0) {
+ return dirfd;
+ }
+ ret = symlinkat(oldpath, dirfd, name);
+ if (!ret) {
+ fd = openat(dirfd, name, O_PATH | O_NOFOLLOW);
+ if (fd < 0) {
+ ret = fd;
+ goto err_out;
+ }
+ ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+ close(fd);
+ }
+err_out:
+ close(dirfd);
+ return ret;
+}
+
+static int handle_link(FsContext *ctx, V9fsPath *oldpath,
+ V9fsPath *dirpath, const char *name)
+{
+ int oldfd, newdirfd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH);
+ if (oldfd < 0) {
+ return oldfd;
+ }
+ newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH);
+ if (newdirfd < 0) {
+ close(oldfd);
+ return newdirfd;
+ }
+ ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH);
+ close(newdirfd);
+ close(oldfd);
+ return ret;
+}
+
+static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = ftruncate(fd, size);
+ close(fd);
+ return ret;
+}
+
+static int handle_rename(FsContext *ctx, const char *oldpath,
+ const char *newpath)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+ close(fd);
+ return ret;
+}
+
+static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
+ const struct timespec *buf)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = futimens(fd, buf);
+ close(fd);
+ return ret;
+}
+
+static int handle_remove(FsContext *ctx, const char *path)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int handle_fsync(FsContext *ctx, int fd, int datasync)
+{
+ if (datasync) {
+ return qemu_fdatasync(fd);
+ } else {
+ return fsync(fd);
+ }
+}
+
+static int handle_statfs(FsContext *ctx, V9fsPath *fs_path,
+ struct statfs *stbuf)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = fstatfs(fd, stbuf);
+ close(fd);
+ return ret;
+}
+
+static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
+ const char *name, void *value, size_t size)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = fgetxattr(fd, name, value, size);
+ close(fd);
+ return ret;
+}
+
+static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
+ void *value, size_t size)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = flistxattr(fd, value, size);
+ close(fd);
+ return ret;
+}
+
+static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
+ void *value, size_t size, int flags)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = fsetxattr(fd, name, value, size, flags);
+ close(fd);
+ return ret;
+}
+
+static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+ const char *name)
+{
+ int fd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+ if (fd < 0) {
+ return fd;
+ }
+ ret = fremovexattr(fd, name);
+ close(fd);
+ return ret;
+}
+
+static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+ const char *name, V9fsPath *target)
+{
+ char buffer[PATH_MAX];
+ struct file_handle *fh;
+ int dirfd, ret, mnt_id;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ /* "." and ".." are not allowed */
+ if (!strcmp(name, ".") || !strcmp(name, "..")) {
+ errno = EINVAL;
+ return -1;
+
+ }
+ if (dir_path) {
+ dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+ } else {
+ /* relative to export root */
+ dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY);
+ }
+ if (dirfd < 0) {
+ return dirfd;
+ }
+ fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
+ fh->handle_bytes = data->handle_bytes;
+ /* add a "./" at the begining of the path */
+ snprintf(buffer, PATH_MAX, "./%s", name);
+ /* flag = 0 imply don't follow symlink */
+ ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
+ if (!ret) {
+ target->data = (char *)fh;
+ target->size = sizeof(struct file_handle) + data->handle_bytes;
+ } else {
+ g_free(fh);
+ }
+ close(dirfd);
+ return ret;
+}
+
+static int handle_renameat(FsContext *ctx, V9fsPath *olddir,
+ const char *old_name, V9fsPath *newdir,
+ const char *new_name)
+{
+ int olddirfd, newdirfd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH);
+ if (olddirfd < 0) {
+ return olddirfd;
+ }
+ newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH);
+ if (newdirfd < 0) {
+ close(olddirfd);
+ return newdirfd;
+ }
+ ret = renameat(olddirfd, old_name, newdirfd, new_name);
+ close(newdirfd);
+ close(olddirfd);
+ return ret;
+}
+
+static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
+ const char *name, int flags)
+{
+ int dirfd, ret;
+ struct handle_data *data = (struct handle_data *)ctx->private;
+
+ dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
+ if (dirfd < 0) {
+ return dirfd;
+ }
+
+ ret = unlinkat(dirfd, name, flags);
+ close(dirfd);
+ return ret;
+}
+
+static int handle_init(FsContext *ctx)
+{
+ int ret, mnt_id;
+ struct file_handle fh;
+ struct handle_data *data = g_malloc(sizeof(struct handle_data));
+ data->mountfd = open(ctx->fs_root, O_DIRECTORY);
+ if (data->mountfd < 0) {
+ ret = data->mountfd;
+ goto err_out;
+ }
+ memset(&fh, 0, sizeof(struct file_handle));
+ ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
+ if (ret && errno == EOVERFLOW) {
+ data->handle_bytes = fh.handle_bytes;
+ ctx->private = data;
+ ret = 0;
+ goto out;
+ }
+ /* we got 0 byte handle ? */
+ ret = -1;
+ close(data->mountfd);
+err_out:
+ g_free(data);
+out:
+ return ret;
+}
+
+FileOperations handle_ops = {
+ .init = handle_init,
+ .lstat = handle_lstat,
+ .readlink = handle_readlink,
+ .close = handle_close,
+ .closedir = handle_closedir,
+ .open = handle_open,
+ .opendir = handle_opendir,
+ .rewinddir = handle_rewinddir,
+ .telldir = handle_telldir,
+ .readdir_r = handle_readdir_r,
+ .seekdir = handle_seekdir,
+ .preadv = handle_preadv,
+ .pwritev = handle_pwritev,
+ .chmod = handle_chmod,
+ .mknod = handle_mknod,
+ .mkdir = handle_mkdir,
+ .fstat = handle_fstat,
+ .open2 = handle_open2,
+ .symlink = handle_symlink,
+ .link = handle_link,
+ .truncate = handle_truncate,
+ .rename = handle_rename,
+ .chown = handle_chown,
+ .utimensat = handle_utimensat,
+ .remove = handle_remove,
+ .fsync = handle_fsync,
+ .statfs = handle_statfs,
+ .lgetxattr = handle_lgetxattr,
+ .llistxattr = handle_llistxattr,
+ .lsetxattr = handle_lsetxattr,
+ .lremovexattr = handle_lremovexattr,
+ .name_to_path = handle_name_to_path,
+ .renameat = handle_renameat,
+ .unlinkat = handle_unlinkat,
+};
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 61cbf8db14..9559ff6550 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -21,11 +21,12 @@
#include <sys/un.h>
#include <attr/xattr.h>
-
-static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
+static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
{
int err;
char buffer[PATH_MAX];
+ char *path = fs_path->data;
+
err = lstat(rpath(fs_ctx, path, buffer), stbuf);
if (err) {
return err;
@@ -59,6 +60,7 @@ static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
static int local_set_xattr(const char *path, FsCred *credp)
{
int err;
+
if (credp->fc_uid != -1) {
err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
0);
@@ -91,9 +93,10 @@ static int local_set_xattr(const char *path, FsCred *credp)
}
static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
- FsCred *credp)
+ FsCred *credp)
{
char buffer[PATH_MAX];
+
if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
return -1;
}
@@ -110,11 +113,13 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
return 0;
}
-static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
- char *buf, size_t bufsz)
+static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
+ char *buf, size_t bufsz)
{
ssize_t tsize = -1;
char buffer[PATH_MAX];
+ char *path = fs_path->data;
+
if (fs_ctx->fs_sm == SM_MAPPED) {
int fd;
fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
@@ -143,15 +148,19 @@ static int local_closedir(FsContext *ctx, DIR *dir)
return closedir(dir);
}
-static int local_open(FsContext *ctx, const char *path, int flags)
+static int local_open(FsContext *ctx, V9fsPath *fs_path, int flags)
{
char buffer[PATH_MAX];
+ char *path = fs_path->data;
+
return open(rpath(ctx, path, buffer), flags);
}
-static DIR *local_opendir(FsContext *ctx, const char *path)
+static DIR *local_opendir(FsContext *ctx, V9fsPath *fs_path)
{
char buffer[PATH_MAX];
+ char *path = fs_path->data;
+
return opendir(rpath(ctx, path, buffer));
}
@@ -166,7 +175,7 @@ static off_t local_telldir(FsContext *ctx, DIR *dir)
}
static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
- struct dirent **result)
+ struct dirent **result)
{
return readdir_r(dir, entry, result);
}
@@ -192,7 +201,7 @@ static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
}
static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
- int iovcnt, off_t offset)
+ int iovcnt, off_t offset)
{
#ifdef CONFIG_PREADV
return pwritev(fd, iov, iovcnt, offset);
@@ -206,9 +215,11 @@ static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
#endif
}
-static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
char buffer[PATH_MAX];
+ char *path = fs_path->data;
+
if (fs_ctx->fs_sm == SM_MAPPED) {
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
@@ -218,18 +229,25 @@ static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
return -1;
}
-static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+ const char *name, FsCred *credp)
{
+ char *path;
int err = -1;
int serrno = 0;
+ V9fsString fullname;
char buffer[PATH_MAX];
+ v9fs_string_init(&fullname);
+ v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+ path = fullname.data;
+
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
err = mknod(rpath(fs_ctx, path, buffer),
SM_LOCAL_MODE_BITS|S_IFREG, 0);
if (err == -1) {
- return err;
+ goto out;
}
local_set_xattr(rpath(fs_ctx, path, buffer), credp);
if (err == -1) {
@@ -241,7 +259,7 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
credp->fc_rdev);
if (err == -1) {
- return err;
+ goto out;
}
err = local_post_create_passthrough(fs_ctx, path, credp);
if (err == -1) {
@@ -249,25 +267,34 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
goto err_end;
}
}
- return err;
+ goto out;
err_end:
remove(rpath(fs_ctx, path, buffer));
errno = serrno;
+out:
+ v9fs_string_free(&fullname);
return err;
}
-static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+ const char *name, FsCred *credp)
{
+ char *path;
int err = -1;
int serrno = 0;
+ V9fsString fullname;
char buffer[PATH_MAX];
+ v9fs_string_init(&fullname);
+ v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+ path = fullname.data;
+
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
if (err == -1) {
- return err;
+ goto out;
}
credp->fc_mode = credp->fc_mode|S_IFDIR;
err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
@@ -279,7 +306,7 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
(fs_ctx->fs_sm == SM_NONE)) {
err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
if (err == -1) {
- return err;
+ goto out;
}
err = local_post_create_passthrough(fs_ctx, path, credp);
if (err == -1) {
@@ -287,11 +314,13 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
goto err_end;
}
}
- return err;
+ goto out;
err_end:
remove(rpath(fs_ctx, path, buffer));
errno = serrno;
+out:
+ v9fs_string_free(&fullname);
return err;
}
@@ -325,19 +354,26 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
return err;
}
-static int local_open2(FsContext *fs_ctx, const char *path, int flags,
- FsCred *credp)
+static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
+ int flags, FsCred *credp)
{
+ char *path;
int fd = -1;
int err = -1;
int serrno = 0;
+ V9fsString fullname;
char buffer[PATH_MAX];
+ v9fs_string_init(&fullname);
+ v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+ path = fullname.data;
+
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
if (fd == -1) {
- return fd;
+ err = fd;
+ goto out;
}
credp->fc_mode = credp->fc_mode|S_IFREG;
/* Set cleint credentials in xattr */
@@ -350,7 +386,8 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
(fs_ctx->fs_sm == SM_NONE)) {
fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
if (fd == -1) {
- return fd;
+ err = fd;
+ goto out;
}
err = local_post_create_passthrough(fs_ctx, path, credp);
if (err == -1) {
@@ -358,23 +395,32 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
goto err_end;
}
}
- return fd;
+ err = fd;
+ goto out;
err_end:
close(fd);
remove(rpath(fs_ctx, path, buffer));
errno = serrno;
+out:
+ v9fs_string_free(&fullname);
return err;
}
static int local_symlink(FsContext *fs_ctx, const char *oldpath,
- const char *newpath, FsCred *credp)
+ V9fsPath *dir_path, const char *name, FsCred *credp)
{
int err = -1;
int serrno = 0;
+ char *newpath;
+ V9fsString fullname;
char buffer[PATH_MAX];
+ v9fs_string_init(&fullname);
+ v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+ newpath = fullname.data;
+
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
int fd;
@@ -382,7 +428,8 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
SM_LOCAL_MODE_BITS);
if (fd == -1) {
- return fd;
+ err = fd;
+ goto out;
}
/* Write the oldpath (target) to the file. */
oldpath_size = strlen(oldpath);
@@ -408,10 +455,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
(fs_ctx->fs_sm == SM_NONE)) {
err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
if (err) {
- return err;
+ goto out;
}
err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
- credp->fc_gid);
+ credp->fc_gid);
if (err == -1) {
/*
* If we fail to change ownership and if we are
@@ -424,24 +471,37 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
err = 0;
}
}
- return err;
+ goto out;
err_end:
remove(rpath(fs_ctx, newpath, buffer));
errno = serrno;
+out:
+ v9fs_string_free(&fullname);
return err;
}
-static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
+static int local_link(FsContext *ctx, V9fsPath *oldpath,
+ V9fsPath *dirpath, const char *name)
{
+ int ret;
+ V9fsString newpath;
char buffer[PATH_MAX], buffer1[PATH_MAX];
- return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
+ v9fs_string_init(&newpath);
+ v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
+
+ ret = link(rpath(ctx, oldpath->data, buffer),
+ rpath(ctx, newpath.data, buffer1));
+ v9fs_string_free(&newpath);
+ return ret;
}
-static int local_truncate(FsContext *ctx, const char *path, off_t size)
+static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
{
char buffer[PATH_MAX];
+ char *path = fs_path->data;
+
return truncate(rpath(ctx, path, buffer), size);
}
@@ -453,9 +513,11 @@ static int local_rename(FsContext *ctx, const char *oldpath,
return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
}
-static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
char buffer[PATH_MAX];
+ char *path = fs_path->data;
+
if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
(fs_ctx->fs_sm == SM_PASSTHROUGH)) {
return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
@@ -470,12 +532,14 @@ static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
return -1;
}
-static int local_utimensat(FsContext *s, const char *path,
+static int local_utimensat(FsContext *s, V9fsPath *fs_path,
const struct timespec *buf)
{
char buffer[PATH_MAX];
+ char *path = fs_path->data;
+
return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf,
- AT_SYMLINK_NOFOLLOW);
+ AT_SYMLINK_NOFOLLOW);
}
static int local_remove(FsContext *ctx, const char *path)
@@ -493,38 +557,102 @@ static int local_fsync(FsContext *ctx, int fd, int datasync)
}
}
-static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
+static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
{
char buffer[PATH_MAX];
- return statfs(rpath(s, path, buffer), stbuf);
+ char *path = fs_path->data;
+
+ return statfs(rpath(s, path, buffer), stbuf);
}
-static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
+static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
const char *name, void *value, size_t size)
{
+ char *path = fs_path->data;
+
return v9fs_get_xattr(ctx, path, name, value, size);
}
-static ssize_t local_llistxattr(FsContext *ctx, const char *path,
+static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
void *value, size_t size)
{
+ char *path = fs_path->data;
+
return v9fs_list_xattr(ctx, path, value, size);
}
-static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
+static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
void *value, size_t size, int flags)
{
+ char *path = fs_path->data;
+
return v9fs_set_xattr(ctx, path, name, value, size, flags);
}
-static int local_lremovexattr(FsContext *ctx,
- const char *path, const char *name)
+static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+ const char *name)
{
+ char *path = fs_path->data;
+
return v9fs_remove_xattr(ctx, path, name);
}
+static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+ const char *name, V9fsPath *target)
+{
+ if (dir_path) {
+ v9fs_string_sprintf((V9fsString *)target, "%s/%s",
+ dir_path->data, name);
+ } else {
+ v9fs_string_sprintf((V9fsString *)target, "%s", name);
+ }
+ /* Bump the size for including terminating NULL */
+ target->size++;
+ return 0;
+}
+
+static int local_renameat(FsContext *ctx, V9fsPath *olddir,
+ const char *old_name, V9fsPath *newdir,
+ const char *new_name)
+{
+ int ret;
+ V9fsString old_full_name, new_full_name;
+
+ v9fs_string_init(&old_full_name);
+ v9fs_string_init(&new_full_name);
+
+ v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
+ v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
+
+ ret = local_rename(ctx, old_full_name.data, new_full_name.data);
+ v9fs_string_free(&old_full_name);
+ v9fs_string_free(&new_full_name);
+ return ret;
+}
+
+static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
+ const char *name, int flags)
+{
+ int ret;
+ V9fsString fullname;
+ char buffer[PATH_MAX];
+ v9fs_string_init(&fullname);
+
+ v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
+ ret = remove(rpath(ctx, fullname.data, buffer));
+ v9fs_string_free(&fullname);
+
+ return ret;
+}
+
+static int local_init(FsContext *ctx)
+{
+ ctx->flags |= PATHNAME_FSCONTEXT;
+ return 0;
+}
FileOperations local_ops = {
+ .init = local_init,
.lstat = local_lstat,
.readlink = local_readlink,
.close = local_close,
@@ -555,4 +683,7 @@ FileOperations local_ops = {
.llistxattr = local_llistxattr,
.lsetxattr = local_lsetxattr,
.lremovexattr = local_lremovexattr,
+ .name_to_path = local_name_to_path,
+ .renameat = local_renameat,
+ .unlinkat = local_unlinkat,
};
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index d28edb799a..c01c31aa25 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -80,20 +80,20 @@ void cred_init(FsCred *credp)
credp->fc_rdev = -1;
}
-static void v9fs_string_init(V9fsString *str)
+void v9fs_string_init(V9fsString *str)
{
str->data = NULL;
str->size = 0;
}
-static void v9fs_string_free(V9fsString *str)
+void v9fs_string_free(V9fsString *str)
{
g_free(str->data);
str->data = NULL;
str->size = 0;
}
-static void v9fs_string_null(V9fsString *str)
+void v9fs_string_null(V9fsString *str)
{
v9fs_string_free(str);
}
@@ -192,7 +192,7 @@ alloc_print:
return vsprintf(*strp, fmt, ap);
}
-static void GCC_FMT_ATTR(2, 3)
+void GCC_FMT_ATTR(2, 3)
v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
{
va_list ap;
@@ -208,22 +208,54 @@ v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
str->size = err;
}
-static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
+void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
{
v9fs_string_free(lhs);
v9fs_string_sprintf(lhs, "%s", rhs->data);
}
+void v9fs_path_init(V9fsPath *path)
+{
+ path->data = NULL;
+ path->size = 0;
+}
+
+void v9fs_path_free(V9fsPath *path)
+{
+ g_free(path->data);
+ path->data = NULL;
+ path->size = 0;
+}
+
+void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
+{
+ v9fs_path_free(lhs);
+ lhs->data = g_malloc(rhs->size);
+ memcpy(lhs->data, rhs->data, rhs->size);
+ lhs->size = rhs->size;
+}
+
+int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
+ const char *name, V9fsPath *path)
+{
+ int err;
+ err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+ if (err < 0) {
+ err = -errno;
+ }
+ return err;
+}
+
/*
* Return TRUE if s1 is an ancestor of s2.
*
* E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
* As a special case, We treat s1 as ancestor of s2 if they are same!
*/
-static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
+static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
{
- if (!strncmp(s1->data, s2->data, s1->size)) {
- if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
+ if (!strncmp(s1->data, s2->data, s1->size - 1)) {
+ if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
return 1;
}
}
@@ -237,29 +269,30 @@ static size_t v9fs_string_size(V9fsString *str)
/*
* returns 0 if fid got re-opened, 1 if not, < 0 on error */
-static int v9fs_reopen_fid(V9fsState *s, V9fsFidState *f)
+static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
{
int err = 1;
if (f->fid_type == P9_FID_FILE) {
if (f->fs.fd == -1) {
do {
- err = v9fs_co_open(s, f, f->open_flags);
- } while (err == -EINTR);
+ err = v9fs_co_open(pdu, f, f->open_flags);
+ } while (err == -EINTR && !pdu->cancelled);
}
} else if (f->fid_type == P9_FID_DIR) {
if (f->fs.dir == NULL) {
do {
- err = v9fs_co_opendir(s, f);
- } while (err == -EINTR);
+ err = v9fs_co_opendir(pdu, f);
+ } while (err == -EINTR && !pdu->cancelled);
}
}
return err;
}
-static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
+static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
{
int err;
V9fsFidState *f;
+ V9fsState *s = pdu->s;
for (f = s->fid_list; f; f = f->next) {
BUG_ON(f->clunked);
@@ -276,7 +309,7 @@ static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
* while trying to free up some file
* descriptors.
*/
- err = v9fs_reopen_fid(s, f);
+ err = v9fs_reopen_fid(pdu, f);
if (err < 0) {
f->ref--;
return NULL;
@@ -318,7 +351,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
return f;
}
-static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
+static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
{
int retval = 0;
@@ -336,12 +369,12 @@ static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
goto free_out;
}
if (fidp->fs.xattr.len) {
- retval = v9fs_co_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
+ retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
fidp->fs.xattr.value,
fidp->fs.xattr.len,
fidp->fs.xattr.flags);
} else {
- retval = v9fs_co_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
+ retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
}
free_out:
v9fs_string_free(&fidp->fs.xattr.name);
@@ -352,28 +385,28 @@ free_value:
return retval;
}
-static int free_fid(V9fsState *s, V9fsFidState *fidp)
+static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
{
int retval = 0;
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(s, fidp->fs.fd);
+ retval = v9fs_co_close(pdu, fidp->fs.fd);
}
} else if (fidp->fid_type == P9_FID_DIR) {
if (fidp->fs.dir != NULL) {
- retval = v9fs_co_closedir(s, fidp->fs.dir);
+ retval = v9fs_co_closedir(pdu, fidp->fs.dir);
}
} else if (fidp->fid_type == P9_FID_XATTR) {
- retval = v9fs_xattr_fid_clunk(s, fidp);
+ retval = v9fs_xattr_fid_clunk(pdu, fidp);
}
- v9fs_string_free(&fidp->path);
+ v9fs_path_free(&fidp->path);
g_free(fidp);
return retval;
}
-static void put_fid(V9fsState *s, V9fsFidState *fidp)
+static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
{
BUG_ON(!fidp->ref);
fidp->ref--;
@@ -381,11 +414,11 @@ static void put_fid(V9fsState *s, V9fsFidState *fidp)
* Don't free the fid if it is in reclaim list
*/
if (!fidp->ref && fidp->clunked) {
- free_fid(s, fidp);
+ free_fid(pdu, fidp);
}
}
-static int clunk_fid(V9fsState *s, int32_t fid)
+static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
{
V9fsFidState **fidpp, *fidp;
@@ -394,19 +427,19 @@ static int clunk_fid(V9fsState *s, int32_t fid)
break;
}
}
-
if (*fidpp == NULL) {
- return -ENOENT;
+ return NULL;
}
fidp = *fidpp;
*fidpp = fidp->next;
fidp->clunked = 1;
- return 0;
+ return fidp;
}
-void v9fs_reclaim_fd(V9fsState *s)
+void v9fs_reclaim_fd(V9fsPDU *pdu)
{
int reclaim_count = 0;
+ V9fsState *s = pdu->s;
V9fsFidState *f, *reclaim_list = NULL;
for (f = s->fid_list; f; f = f->next) {
@@ -471,32 +504,36 @@ void v9fs_reclaim_fd(V9fsState *s)
f = reclaim_list;
reclaim_list = f->rclm_lst;
if (f->fid_type == P9_FID_FILE) {
- v9fs_co_close(s, f->fs_reclaim.fd);
+ v9fs_co_close(pdu, f->fs_reclaim.fd);
} else if (f->fid_type == P9_FID_DIR) {
- v9fs_co_closedir(s, f->fs_reclaim.dir);
+ v9fs_co_closedir(pdu, f->fs_reclaim.dir);
}
f->rclm_lst = NULL;
/*
* Now drop the fid reference, free it
* if clunked.
*/
- put_fid(s, f);
+ put_fid(pdu, f);
}
}
-static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsString *str)
+static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
{
int err;
+ V9fsState *s = pdu->s;
V9fsFidState *fidp, head_fid;
head_fid.next = s->fid_list;
for (fidp = s->fid_list; fidp; fidp = fidp->next) {
- if (!strcmp(fidp->path.data, str->data)) {
+ if (fidp->path.size != path->size) {
+ continue;
+ }
+ if (!memcmp(fidp->path.data, path->data, path->size)) {
/* Mark the fid non reclaimable. */
fidp->flags |= FID_NON_RECLAIMABLE;
/* reopen the file/dir if already closed */
- err = v9fs_reopen_fid(s, fidp);
+ err = v9fs_reopen_fid(pdu, fidp);
if (err < 0) {
return -1;
}
@@ -556,12 +593,12 @@ static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
}
}
-static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
+static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
{
struct stat stbuf;
int err;
- err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+ err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
if (err < 0) {
return err;
}
@@ -574,8 +611,9 @@ static V9fsPDU *alloc_pdu(V9fsState *s)
V9fsPDU *pdu = NULL;
if (!QLIST_EMPTY(&s->free_list)) {
- pdu = QLIST_FIRST(&s->free_list);
- QLIST_REMOVE(pdu, next);
+ pdu = QLIST_FIRST(&s->free_list);
+ QLIST_REMOVE(pdu, next);
+ QLIST_INSERT_HEAD(&s->active_list, pdu, next);
}
return pdu;
}
@@ -586,7 +624,14 @@ static void free_pdu(V9fsState *s, V9fsPDU *pdu)
if (debug_9p_pdu) {
pprint_pdu(pdu);
}
- QLIST_INSERT_HEAD(&s->free_list, pdu, next);
+ /*
+ * Cancelled pdu are added back to the freelist
+ * by flush request .
+ */
+ if (!pdu->cancelled) {
+ QLIST_REMOVE(pdu, next);
+ QLIST_INSERT_HEAD(&s->free_list, pdu, next);
+ }
}
}
@@ -879,6 +924,9 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
/* FIXME: we should batch these completions */
virtio_notify(&s->vdev, s->vq);
+ /* Now wakeup anybody waiting in flush for this request */
+ qemu_co_queue_next(&pdu->complete);
+
free_pdu(s, pdu);
}
@@ -998,7 +1046,7 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
return mode;
}
-static int stat_to_v9stat(V9fsState *s, V9fsString *name,
+static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
const struct stat *stbuf,
V9fsStat *v9stat)
{
@@ -1024,7 +1072,7 @@ static int stat_to_v9stat(V9fsState *s, V9fsString *name,
v9fs_string_null(&v9stat->extension);
if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
- err = v9fs_co_readlink(s, name, &v9stat->extension);
+ err = v9fs_co_readlink(pdu, name, &v9stat->extension);
if (err < 0) {
return err;
}
@@ -1150,13 +1198,16 @@ static void print_sg(struct iovec *sg, int cnt)
printf("}\n");
}
-static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
+/* Will call this only for path name based fid */
+static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
{
- V9fsString str;
- v9fs_string_init(&str);
- v9fs_string_copy(&str, dst);
- v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
- v9fs_string_free(&str);
+ V9fsPath str;
+ v9fs_path_init(&str);
+ v9fs_path_copy(&str, dst);
+ v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
+ v9fs_path_free(&str);
+ /* +1 to include terminating NULL */
+ dst->size++;
}
static void v9fs_version(void *opaque)
@@ -1202,8 +1253,13 @@ static void v9fs_attach(void *opaque)
goto out_nofid;
}
fidp->uid = n_uname;
- v9fs_string_sprintf(&fidp->path, "%s", "/");
- err = fid_to_qid(s, fidp, &qid);
+ err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
+ if (err < 0) {
+ err = -EINVAL;
+ clunk_fid(s, fid);
+ goto out;
+ }
+ err = fid_to_qid(pdu, fidp, &qid);
if (err < 0) {
err = -EINVAL;
clunk_fid(s, fid);
@@ -1212,7 +1268,7 @@ static void v9fs_attach(void *opaque)
offset += pdu_marshal(pdu, offset, "Q", &qid);
err = offset;
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
v9fs_string_free(&uname);
@@ -1232,16 +1288,16 @@ static void v9fs_stat(void *opaque)
pdu_unmarshal(pdu, offset, "d", &fid);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
- err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+ err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
if (err < 0) {
goto out;
}
- err = stat_to_v9stat(s, &fidp->path, &stbuf, &v9stat);
+ err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
if (err < 0) {
goto out;
}
@@ -1249,7 +1305,7 @@ static void v9fs_stat(void *opaque)
err = offset;
v9fs_stat_free(&v9stat);
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
}
@@ -1268,7 +1324,7 @@ static void v9fs_getattr(void *opaque)
pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
retval = -ENOENT;
goto out_nofid;
@@ -1277,7 +1333,7 @@ static void v9fs_getattr(void *opaque)
* Currently we only support BASIC fields in stat, so there is no
* need to look at request_mask.
*/
- retval = v9fs_co_lstat(s, &fidp->path, &stbuf);
+ retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
if (retval < 0) {
goto out;
}
@@ -1285,7 +1341,7 @@ static void v9fs_getattr(void *opaque)
retval = offset;
retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, retval);
}
@@ -1314,13 +1370,13 @@ static void v9fs_setattr(void *opaque)
pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -EINVAL;
goto out_nofid;
}
if (v9iattr.valid & ATTR_MODE) {
- err = v9fs_co_chmod(s, &fidp->path, v9iattr.mode);
+ err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
if (err < 0) {
goto out;
}
@@ -1347,7 +1403,7 @@ static void v9fs_setattr(void *opaque)
} else {
times[1].tv_nsec = UTIME_OMIT;
}
- err = v9fs_co_utimensat(s, &fidp->path, times);
+ err = v9fs_co_utimensat(pdu, &fidp->path, times);
if (err < 0) {
goto out;
}
@@ -1365,21 +1421,21 @@ static void v9fs_setattr(void *opaque)
if (!(v9iattr.valid & ATTR_GID)) {
v9iattr.gid = -1;
}
- err = v9fs_co_chown(s, &fidp->path, v9iattr.uid,
+ err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
v9iattr.gid);
if (err < 0) {
goto out;
}
}
if (v9iattr.valid & (ATTR_SIZE)) {
- err = v9fs_co_truncate(s, &fidp->path, v9iattr.size);
+ err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
if (err < 0) {
goto out;
}
}
err = offset;
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
}
@@ -1400,7 +1456,7 @@ static void v9fs_walk(void *opaque)
int name_idx;
V9fsQID *qids = NULL;
int i, err = 0;
- V9fsString path;
+ V9fsPath dpath, path;
uint16_t nwnames;
struct stat stbuf;
size_t offset = 7;
@@ -1420,32 +1476,38 @@ static void v9fs_walk(void *opaque)
for (i = 0; i < nwnames; i++) {
offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
}
-
} else if (nwnames > P9_MAXWELEM) {
err = -EINVAL;
goto out_nofid;
}
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
+ v9fs_path_init(&dpath);
+ v9fs_path_init(&path);
+ /*
+ * Both dpath and path initially poin to fidp.
+ * Needed to handle request with nwnames == 0
+ */
+ v9fs_path_copy(&dpath, &fidp->path);
+ v9fs_path_copy(&path, &fidp->path);
+ for (name_idx = 0; name_idx < nwnames; name_idx++) {
+ err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
+ if (err < 0) {
+ goto out;
+ }
+ err = v9fs_co_lstat(pdu, &path, &stbuf);
+ if (err < 0) {
+ goto out;
+ }
+ stat_to_qid(&stbuf, &qids[name_idx]);
+ v9fs_path_copy(&dpath, &path);
+ }
if (fid == newfid) {
BUG_ON(fidp->fid_type != P9_FID_NONE);
- v9fs_string_init(&path);
- for (name_idx = 0; name_idx < nwnames; name_idx++) {
- v9fs_string_sprintf(&path, "%s/%s",
- fidp->path.data, wnames[name_idx].data);
- v9fs_string_copy(&fidp->path, &path);
-
- err = v9fs_co_lstat(s, &fidp->path, &stbuf);
- if (err < 0) {
- v9fs_string_free(&path);
- goto out;
- }
- stat_to_qid(&stbuf, &qids[name_idx]);
- }
- v9fs_string_free(&path);
+ v9fs_path_copy(&fidp->path, &path);
} else {
newfidp = alloc_fid(s, newfid);
if (newfidp == NULL) {
@@ -1453,28 +1515,16 @@ static void v9fs_walk(void *opaque)
goto out;
}
newfidp->uid = fidp->uid;
- v9fs_string_init(&path);
- v9fs_string_copy(&newfidp->path, &fidp->path);
- for (name_idx = 0; name_idx < nwnames; name_idx++) {
- v9fs_string_sprintf(&path, "%s/%s", newfidp->path.data,
- wnames[name_idx].data);
- v9fs_string_copy(&newfidp->path, &path);
- err = v9fs_co_lstat(s, &newfidp->path, &stbuf);
- if (err < 0) {
- clunk_fid(s, newfidp->fid);
- v9fs_string_free(&path);
- goto out;
- }
- stat_to_qid(&stbuf, &qids[name_idx]);
- }
- v9fs_string_free(&path);
+ v9fs_path_copy(&newfidp->path, &path);
}
err = v9fs_walk_marshal(pdu, nwnames, qids);
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
if (newfidp) {
- put_fid(s, newfidp);
+ put_fid(pdu, newfidp);
}
+ v9fs_path_free(&dpath);
+ v9fs_path_free(&path);
out_nofid:
complete_pdu(s, pdu, err);
if (nwnames && nwnames <= P9_MAXWELEM) {
@@ -1484,18 +1534,20 @@ out_nofid:
g_free(wnames);
g_free(qids);
}
+ return;
}
-static int32_t get_iounit(V9fsState *s, V9fsString *name)
+static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
{
struct statfs stbuf;
int32_t iounit = 0;
+ V9fsState *s = pdu->s;
/*
* iounit should be multiples of f_bsize (host filesystem block size
* and as well as less than (client msize - P9_IOHDRSZ))
*/
- if (!v9fs_co_statfs(s, name, &stbuf)) {
+ if (!v9fs_co_statfs(pdu, path, &stbuf)) {
iounit = stbuf.f_bsize;
iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
}
@@ -1524,20 +1576,20 @@ static void v9fs_open(void *opaque)
} else {
pdu_unmarshal(pdu, offset, "db", &fid, &mode);
}
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
BUG_ON(fidp->fid_type != P9_FID_NONE);
- err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+ err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
if (err < 0) {
goto out;
}
stat_to_qid(&stbuf, &qid);
if (S_ISDIR(stbuf.st_mode)) {
- err = v9fs_co_opendir(s, fidp);
+ err = v9fs_co_opendir(pdu, fidp);
if (err < 0) {
goto out;
}
@@ -1553,7 +1605,7 @@ static void v9fs_open(void *opaque)
} else {
flags = omode_to_uflags(mode);
}
- err = v9fs_co_open(s, fidp, flags);
+ err = v9fs_co_open(pdu, fidp, flags);
if (err < 0) {
goto out;
}
@@ -1566,12 +1618,12 @@ static void v9fs_open(void *opaque)
*/
fidp->flags |= FID_NON_RECLAIMABLE;
}
- iounit = get_iounit(s, &fidp->path);
+ iounit = get_iounit(pdu, &fidp->path);
offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
err = offset;
}
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
}
@@ -1582,7 +1634,6 @@ static void v9fs_lcreate(void *opaque)
gid_t gid;
ssize_t err = 0;
ssize_t offset = 7;
- V9fsString fullname;
V9fsString name;
V9fsFidState *fidp;
struct stat stbuf;
@@ -1590,21 +1641,19 @@ static void v9fs_lcreate(void *opaque)
int32_t iounit;
V9fsPDU *pdu = opaque;
- v9fs_string_init(&fullname);
pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
&mode, &gid);
- fidp = get_fid(pdu->s, dfid);
+ fidp = get_fid(pdu, dfid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
- v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
/* Ignore direct disk access hint until the server supports it. */
flags &= ~O_DIRECT;
-
- err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, flags, mode);
+ err = v9fs_co_open2(pdu, fidp, &name, gid,
+ flags | O_CREAT, mode, &stbuf);
if (err < 0) {
goto out;
}
@@ -1617,26 +1666,15 @@ static void v9fs_lcreate(void *opaque)
*/
fidp->flags |= FID_NON_RECLAIMABLE;
}
- iounit = get_iounit(pdu->s, &fullname);
-
- err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
- if (err < 0) {
- fidp->fid_type = P9_FID_NONE;
- if (fidp->fs.fd > 0) {
- v9fs_co_close(pdu->s, fidp->fs.fd);
- }
- goto out;
- }
- v9fs_string_copy(&fidp->path, &fullname);
+ iounit = get_iounit(pdu, &fidp->path);
stat_to_qid(&stbuf, &qid);
offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
err = offset;
out:
- put_fid(pdu->s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(pdu->s, pdu, err);
v9fs_string_free(&name);
- v9fs_string_free(&fullname);
}
static void v9fs_fsync(void *opaque)
@@ -1650,16 +1688,16 @@ static void v9fs_fsync(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
- err = v9fs_co_fsync(s, fidp, datasync);
+ err = v9fs_co_fsync(pdu, fidp, datasync);
if (!err) {
err = offset;
}
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
}
@@ -1675,18 +1713,19 @@ static void v9fs_clunk(void *opaque)
pdu_unmarshal(pdu, offset, "d", &fid);
- fidp = get_fid(s, fid);
+ fidp = clunk_fid(s, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
- err = clunk_fid(s, fidp->fid);
- if (err < 0) {
- goto out;
- }
+ /*
+ * Bump the ref so that put_fid will
+ * free the fid.
+ */
+ fidp->ref++;
err = offset;
-out:
- put_fid(s, fidp);
+
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
}
@@ -1715,10 +1754,10 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
return offset;
}
-static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
+static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
V9fsFidState *fidp, int32_t max_count)
{
- V9fsString name;
+ V9fsPath path;
V9fsStat v9stat;
int len, err = 0;
int32_t count = 0;
@@ -1727,7 +1766,7 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
struct dirent *dent, *result;
/* save the directory position */
- saved_dir_pos = v9fs_co_telldir(s, fidp);
+ saved_dir_pos = v9fs_co_telldir(pdu, fidp);
if (saved_dir_pos < 0) {
return saved_dir_pos;
}
@@ -1735,17 +1774,20 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
dent = g_malloc(sizeof(struct dirent));
while (1) {
- v9fs_string_init(&name);
- err = v9fs_co_readdir_r(s, fidp, dent, &result);
+ v9fs_path_init(&path);
+ err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
if (err || !result) {
break;
}
- v9fs_string_sprintf(&name, "%s/%s", fidp->path.data, dent->d_name);
- err = v9fs_co_lstat(s, &name, &stbuf);
+ err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
+ if (err < 0) {
+ goto out;
+ }
+ err = v9fs_co_lstat(pdu, &path, &stbuf);
if (err < 0) {
goto out;
}
- err = stat_to_v9stat(s, &name, &stbuf, &v9stat);
+ err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
if (err < 0) {
goto out;
}
@@ -1753,20 +1795,20 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
/* Ran out of buffer. Set dir back to old position and return */
- v9fs_co_seekdir(s, fidp, saved_dir_pos);
+ v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
v9fs_stat_free(&v9stat);
- v9fs_string_free(&name);
+ v9fs_path_free(&path);
g_free(dent);
return count;
}
count += len;
v9fs_stat_free(&v9stat);
- v9fs_string_free(&name);
+ v9fs_path_free(&path);
saved_dir_pos = dent->d_off;
}
out:
g_free(dent);
- v9fs_string_free(&name);
+ v9fs_path_free(&path);
if (err < 0) {
return err;
}
@@ -1787,7 +1829,7 @@ static void v9fs_read(void *opaque)
pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -EINVAL;
goto out_nofid;
@@ -1795,9 +1837,9 @@ static void v9fs_read(void *opaque)
if (fidp->fid_type == P9_FID_DIR) {
if (off == 0) {
- v9fs_co_rewinddir(s, fidp);
+ v9fs_co_rewinddir(pdu, fidp);
}
- count = v9fs_do_readdir_with_stat(s, pdu, fidp, max_count);
+ count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
if (count < 0) {
err = count;
goto out;
@@ -1820,12 +1862,12 @@ static void v9fs_read(void *opaque)
}
/* Loop in case of EINTR */
do {
- len = v9fs_co_preadv(s, fidp, sg, cnt, off);
+ len = v9fs_co_preadv(pdu, fidp, sg, cnt, off);
if (len >= 0) {
off += len;
count += len;
}
- } while (len == -EINTR);
+ } while (len == -EINTR && !pdu->cancelled);
if (len < 0) {
/* IO error return the error */
err = len;
@@ -1842,7 +1884,7 @@ static void v9fs_read(void *opaque)
err = -EINVAL;
}
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
}
@@ -1856,7 +1898,7 @@ static size_t v9fs_readdir_data_size(V9fsString *name)
return 24 + v9fs_string_size(name);
}
-static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
+static int v9fs_do_readdir(V9fsPDU *pdu,
V9fsFidState *fidp, int32_t max_count)
{
size_t size;
@@ -1868,7 +1910,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
struct dirent *dent, *result;
/* save the directory position */
- saved_dir_pos = v9fs_co_telldir(s, fidp);
+ saved_dir_pos = v9fs_co_telldir(pdu, fidp);
if (saved_dir_pos < 0) {
return saved_dir_pos;
}
@@ -1876,7 +1918,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
dent = g_malloc(sizeof(struct dirent));
while (1) {
- err = v9fs_co_readdir_r(s, fidp, dent, &result);
+ err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
if (err || !result) {
break;
}
@@ -1884,7 +1926,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
v9fs_string_sprintf(&name, "%s", dent->d_name);
if ((count + v9fs_readdir_data_size(&name)) > max_count) {
/* Ran out of buffer. Set dir back to old position and return */
- v9fs_co_seekdir(s, fidp, saved_dir_pos);
+ v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
v9fs_string_free(&name);
g_free(dent);
return count;
@@ -1928,7 +1970,7 @@ static void v9fs_readdir(void *opaque)
pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
retval = -EINVAL;
goto out_nofid;
@@ -1938,11 +1980,11 @@ static void v9fs_readdir(void *opaque)
goto out;
}
if (initial_offset == 0) {
- v9fs_co_rewinddir(s, fidp);
+ v9fs_co_rewinddir(pdu, fidp);
} else {
- v9fs_co_seekdir(s, fidp, initial_offset);
+ v9fs_co_seekdir(pdu, fidp, initial_offset);
}
- count = v9fs_do_readdir(s, pdu, fidp, max_count);
+ count = v9fs_do_readdir(pdu, fidp, max_count);
if (count < 0) {
retval = count;
goto out;
@@ -1951,7 +1993,7 @@ static void v9fs_readdir(void *opaque)
retval += pdu_marshal(pdu, offset, "d", count);
retval += count;
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, retval);
}
@@ -2018,7 +2060,7 @@ static void v9fs_write(void *opaque)
pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -EINVAL;
goto out_nofid;
@@ -2045,12 +2087,12 @@ static void v9fs_write(void *opaque)
}
/* Loop in case of EINTR */
do {
- len = v9fs_co_pwritev(s, fidp, sg, cnt, off);
+ len = v9fs_co_pwritev(pdu, fidp, sg, cnt, off);
if (len >= 0) {
off += len;
total += len;
}
- } while (len == -EINTR);
+ } while (len == -EINTR && !pdu->cancelled);
if (len < 0) {
/* IO error return the error */
err = len;
@@ -2061,7 +2103,7 @@ static void v9fs_write(void *opaque)
offset += pdu_marshal(pdu, offset, "d", total);
err = offset;
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
}
@@ -2075,63 +2117,73 @@ static void v9fs_create(void *opaque)
V9fsQID qid;
int32_t perm;
int8_t mode;
+ V9fsPath path;
struct stat stbuf;
V9fsString name;
V9fsString extension;
- V9fsString fullname;
int iounit;
V9fsPDU *pdu = opaque;
- v9fs_string_init(&fullname);
+ v9fs_path_init(&path);
pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
&perm, &mode, &extension);
- fidp = get_fid(pdu->s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -EINVAL;
goto out_nofid;
}
-
- v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
- err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
- if (!err) {
- err = -EEXIST;
- goto out;
- } else if (err != -ENOENT) {
- goto out;
- }
if (perm & P9_STAT_MODE_DIR) {
- err = v9fs_co_mkdir(pdu->s, fullname.data, perm & 0777,
- fidp->uid, -1);
+ err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
+ fidp->uid, -1, &stbuf);
if (err < 0) {
goto out;
}
- v9fs_string_copy(&fidp->path, &fullname);
- err = v9fs_co_opendir(pdu->s, fidp);
+ err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
+ if (err < 0) {
+ goto out;
+ }
+ v9fs_path_copy(&fidp->path, &path);
+ err = v9fs_co_opendir(pdu, fidp);
if (err < 0) {
goto out;
}
fidp->fid_type = P9_FID_DIR;
} else if (perm & P9_STAT_MODE_SYMLINK) {
- err = v9fs_co_symlink(pdu->s, fidp, extension.data,
- fullname.data, -1);
+ err = v9fs_co_symlink(pdu, fidp, &name,
+ extension.data, -1 , &stbuf);
+ if (err < 0) {
+ goto out;
+ }
+ err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
if (err < 0) {
goto out;
}
+ v9fs_path_copy(&fidp->path, &path);
} else if (perm & P9_STAT_MODE_LINK) {
- int32_t nfid = atoi(extension.data);
- V9fsFidState *nfidp = get_fid(pdu->s, nfid);
- if (nfidp == NULL) {
+ int32_t ofid = atoi(extension.data);
+ V9fsFidState *ofidp = get_fid(pdu, ofid);
+ if (ofidp == NULL) {
err = -EINVAL;
goto out;
}
- err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
+ err = v9fs_co_link(pdu, ofidp, fidp, &name);
+ put_fid(pdu, ofidp);
if (err < 0) {
- put_fid(pdu->s, nfidp);
goto out;
}
- put_fid(pdu->s, nfidp);
+ err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
+ if (err < 0) {
+ fidp->fid_type = P9_FID_NONE;
+ goto out;
+ }
+ v9fs_path_copy(&fidp->path, &path);
+ err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
+ if (err < 0) {
+ fidp->fid_type = P9_FID_NONE;
+ goto out;
+ }
} else if (perm & P9_STAT_MODE_DEVICE) {
char ctype;
uint32_t major, minor;
@@ -2155,26 +2207,41 @@ static void v9fs_create(void *opaque)
}
nmode |= perm & 0777;
- err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
- makedev(major, minor), nmode);
+ err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
+ makedev(major, minor), nmode, &stbuf);
+ if (err < 0) {
+ goto out;
+ }
+ err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
if (err < 0) {
goto out;
}
+ v9fs_path_copy(&fidp->path, &path);
} else if (perm & P9_STAT_MODE_NAMED_PIPE) {
- err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
- 0, S_IFIFO | (perm & 0777));
+ err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
+ 0, S_IFIFO | (perm & 0777), &stbuf);
+ if (err < 0) {
+ goto out;
+ }
+ err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
if (err < 0) {
goto out;
}
+ v9fs_path_copy(&fidp->path, &path);
} else if (perm & P9_STAT_MODE_SOCKET) {
- err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
- 0, S_IFSOCK | (perm & 0777));
+ err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
+ 0, S_IFSOCK | (perm & 0777), &stbuf);
+ if (err < 0) {
+ goto out;
+ }
+ err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
if (err < 0) {
goto out;
}
+ v9fs_path_copy(&fidp->path, &path);
} else {
- err = v9fs_co_open2(pdu->s, fidp, fullname.data, -1,
- omode_to_uflags(mode)|O_CREAT, perm);
+ err = v9fs_co_open2(pdu, fidp, &name, -1,
+ omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
if (err < 0) {
goto out;
}
@@ -2188,26 +2255,17 @@ static void v9fs_create(void *opaque)
fidp->flags |= FID_NON_RECLAIMABLE;
}
}
- err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
- if (err < 0) {
- fidp->fid_type = P9_FID_NONE;
- if (fidp->fs.fd) {
- v9fs_co_close(pdu->s, fidp->fs.fd);
- }
- goto out;
- }
- iounit = get_iounit(pdu->s, &fidp->path);
- v9fs_string_copy(&fidp->path, &fullname);
+ iounit = get_iounit(pdu, &fidp->path);
stat_to_qid(&stbuf, &qid);
offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
err = offset;
out:
- put_fid(pdu->s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(pdu->s, pdu, err);
v9fs_string_free(&name);
v9fs_string_free(&extension);
- v9fs_string_free(&fullname);
+ v9fs_path_free(&path);
}
static void v9fs_symlink(void *opaque)
@@ -2215,7 +2273,6 @@ static void v9fs_symlink(void *opaque)
V9fsPDU *pdu = opaque;
V9fsString name;
V9fsString symname;
- V9fsString fullname;
V9fsFidState *dfidp;
V9fsQID qid;
struct stat stbuf;
@@ -2224,21 +2281,14 @@ static void v9fs_symlink(void *opaque)
gid_t gid;
size_t offset = 7;
- v9fs_string_init(&fullname);
pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
- dfidp = get_fid(pdu->s, dfid);
+ dfidp = get_fid(pdu, dfid);
if (dfidp == NULL) {
err = -EINVAL;
goto out_nofid;
}
-
- v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
- err = v9fs_co_symlink(pdu->s, dfidp, symname.data, fullname.data, gid);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+ err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
if (err < 0) {
goto out;
}
@@ -2246,19 +2296,37 @@ static void v9fs_symlink(void *opaque)
offset += pdu_marshal(pdu, offset, "Q", &qid);
err = offset;
out:
- put_fid(pdu->s, dfidp);
+ put_fid(pdu, dfidp);
out_nofid:
complete_pdu(pdu->s, pdu, err);
v9fs_string_free(&name);
v9fs_string_free(&symname);
- v9fs_string_free(&fullname);
}
static void v9fs_flush(void *opaque)
{
+ int16_t tag;
+ size_t offset = 7;
+ V9fsPDU *cancel_pdu;
V9fsPDU *pdu = opaque;
V9fsState *s = pdu->s;
- /* A nop call with no return */
+
+ pdu_unmarshal(pdu, offset, "w", &tag);
+
+ QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
+ if (cancel_pdu->tag == tag) {
+ break;
+ }
+ }
+ if (cancel_pdu) {
+ cancel_pdu->cancelled = 1;
+ /*
+ * Wait for pdu to complete.
+ */
+ qemu_co_queue_wait(&cancel_pdu->complete);
+ cancel_pdu->cancelled = 0;
+ free_pdu(pdu->s, cancel_pdu);
+ }
complete_pdu(s, pdu, 7);
return;
}
@@ -2269,40 +2337,35 @@ static void v9fs_link(void *opaque)
V9fsState *s = pdu->s;
int32_t dfid, oldfid;
V9fsFidState *dfidp, *oldfidp;
- V9fsString name, fullname;
+ V9fsString name;;
size_t offset = 7;
int err = 0;
- v9fs_string_init(&fullname);
-
pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
- dfidp = get_fid(s, dfid);
+ dfidp = get_fid(pdu, dfid);
if (dfidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
- oldfidp = get_fid(s, oldfid);
+ oldfidp = get_fid(pdu, oldfid);
if (oldfidp == NULL) {
err = -ENOENT;
goto out;
}
-
- v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
- err = v9fs_co_link(s, &oldfidp->path, &fullname);
+ err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
if (!err) {
err = offset;
}
- v9fs_string_free(&fullname);
-
out:
- put_fid(s, dfidp);
+ put_fid(pdu, dfidp);
out_nofid:
v9fs_string_free(&name);
complete_pdu(s, pdu, err);
}
+/* Only works with path name based fid */
static void v9fs_remove(void *opaque)
{
int32_t fid;
@@ -2313,27 +2376,32 @@ static void v9fs_remove(void *opaque)
pdu_unmarshal(pdu, offset, "d", &fid);
- fidp = get_fid(pdu->s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -EINVAL;
goto out_nofid;
}
+ /* if fs driver is not path based, return EOPNOTSUPP */
+ if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
+ err = -EOPNOTSUPP;
+ goto out_err;
+ }
/*
* IF the file is unlinked, we cannot reopen
* the file later. So don't reclaim fd
*/
- err = v9fs_mark_fids_unreclaim(pdu->s, &fidp->path);
+ err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
if (err < 0) {
goto out_err;
}
- err = v9fs_co_remove(pdu->s, &fidp->path);
+ err = v9fs_co_remove(pdu, &fidp->path);
if (!err) {
err = offset;
}
out_err:
/* For TREMOVE we need to clunk the fid even on failed remove */
clunk_fid(pdu->s, fidp->fid);
- put_fid(pdu->s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(pdu->s, pdu, err);
}
@@ -2344,60 +2412,64 @@ static void v9fs_unlinkat(void *opaque)
V9fsString name;
int32_t dfid, flags;
size_t offset = 7;
+ V9fsPath path;
V9fsFidState *dfidp;
V9fsPDU *pdu = opaque;
- V9fsString full_name;
pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
- dfidp = get_fid(pdu->s, dfid);
+ dfidp = get_fid(pdu, dfid);
if (dfidp == NULL) {
err = -EINVAL;
goto out_nofid;
}
- v9fs_string_init(&full_name);
- v9fs_string_sprintf(&full_name, "%s/%s", dfidp->path.data, name.data);
/*
* IF the file is unlinked, we cannot reopen
* the file later. So don't reclaim fd
*/
- err = v9fs_mark_fids_unreclaim(pdu->s, &full_name);
+ v9fs_path_init(&path);
+ err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
+ if (err < 0) {
+ goto out_err;
+ }
+ err = v9fs_mark_fids_unreclaim(pdu, &path);
if (err < 0) {
goto out_err;
}
- err = v9fs_co_remove(pdu->s, &full_name);
+ err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
if (!err) {
err = offset;
}
out_err:
- put_fid(pdu->s, dfidp);
- v9fs_string_free(&full_name);
+ put_fid(pdu, dfidp);
+ v9fs_path_free(&path);
out_nofid:
complete_pdu(pdu->s, pdu, err);
v9fs_string_free(&name);
}
-static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
+
+/* Only works with path name based fid */
+static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
int32_t newdirfid, V9fsString *name)
{
char *end;
int err = 0;
+ V9fsPath new_path;
+ V9fsFidState *tfidp;
+ V9fsState *s = pdu->s;
V9fsFidState *dirfidp = NULL;
char *old_name, *new_name;
+ v9fs_path_init(&new_path);
if (newdirfid != -1) {
- dirfidp = get_fid(s, newdirfid);
+ dirfidp = get_fid(pdu, newdirfid);
if (dirfidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
BUG_ON(dirfidp->fid_type != P9_FID_NONE);
-
- new_name = g_malloc0(dirfidp->path.size + name->size + 2);
-
- strcpy(new_name, dirfidp->path.data);
- strcat(new_name, "/");
- strcat(new_name + dirfidp->path.size, name->data);
+ v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
} else {
old_name = fidp->path.data;
end = strrchr(old_name, '/');
@@ -2407,48 +2479,35 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
end = old_name;
}
new_name = g_malloc0(end - old_name + name->size + 1);
-
strncat(new_name, old_name, end - old_name);
strncat(new_name + (end - old_name), name->data, name->size);
+ v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
+ g_free(new_name);
}
-
- v9fs_string_free(name);
- name->data = new_name;
- name->size = strlen(new_name);
-
- if (strcmp(new_name, fidp->path.data) != 0) {
- err = v9fs_co_rename(s, &fidp->path, name);
- if (err < 0) {
- goto out;
- }
- V9fsFidState *tfidp;
- /*
- * Fixup fid's pointing to the old name to
- * start pointing to the new name
- */
- for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
- if (fidp == tfidp) {
- /*
- * we replace name of this fid towards the end
- * so that our below strcmp will work
- */
- continue;
- }
- if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
- /* replace the name */
- v9fs_fix_path(&tfidp->path, name, strlen(fidp->path.data));
- }
+ err = v9fs_co_rename(pdu, &fidp->path, &new_path);
+ if (err < 0) {
+ goto out;
+ }
+ /*
+ * Fixup fid's pointing to the old name to
+ * start pointing to the new name
+ */
+ for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+ if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
+ /* replace the name */
+ v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
}
- v9fs_string_copy(&fidp->path, name);
}
out:
if (dirfidp) {
- put_fid(s, dirfidp);
+ put_fid(pdu, dirfidp);
}
+ v9fs_path_free(&new_path);
out_nofid:
return err;
}
+/* Only works with path name based fid */
static void v9fs_rename(void *opaque)
{
int32_t fid;
@@ -2462,80 +2521,98 @@ static void v9fs_rename(void *opaque)
pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
BUG_ON(fidp->fid_type != P9_FID_NONE);
-
- err = v9fs_complete_rename(s, fidp, newdirfid, &name);
+ /* if fs driver is not path based, return EOPNOTSUPP */
+ if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+ v9fs_path_write_lock(s);
+ err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
+ v9fs_path_unlock(s);
if (!err) {
err = offset;
}
- put_fid(s, fidp);
+out:
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
v9fs_string_free(&name);
}
-static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
+static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
+ V9fsString *old_name, V9fsPath *newdir,
+ V9fsString *new_name)
+{
+ V9fsFidState *tfidp;
+ V9fsPath oldpath, newpath;
+ V9fsState *s = pdu->s;
+
+
+ v9fs_path_init(&oldpath);
+ v9fs_path_init(&newpath);
+ v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
+ v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
+
+ /*
+ * Fixup fid's pointing to the old name to
+ * start pointing to the new name
+ */
+ for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+ if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
+ /* replace the name */
+ v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
+ }
+ }
+ v9fs_path_free(&oldpath);
+ v9fs_path_free(&newpath);
+}
+
+static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
V9fsString *old_name, int32_t newdirfid,
V9fsString *new_name)
{
int err = 0;
- V9fsString old_full_name, new_full_name;
+ V9fsState *s = pdu->s;
V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
- olddirfidp = get_fid(s, olddirfid);
+ olddirfidp = get_fid(pdu, olddirfid);
if (olddirfidp == NULL) {
err = -ENOENT;
goto out;
}
- v9fs_string_init(&old_full_name);
- v9fs_string_init(&new_full_name);
-
- v9fs_string_sprintf(&old_full_name, "%s/%s",
- olddirfidp->path.data, old_name->data);
if (newdirfid != -1) {
- newdirfidp = get_fid(s, newdirfid);
+ newdirfidp = get_fid(pdu, newdirfid);
if (newdirfidp == NULL) {
err = -ENOENT;
goto out;
}
- v9fs_string_sprintf(&new_full_name, "%s/%s",
- newdirfidp->path.data, new_name->data);
} else {
- v9fs_string_sprintf(&new_full_name, "%s/%s",
- olddirfidp->path.data, new_name->data);
+ newdirfidp = get_fid(pdu, olddirfid);
}
- if (strcmp(old_full_name.data, new_full_name.data) != 0) {
- V9fsFidState *tfidp;
- err = v9fs_co_rename(s, &old_full_name, &new_full_name);
- if (err < 0) {
- goto out;
- }
- /*
- * Fixup fid's pointing to the old name to
- * start pointing to the new name
- */
- for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
- if (v9fs_path_is_ancestor(&old_full_name, &tfidp->path)) {
- /* replace the name */
- v9fs_fix_path(&tfidp->path, &new_full_name, old_full_name.size);
- }
- }
+ err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
+ &newdirfidp->path, new_name);
+ if (err < 0) {
+ goto out;
+ }
+ if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+ /* Only for path based fid we need to do the below fixup */
+ v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
+ &newdirfidp->path, new_name);
}
out:
if (olddirfidp) {
- put_fid(s, olddirfidp);
+ put_fid(pdu, olddirfidp);
}
if (newdirfidp) {
- put_fid(s, newdirfidp);
+ put_fid(pdu, newdirfidp);
}
- v9fs_string_free(&old_full_name);
- v9fs_string_free(&new_full_name);
return err;
}
@@ -2551,7 +2628,10 @@ static void v9fs_renameat(void *opaque)
pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
&old_name, &newdirfid, &new_name);
- err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
+ v9fs_path_write_lock(s);
+ err = v9fs_complete_renameat(pdu, olddirfid,
+ &old_name, newdirfid, &new_name);
+ v9fs_path_unlock(s);
if (!err) {
err = offset;
}
@@ -2574,19 +2654,19 @@ static void v9fs_wstat(void *opaque)
pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -EINVAL;
goto out_nofid;
}
/* do we need to sync the file? */
if (donttouch_stat(&v9stat)) {
- err = v9fs_co_fsync(s, fidp, 0);
+ err = v9fs_co_fsync(pdu, fidp, 0);
goto out;
}
if (v9stat.mode != -1) {
uint32_t v9_mode;
- err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+ err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
if (err < 0) {
goto out;
}
@@ -2597,7 +2677,7 @@ static void v9fs_wstat(void *opaque)
err = -EIO;
goto out;
}
- err = v9fs_co_chmod(s, &fidp->path,
+ err = v9fs_co_chmod(pdu, &fidp->path,
v9mode_to_mode(v9stat.mode,
&v9stat.extension));
if (err < 0) {
@@ -2618,32 +2698,32 @@ static void v9fs_wstat(void *opaque)
} else {
times[1].tv_nsec = UTIME_OMIT;
}
- err = v9fs_co_utimensat(s, &fidp->path, times);
+ err = v9fs_co_utimensat(pdu, &fidp->path, times);
if (err < 0) {
goto out;
}
}
if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
- err = v9fs_co_chown(s, &fidp->path, v9stat.n_uid, v9stat.n_gid);
+ err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
if (err < 0) {
goto out;
}
}
if (v9stat.name.size != 0) {
- err = v9fs_complete_rename(s, fidp, -1, &v9stat.name);
+ err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
if (err < 0) {
goto out;
}
}
if (v9stat.length != -1) {
- err = v9fs_co_truncate(s, &fidp->path, v9stat.length);
+ err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
if (err < 0) {
goto out;
}
}
err = offset;
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
v9fs_stat_free(&v9stat);
complete_pdu(s, pdu, err);
@@ -2705,19 +2785,19 @@ static void v9fs_statfs(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "d", &fid);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
retval = -ENOENT;
goto out_nofid;
}
- retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
+ retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
if (retval < 0) {
goto out;
}
retval = offset;
retval += v9fs_fill_statfs(s, pdu, &stbuf);
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, retval);
return;
@@ -2735,27 +2815,20 @@ static void v9fs_mknod(void *opaque)
size_t offset = 7;
V9fsString name;
struct stat stbuf;
- V9fsString fullname;
V9fsFidState *fidp;
V9fsPDU *pdu = opaque;
V9fsState *s = pdu->s;
- v9fs_string_init(&fullname);
pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
&major, &minor, &gid);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
- v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
- err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
- makedev(major, minor), mode);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_lstat(s, &fullname, &stbuf);
+ err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
+ makedev(major, minor), mode, &stbuf);
if (err < 0) {
goto out;
}
@@ -2763,10 +2836,9 @@ static void v9fs_mknod(void *opaque)
err = offset;
err += pdu_marshal(pdu, offset, "Q", &qid);
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
- v9fs_string_free(&fullname);
v9fs_string_free(&name);
}
@@ -2800,18 +2872,18 @@ static void v9fs_lock(void *opaque)
err = -EINVAL;
goto out_nofid;
}
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
- err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
+ err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
if (err < 0) {
goto out;
}
status = P9_LOCK_SUCCESS;
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
err = offset;
err += pdu_marshal(pdu, offset, "b", status);
@@ -2839,12 +2911,12 @@ static void v9fs_getlock(void *opaque)
&glock->start, &glock->length, &glock->proc_id,
&glock->client_id);
- fidp = get_fid(s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
- err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
+ err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
if (err < 0) {
goto out;
}
@@ -2854,7 +2926,7 @@ static void v9fs_getlock(void *opaque)
&glock->client_id);
err = offset;
out:
- put_fid(s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(s, pdu, err);
v9fs_string_free(&glock->client_id);
@@ -2867,27 +2939,21 @@ static void v9fs_mkdir(void *opaque)
size_t offset = 7;
int32_t fid;
struct stat stbuf;
- V9fsString name, fullname;
V9fsQID qid;
+ V9fsString name;
V9fsFidState *fidp;
gid_t gid;
int mode;
int err = 0;
- v9fs_string_init(&fullname);
pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
- fidp = get_fid(pdu->s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
- v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
- err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
- if (err < 0) {
- goto out;
- }
- err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+ err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
if (err < 0) {
goto out;
}
@@ -2895,10 +2961,9 @@ static void v9fs_mkdir(void *opaque)
offset += pdu_marshal(pdu, offset, "Q", &qid);
err = offset;
out:
- put_fid(pdu->s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(pdu->s, pdu, err);
- v9fs_string_free(&fullname);
v9fs_string_free(&name);
}
@@ -2915,7 +2980,7 @@ static void v9fs_xattrwalk(void *opaque)
V9fsState *s = pdu->s;
pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
- file_fidp = get_fid(s, fid);
+ file_fidp = get_fid(pdu, fid);
if (file_fidp == NULL) {
err = -ENOENT;
goto out_nofid;
@@ -2925,12 +2990,12 @@ static void v9fs_xattrwalk(void *opaque)
err = -EINVAL;
goto out;
}
- v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
+ v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
if (name.data[0] == 0) {
/*
* listxattr request. Get the size first
*/
- size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
+ size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
if (size < 0) {
err = size;
clunk_fid(s, xattr_fidp->fid);
@@ -2944,7 +3009,7 @@ static void v9fs_xattrwalk(void *opaque)
xattr_fidp->fs.xattr.copied_len = -1;
if (size) {
xattr_fidp->fs.xattr.value = g_malloc(size);
- err = v9fs_co_llistxattr(s, &xattr_fidp->path,
+ err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
xattr_fidp->fs.xattr.value,
xattr_fidp->fs.xattr.len);
if (err < 0) {
@@ -2959,7 +3024,7 @@ static void v9fs_xattrwalk(void *opaque)
* specific xattr fid. We check for xattr
* presence also collect the xattr size
*/
- size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
+ size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
&name, NULL, 0);
if (size < 0) {
err = size;
@@ -2974,7 +3039,7 @@ static void v9fs_xattrwalk(void *opaque)
xattr_fidp->fs.xattr.copied_len = -1;
if (size) {
xattr_fidp->fs.xattr.value = g_malloc(size);
- err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
+ err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
&name, xattr_fidp->fs.xattr.value,
xattr_fidp->fs.xattr.len);
if (err < 0) {
@@ -2986,9 +3051,9 @@ static void v9fs_xattrwalk(void *opaque)
err = offset;
}
out:
- put_fid(s, file_fidp);
+ put_fid(pdu, file_fidp);
if (xattr_fidp) {
- put_fid(s, xattr_fidp);
+ put_fid(pdu, xattr_fidp);
}
out_nofid:
complete_pdu(s, pdu, err);
@@ -3011,7 +3076,7 @@ static void v9fs_xattrcreate(void *opaque)
pdu_unmarshal(pdu, offset, "dsqd",
&fid, &name, &size, &flags);
- file_fidp = get_fid(s, fid);
+ file_fidp = get_fid(pdu, fid);
if (file_fidp == NULL) {
err = -EINVAL;
goto out_nofid;
@@ -3030,7 +3095,7 @@ static void v9fs_xattrcreate(void *opaque)
xattr_fidp->fs.xattr.value = NULL;
}
err = offset;
- put_fid(s, file_fidp);
+ put_fid(pdu, file_fidp);
out_nofid:
complete_pdu(s, pdu, err);
v9fs_string_free(&name);
@@ -3046,14 +3111,14 @@ static void v9fs_readlink(void *opaque)
V9fsFidState *fidp;
pdu_unmarshal(pdu, offset, "d", &fid);
- fidp = get_fid(pdu->s, fid);
+ fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -ENOENT;
goto out_nofid;
}
v9fs_string_init(&target);
- err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
+ err = v9fs_co_readlink(pdu, &fidp->path, &target);
if (err < 0) {
goto out;
}
@@ -3061,7 +3126,7 @@ static void v9fs_readlink(void *opaque)
err = offset;
v9fs_string_free(&target);
out:
- put_fid(pdu->s, fidp);
+ put_fid(pdu, fidp);
out_nofid:
complete_pdu(pdu->s, pdu, err);
}
@@ -3145,6 +3210,7 @@ void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
memcpy(&pdu->size, ptr, 4);
pdu->id = ptr[4];
memcpy(&pdu->tag, ptr + 5, 2);
+ qemu_co_queue_init(&pdu->complete);
submit_pdu(s, pdu);
}
free_pdu(s, pdu);
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 17d44b41ca..60b8a56e57 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -8,6 +8,8 @@
#include <sys/resource.h>
#include "hw/virtio.h"
#include "fsdev/file-op-9p.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
/* The feature bitmap for virtio 9P */
/* The mount point is specified in a config variable */
@@ -129,6 +131,8 @@ struct V9fsPDU
uint32_t size;
uint16_t tag;
uint8_t id;
+ uint8_t cancelled;
+ CoQueue complete;
VirtQueueElement elem;
struct V9fsState *s;
QLIST_ENTRY(V9fsPDU) next;
@@ -204,7 +208,7 @@ struct V9fsFidState
{
int fid_type;
int32_t fid;
- V9fsString path;
+ V9fsPath path;
union {
int fd;
DIR *dir;
@@ -229,6 +233,7 @@ typedef struct V9fsState
VirtQueue *vq;
V9fsPDU pdus[MAX_REQ];
QLIST_HEAD(, V9fsPDU) free_list;
+ QLIST_HEAD(, V9fsPDU) active_list;
V9fsFidState *fid_list;
FileOperations *ops;
FsContext ctx;
@@ -237,6 +242,11 @@ typedef struct V9fsState
size_t config_size;
enum p9_proto_version proto_version;
int32_t msize;
+ /*
+ * lock ensuring atomic path update
+ * on rename.
+ */
+ CoRwlock rename_lock;
} V9fsState;
typedef struct V9fsStatState {
@@ -381,7 +391,43 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
return pdu_packunpack(dst, sg, sg_count, offset, size, 0);
}
+static inline void v9fs_path_write_lock(V9fsState *s)
+{
+ if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+ qemu_co_rwlock_wrlock(&s->rename_lock);
+ }
+}
+
+static inline void v9fs_path_read_lock(V9fsState *s)
+{
+ if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+ qemu_co_rwlock_rdlock(&s->rename_lock);
+ }
+}
+
+static inline void v9fs_path_unlock(V9fsState *s)
+{
+ if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+ qemu_co_rwlock_unlock(&s->rename_lock);
+ }
+}
+
+static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu)
+{
+ return pdu->cancelled;
+}
+
extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
extern void virtio_9p_set_fd_limit(void);
-extern void v9fs_reclaim_fd(V9fsState *s);
+extern void v9fs_reclaim_fd(V9fsPDU *pdu);
+extern void v9fs_string_init(V9fsString *str);
+extern void v9fs_string_free(V9fsString *str);
+extern void v9fs_string_null(V9fsString *str);
+extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
+extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
+extern void v9fs_path_init(V9fsPath *path);
+extern void v9fs_path_free(V9fsPath *path);
+extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
+extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
+ const char *name, V9fsPath *path);
#endif