ARMv8 Linux内核错误处理过程分析怎么解决

ARMv8 Linux内核错误处理过程分析怎么解决,第1张

1.1 Linux内核异常处理相关文件

Linux内核中,异常处理主要由两个文件完成,entry.S和traps.c,当然还有一些其它异常处理函数分布于fault.c, memory.c等等。entry.S包含异常的入口、进入异常处理C函数前的压栈、退出C函数前的出栈、一些fork函数相关的处理代码(暂不分析)、任务切换汇编处理过程(cpu_switch_to函数,暂不分析)。traps.c主要包含异常处理C函数。

本文主要分析entry.S,对于traps.c作简要介绍。

1.2 执行kernel_entry之前的栈

1.3 执行kernel_entry时的栈

1.4 执行kernel_exit 时的栈

1.5 entry.s代码分析

/*

* Low-level exception handling code

*

* Copyright (C) 2012 ARM Ltd.

* Authors: Catalin Marinas [email protected]>

* Will Deacon [email protected]>

*

* This program is free softwareyou can redistribute it and/or modify

* it under the terms of the GNU General Public License version 2 as

* published by the Free Software Foundation.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTYwithout even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program. If not, see <http://www.gnu.org/licenses/>.

*/

#include <linux/init.h>

#include <linux/linkage.h>

#include <asm/assembler.h>

#include <asm/asm-offsets.h>

#include <asm/errno.h>

#include <asm/thread_info.h>

#include <asm/unistd.h>

#include <asm/unistd32.h>

/*

* Bad Abort numbers

*-----------------

*/

#define BAD_SYNC 0

#define BAD_IRQ 1

#define BAD_FIQ 2

#define BAD_ERROR 3

//根据该结构体内容

/*

struct pt_regs {

union {

struct user_pt_regs user_regs//结构体user_pt_regs和结构体pt_regs内容一样

struct { //共用体存储31个通用寄存器,外加sp,pc,pstate三个特殊寄存器

//该结构体用于异常处理的压栈d栈 *** 作

u64 regs[31]

u64 sp

u64 pc

u64 pstate

}

}

u64 orig_x0

u64 syscallno

}

*/

//S_FRAME_SIZE定义在asm-offsets.c中,DEFINE(S_FRAME_SIZE,sizeof(struct pt_regs))

//即结构体pt_regs的大小,结构体pt_regs的定义见上面

//S_LR定义:DEFINE(S_LR,offsetof(struct pt_regs, regs[30]))

//即31号寄存器在结构体pt_regs中的偏移量

//阅读以下内容请参考图1 和图2

.macro kernel_entry, el, regsize = 64

sub sp, sp, #S_FRAME_SIZE - S_LR // room for LR, SP, SPSR, ELR,见图2中sp'指向的位置

.if \regsize == 32

mov w0, w0 // zero upper 32 bits of x0

.endif

/*

*.macro push, xreg1, xreg2 //压栈两个寄存器

*stp \xreg1, \xreg2, [sp, #-16]! //注意!!!push指令也改变sp的值!!!

*.endm

*/

push x28, x29 //进行压栈 *** 作,push也是一个宏定义,因为ARMv8没有push指令,用stp代替

push x26, x27

push x24, x25

push x22, x23

push x20, x21

push x18, x19

push x16, x17

push x14, x15

push x12, x13

push x10, x11

push x8, x9

push x6, x7

push x4, x5

push x2, x3

push x0, x1 //此时sp指向位置见图2中sp''

.if \el == 0 //如果异常级是el0,把el0的sp栈指针给x21寄存器

mrs x21, sp_el0

.else

add x21, sp, #S_FRAME_SIZE //如果异常级不是el0,把sp指针指向的地方加上pt_regs大小后的地址放入x21,

//即指向没进入kernel_entry函数钱的sp指向的位置,见图2中x21指向的地址

.endif

mrs x22, elr_el1 //把el1的lr寄存器给x22

mrs x23, spsr_el1 //把spsr给x23

stp lr, x21, [sp, #S_LR] //把lr,x21寄存器存入sp+S_LR指向的地方

stp x22, x23, [sp, #S_PC] //把lr,存入sp+s_PC指向的位置,用于异常返回

/*

* Set syscallno to -1 by default (overridden later if real syscall).

*/

.if \el == 0

mvn x21, xzr

str x21, [sp, #S_SYSCALLNO]

.endif

/*

* Registers that may be useful after this macro is invoked:

*

* x21 - aborted SP

* x22 - aborted PC

* x23 - aborted PSTATE

*/

.endm

.macro kernel_exit, el, ret = 0

//把此时sp(即图2中sp'')+S_PC位置处开始的16字节内容分别给x21,x22

//即把栈中存的x21和x22内容取出来

ldp x21, x22, [sp, #S_PC] // load ELR, SPSR

.if \el == 0

ldr x23, [sp, #S_SP] // load return stack pointer,取出

.endif

.if \ret

ldr x1, [sp, #S_X1] // preserve x0 (syscall return),如果ret=1,则保存x0,用于系统调用,暂不分析

add sp, sp, S_X2

.else

pop x0, x1 //如果ret=0,d出x0,x1

.endif

pop x2, x3 // load the rest of the registers

pop x4, x5

pop x6, x7

pop x8, x9

msr elr_el1, x21 // set up the return data,把前面d出的x21,x22分别赋值给elr_el1,spsr_el1

msr spsr_el1, x22

.if \el == 0

msr sp_el0, x23

.endif

pop x10, x11

pop x12, x13

pop x14, x15

pop x16, x17

pop x18, x19

pop x20, x21

pop x22, x23

pop x24, x25

pop x26, x27

pop x28, x29

ldr lr, [sp], #S_FRAME_SIZE - S_LR // load LR and restore SP,把lrd出

eret // return to kernel,异常返回,该指令会把lr给pc,完成跳转

.endm

.macro get_thread_info, rd

mov \rd, sp

and \rd, \rd, #~((1 <<13) - 1) // top of 8K stack

.endm

/*

* These are the registers used in the syscall handler, and allow us to

* have in theory up to 7 arguments to a function - x0 to x6.

*

* x7 is reserved for the system call number in 32-bit mode.

*/

sc_nr .req x25 // number of system calls

scno .req x26 // syscall number

stbl .req x27 // syscall table pointer

tsk .req x28 // current thread_info

/*

* Interrupt handling.

*/

.macro irq_handler

ldr x1, handle_arch_irq

mov x0, sp

blr x1

.endm

.text

/*

* Exception vectors.

*/

.macro ventry label //这里是2^7对齐,即对齐到内存地址的0x80

.align 7

b \label

.endm

.align 11

/* ENTRY也是一个宏,定义在include/linkage.h中

* #ifndef ENTRY

* #define ENTRY(name) \

* .globl name\

* ALIGN\

* name:

* #endif

1.安装vmware server软件

从www.vmware.com下载vmware server 1.0 for linux软件,安装过程很简单,基本上是一路Enter.只是需要sn,在这里提供几个使用

928WH-Y65AW-21394-4C70J,92EY4-Y4NAT-23L07-4U7CH,9AWPN-Y400W-2179N-4K5HM

安装vmware server console,以便远程管理vmware server

2.安装虚拟服务器 *** 作系统

我用的是OS是Redhat AS4,kernel 2.6.9-22,虚拟出两块网卡,开始安装 *** 作系统,主机名叫ha1pub,eth0:10.1.250.17,eth1:192.168.100.100.具体过程省略.安装结束后,使用ntsysv命令,关闭掉一些不常使用的进程,只留下一下一些需要的,如ssh,ftp等等.然后关机!

然后cp ha1pub的所有配置文件到一个新的目录,在虚拟机console里面打开,就会出现一个新的系统,但是由于里面的ip信息和第一台机器的重复,进入系统后修改一下

编辑/etc/sysconfig/network文件,将ha1pub修改为ha2pub,然后修改ip,eth0:10.1.250.18,eth1:192.168.100.200.

注意,redhat系统里面,ip的配置文件ifcfg-eth文件里面,有可能包含mac地址的信息,需要删除掉,否则会mac地址重复的错误.ha2pub也关机

3.设置共享存储

由于安装RAC需要共享存储,所以必须为两台机器设置共享存储,我使用vmware-vdiskmanager命令创建一些虚拟硬盘

________________________________________________________________________

vmware-vdiskmanager -c -s 1Gb -a lsilogic -t 2 "/vmware/share/ocfs.vmdk" |用于Oracle集群注册表文件和CRS表决磁盘

________________________________________________________________________

vmware-vdiskmanager -c -s 2Gb -a lsilogic -t 2 "/vmware/share/asm1.vmdk" |用于Oracle的数据文件

________________________________________________________________________

vmware-vdiskmanager -c -s 2Gb -a lsilogic -t 2 "/vmware/share/asm2.vmdk" |用于Oracle的数据文件

________________________________________________________________________

vmware-vdiskmanager -c -s 2Gb -a lsilogic -t 2 "/vmware/share/asm3.vmdk" |用于Oracle的数据文件

________________________________________________________________________

vmware-vdiskmanager -c -s 2Gb -a lsilogic -t 2 "/vmware/share/asm4.vmdk" |用于Oracle的闪回恢复区

____________________________________________________________________

然后分别在两个虚拟服务器的的配置文件,ha1.vmx和ha2vmx文件里面添加如下信息

scsi1.present = "TRUE"

scsi1.virtualDev = "lsilogic"

scsi1.sharedBus = "virtual"

scsi1:1.present = "TRUE"

scsi1:1.mode = "independent-persistent"

scsi1:1.filename = "/vmware/share/ocfs.vmdk"

scsi1:1.deviceType = "disk"

scsi1:2.present = "TRUE"

scsi1:2.mode = "independent-persistent"

scsi1:2.filename = "/vmware/share/asm1.vmdk"

scsi1:2.deviceType = "disk"

scsi1:3.present = "TRUE"

scsi1:3.mode = "independent-persistent"

scsi1:3.filename = "/vmware/share/asm2.vmdk"

scsi1:3.deviceType = "disk"

scsi1:4.present = "TRUE"

scsi1:4.mode = "independent-persistent"

scsi1:4.filename = "/vmware/share/asm3.vmdk"

scsi1:4.deviceType = "disk"

scsi1:5.present = "TRUE"

scsi1:5.mode = "independent-persistent"

scsi1:5.filename = "/vmware/share/asm4.vmdk"

scsi1:5.deviceType = "disk"

disk.locking = "false"

diskLib.dataCacheMaxSize = "0"

diskLib.dataCacheMaxReadAheadSize = "0"

diskLib.DataCacheMinReadAheadSize = "0"

diskLib.dataCachePageSize = "4096"

diskLib.maxUnsyncedWrites = "0"

保存后,打开vmware console就可以看到添加的硬盘,启动ha1pub和ha2pub!随便进入一台系统,用fdisk格式化这些新添加的硬盘.

fdisk -l可以看到如下

__________________________________________________________________

Disk /dev/sda: 16.1 GB, 16106127360 bytes

255 heads, 63 sectors/track, 1958 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System

/dev/sda1 * 1 13 104391 83 Linux

/dev/sda2 14 275 2104515 82 Linux swap

/dev/sda3 276195813518697+ 83 Linux

Disk /dev/sdb: 1073 MB, 1073741824 bytes

255 heads, 63 sectors/track, 130 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System

/dev/sdb1 1 130 1044193+ 83 Linux

Disk /dev/sdc: 2147 MB, 2147483648 bytes

255 heads, 63 sectors/track, 261 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System

/dev/sdc1 1 261 2096451 83 Linux

Disk /dev/sdd: 2147 MB, 2147483648 bytes

255 heads, 63 sectors/track, 261 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System

/dev/sdd1 1 261 2096451 83 Linux

Disk /dev/sde: 2147 MB, 2147483648 bytes

255 heads, 63 sectors/track, 261 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System

/dev/sde1 1 261 2096451 83 Linux

Disk /dev/sdf: 2147 MB, 2147483648 bytes

255 heads, 63 sectors/track, 261 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System

/dev/sdf1 1 261 2096451 83 Linux

____________________________________________________________________

修改/etc/hosts文件,如下所示

127.0.0.1localhost(这里必须这样修改,否则RAC节点名出现在回送地址中,安装RAC期间可能会报错)

10.1.250.17 ha1pub

10.1.250.18 ha2pub

192.168.100.100 ha1prv

192.168.100.200 ha2prv

10.1.250.19 ha1vip

10.1.250.20 ha2vip

4.调整网络设置,设置共享内存和信号参数

分别在ha1pub和ha2pub上,编辑/etc/sysctl.conf文件,添加如下信息,这些信息可以根据自己的机器实际情况来调整

net.core.rmem_default=262144

net.core.wmem_default=262144

net.core.rmem_max=262144

net.core.wmem_max=262144

kernel.shmall = 2097152

kernel.shmmax = 536870912

kernel.shmmni = 4096

kernel.sem = 250 32000 100 128

fs.file-max = 65536

net.ipv4.ip_local_port_range = 1024 65000

5. 配置 hangcheck-timer 内核模块

该模块是用来监控集群的状态情况,linux as4中已经安装了此模块,使用下面的命令确认

find /lib/modules -name "hangcheck-timer.o" 看看有没有,如果有,配置并加载该模块

#echo "/sbin/modprobe hangcheck-timer" >>/etc/rc.local

#modprobe hangcheck-timer

#grep Hangcheck /var/log/messages | tail -2

Jul 31 15:01:49 ha2pub kernel: Hangcheck: starting hangcheck timer 0.5.0 (tick is 30 seconds, margin is 180 seconds).

如果看到上面的信息,说明模块的设置工作正确

6. 在两个节点上创建oracle用户和目录

groupadd oinstall

groupadd dba

useradd -g oinstall -G dba oracle

passwd oracle

以oracle用户登陆,分别建立两个目录

mkdir /home/oracle/app 用于安装oracle 数据库

mkdir /home/oracle/orcl 用于Oracle 集群文件系统 (OCFS) 的挂载点

修改oracle用户的.bash_profile文件如下所示

__________________________________________________________________

export ORACLE_BASE=/home/oracle/app/oracle

export ORACLE_HOME=$ORACLE_BASE/product/10.2.0/db_1

export ORA_CRS_HOME=/home/oracle/app/oracle/product/10.2.0/crs/

export ORACLE_SID=orcl1

export PATH=.:${PATH}:$HOME/bin:$ORACLE_HOME/bin

export PATH=${PATH}:/usr/bin:/bin:/usr/bin/X11:/usr/local/bin

export PATH=${PATH}:$ORACLE_BASE/common/oracle/bin

export ORACLE_TERM=xterm

export TNS_ADMIN=$ORACLE_HOME/network/admin

export ORA_NLS10=$ORACLE_HOME/nls/data

export LD_LIBRARY_PATH=$ORACLE_HOME/lib

export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$ORACLE_HOME/oracm/lib

export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/lib:/usr/lib:/usr/local/lib

export CLASSPATH=$ORACLE_HOME/JRE

export CLASSPATH=${CLASSPATH}:$ORACLE_HOME/jlib

export CLASSPATH=${CLASSPATH}:$ORACLE_HOME/rdbms/jlib

export CLASSPATH=${CLASSPATH}:$ORACLE_HOME/network/jlib

export THREADS_FLAG=native

export TEMP=/tmp

export TMPDIR=/tmp

________________________________________________________________________

注意,在第二个节点上,修改SID=orcl2

7.建立节点之间的互信

我采用的是ssh,具体过程有很多文档说明,这里省略.分别要建立root用户,oracle用户的互信.

然后在分别以root用户,oracle在两个节点上执行如下命令

ssh localhost

ssh ha1pub

ssh ha2pub

ssh ha1prv

ssh ha2prv

8.安装配置ocfs2

从http://oss.oracle.com/projects/ocfs2/下载与自己 *** 作系统版本相符合的ocfs,ocfs console

比如我的内核是2.6.9-22.EL,于是我下载的就是ocfs2-2.6.9-22.EL-1.2.2-1.i686.rpm,这点非常重要

安装很简单,把该下载的包都下载了rpm安装就ok了

8.1 ocfs2的配置

先使用下面命令禁用SElinux

#system-config-securitylevel &

然后在集群中的每个节点上生成和配置 /etc/ocfs2/cluster.conf

可以使用ocfs2console命令调出图形界面,将ha1pub和ha2pub两个节点都加入,点击apply,然后退出.

在/etc/ocfs2/目录下面将有cluster.conf文件,内容应该如下

______________________________________________________

node:

ip_port = 7777

ip_address = 10.1.250.17

number = 0

name = ha1pub

cluster = ocfs2

node:

ip_port = 7777

ip_address = 10.1.250.18

number = 1

name = ha2pub

cluster = ocfs2

cluster:

node_count = 2

name = ocfs2

________________________________________________________

接着编辑 /etc/init.d/o2cb, 删除开始带 #的配置行

然后 /etc/init.d/o2cb offline ocfs2

/etc/init.d/o2cb unload ocfs2

/etc/init.d/o2cb configure ocfs2 输入y就ok了

8.2 创建ocfs2文件系统

mkfs.ocfs2 -b 4k -C 32k -L oradatafiles /dev/sdb1

然后挂载ocfs2文件系统

mount -t ocfs2 -o datavolume /dev/sdb1 /home/oracle/orcl

修改/etc/fstab,添加

/dev/sdb1 /home/oracle/orcl ocfs2 _netdev,datavolume 0 0

8.3 调O2CB的心跳阀值

修改文件/etc/sysconfig/o2cb将O2CB_HEARTBEAT_THRESHOLD 设置为 301

修改文件 /etc/sysconfig/o2cb 后,需要更改 o2cb 配置。同样,应在集群的所有节点上执行以下 *** 作。

# umount /home/oracle/orcl/

# /etc/init.d/o2cb unload

# /etc/init.d/o2cb configure

reboot两个节点

9. 安装,配置自动存储管理ASM2.0

可以从http://www.oracle.com/technology ... x/asmlib/rhel4.html这里下载相关rpm包

rpm安装过程省略

执行/etc/init.d/oracleasm configure

默认用户输入oracle,默认组输入dba,其他都y,y就可以了

9.1创建ASM磁盘

在一个节点上执行

/etc/init.d/oracleasm createdisk VOL1 /dev/sdc1

/etc/init.d/oracleasm createdisk VOL2 /dev/sdd1

/etc/init.d/oracleasm createdisk VOL3 /dev/sde1

/etc/init.d/oracleasm createdisk VOL4 /dev/sdf1

创建好后,执行/etc/init.d/oracleasm listdisks可以看到

VOL1

VOL2

VOL3

VOL4

然后在另外一个节点上执行

/etc/init.d/oracleasm scandisks

完成后执行

/etc/init.d/oracleasm listdisks应该可以看到和的一个节点相同的内容

10. 安装Oracle 10G cluster软件

从oracle网站下载10201_clusterware_linux32

以oracle用户登录,unset掉一些环境变量,如下

$ unset ORA_CRS_HOME

$ unset ORACLE_HOME

$ unset ORA_NLS10

$ unset TNS_ADMIN

开始安装cluster软件

./runInstaller -ignoreSysPrereqs

*确认安装目录是/home/oracle/app/oracle/product/10.2.0/crs/

*如果愿意可以将clustername由crs修改成其他的名称

*添加两个节点,如下所示

____________________________________________________________________

Public Node NamePrivate Node NameVirtual Node Name

ha1pubha1prvha1vip

ha2pubha2prvha2vip

____________________________________________________________________

*要修改一下eth0的类型,他默认的是private,修改为public

*指定OCR和mirror的路径

Specify OCR Location: /home/oracle/orcl/OCRFile

Specify OCR Mirror Location:/home/oracle/orcl/OCRFile_mirror

*指定Voting磁盘路径

Voting Disk Location: /home/oracle/orcl/CSSFile

Additional Voting Disk 1 Location:/home/oracle/orcl/CSSFile_mirror1

Additional Voting Disk 2 Location:/home/oracle/orcl/CSSFile_mirror2

*安装快结束时.会要求以root执行orainsRoot.sh和root.sh脚本,以root用户打开一个新的终端,一个一个节点顺序执行,千万不要抢时间一起执行

*执行最后一个root.sh的时候,可能会报""eth0" is not public.Public interfaces should be used to configure virtual IPs."这样的错误.这时候需要以root用户去执行$ORA_CRS_HOME/bin/vipca,选择两个节点,配置一下虚拟ip的信息.

至此,clusterware安装就ok了,检查一下集群节点

$ORA_CRS_HOME/bin/olsnodes -n

ha1pub 1

ha2pub 2

11. 安装Oracle 10g软件

从oracle网站下载10201_database_linux32

unset掉一些环境变量

$ unset ORA_CRS_HOME

$ unset ORACLE_HOME

$ unset ORA_NLS10

$ unset TNS_ADMIN

Oracle的安装省略,既然敢玩RAC,肯定以前也安装过oracle,只是有些地方需要注意

*节点的选择上,一定要选上所有的节点

*选择 "Install database software only",先不要建instance,等数据库安装完毕后时候dbca创建

*安装完成后,需要执行root.sh脚本,不要着急,一个节点一个节点执行

12. 建立TNS侦听

以oracle用户执行

$ netca &

*选择所有节点

*选择Listener configuration

*其他的都选择默认即可

结束后可以验证一下侦听是否已经在所有节点上运行

ps -ef|grep LISTEN

应该可以看到

/home/oracle/app/oracle/product/10.2.0/db_1/bin/tnslsnr LISTENER_HA1PUB -inherit

另外一个节点应该是

/home/oracle/app/oracle/product/10.2.0/db_1/bin/tnslsnr LISTENER_HA2PUB -inherit

13. 创建数据库实例

以oracle用户在任一节点执行

dbca &

*选择 Create a Database

*选择所有节点

*选择Custom Database

*全局数据库名输入orcl,SID也是orcl

*选择使用相同的密码对所有用户

*存储选项选择 use ASM

*修改“Create server parameter file (SPFILE)”为/home/oracle/orcl/dbs/spfile+ASM.ora。所有其他选项可以保留其默认值。

*在ASM Disk Groups配置界面,选择Create New,会显示之前通过ASMlib创建的4个卷VOL1到VOL4

选择前三个,VOL1,VOL2,VOL3,Disk group name输入DATA,Redundancy,选择Normal,单击ok,完成后再次单击Create New.选择最后一个VOL4,Disk group name输入FLASH_RECOVERY_AREA, Redundancy选择External,单击ok,完成ASM的磁盘组创建.

*Database File Locations 选择DATA

*Recovery Configuration 选择FLASH_RECOVERY_AREA

*Database Content由于是测试,可以取消掉所有选项

*Service name 可以输入orcltest,TAF Policy选择Basic

*Database Storage 根据自己系统的硬件条件可以更改一些参数.

完成dbca,Oracle RAC就可以所已经完全安装成功了!

14. RAC的启动和关闭

如果都遵循了上面的安装步骤,那么每次节点重新启动的时候,所有服务都会自动启动,如果需要关闭或者启动某个节点,如下所示

*停止RAC

1.emctl stop dbconsole

2.srvctl stop instance -d orcl -i orcl1

3.srvctl stop asm -n ha1pub

4.srvctl stop nodeapps -n ha1pub

*启动RAC

和上面的步骤正好相反即

1.srvctl start nodeapps -n ha1pub

2.srvctl start asm -n ha1pub

3.srvctl start instance -d orcl -i orcl1

4.srvctl start dbconsole

15. RAC的验证和测试

有很多文档写的都很详细,本文就不赘述了

16. 参考文档

在 Linux 和 FireWire 上构建您自己的 Oracle RAC 10g 第 2 版集群

作者:Jeffrey Hunter

http://www.oracle.com/technology ... unter_rac10gr2.html


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/9012023.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-23
下一篇 2023-04-23

发表评论

登录后才能评论

评论列表(0条)

保存