hw/9pfs: use migration blockers to prevent live migration when virtfs export path is mounted

Now when you try to migrate with VirtFS export path mounted, you get a proper QMP error:

(qemu) migrate tcp:localhost:4444
Migration is disabled when VirtFS export path '/tmp/' is mounted in the guest using mount_tag 'v_tmp'
(qemu)

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
This commit is contained in:
Aneesh Kumar K.V 2011-12-04 22:35:28 +05:30
parent 77eec1b3f1
commit e9a0152ba1
5 changed files with 41 additions and 13 deletions

View File

@ -33,13 +33,15 @@ static V9fsState *to_virtio_9p(VirtIODevice *vdev)
static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
{ {
int len;
struct virtio_9p_config *cfg; struct virtio_9p_config *cfg;
V9fsState *s = to_virtio_9p(vdev); V9fsState *s = to_virtio_9p(vdev);
cfg = g_malloc0(sizeof(struct virtio_9p_config) + len = strlen(s->tag);
s->tag_len); cfg = g_malloc0(sizeof(struct virtio_9p_config) + len);
stw_raw(&cfg->tag_len, s->tag_len); stw_raw(&cfg->tag_len, len);
memcpy(cfg->tag, s->tag, s->tag_len); /* We don't copy the terminating null to config space */
memcpy(cfg->tag, s->tag, len);
memcpy(config, cfg, s->config_size); memcpy(config, cfg, s->config_size);
g_free(cfg); g_free(cfg);
} }
@ -96,20 +98,18 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
} }
len = strlen(conf->tag); 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 " 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); exit(1);
} }
/* s->tag is non-NULL terminated string */
s->tag = g_malloc(len); s->tag = strdup(conf->tag);
memcpy(s->tag, conf->tag, len);
s->tag_len = len;
s->ctx.uid = -1; s->ctx.uid = -1;
s->ops = fse->ops; s->ops = fse->ops;
s->vdev.get_features = virtio_9p_get_features; 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->vdev.get_config = virtio_9p_get_config;
s->fid_list = NULL; s->fid_list = NULL;
qemu_co_rwlock_init(&s->rename_lock); qemu_co_rwlock_init(&s->rename_lock);

View File

@ -23,6 +23,7 @@
#include "virtio-9p-xattr.h" #include "virtio-9p-xattr.h"
#include "virtio-9p-coth.h" #include "virtio-9p-coth.h"
#include "trace.h" #include "trace.h"
#include "migration.h"
int open_fd_hw; int open_fd_hw;
int total_open_fd; 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 * Don't free the fid if it is in reclaim list
*/ */
if (!fidp->ref && fidp->clunked) { 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); free_fid(pdu, fidp);
} }
} }
@ -1235,6 +1249,11 @@ static void v9fs_attach(void *opaque)
err = offset; err = offset;
trace_v9fs_attach_return(pdu->tag, pdu->id, trace_v9fs_attach_return(pdu->tag, pdu->id,
qid.type, qid.version, qid.path); 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: out:
put_fid(pdu, fidp); put_fid(pdu, fidp);
out_nofid: out_nofid:

View File

@ -246,8 +246,7 @@ typedef struct V9fsState
V9fsFidState *fid_list; V9fsFidState *fid_list;
FileOperations *ops; FileOperations *ops;
FsContext ctx; FsContext ctx;
uint16_t tag_len; char *tag;
uint8_t *tag;
size_t config_size; size_t config_size;
enum p9_proto_version proto_version; enum p9_proto_version proto_version;
int32_t msize; int32_t msize;
@ -256,6 +255,8 @@ typedef struct V9fsState
* on rename. * on rename.
*/ */
CoRwlock rename_lock; CoRwlock rename_lock;
int32_t root_fid;
Error *migration_blocker;
} V9fsState; } V9fsState;
typedef struct V9fsStatState { typedef struct V9fsStatState {

View File

@ -234,6 +234,11 @@ static const QErrorStringTable qerror_table[] = {
.desc = "'%(device)' uses a %(format) feature which is not " .desc = "'%(device)' uses a %(format) feature which is not "
"supported by this qemu version: %(feature)", "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, .error_fmt = QERR_VNC_SERVER_FAILED,
.desc = "Could not start VNC server on %(target)", .desc = "Could not start VNC server on %(target)",

View File

@ -192,6 +192,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \ #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }" "{ '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 \ #define QERR_VNC_SERVER_FAILED \
"{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"