Compare commits
39 Commits
queue/ui+i
...
stable-1.0
Author | SHA1 | Date | |
---|---|---|---|
|
3ffb4001c2 | ||
|
86a8d63bc1 | ||
|
102dd9167c | ||
|
d0ed2d2e8e | ||
|
d194ba1cdb | ||
|
8a0a9cf35b | ||
|
d928541b51 | ||
|
7a6d80e93c | ||
|
447a3b3473 | ||
|
e295c31e25 | ||
|
adf6c527b0 | ||
|
57ee5f77c0 | ||
|
986626efec | ||
|
85a4ca797d | ||
|
e47c212cb5 | ||
|
8afe984ef7 | ||
|
5bb37d151b | ||
|
fe5c13ebf1 | ||
|
6061f16a8a | ||
|
fbcf305e5a | ||
|
37769d2727 | ||
|
23201c64a7 | ||
|
c936f649d4 | ||
|
f63d074313 | ||
|
9b81fbdbb0 | ||
|
7e2191ae98 | ||
|
a25808dc5b | ||
|
3e8088148b | ||
|
6d450bfbc8 | ||
|
abf80f8804 | ||
|
3d3ec7b809 | ||
|
45d6cdff48 | ||
|
ed6857bf98 | ||
|
64dd41bc2d | ||
|
c554919f74 | ||
|
77a0262181 | ||
|
f03969b952 | ||
|
2061800b85 | ||
|
0b23c5d40e |
@@ -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)
|
||||
|
@@ -808,7 +808,7 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
|
||||
} while (snap_count == -ERANGE);
|
||||
|
||||
if (snap_count <= 0) {
|
||||
return snap_count;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sn_tab = g_malloc0(snap_count * sizeof(QEMUSnapshotInfo));
|
||||
@@ -827,6 +827,7 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
|
||||
}
|
||||
rbd_snap_list_end(snaps);
|
||||
|
||||
done:
|
||||
*psn_tab = sn_tab;
|
||||
return snap_count;
|
||||
}
|
||||
|
2
configure
vendored
2
configure
vendored
@@ -1116,7 +1116,7 @@ fi
|
||||
|
||||
if test "$pie" = ""; then
|
||||
case "$cpu-$targetos" in
|
||||
i386-Linux|x86_64-Linux)
|
||||
i386-Linux|x86_64-Linux|i386-OpenBSD|x86_64-OpenBSD)
|
||||
;;
|
||||
*)
|
||||
pie="no"
|
||||
|
@@ -186,7 +186,9 @@ void vga_hw_screen_dump(const char *filename)
|
||||
consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
|
||||
}
|
||||
|
||||
console_select(previous_active_console->index);
|
||||
if (previous_active_console) {
|
||||
console_select(previous_active_console->index);
|
||||
}
|
||||
}
|
||||
|
||||
void vga_hw_text_update(console_ch_t *chardata)
|
||||
|
@@ -35,6 +35,10 @@ enum {
|
||||
POOL_MAX_SIZE = 64,
|
||||
};
|
||||
|
||||
/** Free list to speed up creation */
|
||||
static QLIST_HEAD(, Coroutine) pool = QLIST_HEAD_INITIALIZER(pool);
|
||||
static unsigned int pool_size;
|
||||
|
||||
typedef struct {
|
||||
Coroutine base;
|
||||
void *stack;
|
||||
@@ -48,10 +52,6 @@ typedef struct {
|
||||
/** Currently executing coroutine */
|
||||
Coroutine *current;
|
||||
|
||||
/** Free list to speed up creation */
|
||||
QLIST_HEAD(, Coroutine) pool;
|
||||
unsigned int pool_size;
|
||||
|
||||
/** The default coroutine */
|
||||
CoroutineUContext leader;
|
||||
} CoroutineThreadState;
|
||||
@@ -75,7 +75,6 @@ static CoroutineThreadState *coroutine_get_thread_state(void)
|
||||
if (!s) {
|
||||
s = g_malloc0(sizeof(*s));
|
||||
s->current = &s->leader.base;
|
||||
QLIST_INIT(&s->pool);
|
||||
pthread_setspecific(thread_state_key, s);
|
||||
}
|
||||
return s;
|
||||
@@ -84,14 +83,19 @@ static CoroutineThreadState *coroutine_get_thread_state(void)
|
||||
static void qemu_coroutine_thread_cleanup(void *opaque)
|
||||
{
|
||||
CoroutineThreadState *s = opaque;
|
||||
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static void __attribute__((destructor)) coroutine_cleanup(void)
|
||||
{
|
||||
Coroutine *co;
|
||||
Coroutine *tmp;
|
||||
|
||||
QLIST_FOREACH_SAFE(co, &s->pool, pool_next, tmp) {
|
||||
QLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
|
||||
g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
|
||||
g_free(co);
|
||||
}
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) coroutine_init(void)
|
||||
@@ -169,13 +173,12 @@ static Coroutine *coroutine_new(void)
|
||||
|
||||
Coroutine *qemu_coroutine_new(void)
|
||||
{
|
||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
||||
Coroutine *co;
|
||||
|
||||
co = QLIST_FIRST(&s->pool);
|
||||
co = QLIST_FIRST(&pool);
|
||||
if (co) {
|
||||
QLIST_REMOVE(co, pool_next);
|
||||
s->pool_size--;
|
||||
pool_size--;
|
||||
} else {
|
||||
co = coroutine_new();
|
||||
}
|
||||
@@ -184,13 +187,12 @@ Coroutine *qemu_coroutine_new(void)
|
||||
|
||||
void qemu_coroutine_delete(Coroutine *co_)
|
||||
{
|
||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
||||
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
|
||||
|
||||
if (s->pool_size < POOL_MAX_SIZE) {
|
||||
QLIST_INSERT_HEAD(&s->pool, &co->base, pool_next);
|
||||
if (pool_size < POOL_MAX_SIZE) {
|
||||
QLIST_INSERT_HEAD(&pool, &co->base, pool_next);
|
||||
co->base.caller = NULL;
|
||||
s->pool_size++;
|
||||
pool_size++;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -172,6 +172,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr,
|
||||
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
|
||||
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
|
||||
#define IO_MEM_NOTDIRTY (3 << IO_MEM_SHIFT)
|
||||
#define IO_MEM_SUBPAGE_RAM (4 << IO_MEM_SHIFT)
|
||||
|
||||
/* Acts like a ROM when read and like a device when written. */
|
||||
#define IO_MEM_ROMD (1)
|
||||
|
3
cutils.c
3
cutils.c
@@ -217,7 +217,10 @@ void qemu_iovec_destroy(QEMUIOVector *qiov)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
||||
qemu_iovec_reset(qiov);
|
||||
g_free(qiov->iov);
|
||||
qiov->nalloc = 0;
|
||||
qiov->iov = NULL;
|
||||
}
|
||||
|
||||
void qemu_iovec_reset(QEMUIOVector *qiov)
|
||||
|
65
exec.c
65
exec.c
@@ -3570,6 +3570,63 @@ static CPUWriteMemoryFunc * const subpage_write[] = {
|
||||
&subpage_writel,
|
||||
};
|
||||
|
||||
static uint32_t subpage_ram_readb(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
return ldub_p(ptr);
|
||||
}
|
||||
|
||||
static void subpage_ram_writeb(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
stb_p(ptr, value);
|
||||
}
|
||||
|
||||
static uint32_t subpage_ram_readw(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
return lduw_p(ptr);
|
||||
}
|
||||
|
||||
static void subpage_ram_writew(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
stw_p(ptr, value);
|
||||
}
|
||||
|
||||
static uint32_t subpage_ram_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
return ldl_p(ptr);
|
||||
}
|
||||
|
||||
static void subpage_ram_writel(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
stl_p(ptr, value);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc * const subpage_ram_read[] = {
|
||||
&subpage_ram_readb,
|
||||
&subpage_ram_readw,
|
||||
&subpage_ram_readl,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc * const subpage_ram_write[] = {
|
||||
&subpage_ram_writeb,
|
||||
&subpage_ram_writew,
|
||||
&subpage_ram_writel,
|
||||
};
|
||||
|
||||
static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
|
||||
ram_addr_t memory, ram_addr_t region_offset)
|
||||
{
|
||||
@@ -3583,8 +3640,9 @@ static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
|
||||
printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__,
|
||||
mmio, start, end, idx, eidx, memory);
|
||||
#endif
|
||||
if ((memory & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
|
||||
memory = IO_MEM_UNASSIGNED;
|
||||
if ((memory & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
|
||||
memory = IO_MEM_SUBPAGE_RAM;
|
||||
}
|
||||
memory = (memory >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
for (; idx <= eidx; idx++) {
|
||||
mmio->sub_io_index[idx] = memory;
|
||||
@@ -3817,6 +3875,9 @@ static void io_mem_init(void)
|
||||
cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read,
|
||||
notdirty_mem_write, NULL,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
cpu_register_io_memory_fixed(IO_MEM_SUBPAGE_RAM, subpage_ram_read,
|
||||
subpage_ram_write, NULL,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
for (i=0; i<5; i++)
|
||||
io_mem_used[i] = 1;
|
||||
|
||||
|
@@ -74,7 +74,7 @@ typedef struct FsContext
|
||||
} FsContext;
|
||||
|
||||
typedef struct V9fsPath {
|
||||
int16_t size;
|
||||
uint16_t size;
|
||||
char *data;
|
||||
} V9fsPath;
|
||||
|
||||
@@ -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);
|
||||
|
@@ -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},
|
||||
};
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
{
|
||||
if (datasync) {
|
||||
return qemu_fdatasync(fs->fd);
|
||||
int fd;
|
||||
|
||||
if (fid_type == P9_FID_DIR) {
|
||||
fd = dirfd(fs->dir);
|
||||
} else {
|
||||
return fsync(fs->fd);
|
||||
fd = fs->fd;
|
||||
}
|
||||
|
||||
if (datasync) {
|
||||
return qemu_fdatasync(fd);
|
||||
} else {
|
||||
return fsync(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
{
|
||||
if (datasync) {
|
||||
return qemu_fdatasync(fs->fd);
|
||||
int fd;
|
||||
|
||||
if (fid_type == P9_FID_DIR) {
|
||||
fd = dirfd(fs->dir);
|
||||
} else {
|
||||
return fsync(fs->fd);
|
||||
fd = fs->fd;
|
||||
}
|
||||
|
||||
if (datasync) {
|
||||
return qemu_fdatasync(fd);
|
||||
} else {
|
||||
return fsync(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
||||
@@ -636,40 +674,6 @@ static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
|
||||
offset, size, 1);
|
||||
}
|
||||
|
||||
static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
|
||||
{
|
||||
size_t pos = 0;
|
||||
int i, j;
|
||||
struct iovec *src_sg;
|
||||
unsigned int num;
|
||||
|
||||
if (rx) {
|
||||
src_sg = pdu->elem.in_sg;
|
||||
num = pdu->elem.in_num;
|
||||
} else {
|
||||
src_sg = pdu->elem.out_sg;
|
||||
num = pdu->elem.out_num;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
for (i = 0; i < num; i++) {
|
||||
if (offset <= pos) {
|
||||
sg[j].iov_base = src_sg[i].iov_base;
|
||||
sg[j].iov_len = src_sg[i].iov_len;
|
||||
j++;
|
||||
} else if (offset < (src_sg[i].iov_len + pos)) {
|
||||
sg[j].iov_base = src_sg[i].iov_base;
|
||||
sg[j].iov_len = src_sg[i].iov_len;
|
||||
sg[j].iov_base += (offset - pos);
|
||||
sg[j].iov_len -= (offset - pos);
|
||||
j++;
|
||||
}
|
||||
pos += src_sg[i].iov_len;
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
|
||||
{
|
||||
size_t old_offset = offset;
|
||||
@@ -705,12 +709,6 @@ static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
|
||||
*valp = le64_to_cpu(val);
|
||||
break;
|
||||
}
|
||||
case 'v': {
|
||||
struct iovec *iov = va_arg(ap, struct iovec *);
|
||||
int *iovcnt = va_arg(ap, int *);
|
||||
*iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
V9fsString *str = va_arg(ap, V9fsString *);
|
||||
offset += pdu_unmarshal(pdu, offset, "w", &str->size);
|
||||
@@ -789,12 +787,6 @@ static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
|
||||
offset += pdu_pack(pdu, offset, &val, sizeof(val));
|
||||
break;
|
||||
}
|
||||
case 'v': {
|
||||
struct iovec *iov = va_arg(ap, struct iovec *);
|
||||
int *iovcnt = va_arg(ap, int *);
|
||||
*iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
V9fsString *str = va_arg(ap, V9fsString *);
|
||||
offset += pdu_marshal(pdu, offset, "w", str->size);
|
||||
@@ -1105,42 +1097,6 @@ static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
|
||||
stat_to_qid(stbuf, &v9lstat->qid);
|
||||
}
|
||||
|
||||
static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
|
||||
{
|
||||
while (len && *iovcnt) {
|
||||
if (len < sg->iov_len) {
|
||||
sg->iov_len -= len;
|
||||
sg->iov_base += len;
|
||||
len = 0;
|
||||
} else {
|
||||
len -= sg->iov_len;
|
||||
sg++;
|
||||
*iovcnt -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
|
||||
{
|
||||
int i;
|
||||
int total = 0;
|
||||
|
||||
for (i = 0; i < *cnt; i++) {
|
||||
if ((total + sg[i].iov_len) > cap) {
|
||||
sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
total += sg[i].iov_len;
|
||||
}
|
||||
|
||||
*cnt = i;
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
static void print_sg(struct iovec *sg, int cnt)
|
||||
{
|
||||
int i;
|
||||
@@ -1182,6 +1138,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 +1193,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:
|
||||
@@ -1731,8 +1694,8 @@ out_nofid:
|
||||
complete_pdu(s, pdu, err);
|
||||
}
|
||||
|
||||
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
|
||||
V9fsFidState *fidp, int64_t off, int32_t max_count)
|
||||
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
|
||||
uint64_t off, uint32_t max_count)
|
||||
{
|
||||
size_t offset = 7;
|
||||
int read_count;
|
||||
@@ -1756,7 +1719,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
|
||||
}
|
||||
|
||||
static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
|
||||
V9fsFidState *fidp, int32_t max_count)
|
||||
V9fsFidState *fidp, uint32_t max_count)
|
||||
{
|
||||
V9fsPath path;
|
||||
V9fsStat v9stat;
|
||||
@@ -1816,14 +1779,46 @@ out:
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a QEMUIOVector for a sub-region of PDU iovecs
|
||||
*
|
||||
* @qiov: uninitialized QEMUIOVector
|
||||
* @skip: number of bytes to skip from beginning of PDU
|
||||
* @size: number of bytes to include
|
||||
* @is_write: true - write, false - read
|
||||
*
|
||||
* The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
|
||||
* with qemu_iovec_destroy().
|
||||
*/
|
||||
static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
|
||||
uint64_t skip, size_t size,
|
||||
bool is_write)
|
||||
{
|
||||
QEMUIOVector elem;
|
||||
struct iovec *iov;
|
||||
unsigned int niov;
|
||||
|
||||
if (is_write) {
|
||||
iov = pdu->elem.out_sg;
|
||||
niov = pdu->elem.out_num;
|
||||
} else {
|
||||
iov = pdu->elem.in_sg;
|
||||
niov = pdu->elem.in_num;
|
||||
}
|
||||
|
||||
qemu_iovec_init_external(&elem, iov, niov);
|
||||
qemu_iovec_init(qiov, niov);
|
||||
qemu_iovec_copy(qiov, &elem, skip, size);
|
||||
}
|
||||
|
||||
static void v9fs_read(void *opaque)
|
||||
{
|
||||
int32_t fid;
|
||||
int64_t off;
|
||||
uint64_t off;
|
||||
ssize_t err = 0;
|
||||
int32_t count = 0;
|
||||
size_t offset = 7;
|
||||
int32_t max_count;
|
||||
uint32_t max_count;
|
||||
V9fsFidState *fidp;
|
||||
V9fsPDU *pdu = opaque;
|
||||
V9fsState *s = pdu->s;
|
||||
@@ -1850,21 +1845,21 @@ static void v9fs_read(void *opaque)
|
||||
err += pdu_marshal(pdu, offset, "d", count);
|
||||
err += count;
|
||||
} else if (fidp->fid_type == P9_FID_FILE) {
|
||||
int32_t cnt;
|
||||
QEMUIOVector qiov_full;
|
||||
QEMUIOVector qiov;
|
||||
int32_t len;
|
||||
struct iovec *sg;
|
||||
struct iovec iov[128]; /* FIXME: bad, bad, bad */
|
||||
|
||||
sg = iov;
|
||||
pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
|
||||
sg = cap_sg(sg, max_count, &cnt);
|
||||
v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
|
||||
qemu_iovec_init(&qiov, qiov_full.niov);
|
||||
do {
|
||||
qemu_iovec_reset(&qiov);
|
||||
qemu_iovec_copy(&qiov, &qiov_full, count, qiov_full.size - count);
|
||||
if (0) {
|
||||
print_sg(sg, cnt);
|
||||
print_sg(qiov.iov, qiov.niov);
|
||||
}
|
||||
/* Loop in case of EINTR */
|
||||
do {
|
||||
len = v9fs_co_preadv(pdu, fidp, sg, cnt, off);
|
||||
len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
|
||||
if (len >= 0) {
|
||||
off += len;
|
||||
count += len;
|
||||
@@ -1875,11 +1870,12 @@ static void v9fs_read(void *opaque)
|
||||
err = len;
|
||||
goto out;
|
||||
}
|
||||
sg = adjust_sg(sg, len, &cnt);
|
||||
} while (count < max_count && len > 0);
|
||||
err = offset;
|
||||
err += pdu_marshal(pdu, offset, "d", count);
|
||||
err += count;
|
||||
qemu_iovec_destroy(&qiov);
|
||||
qemu_iovec_destroy(&qiov_full);
|
||||
} else if (fidp->fid_type == P9_FID_XATTR) {
|
||||
err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
|
||||
} else {
|
||||
@@ -1966,8 +1962,9 @@ static void v9fs_readdir(void *opaque)
|
||||
V9fsFidState *fidp;
|
||||
ssize_t retval = 0;
|
||||
size_t offset = 7;
|
||||
int64_t initial_offset;
|
||||
int32_t count, max_count;
|
||||
uint64_t initial_offset;
|
||||
int32_t count;
|
||||
uint32_t max_count;
|
||||
V9fsPDU *pdu = opaque;
|
||||
V9fsState *s = pdu->s;
|
||||
|
||||
@@ -2005,7 +2002,7 @@ out_nofid:
|
||||
}
|
||||
|
||||
static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
|
||||
int64_t off, int32_t count,
|
||||
uint64_t off, uint32_t count,
|
||||
struct iovec *sg, int cnt)
|
||||
{
|
||||
int i, to_copy;
|
||||
@@ -2050,22 +2047,22 @@ out:
|
||||
|
||||
static void v9fs_write(void *opaque)
|
||||
{
|
||||
int cnt;
|
||||
ssize_t err;
|
||||
int32_t fid;
|
||||
int64_t off;
|
||||
int32_t count;
|
||||
uint64_t off;
|
||||
uint32_t count;
|
||||
int32_t len = 0;
|
||||
int32_t total = 0;
|
||||
size_t offset = 7;
|
||||
V9fsFidState *fidp;
|
||||
struct iovec iov[128]; /* FIXME: bad, bad, bad */
|
||||
struct iovec *sg = iov;
|
||||
V9fsPDU *pdu = opaque;
|
||||
V9fsState *s = pdu->s;
|
||||
QEMUIOVector qiov_full;
|
||||
QEMUIOVector qiov;
|
||||
|
||||
pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
|
||||
trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, cnt);
|
||||
offset += pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
|
||||
v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
|
||||
trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
|
||||
|
||||
fidp = get_fid(pdu, fid);
|
||||
if (fidp == NULL) {
|
||||
@@ -2081,20 +2078,23 @@ static void v9fs_write(void *opaque)
|
||||
/*
|
||||
* setxattr operation
|
||||
*/
|
||||
err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt);
|
||||
err = v9fs_xattr_write(s, pdu, fidp, off, count,
|
||||
qiov_full.iov, qiov_full.niov);
|
||||
goto out;
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
sg = cap_sg(sg, count, &cnt);
|
||||
qemu_iovec_init(&qiov, qiov_full.niov);
|
||||
do {
|
||||
qemu_iovec_reset(&qiov);
|
||||
qemu_iovec_copy(&qiov, &qiov_full, total, qiov_full.size - total);
|
||||
if (0) {
|
||||
print_sg(sg, cnt);
|
||||
print_sg(qiov.iov, qiov.niov);
|
||||
}
|
||||
/* Loop in case of EINTR */
|
||||
do {
|
||||
len = v9fs_co_pwritev(pdu, fidp, sg, cnt, off);
|
||||
len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
|
||||
if (len >= 0) {
|
||||
off += len;
|
||||
total += len;
|
||||
@@ -2103,16 +2103,20 @@ static void v9fs_write(void *opaque)
|
||||
if (len < 0) {
|
||||
/* IO error return the error */
|
||||
err = len;
|
||||
goto out;
|
||||
goto out_qiov;
|
||||
}
|
||||
sg = adjust_sg(sg, len, &cnt);
|
||||
} while (total < count && len > 0);
|
||||
|
||||
offset = 7;
|
||||
offset += pdu_marshal(pdu, offset, "d", total);
|
||||
err = offset;
|
||||
trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
|
||||
out_qiov:
|
||||
qemu_iovec_destroy(&qiov);
|
||||
out:
|
||||
put_fid(pdu, fidp);
|
||||
out_nofid:
|
||||
qemu_iovec_destroy(&qiov_full);
|
||||
complete_pdu(s, pdu, err);
|
||||
}
|
||||
|
||||
|
@@ -156,7 +156,7 @@ typedef struct V9fsFidState V9fsFidState;
|
||||
|
||||
typedef struct V9fsString
|
||||
{
|
||||
int16_t size;
|
||||
uint16_t size;
|
||||
char *data;
|
||||
} V9fsString;
|
||||
|
||||
@@ -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 {
|
||||
|
@@ -466,6 +466,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
||||
bytes = split_size;
|
||||
if (tp->size + bytes > msh)
|
||||
bytes = msh - tp->size;
|
||||
|
||||
bytes = MIN(sizeof(tp->data) - tp->size, bytes);
|
||||
pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes);
|
||||
if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
|
||||
memmove(tp->header, tp->data, hdr);
|
||||
@@ -481,6 +483,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
||||
// context descriptor TSE is not set, while data descriptor TSE is set
|
||||
DBGOUT(TXERR, "TCP segmentaion Error\n");
|
||||
} else {
|
||||
split_size = MIN(sizeof(tp->data) - tp->size, split_size);
|
||||
pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
|
||||
tp->size += split_size;
|
||||
}
|
||||
|
@@ -47,6 +47,7 @@
|
||||
#include "mc146818rtc.h"
|
||||
#include "blockdev.h"
|
||||
#include "exec-memory.h"
|
||||
#include "sysbus.h" /* SysBusDevice */
|
||||
|
||||
//#define DEBUG_BOARD_INIT
|
||||
|
||||
@@ -72,6 +73,11 @@ typedef struct {
|
||||
SerialState *uart;
|
||||
} MaltaFPGAState;
|
||||
|
||||
typedef struct {
|
||||
SysBusDevice busdev;
|
||||
qemu_irq *i8259;
|
||||
} MaltaState;
|
||||
|
||||
static ISADevice *pit;
|
||||
|
||||
static struct _loaderparams {
|
||||
@@ -775,7 +781,7 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
int64_t kernel_entry;
|
||||
PCIBus *pci_bus;
|
||||
CPUState *env;
|
||||
qemu_irq *i8259 = NULL, *isa_irq;
|
||||
qemu_irq *isa_irq;
|
||||
qemu_irq *cpu_exit_irq;
|
||||
int piix4_devfn;
|
||||
i2c_bus *smbus;
|
||||
@@ -787,6 +793,11 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
int fl_sectors = 0;
|
||||
int be;
|
||||
|
||||
DeviceState *dev = qdev_create(NULL, "mips-malta");
|
||||
MaltaState *s = DO_UPCAST(MaltaState, busdev.qdev, dev);
|
||||
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* Make sure the first 3 serial ports are associated with a device. */
|
||||
for(i = 0; i < 3; i++) {
|
||||
if (!serial_hds[i]) {
|
||||
@@ -932,7 +943,7 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
* qemu_irq_proxy() adds an extra bit of indirection, allowing us
|
||||
* to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
|
||||
*/
|
||||
isa_irq = qemu_irq_proxy(&i8259, 16);
|
||||
isa_irq = qemu_irq_proxy(&s->i8259, 16);
|
||||
|
||||
/* Northbridge */
|
||||
pci_bus = gt64120_register(isa_irq);
|
||||
@@ -944,9 +955,9 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
|
||||
/* Interrupt controller */
|
||||
/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
|
||||
i8259 = i8259_init(env->irq[2]);
|
||||
s->i8259 = i8259_init(env->irq[2]);
|
||||
|
||||
isa_bus_irqs(i8259);
|
||||
isa_bus_irqs(s->i8259);
|
||||
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
|
||||
usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
|
||||
smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(9),
|
||||
@@ -990,6 +1001,20 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
}
|
||||
}
|
||||
|
||||
static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SysBusDeviceInfo mips_malta_device = {
|
||||
.init = mips_malta_sysbus_device_init,
|
||||
.qdev.name = "mips-malta",
|
||||
.qdev.size = sizeof(MaltaState),
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
static QEMUMachine mips_malta_machine = {
|
||||
.name = "malta",
|
||||
.desc = "MIPS Malta Core LV",
|
||||
@@ -998,9 +1023,15 @@ static QEMUMachine mips_malta_machine = {
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
static void mips_malta_device_init(void)
|
||||
{
|
||||
sysbus_register_withprop(&mips_malta_device);
|
||||
}
|
||||
|
||||
static void mips_malta_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&mips_malta_machine);
|
||||
}
|
||||
|
||||
device_init(mips_malta_device_init);
|
||||
machine_init(mips_malta_machine_init);
|
||||
|
41
hw/pc_piix.c
41
hw/pc_piix.c
@@ -306,6 +306,14 @@ static QEMUMachine pc_machine_v1_0 = {
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
static QEMUMachine pc_machine_v0_15 = {
|
||||
.name = "pc-0.15",
|
||||
.desc = "Standard PC",
|
||||
.init = pc_init_pci,
|
||||
.max_cpus = 255,
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
static QEMUMachine pc_machine_v0_14 = {
|
||||
.name = "pc-0.14",
|
||||
.desc = "Standard PC",
|
||||
@@ -320,6 +328,22 @@ static QEMUMachine pc_machine_v0_14 = {
|
||||
.driver = "qxl-vga",
|
||||
.property = "revision",
|
||||
.value = stringify(2),
|
||||
},{
|
||||
.driver = "virtio-blk-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-serial-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
@@ -359,6 +383,10 @@ static QEMUMachine pc_machine_v0_13 = {
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "AC97",
|
||||
.property = "use_broken_id",
|
||||
@@ -406,6 +434,10 @@ static QEMUMachine pc_machine_v0_12 = {
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "AC97",
|
||||
.property = "use_broken_id",
|
||||
@@ -461,6 +493,10 @@ static QEMUMachine pc_machine_v0_11 = {
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "AC97",
|
||||
.property = "use_broken_id",
|
||||
@@ -528,6 +564,10 @@ static QEMUMachine pc_machine_v0_10 = {
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "AC97",
|
||||
.property = "use_broken_id",
|
||||
@@ -557,6 +597,7 @@ static QEMUMachine xenfv_machine = {
|
||||
static void pc_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&pc_machine_v1_0);
|
||||
qemu_register_machine(&pc_machine_v0_15);
|
||||
qemu_register_machine(&pc_machine_v0_14);
|
||||
qemu_register_machine(&pc_machine_v0_13);
|
||||
qemu_register_machine(&pc_machine_v0_12);
|
||||
|
@@ -112,6 +112,7 @@ static void spin_kick(void *data)
|
||||
|
||||
env->halted = 0;
|
||||
env->exception_index = -1;
|
||||
env->stopped = 0;
|
||||
qemu_cpu_kick(env);
|
||||
}
|
||||
|
||||
|
@@ -351,6 +351,8 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
||||
fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
|
||||
}
|
||||
|
||||
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
|
||||
|
||||
_FDT((fdt_pack(fdt)));
|
||||
|
||||
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
|
||||
|
@@ -454,7 +454,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
|
||||
reg[0].size = 0;
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < PCI_NUM_REGIONS; ++i) {
|
||||
for (i = 0; i < ARRAY_SIZE(bars); ++i) {
|
||||
if (0 == dev->io_regions[i].size) {
|
||||
continue;
|
||||
}
|
||||
|
@@ -749,21 +749,95 @@ static void spapr_vio_register_devices(void)
|
||||
device_init(spapr_vio_register_devices)
|
||||
|
||||
#ifdef CONFIG_FDT
|
||||
static int compare_reg(const void *p1, const void *p2)
|
||||
{
|
||||
VIOsPAPRDevice const *dev1, *dev2;
|
||||
|
||||
dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
|
||||
dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
|
||||
|
||||
if (dev1->reg < dev2->reg) {
|
||||
return -1;
|
||||
}
|
||||
if (dev1->reg == dev2->reg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* dev1->reg > dev2->reg */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
|
||||
{
|
||||
DeviceState *qdev;
|
||||
int ret = 0;
|
||||
DeviceState *qdev, **qdevs;
|
||||
int i, num, ret = 0;
|
||||
|
||||
/* Count qdevs on the bus list */
|
||||
num = 0;
|
||||
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
|
||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
|
||||
num++;
|
||||
}
|
||||
|
||||
/* Copy out into an array of pointers */
|
||||
qdevs = g_malloc(sizeof(qdev) * num);
|
||||
num = 0;
|
||||
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
|
||||
qdevs[num++] = qdev;
|
||||
}
|
||||
|
||||
/* Sort the array */
|
||||
qsort(qdevs, num, sizeof(qdev), compare_reg);
|
||||
|
||||
/* Hack alert. Give the devices to libfdt in reverse order, we happen
|
||||
* to know that will mean they are in forward order in the tree. */
|
||||
for (i = num - 1; i >= 0; i--) {
|
||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
|
||||
|
||||
ret = vio_make_devnode(dev, fdt);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
out:
|
||||
free(qdevs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
|
||||
{
|
||||
VIOsPAPRDevice *dev;
|
||||
char *name, *path;
|
||||
int ret, offset;
|
||||
|
||||
dev = spapr_vty_get_default(bus);
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
offset = fdt_path_offset(fdt, "/chosen");
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
name = vio_format_dev_name(dev);
|
||||
if (!name) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (asprintf(&path, "/vdevice/%s", name) < 0) {
|
||||
path = NULL;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
|
||||
out:
|
||||
free(name);
|
||||
free(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_FDT */
|
||||
|
@@ -83,6 +83,7 @@ extern VIOsPAPRBus *spapr_vio_bus_init(void);
|
||||
extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
|
||||
extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
|
||||
extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
|
||||
extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
|
||||
|
||||
extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
|
||||
|
||||
@@ -108,6 +109,8 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
|
||||
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
|
||||
void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg);
|
||||
|
||||
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
|
||||
|
||||
int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
|
||||
void spapr_vio_quiesce(void);
|
||||
|
||||
|
@@ -156,24 +156,53 @@ static VIOsPAPRDeviceInfo spapr_vty = {
|
||||
},
|
||||
};
|
||||
|
||||
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
|
||||
{
|
||||
VIOsPAPRDevice *sdev, *selected;
|
||||
DeviceState *iter;
|
||||
|
||||
/*
|
||||
* To avoid the console bouncing around we want one VTY to be
|
||||
* the "default". We haven't really got anything to go on, so
|
||||
* arbitrarily choose the one with the lowest reg value.
|
||||
*/
|
||||
|
||||
selected = NULL;
|
||||
QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
|
||||
/* Only look at VTY devices */
|
||||
if (iter->info != &spapr_vty.qdev) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
|
||||
|
||||
/* First VTY we've found, so it is selected for now */
|
||||
if (!selected) {
|
||||
selected = sdev;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Choose VTY with lowest reg value */
|
||||
if (sdev->reg < selected->reg) {
|
||||
selected = sdev;
|
||||
}
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
||||
{
|
||||
VIOsPAPRDevice *sdev;
|
||||
|
||||
sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||
if (!sdev && reg == 0) {
|
||||
DeviceState *qdev;
|
||||
|
||||
/* Hack for kernel early debug, which always specifies reg==0.
|
||||
* We search all VIO devices, and grab the first available vty
|
||||
* device. This attempts to mimic existing PowerVM behaviour
|
||||
* We search all VIO devices, and grab the vty with the lowest
|
||||
* reg. This attempts to mimic existing PowerVM behaviour
|
||||
* (early debug does work there, despite having no vty with
|
||||
* reg==0. */
|
||||
QTAILQ_FOREACH(qdev, &spapr->vio_bus->bus.children, sibling) {
|
||||
if (qdev->info == &spapr_vty.qdev) {
|
||||
return DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
|
||||
}
|
||||
}
|
||||
return spapr_vty_get_default(spapr->vio_bus);
|
||||
}
|
||||
|
||||
return sdev;
|
||||
|
12
hw/usb-msd.c
12
hw/usb-msd.c
@@ -278,6 +278,18 @@ static void usb_msd_handle_reset(USBDevice *dev)
|
||||
MSDState *s = (MSDState *)dev;
|
||||
|
||||
DPRINTF("Reset\n");
|
||||
if (s->req) {
|
||||
scsi_req_cancel(s->req);
|
||||
}
|
||||
assert(s->req == NULL);
|
||||
|
||||
if (s->packet) {
|
||||
USBPacket *p = s->packet;
|
||||
s->packet = NULL;
|
||||
p->result = USB_RET_STALL;
|
||||
usb_packet_complete(dev, p);
|
||||
}
|
||||
|
||||
s->mode = USB_MSDM_CBW;
|
||||
}
|
||||
|
||||
|
@@ -1025,10 +1025,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
||||
if (ret == len) {
|
||||
td.cbp = 0;
|
||||
} else {
|
||||
td.cbp += ret;
|
||||
if ((td.cbp & 0xfff) + ret > 0xfff) {
|
||||
td.cbp &= 0xfff;
|
||||
td.cbp |= td.be & ~0xfff;
|
||||
td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
|
||||
} else {
|
||||
td.cbp += ret;
|
||||
}
|
||||
}
|
||||
td.flags |= OHCI_TD_T1;
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
16
ppc.ld
16
ppc.ld
@@ -49,8 +49,20 @@ SECTIONS
|
||||
.rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
|
||||
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
|
||||
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.rel.plt :
|
||||
{
|
||||
*(.rel.plt)
|
||||
PROVIDE (__rel_iplt_start = .);
|
||||
*(.rel.iplt)
|
||||
PROVIDE (__rel_iplt_end = .);
|
||||
}
|
||||
.rela.plt :
|
||||
{
|
||||
*(.rela.plt)
|
||||
PROVIDE (__rela_iplt_start = .);
|
||||
*(.rela.iplt)
|
||||
PROVIDE (__rela_iplt_end = .);
|
||||
}
|
||||
.init :
|
||||
{
|
||||
KEEP (*(.init))
|
||||
|
16
ppc64.ld
16
ppc64.ld
@@ -54,8 +54,20 @@ SECTIONS
|
||||
*(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
|
||||
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||
}
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.rel.plt :
|
||||
{
|
||||
*(.rel.plt)
|
||||
PROVIDE (__rel_iplt_start = .);
|
||||
*(.rel.iplt)
|
||||
PROVIDE (__rel_iplt_end = .);
|
||||
}
|
||||
.rela.plt :
|
||||
{
|
||||
*(.rela.plt)
|
||||
PROVIDE (__rela_iplt_start = .);
|
||||
*(.rela.iplt)
|
||||
PROVIDE (__rela_iplt_end = .);
|
||||
}
|
||||
.rela.tocbss : { *(.rela.tocbss) }
|
||||
.init :
|
||||
{
|
||||
|
@@ -24,13 +24,13 @@ ETEXI
|
||||
DEF("commit", img_commit,
|
||||
"commit [-f fmt] [-t cache] filename")
|
||||
STEXI
|
||||
@item commit [-f @var{fmt}] @var{filename}
|
||||
@item commit [-f @var{fmt}] [-t @var{cache}] @var{filename}
|
||||
ETEXI
|
||||
|
||||
DEF("convert", img_convert,
|
||||
"convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] filename [filename2 [...]] output_filename")
|
||||
STEXI
|
||||
@item convert [-c] [-p] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
||||
@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
||||
ETEXI
|
||||
|
||||
DEF("info", img_info,
|
||||
@@ -48,7 +48,7 @@ ETEXI
|
||||
DEF("rebase", img_rebase,
|
||||
"rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
|
||||
STEXI
|
||||
@item rebase [-f @var{fmt}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
|
||||
@item rebase [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
|
||||
ETEXI
|
||||
|
||||
DEF("resize", img_resize,
|
||||
|
42
qemu-img.c
42
qemu-img.c
@@ -1420,6 +1420,8 @@ static int img_rebase(int argc, char **argv)
|
||||
*/
|
||||
if (!unsafe) {
|
||||
uint64_t num_sectors;
|
||||
uint64_t old_backing_num_sectors;
|
||||
uint64_t new_backing_num_sectors;
|
||||
uint64_t sector;
|
||||
int n;
|
||||
uint8_t * buf_old;
|
||||
@@ -1430,6 +1432,8 @@ static int img_rebase(int argc, char **argv)
|
||||
buf_new = qemu_blockalign(bs, IO_BUF_SIZE);
|
||||
|
||||
bdrv_get_geometry(bs, &num_sectors);
|
||||
bdrv_get_geometry(bs_old_backing, &old_backing_num_sectors);
|
||||
bdrv_get_geometry(bs_new_backing, &new_backing_num_sectors);
|
||||
|
||||
local_progress = (float)100 /
|
||||
(num_sectors / MIN(num_sectors, IO_BUF_SIZE / 512));
|
||||
@@ -1448,16 +1452,36 @@ static int img_rebase(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read old and new backing file */
|
||||
ret = bdrv_read(bs_old_backing, sector, buf_old, n);
|
||||
if (ret < 0) {
|
||||
error_report("error while reading from old backing file");
|
||||
goto out;
|
||||
/*
|
||||
* Read old and new backing file and take into consideration that
|
||||
* backing files may be smaller than the COW image.
|
||||
*/
|
||||
if (sector >= old_backing_num_sectors) {
|
||||
memset(buf_old, 0, n * BDRV_SECTOR_SIZE);
|
||||
} else {
|
||||
if (sector + n > old_backing_num_sectors) {
|
||||
n = old_backing_num_sectors - sector;
|
||||
}
|
||||
|
||||
ret = bdrv_read(bs_old_backing, sector, buf_old, n);
|
||||
if (ret < 0) {
|
||||
error_report("error while reading from old backing file");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = bdrv_read(bs_new_backing, sector, buf_new, n);
|
||||
if (ret < 0) {
|
||||
error_report("error while reading from new backing file");
|
||||
goto out;
|
||||
|
||||
if (sector >= new_backing_num_sectors) {
|
||||
memset(buf_new, 0, n * BDRV_SECTOR_SIZE);
|
||||
} else {
|
||||
if (sector + n > new_backing_num_sectors) {
|
||||
n = new_backing_num_sectors - sector;
|
||||
}
|
||||
|
||||
ret = bdrv_read(bs_new_backing, sector, buf_new, n);
|
||||
if (ret < 0) {
|
||||
error_report("error while reading from new backing file");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* If they differ, we need to write to the COW file */
|
||||
|
@@ -45,6 +45,10 @@ indicates the consecutive number of bytes that must contain only zeros
|
||||
for qemu-img to create a sparse image during conversion. This value is rounded
|
||||
down to the nearest 512 bytes. You may use the common size suffixes like
|
||||
@code{k} for kilobytes.
|
||||
@item -t @var{cache}
|
||||
specifies the cache mode that should be used with the (destination) file. See
|
||||
the documentation of the emulator's @code{-drive cache=...} option for allowed
|
||||
values.
|
||||
@end table
|
||||
|
||||
Parameters to snapshot subcommand:
|
||||
@@ -87,11 +91,11 @@ this case. @var{backing_file} will never be modified unless you use the
|
||||
The size can also be specified using the @var{size} option with @code{-o},
|
||||
it doesn't need to be specified separately in this case.
|
||||
|
||||
@item commit [-f @var{fmt}] @var{filename}
|
||||
@item commit [-f @var{fmt}] [-t @var{cache}] @var{filename}
|
||||
|
||||
Commit the changes recorded in @var{filename} in its base image.
|
||||
|
||||
@item convert [-c] [-p] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
||||
@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
||||
|
||||
Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename}
|
||||
using format @var{output_fmt}. It can be optionally compressed (@code{-c}
|
||||
@@ -121,7 +125,7 @@ they are displayed too.
|
||||
|
||||
List, apply, create or delete snapshots in image @var{filename}.
|
||||
|
||||
@item rebase [-f @var{fmt}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
|
||||
@item rebase [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
|
||||
|
||||
Changes the backing file of an image. Only the formats @code{qcow2} and
|
||||
@code{qed} support changing the backing file.
|
||||
|
5
qerror.c
5
qerror.c
@@ -234,6 +234,11 @@ static const QErrorStringTable qerror_table[] = {
|
||||
.desc = "'%(device)' uses a %(format) feature which is not "
|
||||
"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)",
|
||||
|
3
qerror.h
3
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 } }"
|
||||
|
||||
|
@@ -67,6 +67,8 @@
|
||||
#define Q_FLAG 0x80000000
|
||||
#define M_FLAG 0x40000000
|
||||
#define PFIX_FLAG 0x800 /* CRISv10 Only. */
|
||||
#define F_FLAG_V10 0x400
|
||||
#define P_FLAG_V10 0x200
|
||||
#define S_FLAG 0x200
|
||||
#define R_FLAG 0x100
|
||||
#define P_FLAG 0x80
|
||||
|
@@ -157,6 +157,7 @@ static void do_interruptv10(CPUState *env)
|
||||
/* Now that we are in kernel mode, load the handlers address. */
|
||||
env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
|
||||
env->locked_irq = 1;
|
||||
env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
|
||||
__func__, env->pc, ex_vec,
|
||||
|
@@ -62,6 +62,65 @@ static inline void cris_illegal_insn(DisasContext *dc)
|
||||
t_gen_raise_exception(EXCP_BREAK);
|
||||
}
|
||||
|
||||
static void gen_store_v10_conditional(DisasContext *dc, TCGv addr, TCGv val,
|
||||
unsigned int size, int mem_index)
|
||||
{
|
||||
int l1 = gen_new_label();
|
||||
TCGv taddr = tcg_temp_local_new();
|
||||
TCGv tval = tcg_temp_local_new();
|
||||
TCGv t1 = tcg_temp_local_new();
|
||||
dc->postinc = 0;
|
||||
cris_evaluate_flags(dc);
|
||||
|
||||
tcg_gen_mov_tl(taddr, addr);
|
||||
tcg_gen_mov_tl(tval, val);
|
||||
|
||||
/* Store only if F flag isn't set */
|
||||
tcg_gen_andi_tl(t1, cpu_PR[PR_CCS], F_FLAG_V10);
|
||||
tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
|
||||
if (size == 1) {
|
||||
tcg_gen_qemu_st8(tval, taddr, mem_index);
|
||||
} else if (size == 2) {
|
||||
tcg_gen_qemu_st16(tval, taddr, mem_index);
|
||||
} else {
|
||||
tcg_gen_qemu_st32(tval, taddr, mem_index);
|
||||
}
|
||||
gen_set_label(l1);
|
||||
tcg_gen_shri_tl(t1, t1, 1); /* shift F to P position */
|
||||
tcg_gen_or_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], t1); /*P=F*/
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free(tval);
|
||||
tcg_temp_free(taddr);
|
||||
}
|
||||
|
||||
static void gen_store_v10(DisasContext *dc, TCGv addr, TCGv val,
|
||||
unsigned int size)
|
||||
{
|
||||
int mem_index = cpu_mmu_index(dc->env);
|
||||
|
||||
/* If we get a fault on a delayslot we must keep the jmp state in
|
||||
the cpu-state to be able to re-execute the jmp. */
|
||||
if (dc->delayed_branch == 1) {
|
||||
cris_store_direct_jmp(dc);
|
||||
}
|
||||
|
||||
/* Conditional writes. We only support the kind were X is known
|
||||
at translation time. */
|
||||
if (dc->flagx_known && dc->flags_x) {
|
||||
gen_store_v10_conditional(dc, addr, val, size, mem_index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (size == 1) {
|
||||
tcg_gen_qemu_st8(val, addr, mem_index);
|
||||
} else if (size == 2) {
|
||||
tcg_gen_qemu_st16(val, addr, mem_index);
|
||||
} else {
|
||||
tcg_gen_qemu_st32(val, addr, mem_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Prefix flag and register are used to handle the more complex
|
||||
addressing modes. */
|
||||
static void cris_set_prefix(DisasContext *dc)
|
||||
@@ -313,7 +372,8 @@ static unsigned int dec10_setclrf(DisasContext *dc)
|
||||
if (set) {
|
||||
tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
|
||||
} else {
|
||||
tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags);
|
||||
tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS],
|
||||
~(flags|F_FLAG_V10|P_FLAG_V10));
|
||||
}
|
||||
|
||||
dc->flags_uptodate = 1;
|
||||
@@ -723,7 +783,7 @@ static unsigned int dec10_ind_move_r_m(DisasContext *dc, unsigned int size)
|
||||
LOG_DIS("move.%d $r%d, [$r%d]\n", dc->size, dc->src, dc->dst);
|
||||
addr = tcg_temp_new();
|
||||
crisv10_prepare_memaddr(dc, addr, size);
|
||||
gen_store(dc, addr, cpu_R[dc->dst], size);
|
||||
gen_store_v10(dc, addr, cpu_R[dc->dst], size);
|
||||
insn_len += crisv10_post_memaddr(dc, size);
|
||||
|
||||
return insn_len;
|
||||
@@ -767,10 +827,10 @@ static unsigned int dec10_ind_move_pr_m(DisasContext *dc)
|
||||
t0 = tcg_temp_new();
|
||||
cris_evaluate_flags(dc);
|
||||
tcg_gen_andi_tl(t0, cpu_PR[PR_CCS], ~PFIX_FLAG);
|
||||
gen_store(dc, addr, t0, size);
|
||||
gen_store_v10(dc, addr, t0, size);
|
||||
tcg_temp_free(t0);
|
||||
} else {
|
||||
gen_store(dc, addr, cpu_PR[dc->dst], size);
|
||||
gen_store_v10(dc, addr, cpu_PR[dc->dst], size);
|
||||
}
|
||||
t0 = tcg_temp_new();
|
||||
insn_len += crisv10_post_memaddr(dc, size);
|
||||
@@ -793,9 +853,9 @@ static void dec10_movem_r_m(DisasContext *dc)
|
||||
tcg_gen_mov_tl(t0, addr);
|
||||
for (i = dc->dst; i >= 0; i--) {
|
||||
if ((pfix && dc->mode == CRISV10_MODE_AUTOINC) && dc->src == i) {
|
||||
gen_store(dc, addr, t0, 4);
|
||||
gen_store_v10(dc, addr, t0, 4);
|
||||
} else {
|
||||
gen_store(dc, addr, cpu_R[i], 4);
|
||||
gen_store_v10(dc, addr, cpu_R[i], 4);
|
||||
}
|
||||
tcg_gen_addi_tl(addr, addr, 4);
|
||||
}
|
||||
|
@@ -4870,20 +4870,23 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
tcg_gen_sub_tl(t2, cpu_regs[R_EAX], t0);
|
||||
gen_extu(ot, t2);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
|
||||
label2 = gen_new_label();
|
||||
if (mod == 3) {
|
||||
label2 = gen_new_label();
|
||||
gen_op_mov_reg_v(ot, R_EAX, t0);
|
||||
tcg_gen_br(label2);
|
||||
gen_set_label(label1);
|
||||
gen_op_mov_reg_v(ot, rm, t1);
|
||||
gen_set_label(label2);
|
||||
} else {
|
||||
tcg_gen_mov_tl(t1, t0);
|
||||
/* perform no-op store cycle like physical cpu; must be
|
||||
before changing accumulator to ensure idempotency if
|
||||
the store faults and the instruction is restarted */
|
||||
gen_op_st_v(ot + s->mem_index, t0, a0);
|
||||
gen_op_mov_reg_v(ot, R_EAX, t0);
|
||||
tcg_gen_br(label2);
|
||||
gen_set_label(label1);
|
||||
/* always store */
|
||||
gen_op_st_v(ot + s->mem_index, t1, a0);
|
||||
}
|
||||
gen_set_label(label2);
|
||||
tcg_gen_mov_tl(cpu_cc_src, t0);
|
||||
tcg_gen_mov_tl(cpu_cc_dst, t2);
|
||||
s->cc_op = CC_OP_SUBB + ot;
|
||||
|
@@ -504,7 +504,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
|
||||
|
||||
int kvm_arch_process_async_events(CPUState *env)
|
||||
{
|
||||
return 0;
|
||||
return env->halted;
|
||||
}
|
||||
|
||||
static int kvmppc_handle_halt(CPUState *env)
|
||||
@@ -838,12 +838,18 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
|
||||
int fd;
|
||||
void *table;
|
||||
|
||||
/* Must set fd to -1 so we don't try to munmap when called for
|
||||
* destroying the table, which the upper layers -will- do
|
||||
*/
|
||||
*pfd = -1;
|
||||
if (!cap_spapr_tce) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE, &args);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "KVM: Failed to create TCE table for liobn 0x%x\n",
|
||||
liobn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -852,6 +858,8 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
|
||||
|
||||
table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (table == MAP_FAILED) {
|
||||
fprintf(stderr, "KVM: Failed to map TCE table for liobn 0x%x\n",
|
||||
liobn);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
@@ -871,8 +879,8 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size)
|
||||
len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE)*sizeof(VIOsPAPR_RTCE);
|
||||
if ((munmap(table, len) < 0) ||
|
||||
(close(fd) < 0)) {
|
||||
fprintf(stderr, "KVM: Unexpected error removing KVM SPAPR TCE "
|
||||
"table: %s", strerror(errno));
|
||||
fprintf(stderr, "KVM: Unexpected error removing TCE table: %s",
|
||||
strerror(errno));
|
||||
/* Leak the table */
|
||||
}
|
||||
|
||||
|
@@ -185,9 +185,6 @@ void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,
|
||||
return;
|
||||
}
|
||||
|
||||
s390_add_running_cpu(env);
|
||||
qemu_cpu_kick(env);
|
||||
|
||||
kvmint.type = type;
|
||||
kvmint.parm = parm;
|
||||
kvmint.parm64 = parm64;
|
||||
|
@@ -636,6 +636,9 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
|
||||
case 0x700:
|
||||
cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
|
||||
break;
|
||||
case 0xc00:
|
||||
helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
|
||||
break;
|
||||
default:
|
||||
goto abort;
|
||||
break;
|
||||
|
@@ -1652,18 +1652,10 @@ static void _decode_opc(DisasContext * ctx)
|
||||
}
|
||||
return;
|
||||
case 0x00a3: /* ocbp @Rn */
|
||||
{
|
||||
TCGv dummy = tcg_temp_new();
|
||||
tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx);
|
||||
tcg_temp_free(dummy);
|
||||
}
|
||||
return;
|
||||
case 0x00b3: /* ocbwb @Rn */
|
||||
{
|
||||
TCGv dummy = tcg_temp_new();
|
||||
tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx);
|
||||
tcg_temp_free(dummy);
|
||||
}
|
||||
/* These instructions are supposed to do nothing in case of
|
||||
a cache miss. Given that we only partially emulate caches
|
||||
it is safe to simply ignore them. */
|
||||
return;
|
||||
case 0x0083: /* pref @Rn */
|
||||
return;
|
||||
|
@@ -579,11 +579,11 @@ v9fs_lcreate(uint16_t tag, uint8_t id, int32_t dfid, int32_t flags, int32_t mode
|
||||
v9fs_lcreate_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int32_t iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
|
||||
v9fs_fsync(uint16_t tag, uint8_t id, int32_t fid, int datasync) "tag %d id %d fid %d datasync %d"
|
||||
v9fs_clunk(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
|
||||
v9fs_read(uint16_t tag, uint8_t id, int32_t fid, int64_t off, int32_t max_count) "tag %d id %d fid %d off %"PRId64" max_count %d"
|
||||
v9fs_read(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t max_count) "tag %d id %d fid %d off %"PRIu64" max_count %u"
|
||||
v9fs_read_return(uint16_t tag, uint8_t id, int32_t count, ssize_t err) "tag %d id %d count %d err %zd"
|
||||
v9fs_readdir(uint16_t tag, uint8_t id, int32_t fid, int64_t offset, int32_t max_count) "tag %d id %d fid %d offset %"PRId64" max_count %d"
|
||||
v9fs_readdir_return(uint16_t tag, uint8_t id, int32_t count, ssize_t retval) "tag %d id %d count %d retval %zd"
|
||||
v9fs_write(uint16_t tag, uint8_t id, int32_t fid, int64_t off, int32_t count, int cnt) "tag %d id %d fid %d off %"PRId64" count %d cnt %d"
|
||||
v9fs_readdir(uint16_t tag, uint8_t id, int32_t fid, uint64_t offset, uint32_t max_count) "tag %d id %d fid %d offset %"PRIu64" max_count %u"
|
||||
v9fs_readdir_return(uint16_t tag, uint8_t id, uint32_t count, ssize_t retval) "tag %d id %d count %u retval %zd"
|
||||
v9fs_write(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t count, int cnt) "tag %d id %d fid %d off %"PRIu64" count %u cnt %d"
|
||||
v9fs_write_return(uint16_t tag, uint8_t id, int32_t total, ssize_t err) "tag %d id %d total %d err %zd"
|
||||
v9fs_create(uint16_t tag, uint8_t id, int32_t fid, char* name, int32_t perm, int8_t mode) "tag %d id %d fid %d name %s perm %d mode %d"
|
||||
v9fs_create_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d"
|
||||
|
47
usb-linux.c
47
usb-linux.c
@@ -116,6 +116,7 @@ typedef struct USBHostDevice {
|
||||
USBDevice dev;
|
||||
int fd;
|
||||
int hub_fd;
|
||||
int hub_port;
|
||||
|
||||
uint8_t descr[8192];
|
||||
int descr_len;
|
||||
@@ -434,7 +435,7 @@ static int usb_host_claim_port(USBHostDevice *s)
|
||||
{
|
||||
#ifdef USBDEVFS_CLAIM_PORT
|
||||
char *h, hub_name[64], line[1024];
|
||||
int hub_addr, portnr, ret;
|
||||
int hub_addr, ret;
|
||||
|
||||
snprintf(hub_name, sizeof(hub_name), "%d-%s",
|
||||
s->match.bus_num, s->match.port);
|
||||
@@ -442,13 +443,13 @@ static int usb_host_claim_port(USBHostDevice *s)
|
||||
/* try strip off last ".$portnr" to get hub */
|
||||
h = strrchr(hub_name, '.');
|
||||
if (h != NULL) {
|
||||
portnr = atoi(h+1);
|
||||
s->hub_port = atoi(h+1);
|
||||
*h = '\0';
|
||||
} else {
|
||||
/* no dot in there -> it is the root hub */
|
||||
snprintf(hub_name, sizeof(hub_name), "usb%d",
|
||||
s->match.bus_num);
|
||||
portnr = atoi(s->match.port);
|
||||
s->hub_port = atoi(s->match.port);
|
||||
}
|
||||
|
||||
if (!usb_host_read_file(line, sizeof(line), "devnum",
|
||||
@@ -469,20 +470,32 @@ static int usb_host_claim_port(USBHostDevice *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr);
|
||||
ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
|
||||
if (ret < 0) {
|
||||
close(s->hub_fd);
|
||||
s->hub_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr);
|
||||
trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void usb_host_release_port(USBHostDevice *s)
|
||||
{
|
||||
if (s->hub_fd == -1) {
|
||||
return;
|
||||
}
|
||||
#ifdef USBDEVFS_RELEASE_PORT
|
||||
ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port);
|
||||
#endif
|
||||
close(s->hub_fd);
|
||||
s->hub_fd = -1;
|
||||
}
|
||||
|
||||
static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
|
||||
{
|
||||
/* earlier Linux 2.4 do not support that */
|
||||
@@ -635,10 +648,8 @@ static void usb_host_handle_destroy(USBDevice *dev)
|
||||
{
|
||||
USBHostDevice *s = (USBHostDevice *)dev;
|
||||
|
||||
usb_host_release_port(s);
|
||||
usb_host_close(s);
|
||||
if (s->hub_fd != -1) {
|
||||
close(s->hub_fd);
|
||||
}
|
||||
QTAILQ_REMOVE(&hostdevs, s, next);
|
||||
qemu_remove_exit_notifier(&s->exit);
|
||||
}
|
||||
@@ -1141,15 +1152,18 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
|
||||
length = s->descr_len - 18;
|
||||
i = 0;
|
||||
|
||||
if (descriptors[i + 1] != USB_DT_CONFIG ||
|
||||
descriptors[i + 5] != s->configuration) {
|
||||
fprintf(stderr, "invalid descriptor data - configuration %d\n",
|
||||
s->configuration);
|
||||
return 1;
|
||||
}
|
||||
i += descriptors[i];
|
||||
|
||||
while (i < length) {
|
||||
if (descriptors[i + 1] != USB_DT_CONFIG) {
|
||||
fprintf(stderr, "invalid descriptor data\n");
|
||||
return 1;
|
||||
} else if (descriptors[i + 5] != s->configuration) {
|
||||
DPRINTF("not requested configuration %d\n", s->configuration);
|
||||
i += (descriptors[i + 3] << 8) + descriptors[i + 2];
|
||||
continue;
|
||||
}
|
||||
|
||||
i += descriptors[i];
|
||||
|
||||
if (descriptors[i + 1] != USB_DT_INTERFACE ||
|
||||
(descriptors[i + 1] == USB_DT_INTERFACE &&
|
||||
descriptors[i + 4] == 0)) {
|
||||
@@ -1399,6 +1413,7 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data)
|
||||
{
|
||||
USBHostDevice *s = container_of(n, USBHostDevice, exit);
|
||||
|
||||
usb_host_release_port(s);
|
||||
if (s->fd != -1) {
|
||||
usb_host_do_reset(s);;
|
||||
}
|
||||
|
Reference in New Issue
Block a user