centos量产工具(centos国产化替代方案)
大家好,今天小编来为大家解答以下的问题,关于centos量产工具,centos国产化替代方案这个很多人还不知道,现在让我们一起来看看吧!
u盘量产工具21in1U盘量产工具怎么使用
(U盘量产工具怎么使用)
Rufus中文版是一款小巧实用免费开源的U盘引导盘制作工具及U盘启动工具,它可以快速的将ISO镜像文件制作成可引导启动的USB启动盘,支持Windows/Linux系统启动,堪称写入镜像速度最快的U盘启动制作工具.
特点描述
支持的操作系统ISO镜像:
ArchLinux,Archbang,BartPE/pebuilder,CentOS,damnSmallLinux,Debian,Fedora,FreeDOS,电脑
FreeNAS,Gentoo,GParted,gNewSense,Hiren'sBootCD,LiveXP,Knoppix,KolibrioS,Kubuntu,LinuxMint,NTPasswordRegistryEditor,PartedMagic,PartitionWizard,Raspbian,ReactOS,RedHat,rEFInd,slackware,SuperGrub2disk,Tails,TrinityRescueKit,Ubuntu,UltimateBootCD,WindowsXP(SP2+),WindowsVista,WindowsServer2008,Windows7,Windows8/8.1,Windows10/11,WindowsServer2012,WindowsServer2016,WindowsServer2022
对ISO支持的说明:
Rufusv1.10及之后的所有版本都支持从ISO镜像(.iso)创建可引导USB启动盘。
对DOS支持的说明:
如果创建了一个DOS启动盘,但是没有使用美式键盘,Rufus会尝试根据设备选择一个键盘布局,
在那种情况下推荐使用FreeDOS(默认选项)而不是MS-DOS,因为前者支持更多的键盘布局。
新版变化
Rufus-轻松创建USB启动盘
/f/18720197-738793882-1ddc3f?p=4343(访问密码:4343)
电脑
如何用U盘做一个Centos(linux)安装盘
1、到CentOS的官网上面下载CentOS操作系统,推荐下载CentOS.iso。
2、将镜像挂载到文件夹,这里默认为/mnt:
sudo mount-o loop CentOS.iso/mnt
3、用fdisk将U盘/dev/sdb分为一个区/dev/sdb1,用mkfs-vfat/dev/sdb1格式化为FAT32格式的分区。
将U盘挂载到/media/UDisk。
4、拷贝相应的启动需要使用的文件夹/mnt/images和/mnt/isolinux到U盘/media/UDisk上。
并将isolinux、isolinux/isolinux.bin、isolinux/isolinux.cfg这三个文件(夹)中的iso改为sys,即改为syslinux、syslinux/syslinux.bin、syslinux/syslinux.cfg。
5、到下载syslinux-4.05.tar.gz,解压缩后进入syslinux-4.05/linux文件夹。
6、运行./syslinux-d/syslinux-i/dev/sdb1,将引导程序装入U盘中,-d选项指明启动文件的位置,-i表示覆盖安装引导程序,/dev/sdb1为U盘上的分区对应的设备名。
7、拷贝CentOS.iso到/media/UDisk上,即U盘上。(安装的时候需要选择镜像位置为Hard Drive,然后选择U盘对应的设备)
至此,一个可以用来安装CentOS的U盘启动盘就制作好了。
is917d0量产工具使用
is917d0量产工具使用(is917量产教程)前言也许大家都知道,分析 Kernel Dump有个常用的工具叫 Crash,在我刚开始学习分析 Kernel Dump的时候,总是花大量的时间折腾这个工具的用法,却总是记不住这个工具的功能。后来有一次在参加某次内部分享的时候,有位大佬说了一句话让我印象非常深刻:这些工具怎么用的大家不用记,等到真正开始用的时候你就会猜到这个工具有什么功能。
这篇文章我想通过分析一个实际的案例,尽量把学习Kernel Dump需要用到的知识串起来,虽然某些知识也许只会在这个案例中用到,但是我相信所用到的方法是可以应用到各个地方的。
起
线上有一台 VM宕机了,刚好有抓到 dump,拿到一台测试机上就可以开始分析了。首先需要的是 kernel版本对应的 symbol,如果事先不知道 kernel的版本,可以通过 `strings corefile| grep\"Linux version\"'获取到当前 corefile的 kernel版本,例如 3.10.0-862.14.4.el7.x86_64
在获取到内核版本之后,根据相应的发行版以及系统架构到特定的 symbol发布页面下载 symbol,这里的发行版是 Centos,可以到 下载。如果是 Ubuntu发行版,可以到 下载。要找到指定 kernel版本的 symbol很简单,只需要拿着 kernel版本 3.10.0-862.14.4.el7.x86_64搜一下就能找到了,通常我们需要的 symbol的只有下面这三个中的两个,但是我总是记不住是哪两个,所以我会把三个都下载下来并安装:kernel-debug-debuginfo-3.10.0-862.14.4.el7.x86_64.rpm、kernel-debuginfo-3.10.0-862.14.4.el7.x86_64.rpm、kernel-debuginfo-common-x86_64-3.10.0-862.14.4.el7.x86_64.rpm。在安装的时候由于依赖的关系需要先安装 common的 symbol才能安装其它 symbol,另外如果测试机上的 kernel版本比 corefile的版本新,需要加上--force选项才能安装上。
承
在 symbol安装完之后,就可以通过 crash载入 corefile和 symbol了。
[root@iZxxx1Z crash]# crash/lib/debug/lib/modules/3.10.0-862.14.4.el7.x86_64/vmlinux i-2xxxpe.236725344.208176-2019-02-27-22\:44\:20crash 7.2.3-8.el7Copyright(C) 2002-2017 Red Hat, Inc.Copyright(C) 2004, 2005, 2006, 2010 IBM CorporationCopyright(C) 1999-2006 Hewlett-Packard CoCopyright(C) 2005, 2006, 2011, 2012 Fujitsu LimitedCopyright(C) 2006, 2007 VA Linux Systems Japan K.K.Copyright(C) 2005, 2011 NEC CorporationCopyright(C) 1999, 2002, 2007 Silicon Graphics, Inc.Copyright(C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.This program is free software, covered by the GNU General Public License,and you are welcome to change it and/or distribute copies of it undercertain conditions. Enter\"help copying\" to see the conditions.This program has absolutely no warranty. Enter\"help warranty\" for details.GNU gdb(GDB) 7.6Copyright(C) 2013 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later/gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type\"show copying\"and\"show warranty\" for details.This GDB was configured as\"x86_64-unknown-linux-gnu\"...WARNING: kernel relocated [168MB]: patching 82671 gdb minimal_symbol values KERNEL:/lib/debug/lib/modules/3.10.0-862.14.4.el7.x86_64/vmlinux DUMPFILE: i-2xxxpe.236725344.208176-2019-02-27-22:44:20 CPUS: 4 [OFFLINE: 3] DATE: Wed Feb 27 22:44:18 2019 UPTIME: 11:34:59LOAD AVERAGE: 0.20, 0.07, 0.06 TASKS: 436 NODENAME: iZ2xxxpeZ RELEASE: 3.10.0-862.14.4.el7.x86_64 VERSION:#1 SMP Wed Sep 26 15:12:11 UTC 2018 MACHINE: x86_64(2500 Mhz) MEMORY: 16 GB PANIC:\"kernel BUG at drivers/virtio/virtio_ring.c:278!\" PID: 278 COMMAND:\"kworker/2:1H\" TASK: ffff917c6d3b3f40 [THREAD_INFO: ffff917c64798000] CPU: 2 STATE: TASK_RUNNING(PANIC)通过 crash载入 corefile的时候,crash会自动输出一段信息,这段信息包含了系统的一些基本信息,如 CPU、内存、架构等。如果后面分析的时候还想看这部分信息,可以通过 sys命令来查看。这里我们需要重点关注的信息是
PANIC:\"kernel BUG at drivers/virtio/virtio_ring.c:278!\"
这个信息告诉电脑我们,系统触发了位于 drivers/virtio/virtio_ring.c这个文件的第 278行的 Bug,这里系统之所以知道是 Bug,是因为编写这段代码的大佬在这里埋了一个检测的点,这个待会我们会在源码里看到。
在看完上面的信息后,我的习惯是先看看当时系统在做什么,通过 bt命令可以看到当时的调用堆栈:
crash> btPID: 278 TASK: ffff917c6d3b3f40 CPU: 2 COMMAND:\"kworker/2:1H\"#0 [ffff917c6479b8a0] die at ffffffff8b82f96b#1 [ffff917c6479b8d0] do_trap at ffffffff8bf1cea0#2 [ffff917c6479b920] do_invalid_op at ffffffff8b82c284#3 [ffff917c6479b9d0] invalid_op at ffffffff8bf28aee [exception RIP: virtqueue_add+1186] RIP: ffffffffc023a382 RSP: ffff917c6479ba80 RFLAGS: 00010097 RAX: 0000000000000081 RBX: ffff917c6c67d000 RCX: 0000000000000002 RDX: 0000000000000081 RSI: ffff917c6479bc00 RDI: ffff917c6c67d000 RBP: ffff917c6479bae8 R8: 0000000000000001 R9: ffff917c6b48a380 R10: ffff917c6b410000 R11: 0000000000000002 R12: ffff917c6479bc18 R13: ffff917c6479bc18 R14: ffff917c6479bc00 R15: 0000000000000001 ORIG_RAX:电脑 ffffffffffffffff CS: 0010 SS: 0018#4 [ffff917c6479ba80] __kmalloc at ffffffff8b9fbeb0#5 [ffff917c6479baf0] virtqueue_add_sgs at ffffffffc023a437 [virtio_ring]#6 [ffff917c6479bb48] __virtblk_add_req at ffffffffc03874b2 [virtio_blk]#7 [ffff917c6479bc68] virtio_queue_rq at ffffffffc03876f9 [virtio_blk]#8 [ffff917c6479bcb8] blk_mq_dispatch_rq_list at ffffffff8bb2a8b6#9 [ffff917c6479bd50] blk_mq_do_dispatch_sched at ffffffff8bb2f76e#10 [ffff917c6479bd98] blk_mq_sched_dispatch_requests at ffffffff8bb3012e#11 [ffff917c6479bde8] __blk_mq_run_hw_queue at ffffffff8bb29362#12 [ffff917c6479be10] blk_mq_run_work_fn at ffffffff8bb295c5#13 [ffff917c6479be20] process_one_work at ffffffff8b8b613f#14 [ffff917c6479be68] worker_thread at ffffffff8b8b71d6#15 [ffff917c6479bec8] kthread at ffffffff8b8bdf21上图打印的信息包含函数调用堆栈和各寄存器的值,这里挑几个比较重要的寄存器讲一下。 RIP指向正在执行的指令地址,在发生宕机之前,系统最后执行的函数电脑是 virtqueue_add,导致宕机的语句位于 virtqueue_add+1186。根据 x86_64 Linux系统的函数调用约定,RDI, RSI, RDX, RCX, R8, R9为传入函数的前六个参数,如果参数超过六个,第七个以上的参数将通过栈传递。注意在实际函数执行的过程中,寄存器的值可能会改变。
现在来看看 ffffffffc023a382+1186这行代码到底是什么,通过 dis命令可以查看到对应的汇编。但当我们执行dis virtqueue_add+1186的时候,发现报错了,报错的内容是 symbol有重复。
crash> dis virtqueue_add+1186dis: virtqueue_add+1186: duplicate text symbols found:ffffffffc0239ee0(t) virtqueue_add [virtio_ring]ffffffffc023ab73(t) virtqueue_add [virtio_ring]我们可以通过 RIP的值来计算出当前的 virtqueue_add对应的是哪个 symbol,计算方法很简单,只要把 RIP的值减去偏移量 1186即可。
crash> p/x 0xffffffffc023a382-1186$1= 0xffffffffc0239ee0通过 dis ffffffffc0239ee0可以打印出 virtqueue_add的汇编,找到 virtqueue_add+1186
0xffffffffc023a378: mov 0x60(%rbx),%eax0xffffffffc023a37b: jmpq 0xffffffffc023a299 0xffffffffc023a380: ud20xffffffffc02电脑3a382: ud2该行汇编实际上是 ud2,这是一条 undefined的语句,也正是因为这条语句让系统宕机了。这个时候通常应该往上找,看看之前执行过的指令是什么。这里上一条指令是 jmpq,这是无条件跳转语句,跳转到 virtqueue_add+953,也就是说 ud2指令的上一条指令一定不是 jmpq这条,可以猜到应该是前面有某个跳转直接跳到这里来了,往上找找就可以找到
0xffffffffc0239ef4: mov%rsi,-0x48(%rbp)0xffffffffc0239ef8: mov%edx,-0x2c(%rbp)0xffffffffc0239efb: mov%ecx,-0x38(%rbp)0xffffffffc0239efe: mov%r8d,-0x58(%rbp)0xffffffffc0239f02: mov%r9,-0x60(%rbp)0xffffffffc0239f06: je 0xffffffffc023a384 0xffffffffc0239f0c: cmpb$0x0,0x59(%rdi)0xffffffffc0239f10: mov%rdi,%rbx0xffffffffc0239f13: jne 0xffffffffc023a05d 0xffffffffc0239f19: mov-0x2c(%rbp),%eax0xffffffffc0239f1c: cmp%eax,0x38(%rdi)0xffffffffc0239f1f: jb 0xffffffffc023a382可以看到跳转的语句是 jb 0xffffffffc023a382,跳转的条件是%eax小于 [%rdi+ 0x38]。那%eax和 [%rdi+ 0x38]里面存的值是什么呢?这个时候就需要对照源码来看了。通过 dis-l可以看到函数所在的源文件,但是直接执行 dis-l ffffffffc0239ee0会发现没有源文件的信息,这种情况通常是对应的 debug模块没有导进来。通过 mod命令可以看到当前的模块,找到我们需要的模块,通过 mod-s找到模块对应的目录,再通过相同的命令导入即可,如:
crash> mod-s virtio_ring MODULE NAME SIZE OBJECT FILEffffffffc023c0e0 virtio_ring 22746/usr/lib/debug/usr/lib/modules/3.10.0-862.14.4.el7.x86_64/kernel/drivers/virtio/virtio_ring.ko.debugcrash> mod-s virtio_ring/usr/lib/debug/usr/lib/modules/3.10.0-862.14.4.el7.x86_64/kernel/drivers/virtio/virtio_ring.ko.debug MODULE NAME SIZE OBJECT FILEffffffffc023c0e0 virtio_ring 22746/usr/lib/debug/usr/lib/modules/3.10.0-862.14.4.el7.x86_64/kernel/drivers/virtio/virtio_ring.ko.debug把所有缺少的模块导入进来之后,再次执行dis-l ffffffffc0239ee0就可以看到对应的源文件了。部分 virtqueue_add源代码如下:
241 static inline int virtqueue_add(struct virtqueue*_vq, 242 struct scatterlist*sgs[], 243 unsigned int total_sg, 244 unsigned int out_sgs, 245 unsigned int in_sgs, 246 void*data, 247 gfp_t gfp) 248{ 249 struct vring_virtqueue*vq= to_vvq(_vq); 250 struct scatterlist*sg; 251 struct vring_desc*desc; 252 unsigned int i, n, avail, descs_used, uninitialized_var(prev), err_idx; 253 int head; 254 bool indirect; 255 256 START_USE(vq); 257 258 BUG_ON(data== NULL); 259 260 if(unlikely(vq->broken)){ 261 END_USE(vq); 262 return-EIO; 263} 264 265#ifdef DEBUG 266{ 267 ktime_t now= ktime_get(); 268 269/* No kick or get, with.1 second between? Warn.*/ 270 if(vq->last_add_time_valid) 271 WARN_ON(ktime_to_ms(ktime_sub(now, vq->last_add_time)) 272> 100); 273 vq->last_add_time= now; 274 vq->last_add_time_valid= true; 275} 276#endif 277 278 BUG_ON(total_sg> vq->vring.num); 279 BUG_ON(total_sg== 0); 280 281 head= vq->free_head; 282 283/* If the host supports indirect descriptor tables, and we have multiple 284* buffers, then go indirect. FIXME: tune this threshold*/ 285 if(vq->indirect&& total_sg> 1&& vq->vq.num_free) 286 desc= alloc_indirect(_vq, total_sg, gfp); 287 else 288 desc= NULL; 289 290 if(desc){ 291/* Use a single buffer which doesn't continue*/ 292 indirect= true; 293/* Set up rest to use this indirect table.*/ 294 i= 0; 295 descs_used= 1; 296} else{ 297 indirect= false; 298 desc= vq->vring.desc; 299 i= head; 300 descs_used= total_sg; 301}通过dis-l ffffffffc0239ee0打印出的信息并结合之前的分析,可以知道:1. virtqueue_add的前五个参数分别是 struct virtqueue、struct scatterlist、 unsigned int、 unsigned int、 unsigned int类型的,对应的是 RDI, RSI, RDX, RCX, R8这五个寄存器的值。2.触发 bug的语句是第 278行的 BUG_ON(total_sg> vq->vring.num);
通过 struct virtqueue ffff917c6c67d000可以解析出第一个参数的结构:
crash> struct virtqueue ffff917c6c67d000struct virtqueue{ list={ next= 0xffff917bbefa82c8, prev= 0xffff917bbefa82c8}, callback= 0xffffffffc0387000, name= 0xffff917c6c7a1dcc\"req.0\", vdev= 0xffff917bbefa8000, index= 0, num_free= 1, priv= 0xffffadff81b5e010}回到刚刚我们讨论的%eax和 [%rdi+ 0x38],[%rdi+ 0x38]实际上就是 virtqueue中偏移量为 0x38的值,通过 struct-o virtqueue可以打印出 virtqueue各成员的偏移:
crash> struct-o virtqueuestruct virtqueue{ [0] struct list_head list; [16] void(*callback)(struct virtqueue*); [24] const char*name; [32] struct virtio_device*vdev; [40] unsigned int index; [44] unsigned int num_free; [48] void*priv;}SIZE: 56这里又出现了一个问题,0x38是十进制的 56,而这个结构体的大小总共只有 56个字节,难道是“溢出”了?仔细阅读代码后发现,代码里有一句 struct vring_virtqueue*vq= to_vvq(_vq);,to_vvq是一个宏,定义如下#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq),实际上这就是对 container_of的一个封装,container_of的功能跟字面意思很接近,这里 virtqueue类型的 _vq变量实际上是 vring_virtqueue类型的 vq变量的一个成员变量,通过 container_of(_vq, struct vring_virtqueue, vq)把 vq计算出来。我们通过struct-o vring_virtqueue来查看 vring_virtqueue的结构:
crash> struct-o vring_virtqueuestruct vring_virtqueue{ [0] struct virtqueue vq; [56] struct vring vring; [88] bool weak_barriers; [89] bool broken; [90] bool indirect; [91] bool event; [92] unsigned int free_head; [96] unsigned int num_added; [100] u16 last_used_idx; [104] bool(*notify)(struct virtqueue*); [112] bool we_own_ring; [120] size_t queue_size_in_bytes; [128] dma_addr_t queue_dma_addr; [136] struct vring_desc_state desc_state[];}SIZE: 136可以看到实际上 virtqueue结构就在 vring_virtqueue偏移为 0的地方,因此可以直接通过 struct vring_virtqueue ffff917c6c67d000来解析
vring_virtqueue结构:
crash> struct vring_virtqueue ffff917c6c67d000struct vring_virtqueue{ vq={ list={ next= 0xffff917bbefa82c8, prev= 0xffff917bbefa82c8}, callback= 0xffffffffc0387000, name= 0xffff917c6c7a1dcc\"req.0\", vdev= 0xffff917bbefa8000, index= 0, num_free= 1, priv= 0xffffadff81b5e010}, vring={ num= 128, desc= 0xffff917c6bf68000, avail= 0xffff917c6bf68800, used= 0xffff917c6bf69000}, weak_barriers= true, broken= false, indirect= true, event= false, free_head= 94, num_added= 0, last_used_idx= 38531, notify= 0xffffffffc0249a50, we_own_ring= true, queue_size_in_bytes= 5126, queue_dma_addr= 17917444096, desc_state= 0xffff917c6c67d088}因此 [%rdi+ 0x38]实际上获取的是 vring结构里偏移量为 0的即第一个成员的值,这里获取到的值就是 128。现在我们已经通过这种方法获取到触发 bug的语句中 BUG_ON(total_sg> vq->vring.num);的 vq->vring.num值了,而 total_sg实际上是 virtqueue_add的第三个参数,保存在 RDX寄存器里,是 0x81,即十进制的 129。
合
至此,我只是分析了这几个数据结构中相关的变量内容,还没有解释这些变量或者函数的含义,现在我们已经验证了触发 BUG的条件 total_sg> vq->vring.num,但是为什么会出现这种情况呢?要分析这几个变量的值需要回溯到调用这个函数的函数,最终可能需要一直回溯到发起 IO请求的应用层程序,这显然是一件非常麻烦的事情。换一个角度来想,total_sg是 vm需要的 scatterlist的总数,scatterlist是一个跟物理内存有关的结构,这里可以简单理解为 vm所需要的物理内存,而 vring是 virtio前后端数据传输的载体,这里可以简单理解前后端数据传输的能力。直观的感觉是 total_sg确实不应该比 vring.num大,但实际上 total_sg只比 vring.num大 1,而且这里 total_sg的值与我刚开始的想法不一样,由于 total_sg是 unsigned int类型的,而这里的比较是 total_sg> vq->vring.num,因此我开始的想法是 total_sg下溢出了。分析到这里,我抱着试一试的态度把 BUG_ON(total_sg> vq->vring.num);丢到 Google上搜了一把,发现这行代码已经在某个版本中 patch掉了,最新的 kernel里把 BUG_ON改成了低一级的 WARN_ON_ONCE,同时把条件改成了 total_sg> vq->vring.num&&!vq->indirect。也就是说,在使用了 indirect descriptors的情况下,是允许 total_sg> vq->vring.num这中情况出现的,那如何验证 vm有没有使用 indirect descriptors呢?实际上在 vring_virtqueue中的成员 indirect标示了是否使用 indirect descriptors,在上面执行 struct vring_virtqueue ffff917c6c67d000的时候已经把 indirect的值打印出来了,vm确实使用了 indirect descriptors,因此这个 bug实际上触发得并不合理,仅仅只判断 total_sg> vq->vring.num就触发宕机的条件太过严格了。
总结
这个宕机问题到这里就算分析完了,最后解决的方案是升级内核,考虑到目前 Centos官方还未接受该 patch,需要手动编译修复或通过第三方 repo升级。实际上很多奇奇怪怪的问题都可以通过升级内核来解决,但是最新的内核同样可能遇到奇奇怪怪的问题,谁知道下一个发现内核 bug后写了 patch最后被社区接受的会不会是自己呢?希望大家通过这篇文章能有所收获。文章写得不好或不对的地方请各位大佬不吝赐教。
作者:半人前
电脑电脑