Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
libvirt
提交
f1a43a8e
L
libvirt
项目概览
openeuler
/
libvirt
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
L
libvirt
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f1a43a8e
编写于
9月 14, 2012
作者:
H
Hu Tao
提交者:
Laine Stump
9月 17, 2012
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
use virBitmap to store cpu affinity info
上级
f970d848
变更
5
显示空白变更内容
内联
并排
Showing
5 changed file
with
84 addition
and
131 deletion
+84
-131
src/lxc/lxc_controller.c
src/lxc/lxc_controller.c
+9
-14
src/qemu/qemu_driver.c
src/qemu/qemu_driver.c
+38
-24
src/qemu/qemu_process.c
src/qemu/qemu_process.c
+14
-71
src/util/processinfo.c
src/util/processinfo.c
+20
-16
src/util/processinfo.h
src/util/processinfo.h
+3
-6
未找到文件。
src/lxc/lxc_controller.c
浏览文件 @
f1a43a8e
...
...
@@ -493,8 +493,7 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl)
{
int
i
,
hostcpus
,
maxcpu
=
CPU_SETSIZE
;
virNodeInfo
nodeinfo
;
unsigned
char
*
cpumap
;
int
cpumaplen
;
virBitmapPtr
cpumap
;
VIR_DEBUG
(
"Setting CPU affinity"
);
...
...
@@ -507,37 +506,33 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl)
if
(
maxcpu
>
hostcpus
)
maxcpu
=
hostcpus
;
cpumaplen
=
VIR_CPU_MAPLEN
(
maxcpu
);
if
(
VIR_ALLOC_N
(
cpumap
,
cpumaplen
)
<
0
)
{
virReportOOMError
();
cpumap
=
virBitmapNew
(
maxcpu
);
if
(
!
cpumap
)
return
-
1
;
}
if
(
ctrl
->
def
->
cpumask
)
{
/* XXX why don't we keep 'cpumask' in the libvirt cpumap
* format to start with ?!?! */
for
(
i
=
0
;
i
<
maxcpu
&&
i
<
ctrl
->
def
->
cpumasklen
;
i
++
)
if
(
ctrl
->
def
->
cpumask
[
i
])
VIR_USE_CPU
(
cpumap
,
i
);
ignore_value
(
virBitmapSetBit
(
cpumap
,
i
)
);
}
else
{
/* You may think this is redundant, but we can't assume libvirtd
* itself is running on all pCPUs, so we need to explicitly set
* the spawned LXC instance to all pCPUs if no map is given in
* its config file */
for
(
i
=
0
;
i
<
maxcpu
;
i
++
)
VIR_USE_CPU
(
cpumap
,
i
);
virBitmapSetAll
(
cpumap
);
}
/* We are pres
s
uming we are running between fork/exec of LXC
/* We are presuming we are running between fork/exec of LXC
* so use '0' to indicate our own process ID. No threads are
* running at this point
*/
if
(
virProcessInfoSetAffinity
(
0
,
/* Self */
cpumap
,
cpumaplen
,
maxcpu
)
<
0
)
{
VIR_FREE
(
cpumap
);
if
(
virProcessInfoSetAffinity
(
0
/* Self */
,
cpumap
)
<
0
)
{
virBitmapFree
(
cpumap
);
return
-
1
;
}
VIR_FREE
(
cpumap
);
virBitmapFree
(
cpumap
);
return
0
;
}
...
...
src/qemu/qemu_driver.c
浏览文件 @
f1a43a8e
...
...
@@ -92,6 +92,7 @@
#include "virnodesuspend.h"
#include "virtime.h"
#include "virtypedparam.h"
#include "bitmap.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
...
...
@@ -3715,10 +3716,10 @@ qemudDomainPinVcpuFlags(virDomainPtr dom,
virNodeInfo
nodeinfo
;
int
ret
=
-
1
;
qemuDomainObjPrivatePtr
priv
;
bool
canResetting
=
tru
e
;
bool
doReset
=
fals
e
;
int
newVcpuPinNum
=
0
;
virDomainVcpuPinDefPtr
*
newVcpuPin
=
NULL
;
int
pcpu
;
virBitmapPtr
pcpumap
=
NULL
;
virCheckFlags
(
VIR_DOMAIN_AFFECT_LIVE
|
VIR_DOMAIN_AFFECT_CONFIG
,
-
1
);
...
...
@@ -3754,15 +3755,16 @@ qemudDomainPinVcpuFlags(virDomainPtr dom,
maxcpu
=
maplen
*
8
;
if
(
maxcpu
>
hostcpus
)
maxcpu
=
hostcpus
;
pcpumap
=
virBitmapNewData
(
cpumap
,
maplen
);
if
(
!
pcpumap
)
goto
cleanup
;
/* pinning to all physical cpus means resetting,
* so check if we can reset setting.
*/
for
(
pcpu
=
0
;
pcpu
<
hostcpus
;
pcpu
++
)
{
if
((
cpumap
[
pcpu
/
8
]
&
(
1
<<
(
pcpu
%
8
)))
==
0
)
{
canResetting
=
false
;
break
;
}
}
if
(
virBitmapIsAllSet
(
pcpumap
))
doReset
=
true
;
if
(
flags
&
VIR_DOMAIN_AFFECT_LIVE
)
{
...
...
@@ -3805,8 +3807,7 @@ qemudDomainPinVcpuFlags(virDomainPtr dom,
goto
cleanup
;
}
}
else
{
if
(
virProcessInfoSetAffinity
(
priv
->
vcpupids
[
vcpu
],
cpumap
,
maplen
,
maxcpu
)
<
0
)
{
if
(
virProcessInfoSetAffinity
(
priv
->
vcpupids
[
vcpu
],
pcpumap
)
<
0
)
{
virReportError
(
VIR_ERR_SYSTEM_ERROR
,
_
(
"failed to set cpu affinity for vcpu %d"
),
vcpu
);
...
...
@@ -3814,7 +3815,7 @@ qemudDomainPinVcpuFlags(virDomainPtr dom,
}
}
if
(
canResetting
)
{
if
(
doReset
)
{
if
(
virDomainVcpuPinDel
(
vm
->
def
,
vcpu
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"failed to delete vcpupin xml of "
...
...
@@ -3839,7 +3840,7 @@ qemudDomainPinVcpuFlags(virDomainPtr dom,
if
(
flags
&
VIR_DOMAIN_AFFECT_CONFIG
)
{
if
(
canResetting
)
{
if
(
doReset
)
{
if
(
virDomainVcpuPinDel
(
persistentDef
,
vcpu
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"failed to delete vcpupin xml of "
...
...
@@ -3879,6 +3880,7 @@ cleanup:
virCgroupFree
(
&
cgroup_dom
);
if
(
vm
)
virDomainObjUnlock
(
vm
);
virBitmapFree
(
pcpumap
);
return
ret
;
}
...
...
@@ -3997,10 +3999,10 @@ qemudDomainPinEmulator(virDomainPtr dom,
virNodeInfo
nodeinfo
;
int
ret
=
-
1
;
qemuDomainObjPrivatePtr
priv
;
bool
canResetting
=
true
;
int
pcpu
;
bool
doReset
=
false
;
int
newVcpuPinNum
=
0
;
virDomainVcpuPinDefPtr
*
newVcpuPin
=
NULL
;
virBitmapPtr
pcpumap
=
NULL
;
virCheckFlags
(
VIR_DOMAIN_AFFECT_LIVE
|
VIR_DOMAIN_AFFECT_CONFIG
,
-
1
);
...
...
@@ -4029,15 +4031,16 @@ qemudDomainPinEmulator(virDomainPtr dom,
maxcpu
=
maplen
*
8
;
if
(
maxcpu
>
hostcpus
)
maxcpu
=
hostcpus
;
pcpumap
=
virBitmapNewData
(
cpumap
,
maplen
);
if
(
!
pcpumap
)
goto
cleanup
;
/* pinning to all physical cpus means resetting,
* so check if we can reset setting.
*/
for
(
pcpu
=
0
;
pcpu
<
hostcpus
;
pcpu
++
)
{
if
((
cpumap
[
pcpu
/
8
]
&
(
1
<<
(
pcpu
%
8
)))
==
0
)
{
canResetting
=
false
;
break
;
}
}
if
(
virBitmapIsAllSet
(
pcpumap
))
doReset
=
true
;
pid
=
vm
->
pid
;
...
...
@@ -4075,7 +4078,7 @@ qemudDomainPinEmulator(virDomainPtr dom,
}
}
}
else
{
if
(
virProcessInfoSetAffinity
(
pid
,
cpumap
,
maplen
,
maxcpu
)
<
0
)
{
if
(
virProcessInfoSetAffinity
(
pid
,
pcpumap
)
<
0
)
{
virReportError
(
VIR_ERR_SYSTEM_ERROR
,
"%s"
,
_
(
"failed to set cpu affinity for "
"emulator threads"
));
...
...
@@ -4083,7 +4086,7 @@ qemudDomainPinEmulator(virDomainPtr dom,
}
}
if
(
canResetting
)
{
if
(
doReset
)
{
if
(
virDomainEmulatorPinDel
(
vm
->
def
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"failed to delete emulatorpin xml of "
...
...
@@ -4110,7 +4113,7 @@ qemudDomainPinEmulator(virDomainPtr dom,
if
(
flags
&
VIR_DOMAIN_AFFECT_CONFIG
)
{
if
(
canResetting
)
{
if
(
doReset
)
{
if
(
virDomainEmulatorPinDel
(
persistentDef
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"failed to delete emulatorpin xml of "
...
...
@@ -4137,6 +4140,7 @@ cleanup:
virCgroupFree
(
&
cgroup_emulator
);
if
(
cgroup_dom
)
virCgroupFree
(
&
cgroup_dom
);
virBitmapFree
(
pcpumap
);
if
(
vm
)
virDomainObjUnlock
(
vm
);
...
...
@@ -4291,10 +4295,20 @@ qemudDomainGetVcpus(virDomainPtr dom,
if
(
priv
->
vcpupids
!=
NULL
)
{
for
(
v
=
0
;
v
<
maxinfo
;
v
++
)
{
unsigned
char
*
cpumap
=
VIR_GET_CPUMAP
(
cpumaps
,
maplen
,
v
);
virBitmapPtr
map
=
NULL
;
unsigned
char
*
tmpmap
=
NULL
;
int
tmpmapLen
=
0
;
if
(
virProcessInfoGetAffinity
(
priv
->
vcpupids
[
v
],
cpumap
,
maplen
,
maxcpu
)
<
0
)
&
map
,
maxcpu
)
<
0
)
goto
cleanup
;
virBitmapToData
(
map
,
&
tmpmap
,
&
tmpmapLen
);
if
(
tmpmapLen
>
maplen
)
tmpmapLen
=
maplen
;
memcpy
(
cpumap
,
tmpmap
,
tmpmapLen
);
VIR_FREE
(
tmpmap
);
virBitmapFree
(
map
);
}
}
else
{
virReportError
(
VIR_ERR_OPERATION_INVALID
,
...
...
src/qemu/qemu_process.c
浏览文件 @
f1a43a8e
...
...
@@ -1853,8 +1853,7 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver,
int
ret
=
-
1
;
int
i
,
hostcpus
,
maxcpu
=
QEMUD_CPUMASK_LEN
;
virNodeInfo
nodeinfo
;
unsigned
char
*
cpumap
;
int
cpumaplen
;
virBitmapPtr
cpumap
;
VIR_DEBUG
(
"Setting CPU affinity"
);
...
...
@@ -1867,8 +1866,8 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver,
if
(
maxcpu
>
hostcpus
)
maxcpu
=
hostcpus
;
cpumap
len
=
VIR_CPU_MAPLEN
(
maxcpu
);
if
(
VIR_ALLOC_N
(
cpumap
,
cpumaplen
)
<
0
)
{
cpumap
=
virBitmapNew
(
maxcpu
);
if
(
!
cpumap
)
{
virReportOOMError
();
return
-
1
;
}
...
...
@@ -1881,7 +1880,8 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver,
int
cur_ncpus
=
driver
->
caps
->
host
.
numaCell
[
i
]
->
ncpus
;
if
(
nodemask
[
i
])
{
for
(
j
=
0
;
j
<
cur_ncpus
;
j
++
)
VIR_USE_CPU
(
cpumap
,
driver
->
caps
->
host
.
numaCell
[
i
]
->
cpus
[
j
]);
ignore_value
(
virBitmapSetBit
(
cpumap
,
driver
->
caps
->
host
.
numaCell
[
i
]
->
cpus
[
j
]));
}
}
}
else
{
...
...
@@ -1891,14 +1891,13 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver,
* format to start with ?!?! */
for
(
i
=
0
;
i
<
maxcpu
&&
i
<
vm
->
def
->
cpumasklen
;
i
++
)
if
(
vm
->
def
->
cpumask
[
i
])
VIR_USE_CPU
(
cpumap
,
i
);
ignore_value
(
virBitmapSetBit
(
cpumap
,
i
)
);
}
else
{
/* You may think this is redundant, but we can't assume libvirtd
* itself is running on all pCPUs, so we need to explicitly set
* the spawned QEMU instance to all pCPUs if no map is given in
* its config file */
for
(
i
=
0
;
i
<
maxcpu
;
i
++
)
VIR_USE_CPU
(
cpumap
,
i
);
virBitmapSetAll
(
cpumap
);
}
}
...
...
@@ -1906,14 +1905,13 @@ qemuProcessInitCpuAffinity(struct qemud_driver *driver,
* so use '0' to indicate our own process ID. No threads are
* running at this point
*/
if
(
virProcessInfoSetAffinity
(
0
,
/* Self */
cpumap
,
cpumaplen
,
maxcpu
)
<
0
)
if
(
virProcessInfoSetAffinity
(
0
/* Self */
,
cpumap
)
<
0
)
goto
cleanup
;
ret
=
0
;
cleanup:
VIR_FREE
(
cpumap
);
virBitmapFree
(
cpumap
);
return
ret
;
}
...
...
@@ -1958,10 +1956,7 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn,
qemuDomainObjPrivatePtr
priv
=
vm
->
privateData
;
virDomainDefPtr
def
=
vm
->
def
;
virNodeInfo
nodeinfo
;
pid_t
vcpupid
;
virBitmapPtr
cpumask
;
int
vcpu
,
cpumaplen
,
hostcpus
,
maxcpu
,
n
;
unsigned
char
*
cpumap
=
NULL
;
int
vcpu
,
n
;
int
ret
=
-
1
;
if
(
virNodeGetInfo
(
conn
,
&
nodeinfo
)
!=
0
)
{
...
...
@@ -1977,41 +1972,17 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn,
return
-
1
;
}
hostcpus
=
VIR_NODEINFO_MAXCPUS
(
nodeinfo
);
cpumaplen
=
VIR_CPU_MAPLEN
(
hostcpus
);
maxcpu
=
cpumaplen
*
8
;
if
(
maxcpu
>
hostcpus
)
maxcpu
=
hostcpus
;
if
(
VIR_ALLOC_N
(
cpumap
,
cpumaplen
)
<
0
)
{
virReportOOMError
();
return
-
1
;
}
for
(
n
=
0
;
n
<
def
->
cputune
.
nvcpupin
;
n
++
)
{
int
i
;
vcpu
=
def
->
cputune
.
vcpupin
[
n
]
->
vcpuid
;
memset
(
cpumap
,
0
,
cpumaplen
);
cpumask
=
def
->
cputune
.
vcpupin
[
n
]
->
cpumask
;
vcpupid
=
priv
->
vcpupids
[
vcpu
];
i
=
-
1
;
while
((
i
=
virBitmapNextSetBit
(
cpumask
,
i
))
>=
0
)
VIR_USE_CPU
(
cpumap
,
i
);
if
(
virProcessInfoSetAffinity
(
vcpupid
,
cpumap
,
cpumaplen
,
maxcpu
)
<
0
)
{
if
(
virProcessInfoSetAffinity
(
priv
->
vcpupids
[
vcpu
],
def
->
cputune
.
vcpupin
[
n
]
->
cpumask
)
<
0
)
{
goto
cleanup
;
}
}
ret
=
0
;
cleanup:
VIR_FREE
(
cpumap
);
return
ret
;
}
...
...
@@ -2021,13 +1992,8 @@ qemuProcessSetEmulatorAffinites(virConnectPtr conn,
virDomainObjPtr
vm
)
{
virDomainDefPtr
def
=
vm
->
def
;
pid_t
pid
=
vm
->
pid
;
virBitmapPtr
cpumask
=
NULL
;
unsigned
char
*
cpumap
=
NULL
;
virNodeInfo
nodeinfo
;
int
cpumaplen
,
hostcpus
,
maxcpu
,
i
;
int
ret
=
-
1
;
bool
result
;
if
(
virNodeGetInfo
(
conn
,
&
nodeinfo
)
!=
0
)
return
-
1
;
...
...
@@ -2035,36 +2001,13 @@ qemuProcessSetEmulatorAffinites(virConnectPtr conn,
if
(
!
def
->
cputune
.
emulatorpin
)
return
0
;
hostcpus
=
VIR_NODEINFO_MAXCPUS
(
nodeinfo
);
cpumaplen
=
VIR_CPU_MAPLEN
(
hostcpus
);
maxcpu
=
cpumaplen
*
CHAR_BIT
;
if
(
maxcpu
>
hostcpus
)
maxcpu
=
hostcpus
;
if
(
VIR_ALLOC_N
(
cpumap
,
cpumaplen
)
<
0
)
{
virReportOOMError
();
return
-
1
;
}
cpumask
=
def
->
cputune
.
emulatorpin
->
cpumask
;
for
(
i
=
0
;
i
<
VIR_DOMAIN_CPUMASK_LEN
;
i
++
)
{
if
(
virBitmapGetBit
(
cpumask
,
i
,
&
result
)
<
0
)
goto
cleanup
;
if
(
result
)
VIR_USE_CPU
(
cpumap
,
i
);
}
if
(
virProcessInfoSetAffinity
(
pid
,
cpumap
,
cpumaplen
,
maxcpu
)
<
0
)
{
if
(
virProcessInfoSetAffinity
(
vm
->
pid
,
def
->
cputune
.
emulatorpin
->
cpumask
)
<
0
)
{
goto
cleanup
;
}
ret
=
0
;
cleanup:
VIR_FREE
(
cpumap
);
return
ret
;
}
...
...
src/util/processinfo.c
浏览文件 @
f1a43a8e
...
...
@@ -30,12 +30,10 @@
#if HAVE_SCHED_GETAFFINITY
int
virProcessInfoSetAffinity
(
pid_t
pid
,
const
unsigned
char
*
map
,
size_t
maplen
,
int
maxcpu
)
int
virProcessInfoSetAffinity
(
pid_t
pid
,
virBitmapPtr
map
)
{
int
i
;
bool
set
=
false
;
# ifdef CPU_ALLOC
/* New method dynamically allocates cpu mask, allowing unlimted cpus */
int
numcpus
=
1024
;
...
...
@@ -59,8 +57,10 @@ realloc:
}
CPU_ZERO_S
(
masklen
,
mask
);
for
(
i
=
0
;
i
<
maxcpu
;
i
++
)
{
if
(
VIR_CPU_USABLE
(
map
,
maplen
,
0
,
i
))
for
(
i
=
0
;
i
<
virBitmapSize
(
map
);
i
++
)
{
if
(
virBitmapGetBit
(
map
,
i
,
&
set
)
<
0
)
return
-
1
;
if
(
set
)
CPU_SET_S
(
i
,
masklen
,
mask
);
}
...
...
@@ -81,8 +81,10 @@ realloc:
cpu_set_t
mask
;
CPU_ZERO
(
&
mask
);
for
(
i
=
0
;
i
<
maxcpu
;
i
++
)
{
if
(
VIR_CPU_USABLE
(
map
,
maplen
,
0
,
i
))
for
(
i
=
0
;
i
<
virBitmapSize
(
map
);
i
++
)
{
if
(
virBitmapGetBit
(
map
,
i
,
&
set
)
<
0
)
return
-
1
;
if
(
set
)
CPU_SET
(
i
,
&
mask
);
}
...
...
@@ -97,8 +99,7 @@ realloc:
}
int
virProcessInfoGetAffinity
(
pid_t
pid
,
unsigned
char
*
map
,
size_t
maplen
ATTRIBUTE_UNUSED
,
virBitmapPtr
*
map
,
int
maxcpu
)
{
int
i
;
...
...
@@ -137,9 +138,15 @@ realloc:
return
-
1
;
}
*
map
=
virBitmapNew
(
maxcpu
);
if
(
!
map
)
{
virReportOOMError
();
return
-
1
;
}
for
(
i
=
0
;
i
<
maxcpu
;
i
++
)
if
(
CPU_ISSET_S
(
i
,
masklen
,
mask
))
VIR_USE_CPU
(
map
,
i
);
ignore_value
(
virBitmapSetBit
(
*
map
,
i
)
);
CPU_FREE
(
mask
);
# else
/* Legacy method uses a fixed size cpu mask, only allows upto 1024 cpus */
...
...
@@ -163,9 +170,7 @@ realloc:
#else
/* HAVE_SCHED_GETAFFINITY */
int
virProcessInfoSetAffinity
(
pid_t
pid
ATTRIBUTE_UNUSED
,
const
unsigned
char
*
map
ATTRIBUTE_UNUSED
,
size_t
maplen
ATTRIBUTE_UNUSED
,
int
maxcpu
ATTRIBUTE_UNUSED
)
virBitmapPtr
map
ATTRIBUTE_UNUSED
)
{
virReportSystemError
(
ENOSYS
,
"%s"
,
_
(
"Process CPU affinity is not supported on this platform"
));
...
...
@@ -173,8 +178,7 @@ int virProcessInfoSetAffinity(pid_t pid ATTRIBUTE_UNUSED,
}
int
virProcessInfoGetAffinity
(
pid_t
pid
ATTRIBUTE_UNUSED
,
unsigned
char
*
map
ATTRIBUTE_UNUSED
,
size_t
maplen
ATTRIBUTE_UNUSED
,
virBitmapPtr
*
map
ATTRIBUTE_UNUSED
,
int
maxcpu
ATTRIBUTE_UNUSED
)
{
virReportSystemError
(
ENOSYS
,
"%s"
,
...
...
src/util/processinfo.h
浏览文件 @
f1a43a8e
...
...
@@ -23,15 +23,12 @@
# define __VIR_PROCESSINFO_H__
# include "internal.h"
# include "bitmap.h"
int
virProcessInfoSetAffinity
(
pid_t
pid
,
const
unsigned
char
*
map
,
size_t
maplen
,
int
maxcpu
);
int
virProcessInfoSetAffinity
(
pid_t
pid
,
virBitmapPtr
map
);
int
virProcessInfoGetAffinity
(
pid_t
pid
,
unsigned
char
*
map
,
size_t
maplen
,
virBitmapPtr
*
map
,
int
maxcpu
);
#endif
/* __VIR_PROCESSINFO_H__ */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录