Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
qemu
提交
734003e6
Q
qemu
项目概览
openeuler
/
qemu
通知
10
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Q
qemu
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
734003e6
编写于
7月 06, 2010
作者:
A
Anthony Liguori
浏览文件
操作
浏览文件
下载
差异文件
Merge remote branch 'kwolf/for-anthony' into staging
上级
02d0ba14
de189a1b
变更
34
隐藏空白更改
内联
并排
Showing
34 changed file
with
606 addition
and
259 deletion
+606
-259
block.c
block.c
+103
-22
block.h
block.h
+5
-0
block/blkdebug.c
block/blkdebug.c
+6
-1
block/qcow2.c
block/qcow2.c
+9
-6
block_int.h
block_int.h
+4
-4
blockdev.c
blockdev.c
+28
-17
blockdev.h
blockdev.h
+5
-2
hw/esp.c
hw/esp.c
+1
-2
hw/fdc.c
hw/fdc.c
+18
-14
hw/ide.h
hw/ide.h
+8
-5
hw/ide/core.c
hw/ide/core.c
+10
-8
hw/ide/internal.h
hw/ide/internal.h
+1
-1
hw/ide/isa.c
hw/ide/isa.c
+4
-4
hw/ide/piix.c
hw/ide/piix.c
+4
-2
hw/ide/qdev.c
hw/ide/qdev.c
+16
-6
hw/lsi53c895a.c
hw/lsi53c895a.c
+1
-1
hw/pc.c
hw/pc.c
+59
-35
hw/pc.h
hw/pc.h
+2
-1
hw/pc_piix.c
hw/pc_piix.c
+11
-5
hw/pci-hotplug.c
hw/pci-hotplug.c
+9
-2
hw/qdev-properties.c
hw/qdev-properties.c
+40
-7
hw/qdev.h
hw/qdev.h
+4
-3
hw/s390-virtio.c
hw/s390-virtio.c
+1
-1
hw/scsi-bus.c
hw/scsi-bus.c
+13
-7
hw/scsi-disk.c
hw/scsi-disk.c
+11
-10
hw/scsi-generic.c
hw/scsi-generic.c
+4
-3
hw/scsi.h
hw/scsi.h
+2
-2
hw/usb-msd.c
hw/usb-msd.c
+24
-6
hw/virtio-blk.c
hw/virtio-blk.c
+2
-1
hw/virtio-pci.c
hw/virtio-pci.c
+2
-2
qemu-img.c
qemu-img.c
+185
-52
qemu-option.c
qemu-option.c
+9
-0
qemu-option.h
qemu-option.h
+1
-0
savevm.c
savevm.c
+4
-27
未找到文件。
block.c
浏览文件 @
734003e6
...
...
@@ -63,6 +63,9 @@ static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
static
QLIST_HEAD
(,
BlockDriver
)
bdrv_drivers
=
QLIST_HEAD_INITIALIZER
(
bdrv_drivers
);
/* The device to use for VM snapshots */
static
BlockDriverState
*
bs_snapshots
;
/* If non-zero, use only whitelisted block drivers */
static
int
use_bdrv_whitelist
;
...
...
@@ -288,23 +291,30 @@ BlockDriver *bdrv_find_protocol(const char *filename)
char
protocol
[
128
];
int
len
;
const
char
*
p
;
int
is_drive
;
/* TODO Drivers without bdrv_file_open must be specified explicitly */
/*
* XXX(hch): we really should not let host device detection
* override an explicit protocol specification, but moving this
* later breaks access to device names with colons in them.
* Thanks to the brain-dead persistent naming schemes on udev-
* based Linux systems those actually are quite common.
*/
drv1
=
find_hdev_driver
(
filename
);
if
(
drv1
)
{
return
drv1
;
}
#ifdef _WIN32
is_drive
=
is_windows_drive
(
filename
)
||
is_windows_drive_prefix
(
filename
);
#else
is_drive
=
0
;
if
(
is_windows_drive
(
filename
)
||
is_windows_drive_prefix
(
filename
))
return
bdrv_find_format
(
"file"
);
#endif
p
=
strchr
(
filename
,
':'
);
if
(
!
p
||
is_drive
)
{
drv1
=
find_hdev_driver
(
filename
);
if
(
!
drv1
)
{
drv1
=
bdrv_find_format
(
"file"
);
}
return
drv1
;
if
(
!
p
)
{
return
bdrv_find_format
(
"file"
);
}
len
=
p
-
filename
;
if
(
len
>
sizeof
(
protocol
)
-
1
)
...
...
@@ -393,7 +403,6 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
bs
->
file
=
NULL
;
bs
->
total_sectors
=
0
;
bs
->
is_temporary
=
0
;
bs
->
encrypted
=
0
;
bs
->
valid_key
=
0
;
bs
->
open_flags
=
flags
;
...
...
@@ -623,6 +632,9 @@ unlink_and_fail:
void
bdrv_close
(
BlockDriverState
*
bs
)
{
if
(
bs
->
drv
)
{
if
(
bs
==
bs_snapshots
)
{
bs_snapshots
=
NULL
;
}
if
(
bs
->
backing_hd
)
{
bdrv_delete
(
bs
->
backing_hd
);
bs
->
backing_hd
=
NULL
;
...
...
@@ -659,6 +671,8 @@ void bdrv_close_all(void)
void
bdrv_delete
(
BlockDriverState
*
bs
)
{
assert
(
!
bs
->
peer
);
/* remove from list, if necessary */
if
(
bs
->
device_name
[
0
]
!=
'\0'
)
{
QTAILQ_REMOVE
(
&
bdrv_states
,
bs
,
list
);
...
...
@@ -669,9 +683,30 @@ void bdrv_delete(BlockDriverState *bs)
bdrv_delete
(
bs
->
file
);
}
assert
(
bs
!=
bs_snapshots
);
qemu_free
(
bs
);
}
int
bdrv_attach
(
BlockDriverState
*
bs
,
DeviceState
*
qdev
)
{
if
(
bs
->
peer
)
{
return
-
EBUSY
;
}
bs
->
peer
=
qdev
;
return
0
;
}
void
bdrv_detach
(
BlockDriverState
*
bs
,
DeviceState
*
qdev
)
{
assert
(
bs
->
peer
==
qdev
);
bs
->
peer
=
NULL
;
}
DeviceState
*
bdrv_get_attached
(
BlockDriverState
*
bs
)
{
return
bs
->
peer
;
}
/*
* Run consistency checks on an image
*
...
...
@@ -1264,6 +1299,14 @@ BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read)
return
is_read
?
bs
->
on_read_error
:
bs
->
on_write_error
;
}
void
bdrv_set_removable
(
BlockDriverState
*
bs
,
int
removable
)
{
bs
->
removable
=
removable
;
if
(
removable
&&
bs
==
bs_snapshots
)
{
bs_snapshots
=
NULL
;
}
}
int
bdrv_is_removable
(
BlockDriverState
*
bs
)
{
return
bs
->
removable
;
...
...
@@ -1750,6 +1793,24 @@ int bdrv_can_snapshot(BlockDriverState *bs)
return
1
;
}
BlockDriverState
*
bdrv_snapshots
(
void
)
{
BlockDriverState
*
bs
;
if
(
bs_snapshots
)
{
return
bs_snapshots
;
}
bs
=
NULL
;
while
((
bs
=
bdrv_next
(
bs
)))
{
if
(
bdrv_can_snapshot
(
bs
))
{
bs_snapshots
=
bs
;
return
bs
;
}
}
return
NULL
;
}
int
bdrv_snapshot_create
(
BlockDriverState
*
bs
,
QEMUSnapshotInfo
*
sn_info
)
{
...
...
@@ -1981,14 +2042,11 @@ static void multiwrite_cb(void *opaque, int ret)
if
(
ret
<
0
&&
!
mcb
->
error
)
{
mcb
->
error
=
ret
;
multiwrite_user_cb
(
mcb
);
}
mcb
->
num_requests
--
;
if
(
mcb
->
num_requests
==
0
)
{
if
(
mcb
->
error
==
0
)
{
multiwrite_user_cb
(
mcb
);
}
multiwrite_user_cb
(
mcb
);
qemu_free
(
mcb
);
}
}
...
...
@@ -2122,8 +2180,29 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
// Check for mergable requests
num_reqs
=
multiwrite_merge
(
bs
,
reqs
,
num_reqs
,
mcb
);
// Run the aio requests
/*
* Run the aio requests. As soon as one request can't be submitted
* successfully, fail all requests that are not yet submitted (we must
* return failure for all requests anyway)
*
* num_requests cannot be set to the right value immediately: If
* bdrv_aio_writev fails for some request, num_requests would be too high
* and therefore multiwrite_cb() would never recognize the multiwrite
* request as completed. We also cannot use the loop variable i to set it
* when the first request fails because the callback may already have been
* called for previously submitted requests. Thus, num_requests must be
* incremented for each request that is submitted.
*
* The problem that callbacks may be called early also means that we need
* to take care that num_requests doesn't become 0 before all requests are
* submitted - multiwrite_cb() would consider the multiwrite request
* completed. A dummy request that is "completed" by a manual call to
* multiwrite_cb() takes care of this.
*/
mcb
->
num_requests
=
1
;
for
(
i
=
0
;
i
<
num_reqs
;
i
++
)
{
mcb
->
num_requests
++
;
acb
=
bdrv_aio_writev
(
bs
,
reqs
[
i
].
sector
,
reqs
[
i
].
qiov
,
reqs
[
i
].
nb_sectors
,
multiwrite_cb
,
mcb
);
...
...
@@ -2131,22 +2210,24 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
// We can only fail the whole thing if no request has been
// submitted yet. Otherwise we'll wait for the submitted AIOs to
// complete and report the error in the callback.
if
(
mcb
->
num_requests
==
0
)
{
reqs
[
i
].
error
=
-
EIO
;
if
(
i
==
0
)
{
goto
fail
;
}
else
{
mcb
->
num_requests
++
;
multiwrite_cb
(
mcb
,
-
EIO
);
break
;
}
}
else
{
mcb
->
num_requests
++
;
}
}
/* Complete the dummy request */
multiwrite_cb
(
mcb
,
0
);
return
0
;
fail:
for
(
i
=
0
;
i
<
mcb
->
num_callbacks
;
i
++
)
{
reqs
[
i
].
error
=
-
EIO
;
}
qemu_free
(
mcb
);
return
-
1
;
}
...
...
block.h
浏览文件 @
734003e6
...
...
@@ -71,6 +71,9 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
int
bdrv_open
(
BlockDriverState
*
bs
,
const
char
*
filename
,
int
flags
,
BlockDriver
*
drv
);
void
bdrv_close
(
BlockDriverState
*
bs
);
int
bdrv_attach
(
BlockDriverState
*
bs
,
DeviceState
*
qdev
);
void
bdrv_detach
(
BlockDriverState
*
bs
,
DeviceState
*
qdev
);
DeviceState
*
bdrv_get_attached
(
BlockDriverState
*
bs
);
int
bdrv_check
(
BlockDriverState
*
bs
);
int
bdrv_read
(
BlockDriverState
*
bs
,
int64_t
sector_num
,
uint8_t
*
buf
,
int
nb_sectors
);
...
...
@@ -159,6 +162,7 @@ int bdrv_get_translation_hint(BlockDriverState *bs);
void
bdrv_set_on_error
(
BlockDriverState
*
bs
,
BlockErrorAction
on_read_error
,
BlockErrorAction
on_write_error
);
BlockErrorAction
bdrv_get_on_error
(
BlockDriverState
*
bs
,
int
is_read
);
void
bdrv_set_removable
(
BlockDriverState
*
bs
,
int
removable
);
int
bdrv_is_removable
(
BlockDriverState
*
bs
);
int
bdrv_is_read_only
(
BlockDriverState
*
bs
);
int
bdrv_is_sg
(
BlockDriverState
*
bs
);
...
...
@@ -190,6 +194,7 @@ const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
void
bdrv_get_backing_filename
(
BlockDriverState
*
bs
,
char
*
filename
,
int
filename_size
);
int
bdrv_can_snapshot
(
BlockDriverState
*
bs
);
BlockDriverState
*
bdrv_snapshots
(
void
);
int
bdrv_snapshot_create
(
BlockDriverState
*
bs
,
QEMUSnapshotInfo
*
sn_info
);
int
bdrv_snapshot_goto
(
BlockDriverState
*
bs
,
...
...
block/blkdebug.c
浏览文件 @
734003e6
...
...
@@ -111,7 +111,7 @@ static QemuOptsList inject_error_opts = {
static
QemuOptsList
set_state_opts
=
{
.
name
=
"set-state"
,
.
head
=
QTAILQ_HEAD_INITIALIZER
(
inject_error
_opts
.
head
),
.
head
=
QTAILQ_HEAD_INITIALIZER
(
set_state
_opts
.
head
),
.
desc
=
{
{
.
name
=
"event"
,
...
...
@@ -267,6 +267,8 @@ static int read_config(BDRVBlkdebugState *s, const char *filename)
ret
=
0
;
fail:
qemu_opts_reset
(
&
inject_error_opts
);
qemu_opts_reset
(
&
set_state_opts
);
fclose
(
f
);
return
ret
;
}
...
...
@@ -299,6 +301,9 @@ static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
}
filename
=
c
+
1
;
/* Set initial state */
s
->
vars
.
state
=
1
;
/* Open the backing file */
ret
=
bdrv_file_open
(
&
bs
->
file
,
filename
,
flags
);
if
(
ret
<
0
)
{
...
...
block/qcow2.c
浏览文件 @
734003e6
...
...
@@ -805,14 +805,14 @@ static int preallocate(BlockDriverState *bs)
while
(
nb_sectors
)
{
num
=
MIN
(
nb_sectors
,
INT_MAX
>>
9
);
ret
=
qcow2_alloc_cluster_offset
(
bs
,
offset
,
0
,
num
,
&
num
,
&
meta
);
if
(
ret
<
0
)
{
return
-
1
;
return
ret
;
}
if
(
qcow2_alloc_cluster_link_l2
(
bs
,
&
meta
)
<
0
)
{
ret
=
qcow2_alloc_cluster_link_l2
(
bs
,
&
meta
);
if
(
ret
<
0
)
{
qcow2_free_any_clusters
(
bs
,
meta
.
cluster_offset
,
meta
.
nb_clusters
);
return
-
1
;
return
ret
;
}
/* There are no dependent requests, but we need to remove our request
...
...
@@ -833,7 +833,10 @@ static int preallocate(BlockDriverState *bs)
if
(
meta
.
cluster_offset
!=
0
)
{
uint8_t
buf
[
512
];
memset
(
buf
,
0
,
512
);
bdrv_write
(
bs
->
file
,
(
meta
.
cluster_offset
>>
9
)
+
num
-
1
,
buf
,
1
);
ret
=
bdrv_write
(
bs
->
file
,
(
meta
.
cluster_offset
>>
9
)
+
num
-
1
,
buf
,
1
);
if
(
ret
<
0
)
{
return
ret
;
}
}
return
0
;
...
...
@@ -1030,7 +1033,7 @@ exit:
BlockDriver
*
drv
=
bdrv_find_format
(
"qcow2"
);
bs
=
bdrv_new
(
""
);
bdrv_open
(
bs
,
filename
,
BDRV_O_CACHE_WB
|
BDRV_O_RDWR
,
drv
);
preallocate
(
bs
);
ret
=
preallocate
(
bs
);
bdrv_close
(
bs
);
}
...
...
block_int.h
浏览文件 @
734003e6
...
...
@@ -148,6 +148,8 @@ struct BlockDriverState {
BlockDriver
*
drv
;
/* NULL means no media */
void
*
opaque
;
DeviceState
*
peer
;
char
filename
[
1024
];
char
backing_file
[
1024
];
/* if non zero, the image is a diff of
this file image */
...
...
@@ -210,10 +212,8 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size);
int
is_windows_drive
(
const
char
*
filename
);
#endif
struct
DriveInfo
;
typedef
struct
BlockConf
{
struct
DriveInfo
*
dinfo
;
BlockDriverState
*
bs
;
uint16_t
physical_block_size
;
uint16_t
logical_block_size
;
uint16_t
min_io_size
;
...
...
@@ -234,7 +234,7 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
}
#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
DEFINE_PROP_DRIVE("drive", _state, _conf.
dinfo),
\
DEFINE_PROP_DRIVE("drive", _state, _conf.
bs),
\
DEFINE_PROP_UINT16("logical_block_size", _state, \
_conf.logical_block_size, 512), \
DEFINE_PROP_UINT16("physical_block_size", _state, \
...
...
blockdev.c
浏览文件 @
734003e6
...
...
@@ -17,6 +17,29 @@
static
QTAILQ_HEAD
(
drivelist
,
DriveInfo
)
drives
=
QTAILQ_HEAD_INITIALIZER
(
drives
);
/*
* We automatically delete the drive when a device using it gets
* unplugged. Questionable feature, but we can't just drop it.
* Device models call blockdev_mark_auto_del() to schedule the
* automatic deletion, and generic qdev code calls blockdev_auto_del()
* when deletion is actually safe.
*/
void
blockdev_mark_auto_del
(
BlockDriverState
*
bs
)
{
DriveInfo
*
dinfo
=
drive_get_by_blockdev
(
bs
);
dinfo
->
auto_del
=
1
;
}
void
blockdev_auto_del
(
BlockDriverState
*
bs
)
{
DriveInfo
*
dinfo
=
drive_get_by_blockdev
(
bs
);
if
(
dinfo
->
auto_del
)
{
drive_uninit
(
dinfo
);
}
}
QemuOpts
*
drive_add
(
const
char
*
file
,
const
char
*
fmt
,
...)
{
va_list
ap
;
...
...
@@ -52,18 +75,6 @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
return
NULL
;
}
DriveInfo
*
drive_get_by_id
(
const
char
*
id
)
{
DriveInfo
*
dinfo
;
QTAILQ_FOREACH
(
dinfo
,
&
drives
,
next
)
{
if
(
strcmp
(
id
,
dinfo
->
id
))
continue
;
return
dinfo
;
}
return
NULL
;
}
int
drive_get_max_bus
(
BlockInterfaceType
type
)
{
int
max_bus
;
...
...
@@ -78,16 +89,16 @@ int drive_get_max_bus(BlockInterfaceType type)
return
max_bus
;
}
const
char
*
drive_get_serial
(
BlockDriverState
*
bdrv
)
DriveInfo
*
drive_get_by_blockdev
(
BlockDriverState
*
bs
)
{
DriveInfo
*
dinfo
;
QTAILQ_FOREACH
(
dinfo
,
&
drives
,
next
)
{
if
(
dinfo
->
bdrv
==
bdrv
)
return
dinfo
->
serial
;
if
(
dinfo
->
bdrv
==
bs
)
{
return
dinfo
;
}
}
return
"
\0
"
;
return
NULL
;
}
static
void
bdrv_format_print
(
void
*
opaque
,
const
char
*
name
)
...
...
blockdev.h
浏览文件 @
734003e6
...
...
@@ -13,6 +13,9 @@
#include "block.h"
#include "qemu-queue.h"
void
blockdev_mark_auto_del
(
BlockDriverState
*
bs
);
void
blockdev_auto_del
(
BlockDriverState
*
bs
);
typedef
enum
{
IF_NONE
,
IF_IDE
,
IF_SCSI
,
IF_FLOPPY
,
IF_PFLASH
,
IF_MTD
,
IF_SD
,
IF_VIRTIO
,
IF_XEN
,
...
...
@@ -28,6 +31,7 @@ typedef struct DriveInfo {
BlockInterfaceType
type
;
int
bus
;
int
unit
;
int
auto_del
;
/* see blockdev_mark_auto_del() */
QemuOpts
*
opts
;
char
serial
[
BLOCK_SERIAL_STRLEN
+
1
];
QTAILQ_ENTRY
(
DriveInfo
)
next
;
...
...
@@ -37,10 +41,9 @@ typedef struct DriveInfo {
#define MAX_SCSI_DEVS 7
extern
DriveInfo
*
drive_get
(
BlockInterfaceType
type
,
int
bus
,
int
unit
);
extern
DriveInfo
*
drive_get_by_id
(
const
char
*
id
);
extern
int
drive_get_max_bus
(
BlockInterfaceType
type
);
extern
void
drive_uninit
(
DriveInfo
*
dinfo
);
extern
const
char
*
drive_get_serial
(
BlockDriverState
*
bdrv
);
extern
DriveInfo
*
drive_get_by_blockdev
(
BlockDriverState
*
bs
);
extern
QemuOpts
*
drive_add
(
const
char
*
file
,
const
char
*
fmt
,
...);
extern
DriveInfo
*
drive_init
(
QemuOpts
*
arg
,
int
default_to_scsi
,
...
...
hw/esp.c
浏览文件 @
734003e6
...
...
@@ -679,8 +679,7 @@ static int esp_init1(SysBusDevice *dev)
qdev_init_gpio_in
(
&
dev
->
qdev
,
parent_esp_reset
,
1
);
scsi_bus_new
(
&
s
->
bus
,
&
dev
->
qdev
,
0
,
ESP_MAX_DEVS
,
esp_command_complete
);
scsi_bus_legacy_handle_cmdline
(
&
s
->
bus
);
return
0
;
return
scsi_bus_legacy_handle_cmdline
(
&
s
->
bus
);
}
static
SysBusDeviceInfo
esp_info
=
{
...
...
hw/fdc.c
浏览文件 @
734003e6
...
...
@@ -80,7 +80,6 @@ typedef enum FDiskFlags {
}
FDiskFlags
;
typedef
struct
FDrive
{
DriveInfo
*
dinfo
;
BlockDriverState
*
bs
;
/* Drive status */
FDriveType
drive
;
...
...
@@ -100,7 +99,6 @@ typedef struct FDrive {
static
void
fd_init
(
FDrive
*
drv
)
{
/* Drive */
drv
->
bs
=
drv
->
dinfo
?
drv
->
dinfo
->
bdrv
:
NULL
;
drv
->
drive
=
FDRIVE_DRV_NONE
;
drv
->
perpendicular
=
0
;
/* Disk */
...
...
@@ -1849,10 +1847,16 @@ static void fdctrl_result_timer(void *opaque)
static
void
fdctrl_connect_drives
(
FDCtrl
*
fdctrl
)
{
unsigned
int
i
;
FDrive
*
drive
;
for
(
i
=
0
;
i
<
MAX_FD
;
i
++
)
{
fd_init
(
&
fdctrl
->
drives
[
i
]);
fd_revalidate
(
&
fdctrl
->
drives
[
i
]);
drive
=
&
fdctrl
->
drives
[
i
];
fd_init
(
drive
);
fd_revalidate
(
drive
);
if
(
drive
->
bs
)
{
bdrv_set_removable
(
drive
->
bs
,
1
);
}
}
}
...
...
@@ -1862,10 +1866,10 @@ FDCtrl *fdctrl_init_isa(DriveInfo **fds)
dev
=
isa_create
(
"isa-fdc"
);
if
(
fds
[
0
])
{
qdev_prop_set_drive
(
&
dev
->
qdev
,
"driveA"
,
fds
[
0
]
);
qdev_prop_set_drive
_nofail
(
&
dev
->
qdev
,
"driveA"
,
fds
[
0
]
->
bdrv
);
}
if
(
fds
[
1
])
{
qdev_prop_set_drive
(
&
dev
->
qdev
,
"driveB"
,
fds
[
1
]
);
qdev_prop_set_drive
_nofail
(
&
dev
->
qdev
,
"driveB"
,
fds
[
1
]
->
bdrv
);
}
if
(
qdev_init
(
&
dev
->
qdev
)
<
0
)
return
NULL
;
...
...
@@ -1884,10 +1888,10 @@ FDCtrl *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
fdctrl
=
&
sys
->
state
;
fdctrl
->
dma_chann
=
dma_chann
;
/* FIXME */
if
(
fds
[
0
])
{
qdev_prop_set_drive
(
dev
,
"driveA"
,
fds
[
0
]
);
qdev_prop_set_drive
_nofail
(
dev
,
"driveA"
,
fds
[
0
]
->
bdrv
);
}
if
(
fds
[
1
])
{
qdev_prop_set_drive
(
dev
,
"driveB"
,
fds
[
1
]
);
qdev_prop_set_drive
_nofail
(
dev
,
"driveB"
,
fds
[
1
]
->
bdrv
);
}
qdev_init_nofail
(
dev
);
sysbus_connect_irq
(
&
sys
->
busdev
,
0
,
irq
);
...
...
@@ -1905,7 +1909,7 @@ FDCtrl *sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
dev
=
qdev_create
(
NULL
,
"SUNW,fdtwo"
);
if
(
fds
[
0
])
{
qdev_prop_set_drive
(
dev
,
"drive"
,
fds
[
0
]
);
qdev_prop_set_drive
_nofail
(
dev
,
"drive"
,
fds
[
0
]
->
bdrv
);
}
qdev_init_nofail
(
dev
);
sys
=
DO_UPCAST
(
FDCtrlSysBus
,
busdev
.
qdev
,
dev
);
...
...
@@ -2030,8 +2034,8 @@ static ISADeviceInfo isa_fdc_info = {
.
qdev
.
vmsd
=
&
vmstate_isa_fdc
,
.
qdev
.
reset
=
fdctrl_external_reset_isa
,
.
qdev
.
props
=
(
Property
[])
{
DEFINE_PROP_DRIVE
(
"driveA"
,
FDCtrlISABus
,
state
.
drives
[
0
].
dinfo
),
DEFINE_PROP_DRIVE
(
"driveB"
,
FDCtrlISABus
,
state
.
drives
[
1
].
dinfo
),
DEFINE_PROP_DRIVE
(
"driveA"
,
FDCtrlISABus
,
state
.
drives
[
0
].
bs
),
DEFINE_PROP_DRIVE
(
"driveB"
,
FDCtrlISABus
,
state
.
drives
[
1
].
bs
),
DEFINE_PROP_END_OF_LIST
(),
},
};
...
...
@@ -2053,8 +2057,8 @@ static SysBusDeviceInfo sysbus_fdc_info = {
.
qdev
.
vmsd
=
&
vmstate_sysbus_fdc
,
.
qdev
.
reset
=
fdctrl_external_reset_sysbus
,
.
qdev
.
props
=
(
Property
[])
{
DEFINE_PROP_DRIVE
(
"driveA"
,
FDCtrlSysBus
,
state
.
drives
[
0
].
dinfo
),
DEFINE_PROP_DRIVE
(
"driveB"
,
FDCtrlSysBus
,
state
.
drives
[
1
].
dinfo
),
DEFINE_PROP_DRIVE
(
"driveA"
,
FDCtrlSysBus
,
state
.
drives
[
0
].
bs
),
DEFINE_PROP_DRIVE
(
"driveB"
,
FDCtrlSysBus
,
state
.
drives
[
1
].
bs
),
DEFINE_PROP_END_OF_LIST
(),
},
};
...
...
@@ -2066,7 +2070,7 @@ static SysBusDeviceInfo sun4m_fdc_info = {
.
qdev
.
vmsd
=
&
vmstate_sysbus_fdc
,
.
qdev
.
reset
=
fdctrl_external_reset_sysbus
,
.
qdev
.
props
=
(
Property
[])
{
DEFINE_PROP_DRIVE
(
"drive"
,
FDCtrlSysBus
,
state
.
drives
[
0
].
dinfo
),
DEFINE_PROP_DRIVE
(
"drive"
,
FDCtrlSysBus
,
state
.
drives
[
0
].
bs
),
DEFINE_PROP_END_OF_LIST
(),
},
};
...
...
hw/ide.h
浏览文件 @
734003e6
#ifndef HW_IDE_H
#define HW_IDE_H
#include "qdev.h"
#include "isa.h"
#include "pci.h"
/* ide-isa.c */
int
isa_ide_init
(
int
iobase
,
int
iobase2
,
int
isairq
,
DriveInfo
*
hd0
,
DriveInfo
*
hd1
);
ISADevice
*
isa_ide_init
(
int
iobase
,
int
iobase2
,
int
isairq
,
DriveInfo
*
hd0
,
DriveInfo
*
hd1
);
/* ide-pci.c */
void
pci_cmd646_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
secondary_ide_enabled
);
void
pci_piix3_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
devfn
);
void
pci_piix4_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
devfn
);
PCIDevice
*
pci_piix3_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
devfn
);
PCIDevice
*
pci_piix4_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
devfn
);
void
vt82c686b_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
devfn
);
/* ide-macio.c */
...
...
@@ -23,4 +24,6 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
qemu_irq
irq
,
int
shift
,
DriveInfo
*
hd0
,
DriveInfo
*
hd1
);
void
ide_get_bs
(
BlockDriverState
*
bs
[],
BusState
*
qbus
);
#endif
/* HW_IDE_H */
hw/ide/core.c
浏览文件 @
734003e6
...
...
@@ -2594,15 +2594,15 @@ void ide_bus_reset(IDEBus *bus)
ide_clear_hob
(
bus
);
}
void
ide_init_drive
(
IDEState
*
s
,
DriveInfo
*
dinfo
,
void
ide_init_drive
(
IDEState
*
s
,
BlockDriverState
*
bs
,
const
char
*
version
,
const
char
*
serial
)
{
int
cylinders
,
heads
,
secs
;
uint64_t
nb_sectors
;
s
->
bs
=
dinfo
->
bdrv
;
bdrv_get_geometry
(
s
->
bs
,
&
nb_sectors
);
bdrv_guess_geometry
(
s
->
bs
,
&
cylinders
,
&
heads
,
&
secs
);
s
->
bs
=
bs
;
bdrv_get_geometry
(
bs
,
&
nb_sectors
);
bdrv_guess_geometry
(
bs
,
&
cylinders
,
&
heads
,
&
secs
);
s
->
cylinders
=
cylinders
;
s
->
heads
=
heads
;
s
->
sectors
=
secs
;
...
...
@@ -2613,11 +2613,11 @@ void ide_init_drive(IDEState *s, DriveInfo *dinfo,
s
->
smart_autosave
=
1
;
s
->
smart_errors
=
0
;
s
->
smart_selftest_count
=
0
;
if
(
bdrv_get_type_hint
(
s
->
bs
)
==
BDRV_TYPE_CDROM
)
{
if
(
bdrv_get_type_hint
(
bs
)
==
BDRV_TYPE_CDROM
)
{
s
->
is_cdrom
=
1
;
bdrv_set_change_cb
(
s
->
bs
,
cdrom_change_cb
,
s
);
bdrv_set_change_cb
(
bs
,
cdrom_change_cb
,
s
);
}
if
(
serial
&&
*
serial
)
{
if
(
serial
)
{
strncpy
(
s
->
drive_serial_str
,
serial
,
sizeof
(
s
->
drive_serial_str
));
}
else
{
snprintf
(
s
->
drive_serial_str
,
sizeof
(
s
->
drive_serial_str
),
...
...
@@ -2629,6 +2629,7 @@ void ide_init_drive(IDEState *s, DriveInfo *dinfo,
pstrcpy
(
s
->
version
,
sizeof
(
s
->
version
),
QEMU_VERSION
);
}
ide_reset
(
s
);
bdrv_set_removable
(
bs
,
s
->
is_cdrom
);
}
static
void
ide_init1
(
IDEBus
*
bus
,
int
unit
)
...
...
@@ -2668,7 +2669,8 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
dinfo
=
i
==
0
?
hd0
:
hd1
;
ide_init1
(
bus
,
i
);
if
(
dinfo
)
{
ide_init_drive
(
&
bus
->
ifs
[
i
],
dinfo
,
NULL
,
dinfo
->
serial
);
ide_init_drive
(
&
bus
->
ifs
[
i
],
dinfo
->
bdrv
,
NULL
,
*
dinfo
->
serial
?
dinfo
->
serial
:
NULL
);
}
else
{
ide_reset
(
&
bus
->
ifs
[
i
]);
}
...
...
hw/ide/internal.h
浏览文件 @
734003e6
...
...
@@ -555,7 +555,7 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr);
void
ide_data_writel
(
void
*
opaque
,
uint32_t
addr
,
uint32_t
val
);
uint32_t
ide_data_readl
(
void
*
opaque
,
uint32_t
addr
);
void
ide_init_drive
(
IDEState
*
s
,
DriveInfo
*
dinfo
,
void
ide_init_drive
(
IDEState
*
s
,
BlockDriverState
*
bs
,
const
char
*
version
,
const
char
*
serial
);
void
ide_init2
(
IDEBus
*
bus
,
qemu_irq
irq
);
void
ide_init2_with_non_qdev_drives
(
IDEBus
*
bus
,
DriveInfo
*
hd0
,
...
...
hw/ide/isa.c
浏览文件 @
734003e6
...
...
@@ -75,8 +75,8 @@ static int isa_ide_initfn(ISADevice *dev)
return
0
;
};
int
isa_ide_init
(
int
iobase
,
int
iobase2
,
int
isairq
,
DriveInfo
*
hd0
,
DriveInfo
*
hd1
)
ISADevice
*
isa_ide_init
(
int
iobase
,
int
iobase2
,
int
isairq
,
DriveInfo
*
hd0
,
DriveInfo
*
hd1
)
{
ISADevice
*
dev
;
ISAIDEState
*
s
;
...
...
@@ -86,14 +86,14 @@ int isa_ide_init(int iobase, int iobase2, int isairq,
qdev_prop_set_uint32
(
&
dev
->
qdev
,
"iobase2"
,
iobase2
);
qdev_prop_set_uint32
(
&
dev
->
qdev
,
"irq"
,
isairq
);
if
(
qdev_init
(
&
dev
->
qdev
)
<
0
)
return
-
1
;
return
NULL
;
s
=
DO_UPCAST
(
ISAIDEState
,
dev
,
dev
);
if
(
hd0
)
ide_create_drive
(
&
s
->
bus
,
0
,
hd0
);
if
(
hd1
)
ide_create_drive
(
&
s
->
bus
,
1
,
hd1
);
return
0
;
return
dev
;
}
static
ISADeviceInfo
isa_ide_info
=
{
...
...
hw/ide/piix.c
浏览文件 @
734003e6
...
...
@@ -160,22 +160,24 @@ static int pci_piix4_ide_initfn(PCIDevice *dev)
/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
void
pci_piix3_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
devfn
)
PCIDevice
*
pci_piix3_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
devfn
)
{
PCIDevice
*
dev
;
dev
=
pci_create_simple
(
bus
,
devfn
,
"piix3-ide"
);
pci_ide_create_devs
(
dev
,
hd_table
);
return
dev
;
}
/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
void
pci_piix4_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
devfn
)
PCIDevice
*
pci_piix4_ide_init
(
PCIBus
*
bus
,
DriveInfo
**
hd_table
,
int
devfn
)
{
PCIDevice
*
dev
;
dev
=
pci_create_simple
(
bus
,
devfn
,
"piix4-ide"
);
pci_ide_create_devs
(
dev
,
hd_table
);
return
dev
;
}
static
PCIDeviceInfo
piix_ide_info
[]
=
{
...
...
hw/ide/qdev.c
浏览文件 @
734003e6
...
...
@@ -39,7 +39,7 @@ static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
IDEDeviceInfo
*
info
=
DO_UPCAST
(
IDEDeviceInfo
,
qdev
,
base
);
IDEBus
*
bus
=
DO_UPCAST
(
IDEBus
,
qbus
,
qdev
->
parent_bus
);
if
(
!
dev
->
conf
.
dinfo
)
{
if
(
!
dev
->
conf
.
bs
)
{
fprintf
(
stderr
,
"%s: no drive specified
\n
"
,
qdev
->
info
->
name
);
goto
err
;
}
...
...
@@ -83,12 +83,18 @@ IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
dev
=
qdev_create
(
&
bus
->
qbus
,
"ide-drive"
);
qdev_prop_set_uint32
(
dev
,
"unit"
,
unit
);
qdev_prop_set_drive
(
dev
,
"drive"
,
drive
);
if
(
qdev_init
(
dev
)
<
0
)
return
NULL
;
qdev_prop_set_drive_nofail
(
dev
,
"drive"
,
drive
->
bdrv
);
qdev_init_nofail
(
dev
);
return
DO_UPCAST
(
IDEDevice
,
qdev
,
dev
);
}
void
ide_get_bs
(
BlockDriverState
*
bs
[],
BusState
*
qbus
)
{
IDEBus
*
bus
=
DO_UPCAST
(
IDEBus
,
qbus
,
qbus
);
bs
[
0
]
=
bus
->
master
?
bus
->
master
->
conf
.
bs
:
NULL
;
bs
[
1
]
=
bus
->
slave
?
bus
->
slave
->
conf
.
bs
:
NULL
;
}
/* --------------------------------- */
typedef
struct
IDEDrive
{
...
...
@@ -100,14 +106,18 @@ static int ide_drive_initfn(IDEDevice *dev)
IDEBus
*
bus
=
DO_UPCAST
(
IDEBus
,
qbus
,
dev
->
qdev
.
parent_bus
);
IDEState
*
s
=
bus
->
ifs
+
dev
->
unit
;
const
char
*
serial
;
DriveInfo
*
dinfo
;
serial
=
dev
->
serial
;
if
(
!
serial
)
{
/* try to fall back to value set with legacy -drive serial=... */
serial
=
dev
->
conf
.
dinfo
->
serial
;
dinfo
=
drive_get_by_blockdev
(
dev
->
conf
.
bs
);
if
(
*
dinfo
->
serial
)
{
serial
=
dinfo
->
serial
;
}
}
ide_init_drive
(
s
,
dev
->
conf
.
dinfo
,
dev
->
version
,
serial
);
ide_init_drive
(
s
,
dev
->
conf
.
bs
,
dev
->
version
,
serial
);
if
(
!
dev
->
version
)
{
dev
->
version
=
qemu_strdup
(
s
->
version
);
...
...
hw/lsi53c895a.c
浏览文件 @
734003e6
...
...
@@ -2176,7 +2176,7 @@ static int lsi_scsi_init(PCIDevice *dev)
scsi_bus_new
(
&
s
->
bus
,
&
dev
->
qdev
,
1
,
LSI_MAX_DEVS
,
lsi_command_complete
);
if
(
!
dev
->
qdev
.
hotplugged
)
{
scsi_bus_legacy_handle_cmdline
(
&
s
->
bus
);
return
scsi_bus_legacy_handle_cmdline
(
&
s
->
bus
);
}
return
0
;
}
...
...
hw/pc.c
浏览文件 @
734003e6
...
...
@@ -25,6 +25,7 @@
#include "pc.h"
#include "apic.h"
#include "fdc.h"
#include "ide.h"
#include "pci.h"
#include "vmware_vga.h"
#include "monitor.h"
...
...
@@ -275,14 +276,65 @@ static int pc_boot_set(void *opaque, const char *boot_device)
return
set_boot_dev
(
opaque
,
boot_device
,
0
);
}
/* hd_table must contain 4 block drivers */
typedef
struct
pc_cmos_init_late_arg
{
ISADevice
*
rtc_state
;
BusState
*
idebus0
,
*
idebus1
;
}
pc_cmos_init_late_arg
;
static
void
pc_cmos_init_late
(
void
*
opaque
)
{
pc_cmos_init_late_arg
*
arg
=
opaque
;
ISADevice
*
s
=
arg
->
rtc_state
;
int
val
;
BlockDriverState
*
hd_table
[
4
];
int
i
;
ide_get_bs
(
hd_table
,
arg
->
idebus0
);
ide_get_bs
(
hd_table
+
2
,
arg
->
idebus1
);
rtc_set_memory
(
s
,
0x12
,
(
hd_table
[
0
]
?
0xf0
:
0
)
|
(
hd_table
[
1
]
?
0x0f
:
0
));
if
(
hd_table
[
0
])
cmos_init_hd
(
0x19
,
0x1b
,
hd_table
[
0
],
s
);
if
(
hd_table
[
1
])
cmos_init_hd
(
0x1a
,
0x24
,
hd_table
[
1
],
s
);
val
=
0
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
if
(
hd_table
[
i
])
{
int
cylinders
,
heads
,
sectors
,
translation
;
/* NOTE: bdrv_get_geometry_hint() returns the physical
geometry. It is always such that: 1 <= sects <= 63, 1
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
geometry can be different if a translation is done. */
translation
=
bdrv_get_translation_hint
(
hd_table
[
i
]);
if
(
translation
==
BIOS_ATA_TRANSLATION_AUTO
)
{
bdrv_get_geometry_hint
(
hd_table
[
i
],
&
cylinders
,
&
heads
,
&
sectors
);
if
(
cylinders
<=
1024
&&
heads
<=
16
&&
sectors
<=
63
)
{
/* No translation. */
translation
=
0
;
}
else
{
/* LBA translation. */
translation
=
1
;
}
}
else
{
translation
--
;
}
val
|=
translation
<<
(
i
*
2
);
}
}
rtc_set_memory
(
s
,
0x39
,
val
);
qemu_unregister_reset
(
pc_cmos_init_late
,
opaque
);
}
void
pc_cmos_init
(
ram_addr_t
ram_size
,
ram_addr_t
above_4g_mem_size
,
const
char
*
boot_device
,
DriveInfo
**
hd_table
,
const
char
*
boot_device
,
BusState
*
idebus0
,
BusState
*
idebus1
,
FDCtrl
*
floppy_controller
,
ISADevice
*
s
)
{
int
val
;
int
fd0
,
fd1
,
nb
;
int
i
;
static
pc_cmos_init_late_arg
arg
;
/* various important CMOS locations needed by PC/Bochs bios */
...
...
@@ -351,38 +403,10 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
rtc_set_memory
(
s
,
REG_EQUIPMENT_BYTE
,
val
);
/* hard drives */
rtc_set_memory
(
s
,
0x12
,
(
hd_table
[
0
]
?
0xf0
:
0
)
|
(
hd_table
[
1
]
?
0x0f
:
0
));
if
(
hd_table
[
0
])
cmos_init_hd
(
0x19
,
0x1b
,
hd_table
[
0
]
->
bdrv
,
s
);
if
(
hd_table
[
1
])
cmos_init_hd
(
0x1a
,
0x24
,
hd_table
[
1
]
->
bdrv
,
s
);
val
=
0
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
if
(
hd_table
[
i
])
{
int
cylinders
,
heads
,
sectors
,
translation
;
/* NOTE: bdrv_get_geometry_hint() returns the physical
geometry. It is always such that: 1 <= sects <= 63, 1
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
geometry can be different if a translation is done. */
translation
=
bdrv_get_translation_hint
(
hd_table
[
i
]
->
bdrv
);
if
(
translation
==
BIOS_ATA_TRANSLATION_AUTO
)
{
bdrv_get_geometry_hint
(
hd_table
[
i
]
->
bdrv
,
&
cylinders
,
&
heads
,
&
sectors
);
if
(
cylinders
<=
1024
&&
heads
<=
16
&&
sectors
<=
63
)
{
/* No translation. */
translation
=
0
;
}
else
{
/* LBA translation. */
translation
=
1
;
}
}
else
{
translation
--
;
}
val
|=
translation
<<
(
i
*
2
);
}
}
rtc_set_memory
(
s
,
0x39
,
val
);
arg
.
rtc_state
=
s
;
arg
.
idebus0
=
idebus0
;
arg
.
idebus1
=
idebus1
;
qemu_register_reset
(
pc_cmos_init_late
,
&
arg
);
}
static
void
handle_a20_line_change
(
void
*
opaque
,
int
irq
,
int
level
)
...
...
hw/pc.h
浏览文件 @
734003e6
...
...
@@ -104,7 +104,8 @@ void pc_init_ne2k_isa(NICInfo *nd);
void
pc_audio_init
(
PCIBus
*
pci_bus
,
qemu_irq
*
pic
);
#endif
void
pc_cmos_init
(
ram_addr_t
ram_size
,
ram_addr_t
above_4g_mem_size
,
const
char
*
boot_device
,
DriveInfo
**
hd_table
,
const
char
*
boot_device
,
BusState
*
ide0
,
BusState
*
ide1
,
FDCtrl
*
floppy_controller
,
ISADevice
*
s
);
void
pc_pci_device_init
(
PCIBus
*
pci_bus
);
...
...
hw/pc_piix.c
浏览文件 @
734003e6
...
...
@@ -79,6 +79,7 @@ static void pc_init1(ram_addr_t ram_size,
IsaIrqState
*
isa_irq_state
;
DriveInfo
*
hd
[
MAX_IDE_BUS
*
MAX_IDE_DEVS
];
FDCtrl
*
floppy_controller
;
BusState
*
idebus
[
MAX_IDE_BUS
];
ISADevice
*
rtc_state
;
pc_cpus_init
(
cpu_model
);
...
...
@@ -132,18 +133,23 @@ static void pc_init1(ram_addr_t ram_size,
}
if
(
pci_enabled
)
{
pci_piix3_ide_init
(
pci_bus
,
hd
,
piix3_devfn
+
1
);
PCIDevice
*
dev
;
dev
=
pci_piix3_ide_init
(
pci_bus
,
hd
,
piix3_devfn
+
1
);
idebus
[
0
]
=
qdev_get_child_bus
(
&
dev
->
qdev
,
"ide.0"
);
idebus
[
1
]
=
qdev_get_child_bus
(
&
dev
->
qdev
,
"ide.1"
);
}
else
{
for
(
i
=
0
;
i
<
MAX_IDE_BUS
;
i
++
)
{
isa_ide_init
(
ide_iobase
[
i
],
ide_iobase2
[
i
],
ide_irq
[
i
],
hd
[
MAX_IDE_DEVS
*
i
],
hd
[
MAX_IDE_DEVS
*
i
+
1
]);
ISADevice
*
dev
;
dev
=
isa_ide_init
(
ide_iobase
[
i
],
ide_iobase2
[
i
],
ide_irq
[
i
],
hd
[
MAX_IDE_DEVS
*
i
],
hd
[
MAX_IDE_DEVS
*
i
+
1
]);
idebus
[
i
]
=
qdev_get_child_bus
(
&
dev
->
qdev
,
"ide.0"
);
}
}
pc_audio_init
(
pci_enabled
?
pci_bus
:
NULL
,
isa_irq
);
pc_cmos_init
(
below_4g_mem_size
,
above_4g_mem_size
,
boot_device
,
hd
,
floppy_controller
,
rtc_state
);
pc_cmos_init
(
below_4g_mem_size
,
above_4g_mem_size
,
boot_device
,
idebus
[
0
],
idebus
[
1
],
floppy_controller
,
rtc_state
);
if
(
pci_enabled
&&
usb_enabled
)
{
usb_uhci_piix3_init
(
pci_bus
,
piix3_devfn
+
2
);
...
...
hw/pci-hotplug.c
浏览文件 @
734003e6
...
...
@@ -89,7 +89,10 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
* specified).
*/
dinfo
->
unit
=
qemu_opt_get_number
(
dinfo
->
opts
,
"unit"
,
-
1
);
scsidev
=
scsi_bus_legacy_add_drive
(
scsibus
,
dinfo
,
dinfo
->
unit
);
scsidev
=
scsi_bus_legacy_add_drive
(
scsibus
,
dinfo
->
bdrv
,
dinfo
->
unit
);
if
(
!
scsidev
)
{
return
-
1
;
}
dinfo
->
unit
=
scsidev
->
id
;
if
(
printinfo
)
...
...
@@ -211,7 +214,11 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
return
NULL
;
}
dev
=
pci_create
(
bus
,
devfn
,
"virtio-blk-pci"
);
qdev_prop_set_drive
(
&
dev
->
qdev
,
"drive"
,
dinfo
);
if
(
qdev_prop_set_drive
(
&
dev
->
qdev
,
"drive"
,
dinfo
->
bdrv
)
<
0
)
{
qdev_free
(
&
dev
->
qdev
);
dev
=
NULL
;
break
;
}
if
(
qdev_init
(
&
dev
->
qdev
)
<
0
)
dev
=
NULL
;
break
;
...
...
hw/qdev-properties.c
浏览文件 @
734003e6
...
...
@@ -305,26 +305,42 @@ PropertyInfo qdev_prop_string = {
static
int
parse_drive
(
DeviceState
*
dev
,
Property
*
prop
,
const
char
*
str
)
{
DriveInfo
**
ptr
=
qdev_get_prop_ptr
(
dev
,
prop
);
BlockDriverState
**
ptr
=
qdev_get_prop_ptr
(
dev
,
prop
);
BlockDriverState
*
bs
;
*
ptr
=
drive_get_by_i
d
(
str
);
if
(
*
ptr
==
NULL
)
bs
=
bdrv_fin
d
(
str
);
if
(
bs
==
NULL
)
return
-
ENOENT
;
if
(
bdrv_attach
(
bs
,
dev
)
<
0
)
return
-
EEXIST
;
*
ptr
=
bs
;
return
0
;
}
static
void
free_drive
(
DeviceState
*
dev
,
Property
*
prop
)
{
BlockDriverState
**
ptr
=
qdev_get_prop_ptr
(
dev
,
prop
);
if
(
*
ptr
)
{
bdrv_detach
(
*
ptr
,
dev
);
blockdev_auto_del
(
*
ptr
);
}
}
static
int
print_drive
(
DeviceState
*
dev
,
Property
*
prop
,
char
*
dest
,
size_t
len
)
{
DriveInfo
**
ptr
=
qdev_get_prop_ptr
(
dev
,
prop
);
return
snprintf
(
dest
,
len
,
"%s"
,
(
*
ptr
)
?
(
*
ptr
)
->
id
:
"<null>"
);
BlockDriverState
**
ptr
=
qdev_get_prop_ptr
(
dev
,
prop
);
return
snprintf
(
dest
,
len
,
"%s"
,
*
ptr
?
bdrv_get_device_name
(
*
ptr
)
:
"<null>"
);
}
PropertyInfo
qdev_prop_drive
=
{
.
name
=
"drive"
,
.
type
=
PROP_TYPE_DRIVE
,
.
size
=
sizeof
(
DriveInfo
*
),
.
size
=
sizeof
(
BlockDriverState
*
),
.
parse
=
parse_drive
,
.
print
=
print_drive
,
.
free
=
free_drive
,
};
/* --- character device --- */
...
...
@@ -647,11 +663,28 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
qdev_prop_set
(
dev
,
name
,
&
value
,
PROP_TYPE_STRING
);
}
void
qdev_prop_set_drive
(
DeviceState
*
dev
,
const
char
*
name
,
DriveInfo
*
value
)
int
qdev_prop_set_drive
(
DeviceState
*
dev
,
const
char
*
name
,
BlockDriverState
*
value
)
{
int
res
;
res
=
bdrv_attach
(
value
,
dev
);
if
(
res
<
0
)
{
error_report
(
"Can't attach drive %s to %s.%s: %s"
,
bdrv_get_device_name
(
value
),
dev
->
id
?
dev
->
id
:
dev
->
info
->
name
,
name
,
strerror
(
-
res
));
return
-
1
;
}
qdev_prop_set
(
dev
,
name
,
&
value
,
PROP_TYPE_DRIVE
);
return
0
;
}
void
qdev_prop_set_drive_nofail
(
DeviceState
*
dev
,
const
char
*
name
,
BlockDriverState
*
value
)
{
if
(
qdev_prop_set_drive
(
dev
,
name
,
value
)
<
0
)
{
exit
(
1
);
}
}
void
qdev_prop_set_chr
(
DeviceState
*
dev
,
const
char
*
name
,
CharDriverState
*
value
)
{
qdev_prop_set
(
dev
,
name
,
&
value
,
PROP_TYPE_CHR
);
...
...
hw/qdev.h
浏览文件 @
734003e6
...
...
@@ -253,8 +253,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, VLANClientState*)
#define DEFINE_PROP_VLAN(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, VLANState*)
#define DEFINE_PROP_DRIVE(_n, _s, _f)
\
DEFINE_PROP(_n, _s, _f, qdev_prop_drive,
DriveInfo
*)
#define DEFINE_PROP_DRIVE(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_drive,
BlockDriverState
*)
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
...
...
@@ -275,7 +275,8 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, char *value);
void
qdev_prop_set_chr
(
DeviceState
*
dev
,
const
char
*
name
,
CharDriverState
*
value
);
void
qdev_prop_set_netdev
(
DeviceState
*
dev
,
const
char
*
name
,
VLANClientState
*
value
);
void
qdev_prop_set_vlan
(
DeviceState
*
dev
,
const
char
*
name
,
VLANState
*
value
);
void
qdev_prop_set_drive
(
DeviceState
*
dev
,
const
char
*
name
,
DriveInfo
*
value
);
int
qdev_prop_set_drive
(
DeviceState
*
dev
,
const
char
*
name
,
BlockDriverState
*
value
)
QEMU_WARN_UNUSED_RESULT
;
void
qdev_prop_set_drive_nofail
(
DeviceState
*
dev
,
const
char
*
name
,
BlockDriverState
*
value
);
void
qdev_prop_set_macaddr
(
DeviceState
*
dev
,
const
char
*
name
,
uint8_t
*
value
);
/* FIXME: Remove opaque pointer properties. */
void
qdev_prop_set_ptr
(
DeviceState
*
dev
,
const
char
*
name
,
void
*
value
);
...
...
hw/s390-virtio.c
浏览文件 @
734003e6
...
...
@@ -262,7 +262,7 @@ static void s390_init(ram_addr_t ram_size,
}
dev
=
qdev_create
((
BusState
*
)
s390_bus
,
"virtio-blk-s390"
);
qdev_prop_set_drive
(
dev
,
"drive"
,
dinfo
);
qdev_prop_set_drive
_nofail
(
dev
,
"drive"
,
dinfo
->
bdrv
);
qdev_init_nofail
(
dev
);
}
}
...
...
hw/scsi-bus.c
浏览文件 @
734003e6
...
...
@@ -83,33 +83,39 @@ void scsi_qdev_register(SCSIDeviceInfo *info)
}
/* handle legacy '-drive if=scsi,...' cmd line args */
/* FIXME callers should check for failure, but don't */
SCSIDevice
*
scsi_bus_legacy_add_drive
(
SCSIBus
*
bus
,
DriveInfo
*
dinfo
,
int
unit
)
SCSIDevice
*
scsi_bus_legacy_add_drive
(
SCSIBus
*
bus
,
BlockDriverState
*
bdrv
,
int
unit
)
{
const
char
*
driver
;
DeviceState
*
dev
;
driver
=
bdrv_is_sg
(
dinfo
->
bdrv
)
?
"scsi-generic"
:
"scsi-disk"
;
driver
=
bdrv_is_sg
(
bdrv
)
?
"scsi-generic"
:
"scsi-disk"
;
dev
=
qdev_create
(
&
bus
->
qbus
,
driver
);
qdev_prop_set_uint32
(
dev
,
"scsi-id"
,
unit
);
qdev_prop_set_drive
(
dev
,
"drive"
,
dinfo
);
if
(
qdev_prop_set_drive
(
dev
,
"drive"
,
bdrv
)
<
0
)
{
qdev_free
(
dev
);
return
NULL
;
}
if
(
qdev_init
(
dev
)
<
0
)
return
NULL
;
return
DO_UPCAST
(
SCSIDevice
,
qdev
,
dev
);
}
void
scsi_bus_legacy_handle_cmdline
(
SCSIBus
*
bus
)
int
scsi_bus_legacy_handle_cmdline
(
SCSIBus
*
bus
)
{
DriveInfo
*
dinfo
;
int
unit
;
int
res
=
0
,
unit
;
for
(
unit
=
0
;
unit
<
MAX_SCSI_DEVS
;
unit
++
)
{
dinfo
=
drive_get
(
IF_SCSI
,
bus
->
busnr
,
unit
);
if
(
dinfo
==
NULL
)
{
continue
;
}
scsi_bus_legacy_add_drive
(
bus
,
dinfo
,
unit
);
if
(
!
scsi_bus_legacy_add_drive
(
bus
,
dinfo
->
bdrv
,
unit
))
{
res
=
-
1
;
break
;
}
}
return
res
;
}
void
scsi_dev_clear_sense
(
SCSIDevice
*
dev
)
...
...
hw/scsi-disk.c
浏览文件 @
734003e6
...
...
@@ -1043,26 +1043,26 @@ static void scsi_destroy(SCSIDevice *dev)
SCSIDiskState
*
s
=
DO_UPCAST
(
SCSIDiskState
,
qdev
,
dev
);
scsi_disk_purge_requests
(
s
);
drive_uninit
(
s
->
qdev
.
conf
.
dinfo
);
blockdev_mark_auto_del
(
s
->
qdev
.
conf
.
bs
);
}
static
int
scsi_disk_initfn
(
SCSIDevice
*
dev
)
{
SCSIDiskState
*
s
=
DO_UPCAST
(
SCSIDiskState
,
qdev
,
dev
);
int
is_cd
;
DriveInfo
*
dinfo
;
if
(
!
s
->
qdev
.
conf
.
dinfo
||
!
s
->
qdev
.
conf
.
dinfo
->
bdrv
)
{
if
(
!
s
->
qdev
.
conf
.
bs
)
{
error_report
(
"scsi-disk: drive property not set"
);
return
-
1
;
}
s
->
bs
=
s
->
qdev
.
conf
.
dinfo
->
bdrv
;
s
->
bs
=
s
->
qdev
.
conf
.
bs
;
is_cd
=
bdrv_get_type_hint
(
s
->
bs
)
==
BDRV_TYPE_CDROM
;
if
(
!
s
->
serial
)
{
if
(
*
dev
->
conf
.
dinfo
->
serial
)
{
/* try to fall back to value set with legacy -drive serial=... */
s
->
serial
=
qemu_strdup
(
dev
->
conf
.
dinfo
->
serial
);
}
else
{
s
->
serial
=
qemu_strdup
(
"0"
);
}
/* try to fall back to value set with legacy -drive serial=... */
dinfo
=
drive_get_by_blockdev
(
s
->
bs
);
s
->
serial
=
qemu_strdup
(
*
dinfo
->
serial
?
dinfo
->
serial
:
"0"
);
}
if
(
!
s
->
version
)
{
...
...
@@ -1074,7 +1074,7 @@ static int scsi_disk_initfn(SCSIDevice *dev)
return
-
1
;
}
if
(
bdrv_get_type_hint
(
s
->
bs
)
==
BDRV_TYPE_CDROM
)
{
if
(
is_cd
)
{
s
->
qdev
.
blocksize
=
2048
;
}
else
{
s
->
qdev
.
blocksize
=
s
->
qdev
.
conf
.
logical_block_size
;
...
...
@@ -1083,6 +1083,7 @@ static int scsi_disk_initfn(SCSIDevice *dev)
s
->
qdev
.
type
=
TYPE_DISK
;
qemu_add_vm_change_state_handler
(
scsi_dma_restart_cb
,
s
);
bdrv_set_removable
(
s
->
bs
,
is_cd
);
return
0
;
}
...
...
hw/scsi-generic.c
浏览文件 @
734003e6
...
...
@@ -453,7 +453,7 @@ static void scsi_destroy(SCSIDevice *d)
r
=
DO_UPCAST
(
SCSIGenericReq
,
req
,
QTAILQ_FIRST
(
&
s
->
qdev
.
requests
));
scsi_remove_request
(
r
);
}
drive_uninit
(
s
->
qdev
.
conf
.
dinfo
);
blockdev_mark_auto_del
(
s
->
qdev
.
conf
.
bs
);
}
static
int
scsi_generic_initfn
(
SCSIDevice
*
dev
)
...
...
@@ -462,11 +462,11 @@ static int scsi_generic_initfn(SCSIDevice *dev)
int
sg_version
;
struct
sg_scsi_id
scsiid
;
if
(
!
s
->
qdev
.
conf
.
dinfo
||
!
s
->
qdev
.
conf
.
dinfo
->
bdrv
)
{
if
(
!
s
->
qdev
.
conf
.
bs
)
{
error_report
(
"scsi-generic: drive property not set"
);
return
-
1
;
}
s
->
bs
=
s
->
qdev
.
conf
.
dinfo
->
bdrv
;
s
->
bs
=
s
->
qdev
.
conf
.
bs
;
/* check we are really using a /dev/sg* file */
if
(
!
bdrv_is_sg
(
s
->
bs
))
{
...
...
@@ -509,6 +509,7 @@ static int scsi_generic_initfn(SCSIDevice *dev)
DPRINTF
(
"block size %d
\n
"
,
s
->
qdev
.
blocksize
);
s
->
driver_status
=
0
;
memset
(
s
->
sensebuf
,
0
,
sizeof
(
s
->
sensebuf
));
bdrv_set_removable
(
s
->
bs
,
0
);
return
0
;
}
...
...
hw/scsi.h
浏览文件 @
734003e6
...
...
@@ -97,8 +97,8 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
return
DO_UPCAST
(
SCSIBus
,
qbus
,
d
->
qdev
.
parent_bus
);
}
SCSIDevice
*
scsi_bus_legacy_add_drive
(
SCSIBus
*
bus
,
DriveInfo
*
dinfo
,
int
unit
);
void
scsi_bus_legacy_handle_cmdline
(
SCSIBus
*
bus
);
SCSIDevice
*
scsi_bus_legacy_add_drive
(
SCSIBus
*
bus
,
BlockDriverState
*
bdrv
,
int
unit
);
int
scsi_bus_legacy_handle_cmdline
(
SCSIBus
*
bus
);
void
scsi_dev_clear_sense
(
SCSIDevice
*
dev
);
void
scsi_dev_set_sense
(
SCSIDevice
*
dev
,
uint8_t
key
);
...
...
hw/usb-msd.c
浏览文件 @
734003e6
...
...
@@ -522,22 +522,37 @@ static void usb_msd_password_cb(void *opaque, int err)
static
int
usb_msd_initfn
(
USBDevice
*
dev
)
{
MSDState
*
s
=
DO_UPCAST
(
MSDState
,
dev
,
dev
);
BlockDriverState
*
bs
=
s
->
conf
.
bs
;
if
(
!
s
->
conf
.
dinfo
||
!
s
->
conf
.
dinfo
->
bdrv
)
{
if
(
!
bs
)
{
error_report
(
"usb-msd: drive property not set"
);
return
-
1
;
}
/*
* Hack alert: this pretends to be a block device, but it's really
* a SCSI bus that can serve only a single device, which it
* creates automatically. But first it needs to detach from its
* blockdev, or else scsi_bus_legacy_add_drive() dies when it
* attaches again.
*
* The hack is probably a bad idea.
*/
bdrv_detach
(
bs
,
&
s
->
dev
.
qdev
);
s
->
conf
.
bs
=
NULL
;
s
->
dev
.
speed
=
USB_SPEED_FULL
;
scsi_bus_new
(
&
s
->
bus
,
&
s
->
dev
.
qdev
,
0
,
1
,
usb_msd_command_complete
);
s
->
scsi_dev
=
scsi_bus_legacy_add_drive
(
&
s
->
bus
,
s
->
conf
.
dinfo
,
0
);
s
->
scsi_dev
=
scsi_bus_legacy_add_drive
(
&
s
->
bus
,
bs
,
0
);
if
(
!
s
->
scsi_dev
)
{
return
-
1
;
}
s
->
bus
.
qbus
.
allow_hotplug
=
0
;
usb_msd_handle_reset
(
dev
);
if
(
bdrv_key_required
(
s
->
conf
.
dinfo
->
bdrv
))
{
if
(
bdrv_key_required
(
bs
))
{
if
(
cur_mon
)
{
monitor_read_bdrv_key_start
(
cur_mon
,
s
->
conf
.
dinfo
->
bdrv
,
usb_msd_password_cb
,
s
);
monitor_read_bdrv_key_start
(
cur_mon
,
bs
,
usb_msd_password_cb
,
s
);
s
->
dev
.
auto_attach
=
0
;
}
else
{
autostart
=
0
;
...
...
@@ -595,7 +610,10 @@ static USBDevice *usb_msd_init(const char *filename)
if
(
!
dev
)
{
return
NULL
;
}
qdev_prop_set_drive
(
&
dev
->
qdev
,
"drive"
,
dinfo
);
if
(
qdev_prop_set_drive
(
&
dev
->
qdev
,
"drive"
,
dinfo
->
bdrv
)
<
0
)
{
qdev_free
(
&
dev
->
qdev
);
return
NULL
;
}
if
(
qdev_init
(
&
dev
->
qdev
)
<
0
)
return
NULL
;
...
...
hw/virtio-blk.c
浏览文件 @
734003e6
...
...
@@ -489,7 +489,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
s
->
vdev
.
get_config
=
virtio_blk_update_config
;
s
->
vdev
.
get_features
=
virtio_blk_get_features
;
s
->
vdev
.
reset
=
virtio_blk_reset
;
s
->
bs
=
conf
->
dinfo
->
bdrv
;
s
->
bs
=
conf
->
bs
;
s
->
conf
=
conf
;
s
->
rq
=
NULL
;
s
->
sector_mask
=
(
s
->
conf
->
logical_block_size
/
BDRV_SECTOR_SIZE
)
-
1
;
...
...
@@ -500,6 +500,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
qemu_add_vm_change_state_handler
(
virtio_blk_dma_restart_cb
,
s
);
register_savevm
(
"virtio-blk"
,
virtio_blk_id
++
,
2
,
virtio_blk_save
,
virtio_blk_load
,
s
);
bdrv_set_removable
(
s
->
bs
,
0
);
return
&
s
->
vdev
;
}
hw/virtio-pci.c
浏览文件 @
734003e6
...
...
@@ -547,7 +547,7 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
proxy
->
class_code
!=
PCI_CLASS_STORAGE_OTHER
)
proxy
->
class_code
=
PCI_CLASS_STORAGE_SCSI
;
if
(
!
proxy
->
block
.
dinfo
)
{
if
(
!
proxy
->
block
.
bs
)
{
error_report
(
"virtio-blk-pci: drive property not set"
);
return
-
1
;
}
...
...
@@ -571,7 +571,7 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy
*
proxy
=
DO_UPCAST
(
VirtIOPCIProxy
,
pci_dev
,
pci_dev
);
drive_uninit
(
proxy
->
block
.
dinfo
);
blockdev_mark_auto_del
(
proxy
->
block
.
bs
);
return
virtio_exit_pci
(
pci_dev
);
}
...
...
qemu-img.c
浏览文件 @
734003e6
...
...
@@ -39,14 +39,13 @@ typedef struct img_cmd_t {
/* Default to cache=writeback as data integrity is not important for qemu-tcg. */
#define BDRV_O_FLAGS BDRV_O_CACHE_WB
static
void
QEMU_NORETURN
error
(
const
char
*
fmt
,
...)
static
void
error
(
const
char
*
fmt
,
...)
{
va_list
ap
;
va_start
(
ap
,
fmt
);
fprintf
(
stderr
,
"qemu-img: "
);
vfprintf
(
stderr
,
fmt
,
ap
);
fprintf
(
stderr
,
"
\n
"
);
exit
(
1
);
va_end
(
ap
);
}
...
...
@@ -197,57 +196,76 @@ static BlockDriverState *bdrv_new_open(const char *filename,
char
password
[
256
];
bs
=
bdrv_new
(
""
);
if
(
!
bs
)
if
(
!
bs
)
{
error
(
"Not enough memory"
);
goto
fail
;
}
if
(
fmt
)
{
drv
=
bdrv_find_format
(
fmt
);
if
(
!
drv
)
if
(
!
drv
)
{
error
(
"Unknown file format '%s'"
,
fmt
);
goto
fail
;
}
}
else
{
drv
=
NULL
;
}
if
(
bdrv_open
(
bs
,
filename
,
flags
,
drv
)
<
0
)
{
error
(
"Could not open '%s'"
,
filename
);
goto
fail
;
}
if
(
bdrv_is_encrypted
(
bs
))
{
printf
(
"Disk image '%s' is encrypted.
\n
"
,
filename
);
if
(
read_password
(
password
,
sizeof
(
password
))
<
0
)
if
(
read_password
(
password
,
sizeof
(
password
))
<
0
)
{
error
(
"No password given"
);
if
(
bdrv_set_key
(
bs
,
password
)
<
0
)
goto
fail
;
}
if
(
bdrv_set_key
(
bs
,
password
)
<
0
)
{
error
(
"invalid password"
);
goto
fail
;
}
}
return
bs
;
fail:
if
(
bs
)
{
bdrv_delete
(
bs
);
}
return
NULL
;
}
static
void
add_old_style_options
(
const
char
*
fmt
,
QEMUOptionParameter
*
list
,
static
int
add_old_style_options
(
const
char
*
fmt
,
QEMUOptionParameter
*
list
,
int
flags
,
const
char
*
base_filename
,
const
char
*
base_fmt
)
{
if
(
flags
&
BLOCK_FLAG_ENCRYPT
)
{
if
(
set_option_parameter
(
list
,
BLOCK_OPT_ENCRYPT
,
"on"
))
{
error
(
"Encryption not supported for file format '%s'"
,
fmt
);
return
-
1
;
}
}
if
(
flags
&
BLOCK_FLAG_COMPAT6
)
{
if
(
set_option_parameter
(
list
,
BLOCK_OPT_COMPAT6
,
"on"
))
{
error
(
"VMDK version 6 not supported for file format '%s'"
,
fmt
);
return
-
1
;
}
}
if
(
base_filename
)
{
if
(
set_option_parameter
(
list
,
BLOCK_OPT_BACKING_FILE
,
base_filename
))
{
error
(
"Backing file not supported for file format '%s'"
,
fmt
);
return
-
1
;
}
}
if
(
base_fmt
)
{
if
(
set_option_parameter
(
list
,
BLOCK_OPT_BACKING_FMT
,
base_fmt
))
{
error
(
"Backing file format not supported for file format '%s'"
,
fmt
);
return
-
1
;
}
}
return
0
;
}
static
int
img_create
(
int
argc
,
char
**
argv
)
{
int
c
,
ret
,
flags
;
int
c
,
ret
=
0
,
flags
;
const
char
*
fmt
=
"raw"
;
const
char
*
base_fmt
=
NULL
;
const
char
*
filename
;
...
...
@@ -293,12 +311,16 @@ static int img_create(int argc, char **argv)
/* Find driver and parse its options */
drv
=
bdrv_find_format
(
fmt
);
if
(
!
drv
)
if
(
!
drv
)
{
error
(
"Unknown file format '%s'"
,
fmt
);
return
1
;
}
proto_drv
=
bdrv_find_protocol
(
filename
);
if
(
!
proto_drv
)
if
(
!
proto_drv
)
{
error
(
"Unknown protocol '%s'"
,
filename
);
return
1
;
}
create_options
=
append_option_parameters
(
create_options
,
drv
->
create_options
);
...
...
@@ -307,7 +329,7 @@ static int img_create(int argc, char **argv)
if
(
options
&&
!
strcmp
(
options
,
"?"
))
{
print_option_help
(
create_options
);
return
0
;
goto
out
;
}
/* Create parameter list with default values */
...
...
@@ -319,6 +341,8 @@ static int img_create(int argc, char **argv)
param
=
parse_option_parameters
(
options
,
create_options
,
param
);
if
(
param
==
NULL
)
{
error
(
"Invalid options for file format '%s'."
,
fmt
);
ret
=
-
1
;
goto
out
;
}
}
...
...
@@ -328,7 +352,10 @@ static int img_create(int argc, char **argv)
}
/* Add old-style options to parameters */
add_old_style_options
(
fmt
,
param
,
flags
,
base_filename
,
base_fmt
);
ret
=
add_old_style_options
(
fmt
,
param
,
flags
,
base_filename
,
base_fmt
);
if
(
ret
<
0
)
{
goto
out
;
}
// The size for the image must always be specified, with one exception:
// If we are using a backing file, we can obtain the size from there
...
...
@@ -351,10 +378,16 @@ static int img_create(int argc, char **argv)
}
else
{
error
(
"Unknown backing file format '%s'"
,
backing_fmt
->
value
.
s
);
ret
=
-
1
;
goto
out
;
}
}
bs
=
bdrv_new_open
(
backing_file
->
value
.
s
,
fmt
,
BDRV_O_FLAGS
);
if
(
!
bs
)
{
ret
=
-
1
;
goto
out
;
}
bdrv_get_geometry
(
bs
,
&
size
);
size
*=
512
;
bdrv_delete
(
bs
);
...
...
@@ -363,6 +396,8 @@ static int img_create(int argc, char **argv)
set_option_parameter
(
param
,
BLOCK_OPT_SIZE
,
buf
);
}
else
{
error
(
"Image creation needs a size parameter"
);
ret
=
-
1
;
goto
out
;
}
}
...
...
@@ -383,6 +418,10 @@ static int img_create(int argc, char **argv)
error
(
"%s: error while creating %s: %s"
,
filename
,
fmt
,
strerror
(
-
ret
));
}
}
out:
if
(
ret
)
{
return
1
;
}
return
0
;
}
...
...
@@ -411,6 +450,9 @@ static int img_check(int argc, char **argv)
filename
=
argv
[
optind
++
];
bs
=
bdrv_new_open
(
filename
,
fmt
,
BDRV_O_FLAGS
);
if
(
!
bs
)
{
return
1
;
}
ret
=
bdrv_check
(
bs
);
switch
(
ret
)
{
case
0
:
...
...
@@ -429,6 +471,9 @@ static int img_check(int argc, char **argv)
}
bdrv_delete
(
bs
);
if
(
ret
)
{
return
1
;
}
return
0
;
}
...
...
@@ -457,6 +502,9 @@ static int img_commit(int argc, char **argv)
filename
=
argv
[
optind
++
];
bs
=
bdrv_new_open
(
filename
,
fmt
,
BDRV_O_FLAGS
|
BDRV_O_RDWR
);
if
(
!
bs
)
{
return
1
;
}
ret
=
bdrv_commit
(
bs
);
switch
(
ret
)
{
case
0
:
...
...
@@ -477,6 +525,9 @@ static int img_commit(int argc, char **argv)
}
bdrv_delete
(
bs
);
if
(
ret
)
{
return
1
;
}
return
0
;
}
...
...
@@ -551,13 +602,13 @@ static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
static
int
img_convert
(
int
argc
,
char
**
argv
)
{
int
c
,
ret
,
n
,
n1
,
bs_n
,
bs_i
,
flags
,
cluster_size
,
cluster_sectors
;
int
c
,
ret
=
0
,
n
,
n1
,
bs_n
,
bs_i
,
flags
,
cluster_size
,
cluster_sectors
;
const
char
*
fmt
,
*
out_fmt
,
*
out_baseimg
,
*
out_filename
;
BlockDriver
*
drv
,
*
proto_drv
;
BlockDriverState
**
bs
,
*
out_bs
;
BlockDriverState
**
bs
=
NULL
,
*
out_bs
=
NULL
;
int64_t
total_sectors
,
nb_sectors
,
sector_num
,
bs_offset
;
uint64_t
bs_sectors
;
uint8_t
*
buf
;
uint8_t
*
buf
=
NULL
;
const
uint8_t
*
buf1
;
BlockDriverInfo
bdi
;
QEMUOptionParameter
*
param
=
NULL
,
*
create_options
=
NULL
;
...
...
@@ -604,30 +655,43 @@ static int img_convert(int argc, char **argv)
out_filename
=
argv
[
argc
-
1
];
if
(
bs_n
>
1
&&
out_baseimg
)
if
(
bs_n
>
1
&&
out_baseimg
)
{
error
(
"-B makes no sense when concatenating multiple input images"
);
return
1
;
}
bs
=
calloc
(
bs_n
,
sizeof
(
BlockDriverState
*
));
if
(
!
bs
)
if
(
!
bs
)
{
error
(
"Out of memory"
);
return
1
;
}
total_sectors
=
0
;
for
(
bs_i
=
0
;
bs_i
<
bs_n
;
bs_i
++
)
{
bs
[
bs_i
]
=
bdrv_new_open
(
argv
[
optind
+
bs_i
],
fmt
,
BDRV_O_FLAGS
);
if
(
!
bs
[
bs_i
])
if
(
!
bs
[
bs_i
])
{
error
(
"Could not open '%s'"
,
argv
[
optind
+
bs_i
]);
ret
=
-
1
;
goto
out
;
}
bdrv_get_geometry
(
bs
[
bs_i
],
&
bs_sectors
);
total_sectors
+=
bs_sectors
;
}
/* Find driver and parse its options */
drv
=
bdrv_find_format
(
out_fmt
);
if
(
!
drv
)
if
(
!
drv
)
{
error
(
"Unknown file format '%s'"
,
out_fmt
);
ret
=
-
1
;
goto
out
;
}
proto_drv
=
bdrv_find_protocol
(
out_filename
);
if
(
!
proto_drv
)
if
(
!
proto_drv
)
{
error
(
"Unknown protocol '%s'"
,
out_filename
);
ret
=
-
1
;
goto
out
;
}
create_options
=
append_option_parameters
(
create_options
,
drv
->
create_options
);
...
...
@@ -635,21 +699,25 @@ static int img_convert(int argc, char **argv)
proto_drv
->
create_options
);
if
(
options
&&
!
strcmp
(
options
,
"?"
))
{
print_option_help
(
create_options
);
free
(
bs
);
return
0
;
goto
out
;
}
if
(
options
)
{
param
=
parse_option_parameters
(
options
,
create_options
,
param
);
if
(
param
==
NULL
)
{
error
(
"Invalid options for file format '%s'."
,
out_fmt
);
ret
=
-
1
;
goto
out
;
}
}
else
{
param
=
parse_option_parameters
(
""
,
create_options
,
param
);
}
set_option_parameter_int
(
param
,
BLOCK_OPT_SIZE
,
total_sectors
*
512
);
add_old_style_options
(
out_fmt
,
param
,
flags
,
out_baseimg
,
NULL
);
ret
=
add_old_style_options
(
out_fmt
,
param
,
flags
,
out_baseimg
,
NULL
);
if
(
ret
<
0
)
{
goto
out
;
}
/* Check if compression is supported */
if
(
flags
&
BLOCK_FLAG_COMPRESS
)
{
...
...
@@ -658,18 +726,19 @@ static int img_convert(int argc, char **argv)
if
(
!
drv
->
bdrv_write_compressed
)
{
error
(
"Compression not supported for this file format"
);
ret
=
-
1
;
goto
out
;
}
if
(
encryption
&&
encryption
->
value
.
n
)
{
error
(
"Compression and encryption not supported at the same time"
);
ret
=
-
1
;
goto
out
;
}
}
/* Create the new image */
ret
=
bdrv_create
(
drv
,
out_filename
,
param
);
free_option_parameters
(
create_options
);
free_option_parameters
(
param
);
if
(
ret
<
0
)
{
if
(
ret
==
-
ENOTSUP
)
{
error
(
"Formatting not supported for file format '%s'"
,
out_fmt
);
...
...
@@ -678,9 +747,14 @@ static int img_convert(int argc, char **argv)
}
else
{
error
(
"%s: error while converting %s: %s"
,
out_filename
,
out_fmt
,
strerror
(
-
ret
));
}
goto
out
;
}
out_bs
=
bdrv_new_open
(
out_filename
,
out_fmt
,
BDRV_O_FLAGS
|
BDRV_O_RDWR
);
if
(
!
out_bs
)
{
ret
=
-
1
;
goto
out
;
}
bs_i
=
0
;
bs_offset
=
0
;
...
...
@@ -688,11 +762,17 @@ static int img_convert(int argc, char **argv)
buf
=
qemu_malloc
(
IO_BUF_SIZE
);
if
(
flags
&
BLOCK_FLAG_COMPRESS
)
{
if
(
bdrv_get_info
(
out_bs
,
&
bdi
)
<
0
)
ret
=
bdrv_get_info
(
out_bs
,
&
bdi
);
if
(
ret
<
0
)
{
error
(
"could not get block driver info"
);
goto
out
;
}
cluster_size
=
bdi
.
cluster_size
;
if
(
cluster_size
<=
0
||
cluster_size
>
IO_BUF_SIZE
)
if
(
cluster_size
<=
0
||
cluster_size
>
IO_BUF_SIZE
)
{
error
(
"invalid cluster size"
);
ret
=
-
1
;
goto
out
;
}
cluster_sectors
=
cluster_size
>>
9
;
sector_num
=
0
;
for
(;;)
{
...
...
@@ -728,8 +808,11 @@ static int img_convert(int argc, char **argv)
nlow
=
(
remainder
>
bs_sectors
-
bs_num
)
?
bs_sectors
-
bs_num
:
remainder
;
if
(
bdrv_read
(
bs
[
bs_i
],
bs_num
,
buf2
,
nlow
)
<
0
)
ret
=
bdrv_read
(
bs
[
bs_i
],
bs_num
,
buf2
,
nlow
);
if
(
ret
<
0
)
{
error
(
"error while reading"
);
goto
out
;
}
buf2
+=
nlow
*
512
;
bs_num
+=
nlow
;
...
...
@@ -741,10 +824,13 @@ static int img_convert(int argc, char **argv)
if
(
n
<
cluster_sectors
)
memset
(
buf
+
n
*
512
,
0
,
cluster_size
-
n
*
512
);
if
(
is_not_zero
(
buf
,
cluster_size
))
{
if
(
bdrv_write_compressed
(
out_bs
,
sector_num
,
buf
,
cluster_sectors
)
!=
0
)
ret
=
bdrv_write_compressed
(
out_bs
,
sector_num
,
buf
,
cluster_sectors
);
if
(
ret
!=
0
)
{
error
(
"error while compressing sector %"
PRId64
,
sector_num
);
goto
out
;
}
}
sector_num
+=
n
;
}
...
...
@@ -795,8 +881,11 @@ static int img_convert(int argc, char **argv)
n1
=
n
;
}
if
(
bdrv_read
(
bs
[
bs_i
],
sector_num
-
bs_offset
,
buf
,
n
)
<
0
)
ret
=
bdrv_read
(
bs
[
bs_i
],
sector_num
-
bs_offset
,
buf
,
n
);
if
(
ret
<
0
)
{
error
(
"error while reading"
);
goto
out
;
}
/* NOTE: at the same time we convert, we do not write zero
sectors to have a chance to compress the image. Ideally, we
should add a specific call to have the info to go faster */
...
...
@@ -811,8 +900,11 @@ static int img_convert(int argc, char **argv)
already there is garbage, not 0s. */
if
(
!
has_zero_init
||
out_baseimg
||
is_allocated_sectors
(
buf1
,
n
,
&
n1
))
{
if
(
bdrv_write
(
out_bs
,
sector_num
,
buf1
,
n1
)
<
0
)
ret
=
bdrv_write
(
out_bs
,
sector_num
,
buf1
,
n1
);
if
(
ret
<
0
)
{
error
(
"error while writing"
);
goto
out
;
}
}
sector_num
+=
n1
;
n
-=
n1
;
...
...
@@ -820,11 +912,22 @@ static int img_convert(int argc, char **argv)
}
}
}
out:
free_option_parameters
(
create_options
);
free_option_parameters
(
param
);
qemu_free
(
buf
);
bdrv_delete
(
out_bs
);
for
(
bs_i
=
0
;
bs_i
<
bs_n
;
bs_i
++
)
bdrv_delete
(
bs
[
bs_i
]);
if
(
out_bs
)
{
bdrv_delete
(
out_bs
);
}
for
(
bs_i
=
0
;
bs_i
<
bs_n
;
bs_i
++
)
{
if
(
bs
[
bs_i
])
{
bdrv_delete
(
bs
[
bs_i
]);
}
}
free
(
bs
);
if
(
ret
)
{
return
1
;
}
return
0
;
}
...
...
@@ -907,6 +1010,9 @@ static int img_info(int argc, char **argv)
filename
=
argv
[
optind
++
];
bs
=
bdrv_new_open
(
filename
,
fmt
,
BDRV_O_FLAGS
|
BDRV_O_NO_BACKING
);
if
(
!
bs
)
{
return
1
;
}
bdrv_get_format
(
bs
,
fmt_name
,
sizeof
(
fmt_name
));
bdrv_get_geometry
(
bs
,
&
total_sectors
);
get_human_readable_size
(
size_buf
,
sizeof
(
size_buf
),
total_sectors
*
512
);
...
...
@@ -952,7 +1058,7 @@ static int img_snapshot(int argc, char **argv)
BlockDriverState
*
bs
;
QEMUSnapshotInfo
sn
;
char
*
filename
,
*
snapshot_name
=
NULL
;
int
c
,
ret
,
bdrv_oflags
;
int
c
,
ret
=
0
,
bdrv_oflags
;
int
action
=
0
;
qemu_timeval
tv
;
...
...
@@ -1007,6 +1113,9 @@ static int img_snapshot(int argc, char **argv)
/* Open the image */
bs
=
bdrv_new_open
(
filename
,
NULL
,
bdrv_oflags
);
if
(
!
bs
)
{
return
1
;
}
/* Perform the requested action */
switch
(
action
)
{
...
...
@@ -1045,13 +1154,15 @@ static int img_snapshot(int argc, char **argv)
/* Cleanup */
bdrv_delete
(
bs
);
if
(
ret
)
{
return
1
;
}
return
0
;
}
static
int
img_rebase
(
int
argc
,
char
**
argv
)
{
BlockDriverState
*
bs
,
*
bs_old_backing
,
*
bs_new_backing
;
BlockDriverState
*
bs
,
*
bs_old_backing
=
NULL
,
*
bs_new_backing
=
NULL
;
BlockDriver
*
old_backing_drv
,
*
new_backing_drv
;
char
*
filename
;
const
char
*
fmt
,
*
out_basefmt
,
*
out_baseimg
;
...
...
@@ -1098,6 +1209,9 @@ static int img_rebase(int argc, char **argv)
*/
flags
=
BDRV_O_FLAGS
|
BDRV_O_RDWR
|
(
unsafe
?
BDRV_O_NO_BACKING
:
0
);
bs
=
bdrv_new_open
(
filename
,
fmt
,
flags
);
if
(
!
bs
)
{
return
1
;
}
/* Find the right drivers for the backing files */
old_backing_drv
=
NULL
;
...
...
@@ -1107,6 +1221,8 @@ static int img_rebase(int argc, char **argv)
old_backing_drv
=
bdrv_find_format
(
bs
->
backing_format
);
if
(
old_backing_drv
==
NULL
)
{
error
(
"Invalid format name: '%s'"
,
bs
->
backing_format
);
ret
=
-
1
;
goto
out
;
}
}
...
...
@@ -1114,6 +1230,8 @@ static int img_rebase(int argc, char **argv)
new_backing_drv
=
bdrv_find_format
(
out_basefmt
);
if
(
new_backing_drv
==
NULL
)
{
error
(
"Invalid format name: '%s'"
,
out_basefmt
);
ret
=
-
1
;
goto
out
;
}
}
...
...
@@ -1127,19 +1245,19 @@ static int img_rebase(int argc, char **argv)
bs_old_backing
=
bdrv_new
(
"old_backing"
);
bdrv_get_backing_filename
(
bs
,
backing_name
,
sizeof
(
backing_name
));
if
(
bdrv_open
(
bs_old_backing
,
backing_name
,
BDRV_O_FLAGS
,
old_backing_drv
))
{
ret
=
bdrv_open
(
bs_old_backing
,
backing_name
,
BDRV_O_FLAGS
,
old_backing_drv
);
if
(
ret
)
{
error
(
"Could not open old backing file '%s'"
,
backing_name
);
return
-
1
;
goto
out
;
}
bs_new_backing
=
bdrv_new
(
"new_backing"
);
if
(
bdrv_open
(
bs_new_backing
,
out_baseimg
,
BDRV_O_FLAGS
|
BDRV_O_RDWR
,
new_backing_drv
))
{
ret
=
bdrv_open
(
bs_new_backing
,
out_baseimg
,
BDRV_O_FLAGS
|
BDRV_O_RDWR
,
new_backing_drv
);
if
(
ret
)
{
error
(
"Could not open new backing file '%s'"
,
out_baseimg
);
return
-
1
;
goto
out
;
}
}
...
...
@@ -1180,11 +1298,15 @@ static int img_rebase(int argc, char **argv)
}
/* Read old and new backing file */
if
(
bdrv_read
(
bs_old_backing
,
sector
,
buf_old
,
n
)
<
0
)
{
ret
=
bdrv_read
(
bs_old_backing
,
sector
,
buf_old
,
n
);
if
(
ret
<
0
)
{
error
(
"error while reading from old backing file"
);
goto
out
;
}
if
(
bdrv_read
(
bs_new_backing
,
sector
,
buf_new
,
n
)
<
0
)
{
ret
=
bdrv_read
(
bs_new_backing
,
sector
,
buf_new
,
n
);
if
(
ret
<
0
)
{
error
(
"error while reading from new backing file"
);
goto
out
;
}
/* If they differ, we need to write to the COW file */
...
...
@@ -1201,6 +1323,7 @@ static int img_rebase(int argc, char **argv)
if
(
ret
<
0
)
{
error
(
"Error while writing to COW image: %s"
,
strerror
(
-
ret
));
goto
out
;
}
}
...
...
@@ -1232,7 +1355,7 @@ static int img_rebase(int argc, char **argv)
* could be dropped from the COW file. Don't do this before switching the
* backing file, in case of a crash this would lead to corruption.
*/
out:
/* Cleanup */
if
(
!
unsafe
)
{
bdrv_delete
(
bs_old_backing
);
...
...
@@ -1240,7 +1363,9 @@ static int img_rebase(int argc, char **argv)
}
bdrv_delete
(
bs
);
if
(
ret
)
{
return
1
;
}
return
0
;
}
...
...
@@ -1306,6 +1431,9 @@ static int img_resize(int argc, char **argv)
free_option_parameters
(
param
);
bs
=
bdrv_new_open
(
filename
,
fmt
,
BDRV_O_FLAGS
|
BDRV_O_RDWR
);
if
(
!
bs
)
{
return
1
;
}
if
(
relative
)
{
total_size
=
bdrv_getlength
(
bs
)
+
n
*
relative
;
...
...
@@ -1314,6 +1442,8 @@ static int img_resize(int argc, char **argv)
}
if
(
total_size
<=
0
)
{
error
(
"New image size must be positive"
);
ret
=
-
1
;
goto
out
;
}
ret
=
bdrv_truncate
(
bs
,
total_size
);
...
...
@@ -1331,8 +1461,11 @@ static int img_resize(int argc, char **argv)
error
(
"Error resizing image (%d)"
,
-
ret
);
break
;
}
out:
bdrv_delete
(
bs
);
if
(
ret
)
{
return
1
;
}
return
0
;
}
...
...
qemu-option.c
浏览文件 @
734003e6
...
...
@@ -719,6 +719,15 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exist
return
opts
;
}
void
qemu_opts_reset
(
QemuOptsList
*
list
)
{
QemuOpts
*
opts
,
*
next_opts
;
QTAILQ_FOREACH_SAFE
(
opts
,
&
list
->
head
,
next
,
next_opts
)
{
qemu_opts_del
(
opts
);
}
}
int
qemu_opts_set
(
QemuOptsList
*
list
,
const
char
*
id
,
const
char
*
name
,
const
char
*
value
)
{
...
...
qemu-option.h
浏览文件 @
734003e6
...
...
@@ -115,6 +115,7 @@ int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
QemuOpts
*
qemu_opts_find
(
QemuOptsList
*
list
,
const
char
*
id
);
QemuOpts
*
qemu_opts_create
(
QemuOptsList
*
list
,
const
char
*
id
,
int
fail_if_exists
);
void
qemu_opts_reset
(
QemuOptsList
*
list
);
int
qemu_opts_set
(
QemuOptsList
*
list
,
const
char
*
id
,
const
char
*
name
,
const
char
*
value
);
const
char
*
qemu_opts_id
(
QemuOpts
*
opts
);
...
...
savevm.c
浏览文件 @
734003e6
...
...
@@ -83,9 +83,6 @@
#include "qemu_socket.h"
#include "qemu-queue.h"
/* point to the block driver where the snapshots are managed */
static
BlockDriverState
*
bs_snapshots
;
#define SELF_ANNOUNCE_ROUNDS 5
#ifndef ETH_P_RARP
...
...
@@ -1575,26 +1572,6 @@ out:
return
ret
;
}
static
BlockDriverState
*
get_bs_snapshots
(
void
)
{
BlockDriverState
*
bs
;
if
(
bs_snapshots
)
return
bs_snapshots
;
/* FIXME what if bs_snapshots gets hot-unplugged? */
bs
=
NULL
;
while
((
bs
=
bdrv_next
(
bs
)))
{
if
(
bdrv_can_snapshot
(
bs
))
{
goto
ok
;
}
}
return
NULL
;
ok:
bs_snapshots
=
bs
;
return
bs
;
}
static
int
bdrv_snapshot_find
(
BlockDriverState
*
bs
,
QEMUSnapshotInfo
*
sn_info
,
const
char
*
name
)
{
...
...
@@ -1674,7 +1651,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
}
}
bs
=
get_bs
_snapshots
();
bs
=
bdrv
_snapshots
();
if
(
!
bs
)
{
monitor_printf
(
mon
,
"No block device can accept snapshots
\n
"
);
return
;
...
...
@@ -1769,7 +1746,7 @@ int load_vmstate(const char *name)
}
}
bs
=
get_bs
_snapshots
();
bs
=
bdrv
_snapshots
();
if
(
!
bs
)
{
error_report
(
"No block device supports snapshots"
);
return
-
EINVAL
;
...
...
@@ -1833,7 +1810,7 @@ void do_delvm(Monitor *mon, const QDict *qdict)
int
ret
;
const
char
*
name
=
qdict_get_str
(
qdict
,
"name"
);
bs
=
get_bs
_snapshots
();
bs
=
bdrv
_snapshots
();
if
(
!
bs
)
{
monitor_printf
(
mon
,
"No block device supports snapshots
\n
"
);
return
;
...
...
@@ -1863,7 +1840,7 @@ void do_info_snapshots(Monitor *mon)
int
nb_sns
,
i
;
char
buf
[
256
];
bs
=
get_bs
_snapshots
();
bs
=
bdrv
_snapshots
();
if
(
!
bs
)
{
monitor_printf
(
mon
,
"No available block device supports snapshots
\n
"
);
return
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录