aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs4
-rw-r--r--fsdev/file-op-9p.h4
-rw-r--r--fsdev/qemu-fsdev.c2
-rw-r--r--hw/9pfs/cofile.c4
-rw-r--r--hw/9pfs/virtio-9p-device.c25
-rw-r--r--hw/9pfs/virtio-9p-handle.c61
-rw-r--r--hw/9pfs/virtio-9p-local.c36
-rw-r--r--hw/9pfs/virtio-9p-synth.c5
-rw-r--r--hw/9pfs/virtio-9p.c45
-rw-r--r--hw/9pfs/virtio-9p.h5
-rw-r--r--hw/virtio-pci.c2
-rw-r--r--hw/virtio-pci.h1
-rw-r--r--qerror.c5
-rw-r--r--qerror.h3
14 files changed, 130 insertions, 72 deletions
diff --git a/Makefile.objs b/Makefile.objs
index d7a65393b3..3a699ee7d8 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -310,8 +310,8 @@ hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
-9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-handle.o
-9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-synth.o
+9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-synth.o
+9pfs-nested-$(CONFIG_OPEN_BY_HANDLE) += virtio-9p-handle.o
hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
$(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 1928da2525..a85ecd30b0 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -112,10 +112,10 @@ typedef struct FileOperations
ssize_t (*pwritev)(FsContext *, V9fsFidOpenState *,
const struct iovec *, int, off_t);
int (*mkdir)(FsContext *, V9fsPath *, const char *, FsCred *);
- int (*fstat)(FsContext *, V9fsFidOpenState *, struct stat *);
+ int (*fstat)(FsContext *, int, V9fsFidOpenState *, struct stat *);
int (*rename)(FsContext *, const char *, const char *);
int (*truncate)(FsContext *, V9fsPath *, off_t);
- int (*fsync)(FsContext *, V9fsFidOpenState *, int);
+ int (*fsync)(FsContext *, int, V9fsFidOpenState *, int);
int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf);
ssize_t (*lgetxattr)(FsContext *, V9fsPath *,
const char *, void *, size_t);
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 7fd2aa7793..6684f7ea90 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -23,7 +23,9 @@ static QTAILQ_HEAD(FsDriverEntry_head, FsDriverListEntry) fsdriver_entries =
static FsDriverTable FsDrivers[] = {
{ .name = "local", .ops = &local_ops},
+#ifdef CONFIG_OPEN_BY_HANDLE
{ .name = "handle", .ops = &handle_ops},
+#endif
{ .name = "synth", .ops = &synth_ops},
};
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 586b0382f6..b15838c1e6 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -71,7 +71,7 @@ int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
}
v9fs_co_run_in_worker(
{
- err = s->ops->fstat(&s->ctx, &fidp->fs, stbuf);
+ err = s->ops->fstat(&s->ctx, fidp->fid_type, &fidp->fs, stbuf);
if (err < 0) {
err = -errno;
}
@@ -192,7 +192,7 @@ int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
}
v9fs_co_run_in_worker(
{
- err = s->ops->fsync(&s->ctx, &fidp->fs, datasync);
+ err = s->ops->fsync(&s->ctx, fidp->fid_type, &fidp->fs, datasync);
if (err < 0) {
err = -errno;
}
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index bba4c54762..cd343e1d81 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -33,13 +33,15 @@ static V9fsState *to_virtio_9p(VirtIODevice *vdev)
static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
{
+ int len;
struct virtio_9p_config *cfg;
V9fsState *s = to_virtio_9p(vdev);
- cfg = g_malloc0(sizeof(struct virtio_9p_config) +
- s->tag_len);
- stw_raw(&cfg->tag_len, s->tag_len);
- memcpy(cfg->tag, s->tag, s->tag_len);
+ len = strlen(s->tag);
+ cfg = g_malloc0(sizeof(struct virtio_9p_config) + len);
+ stw_raw(&cfg->tag_len, len);
+ /* We don't copy the terminating null to config space */
+ memcpy(cfg->tag, s->tag, len);
memcpy(config, cfg, s->config_size);
g_free(cfg);
}
@@ -96,20 +98,18 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
}
len = strlen(conf->tag);
- if (len > MAX_TAG_LEN) {
+ if (len > MAX_TAG_LEN - 1) {
fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
- "maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN);
+ "maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN - 1);
exit(1);
}
- /* s->tag is non-NULL terminated string */
- s->tag = g_malloc(len);
- memcpy(s->tag, conf->tag, len);
- s->tag_len = len;
+
+ s->tag = strdup(conf->tag);
s->ctx.uid = -1;
s->ops = fse->ops;
s->vdev.get_features = virtio_9p_get_features;
- s->config_size = sizeof(struct virtio_9p_config) + s->tag_len;
+ s->config_size = sizeof(struct virtio_9p_config) + len;
s->vdev.get_config = virtio_9p_get_config;
s->fid_list = NULL;
qemu_co_rwlock_init(&s->rename_lock);
@@ -176,7 +176,8 @@ static PCIDeviceInfo virtio_9p_info = {
DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
DEFINE_PROP_END_OF_LIST(),
- }
+ },
+ .qdev.reset = virtio_pci_reset,
};
static void virtio_9p_register_devices(void)
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
index 7644ae5ab9..f97d8984bd 100644
--- a/hw/9pfs/virtio-9p-handle.c
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -45,7 +45,6 @@ struct handle_data {
int handle_bytes;
};
-#ifdef CONFIG_OPEN_BY_HANDLE
static inline int name_to_handle(int dirfd, const char *name,
struct file_handle *fh, int *mnt_id, int flags)
{
@@ -56,38 +55,6 @@ static inline int open_by_handle(int mountfd, const char *fh, int flags)
{
return open_by_handle_at(mountfd, (struct file_handle *)fh, flags);
}
-#else
-
-struct rpl_file_handle {
- unsigned int handle_bytes;
- int handle_type;
- unsigned char handle[0];
-};
-#define file_handle rpl_file_handle
-
-#ifndef AT_REMOVEDIR
-#define AT_REMOVEDIR 0x200
-#endif
-#ifndef AT_EMPTY_PATH
-#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
-#endif
-#ifndef O_PATH
-#define O_PATH 010000000
-#endif
-
-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)
{
@@ -288,10 +255,17 @@ static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
return ret;
}
-static int handle_fstat(FsContext *fs_ctx, V9fsFidOpenState *fs,
- struct stat *stbuf)
+static int handle_fstat(FsContext *fs_ctx, int fid_type,
+ V9fsFidOpenState *fs, struct stat *stbuf)
{
- return fstat(fs->fd, stbuf);
+ int fd;
+
+ if (fid_type == P9_FID_DIR) {
+ fd = dirfd(fs->dir);
+ } else {
+ fd = fs->fd;
+ }
+ return fstat(fd, stbuf);
}
static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
@@ -428,12 +402,21 @@ static int handle_remove(FsContext *ctx, const char *path)
return -1;
}
-static int handle_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
+static int handle_fsync(FsContext *ctx, int fid_type,
+ V9fsFidOpenState *fs, int datasync)
{
+ int fd;
+
+ if (fid_type == P9_FID_DIR) {
+ fd = dirfd(fs->dir);
+ } else {
+ fd = fs->fd;
+ }
+
if (datasync) {
- return qemu_fdatasync(fs->fd);
+ return qemu_fdatasync(fd);
} else {
- return fsync(fs->fd);
+ return fsync(fd);
}
}
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 99ef0cd333..371a94dfff 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -366,11 +366,18 @@ out:
return err;
}
-static int local_fstat(FsContext *fs_ctx,
+static int local_fstat(FsContext *fs_ctx, int fid_type,
V9fsFidOpenState *fs, struct stat *stbuf)
{
- int err;
- err = fstat(fs->fd, stbuf);
+ int err, fd;
+
+ if (fid_type == P9_FID_DIR) {
+ fd = dirfd(fs->dir);
+ } else {
+ fd = fs->fd;
+ }
+
+ err = fstat(fd, stbuf);
if (err) {
return err;
}
@@ -381,19 +388,19 @@ static int local_fstat(FsContext *fs_ctx,
mode_t tmp_mode;
dev_t tmp_dev;
- if (fgetxattr(fs->fd, "user.virtfs.uid",
+ if (fgetxattr(fd, "user.virtfs.uid",
&tmp_uid, sizeof(uid_t)) > 0) {
stbuf->st_uid = tmp_uid;
}
- if (fgetxattr(fs->fd, "user.virtfs.gid",
+ if (fgetxattr(fd, "user.virtfs.gid",
&tmp_gid, sizeof(gid_t)) > 0) {
stbuf->st_gid = tmp_gid;
}
- if (fgetxattr(fs->fd, "user.virtfs.mode",
+ if (fgetxattr(fd, "user.virtfs.mode",
&tmp_mode, sizeof(mode_t)) > 0) {
stbuf->st_mode = tmp_mode;
}
- if (fgetxattr(fs->fd, "user.virtfs.rdev",
+ if (fgetxattr(fd, "user.virtfs.rdev",
&tmp_dev, sizeof(dev_t)) > 0) {
stbuf->st_rdev = tmp_dev;
}
@@ -592,12 +599,21 @@ static int local_remove(FsContext *ctx, const char *path)
return remove(rpath(ctx, path, buffer));
}
-static int local_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
+static int local_fsync(FsContext *ctx, int fid_type,
+ V9fsFidOpenState *fs, int datasync)
{
+ int fd;
+
+ if (fid_type == P9_FID_DIR) {
+ fd = dirfd(fs->dir);
+ } else {
+ fd = fs->fd;
+ }
+
if (datasync) {
- return qemu_fdatasync(fs->fd);
+ return qemu_fdatasync(fd);
} else {
- return fsync(fs->fd);
+ return fsync(fd);
}
}
diff --git a/hw/9pfs/virtio-9p-synth.c b/hw/9pfs/virtio-9p-synth.c
index f573616363..92e0b09d38 100644
--- a/hw/9pfs/virtio-9p-synth.c
+++ b/hw/9pfs/virtio-9p-synth.c
@@ -166,7 +166,7 @@ static int v9fs_synth_lstat(FsContext *fs_ctx,
return 0;
}
-static int v9fs_synth_fstat(FsContext *fs_ctx,
+static int v9fs_synth_fstat(FsContext *fs_ctx, int fid_type,
V9fsFidOpenState *fs, struct stat *stbuf)
{
V9fsSynthOpenState *synth_open = fs->private;
@@ -414,7 +414,8 @@ static int v9fs_synth_remove(FsContext *ctx, const char *path)
return -1;
}
-static int v9fs_synth_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
+static int v9fs_synth_fsync(FsContext *ctx, int fid_type,
+ V9fsFidOpenState *fs, int datasync)
{
errno = ENOSYS;
return 0;
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 1b2fc5dfb6..dd432091ff 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -23,6 +23,7 @@
#include "virtio-9p-xattr.h"
#include "virtio-9p-coth.h"
#include "trace.h"
+#include "migration.h"
int open_fd_hw;
int total_open_fd;
@@ -373,6 +374,19 @@ static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
* Don't free the fid if it is in reclaim list
*/
if (!fidp->ref && fidp->clunked) {
+ if (fidp->fid == pdu->s->root_fid) {
+ /*
+ * if the clunked fid is root fid then we
+ * have unmounted the fs on the client side.
+ * delete the migration blocker. Ideally, this
+ * should be hooked to transport close notification
+ */
+ if (pdu->s->migration_blocker) {
+ migrate_del_blocker(pdu->s->migration_blocker);
+ error_free(pdu->s->migration_blocker);
+ pdu->s->migration_blocker = NULL;
+ }
+ }
free_fid(pdu, fidp);
}
}
@@ -509,6 +523,30 @@ static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
return 0;
}
+static void virtfs_reset(V9fsPDU *pdu)
+{
+ V9fsState *s = pdu->s;
+ V9fsFidState *fidp = NULL;
+
+ /* Free all fids */
+ while (s->fid_list) {
+ fidp = s->fid_list;
+ s->fid_list = fidp->next;
+
+ if (fidp->ref) {
+ fidp->clunked = 1;
+ } else {
+ free_fid(pdu, fidp);
+ }
+ }
+ if (fidp) {
+ /* One or more unclunked fids found... */
+ error_report("9pfs:%s: One or more uncluncked fids "
+ "found during reset", __func__);
+ }
+ return;
+}
+
#define P9_QID_TYPE_DIR 0x80
#define P9_QID_TYPE_SYMLINK 0x02
@@ -1182,6 +1220,8 @@ static void v9fs_version(void *opaque)
pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
+ virtfs_reset(pdu);
+
if (!strcmp(version.data, "9P2000.u")) {
s->proto_version = V9FS_PROTO_2000U;
} else if (!strcmp(version.data, "9P2000.L")) {
@@ -1235,6 +1275,11 @@ static void v9fs_attach(void *opaque)
err = offset;
trace_v9fs_attach_return(pdu->tag, pdu->id,
qid.type, qid.version, qid.path);
+ s->root_fid = fid;
+ /* disable migration */
+ error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
+ s->ctx.fs_root, s->tag);
+ migrate_add_blocker(s->migration_blocker);
out:
put_fid(pdu, fidp);
out_nofid:
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 7f883563d6..8b612da529 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -246,8 +246,7 @@ typedef struct V9fsState
V9fsFidState *fid_list;
FileOperations *ops;
FsContext ctx;
- uint16_t tag_len;
- uint8_t *tag;
+ char *tag;
size_t config_size;
enum p9_proto_version proto_version;
int32_t msize;
@@ -256,6 +255,8 @@ typedef struct V9fsState
* on rename.
*/
CoRwlock rename_lock;
+ int32_t root_fid;
+ Error *migration_blocker;
} V9fsState;
typedef struct V9fsStatState {
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 64c6a9414f..c665f5c94b 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -266,7 +266,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
proxy->ioeventfd_started = false;
}
-static void virtio_pci_reset(DeviceState *d)
+void virtio_pci_reset(DeviceState *d)
{
VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
virtio_pci_stop_ioeventfd(proxy);
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
index f8404de92b..344c22b68f 100644
--- a/hw/virtio-pci.h
+++ b/hw/virtio-pci.h
@@ -45,6 +45,7 @@ typedef struct {
} VirtIOPCIProxy;
void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev);
+void virtio_pci_reset(DeviceState *d);
/* Virtio ABI version, if we increment this, we break the guest driver. */
#define VIRTIO_PCI_ABI_VERSION 0
diff --git a/qerror.c b/qerror.c
index b12c85cc1f..935d30f62a 100644
--- a/qerror.c
+++ b/qerror.c
@@ -235,6 +235,11 @@ static const QErrorStringTable qerror_table[] = {
"supported by this qemu version: %(feature)",
},
{
+ .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
+ .desc = "Migration is disabled when VirtFS export path '%(path)' "
+ "is mounted in the guest using mount_tag '%(tag)'",
+ },
+ {
.error_fmt = QERR_VNC_SERVER_FAILED,
.desc = "Could not start VNC server on %(target)",
},
diff --git a/qerror.h b/qerror.h
index 2d3d43bed1..6414cd9d5b 100644
--- a/qerror.h
+++ b/qerror.h
@@ -192,6 +192,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+#define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
+ "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
+
#define QERR_VNC_SERVER_FAILED \
"{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"