当前位置: 首页 > news >正文

龙岩网站设计找哪家公司番禺大石网站建设

龙岩网站设计找哪家公司,番禺大石网站建设,中铁三局招聘信息2021,wordpress播放器源码by fanxiushu 2023-10-15 转载或引用请注明原始作者。 前一章节介绍的是linux平台下的虚拟磁盘驱动开发过程#xff0c;主要讲述了 基于block的磁盘和基于SCSI接口的磁盘。 本文介绍的内容正是基于上文中的SCSI接口的虚拟磁盘实现的无盘启动。 同样的#xff0c;linux系统下也…                by fanxiushu 2023-10-15 转载或引用请注明原始作者。 前一章节介绍的是linux平台下的虚拟磁盘驱动开发过程主要讲述了 基于block的磁盘和基于SCSI接口的磁盘。 本文介绍的内容正是基于上文中的SCSI接口的虚拟磁盘实现的无盘启动。 同样的linux系统下也有系统自己集成的无盘启动方案 这点与windows类似就连协议也能找到一样的也就是windows和linux都可以使用iSCSI进行无盘启动。 但是linux系统可以选择的方案更多除了大家都认可的基于底层磁盘块设备的无盘启动 linux还能基于上层的文件系统进行无盘启动比如linux可以配置NFS网络文件系统来无盘启动。 不过我认为还是基于底层块设备更好些至少服务端对单个的镜像文件更好管理一些。 本文并不介绍linux系统自己集成的无盘启动方案而是如前面文章阐述的windows平台的无盘启动系统一样。 全是自己开发的。 可以先看看下面演示视频   linux的无盘启动 其实linux的无盘启动和windows的无盘启动的大体方向都是一致的 1在电脑引导阶段需要开发 BIOSUEFI引导程序 2接着进入具体的操作系统阶段需要开发对应的虚拟磁盘驱动来接管操作系统的启动和运行过程。 但是linux和windows的启动过程有非常巨大的区别这就造成了上面的第2个步骤中开发的虚拟磁盘驱动的天差地别。 我们来回忆一下前面章节讲述windows的启动阶段。 windows基本分成三个阶段 1boot-start阶段运行 bios引导阶段winloader.efi(exe)程序加载到内存的windows基本内核和boot-start驱动程序 2initsystem阶段 系统初始化 3win logon阶段系统登录 而且也说过对于无盘启动来说最重要的是boot-start阶段的处理问题这是很麻烦的一件事。 具体都在以前的章节中讲述过。 而linux平台下的启动阶段对无盘系统来说就相对友好的多。 当然同样的bios引导阶段会加载linux的引导程序这个一般都是grub引导程序当然可能也有其他引导程序但是目前以grub为主 而grub主要工作就是把 vmlinuz 基本内核文件 加载到内存中 vmlinuz文件都可以在 /boot目录下找到通常是vmlinuz为前缀加一些版本号什么的。 再然后就是加载 initramfs 虚拟文件系统到内存 而 initramfs 就是我们能正常运行我们的虚拟磁盘驱动的关键等下会讲述。 接着grub开始解压 initramfs等虚拟文件系统并且挂载出一个虚拟文件系统运行 vmlinuz 内核把控制权力交接给linux内核。 现在我们来看看 linux为何会有 initramfs 这个虚拟文件系统。 linux和windows或者说任何操作系统都一样都存在一个尴尬的问题 当BIOS引导程序把控制权交接给具体的操作系统 操作系统不可避免的都需要访问磁盘但是在最开始阶段操作系统刚运行磁盘驱动还没加载 磁盘驱动文件不存在需要从磁盘上加载磁盘驱动文件但是这个时候操作系统无法访问磁盘。。。 这就陷入了一个荒诞的循环悖论中。 因此唯一的做法就是在BIOS引导程序还在运行的阶段把磁盘驱动文件首先加载到内存中。 windows的做法就是在BIOS运行阶段winloader.exe程序把windows基本内核ntoskrne.exe等基本文件 以及处于 boot-start阶段其中必然会包括磁盘驱动加载到内存中。 因此到了windows的boot-start阶段就开始运行加载到内存中的这些文件。 而linux的做法我们可以有一个非常简单的办法 反正vmlinuz内核文件肯定首先被加载到内存中我们把对应磁盘的驱动直接编译集成到vmlinuz内核文件中。 反正linux内核开源而且是那种大一统的内核不像windows的ntoskrnel内核 但是这样弊端也非常明显什么东西都朝vmlinuz内核文件中集成会变得越来越臃肿和难以管理。 于是就诞生了 initramfs顾名思义 基于内存的文件系统很像我们在内存中虚拟出一块磁盘然后在上面加载对应的文件系统。 其实在2.6版本之前是initrd也就是直接生成内存磁盘。 2.6之后的版本使用了initramfs来代替因为initrd会直接开辟一块内存作为内存磁盘这样会造成一些浪费。 而initramfs则是完全根据加载的文件来模拟虚拟文件系统不存在initrd那样的浪费。 该如何解释initramfs展现出来的效果呢 就是当grub把vmlinuz和initramfs加载到内存并且initramfs初始化完成vmlinuz接管控制权之后 在没有访问真正的磁盘之前 如果我们这时候登录到linux会神奇的发现像 /etc, /lib ,/bin /usr/lib 等目录就已经存在而且里边有对应的文件了。 可是实际上我们还没真正访问本地磁盘。 这就是initramfs效果它在内存中模拟出本地磁盘文件系统vmlinuz内核像访问真正的目录文件那样访问这些目录中的文件。 于是linux内核找到磁盘驱动文件位置然后加载它之后就能正常访问真正的本地磁盘系统了。 当然这个时候linux内核会把真正的磁盘系统挂载上去替换掉initramfs。 接下来我们需要做的就是利用相关工具程序把我们对应的磁盘驱动加到 initramfs 虚拟系统文件中。 当然如果我们是在具体的电脑中安装对应的linux操作系统安装程序就已经帮我们做好这一步了。 与windows做个对比可以发现使用initramfs比起windows启动阶段显然简单得多 这是不同系统内核的处理方式造成的所以也不大可能搞得windows像linux那样的启动方式。 有了initramfs 我们加载自己的无盘系统就相对简单得多了。 我们主要在iniramfs中添加两个驱动 1网卡驱动 2我们的虚拟磁盘驱动 网卡驱动则是对应网卡硬件厂商在linux下开发的驱动 网卡驱动必须添加到initramfs中否则虚拟磁盘无法访问网络从而无法建立网络磁盘。 接着就是我们的虚拟磁盘驱动。 而虚拟磁盘驱动访问网络方式也不用像windows那样使用底层的NDIS协议 可以直接使用TCP通信因为TCP协议栈直接集成到vmlinuz内核中 也不用担心像windows那样最早阶段连TCP协议栈都没建立起来。 这里以CentOS7vmware虚拟机为例子 简单阐述下如何把这两个驱动添加到 initramfs 中。 首先假设我们开发的无盘启动的虚拟磁盘驱动 是 nbt_scsi.ko 把nbt_scsi.ko 复制到  /usr/lib/modules/$VERSION/kernel/drivers/block 目录中 其中 $VERSION 对应的linux具体的内核版本 然后使用 xz 命令 把 nbt_scsi.ko 压缩成 nbt_scsi.ko.xz 文件 运行 depmod -a 生成关联信息。 同时在 /etc/modules-load.d/ 目录中添加一个文件比如取名 nbt_scsi.conf 使用vi编辑添加 如下两行 nbt_scsi e1000 其中e1000是vmware环境下CentOS7系统对应的网卡驱动。 在 /etc/modules-load.d/ 目录下生成以上文本文件的目的是为了让linux内核自动加载上面两个驱动。 再然后则使用dracut 如下运行 dracut --force --add-drivers nbt_scsi 表示把 nbt_scsi 驱动添加到 initramfs 虚拟文件系统文件中。 不同的linux发行版本可能有不同的命令但总体思路都是一样的。 生成之后如果不放心 可以使用 lsinitrd |grep nbt_scsi 命令查看 initramfs中是否已经新添加了对应驱动文件。 同样的步骤把 e1000 网卡驱动添加到 initramfs 中。 至此CentOS7系统下的无盘配置就算完成然后运行 nbt_scsi.ko  驱动把服务端对应的镜像文件映射成本地scsi磁盘。 接着可以使用 dd 等命令把磁盘数据copy到服务端镜像中。 再然后我们就可以在别的也是同样支持e1000网卡的vmware虚拟机中无盘方式启动 centos7 了。 接着我们来看看nbt_scsi.ko 驱动中关于网络通信部分 至于scsi接口的磁盘部分上面一篇文章中已经阐述过这里就不再重复了。 本文前面也说过通信部分完全可以直接使用TCP通信而且linux内核中socket与应用层的 BSD socket 接口一样的简单方便。 如下代码我们就能封装成几乎跟应用层socket一样的接口方式 kernel socket struct socket* sock_create_v4(BOOLEAN  is_tcp) {     struct socket* sock NULL; #if LINUX_VERSION_CODE KERNEL_VERSION(5, 10, 0)     int ret sock_create_kern(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM , 0, sock); #else     int ret sock_create_kern(init_net, AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, 0, sock); #endif     if (ret 0) {         printk(sock_create_kern err%d\n, ret);         return NULL;     }     if (is_tcp) {         int nodelay 1; #if LINUX_VERSION_CODE KERNEL_VERSION(5, 10, 0)         ret kernel_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)nodelay, sizeof(int)); #else         ret sock_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, KERNEL_SOCKPTR((char*)nodelay), sizeof(int)); #endif         if (ret) {             printk( warnning: set tcp no delay err%d\n, ret);         }     }     return sock; } void sock_destroy(struct socket* s) {     if (s) {         sock_release(s);     } } typedef struct _sock_addr_v4 {     uint32_t   ip;     uint16_t   port;      } sock_addr_v4; int sock_connect(struct socket* s, sock_addr_v4* svr_addr) {     int ret;     struct sockaddr_in addr;     memset(addr, 0, sizeof(addr));     addr.sin_family AF_INET;     addr.sin_addr.s_addr svr_addr-ip;     addr.sin_port svr_addr-port;     ret kernel_connect(s, (struct sockaddr*)addr, sizeof(addr), 0);     if (ret 0) {         printk(*** socket connect err%d\n, ret);     }     return ret; } // 数据传输,包括接收或发送 int sock_transmit(     struct socket* sock, bool send, sock_addr_v4* addr,     char* buf, int size) {     struct msghdr msg;     struct kvec iov;     struct sockaddr_in v4_addr;     int ret;     sock-sk-sk_allocation GFP_NOIO;     iov.iov_base buf;     iov.iov_len size;     msg.msg_name NULL;     msg.msg_namelen 0;     msg.msg_control NULL;     msg.msg_controllen 0;     msg.msg_flags MSG_NOSIGNAL;     if (addr) {         if (send) {             memset(v4_addr, 0, sizeof(v4_addr));             v4_addr.sin_family AF_INET;             v4_addr.sin_addr.s_addr addr-ip;             v4_addr.sin_port addr-port;         }         msg.msg_name (struct sockaddr*)v4_addr;         msg.msg_namelen sizeof(struct sockaddr_in);     }     if (send) ret kernel_sendmsg(sock, msg, iov, 1, size);     else {         ret kernel_recvmsg(sock, msg, iov, 1, size, /*MSG_WAITALL*/ 0); ///完整接收size长度的数据         if (ret 0 addr) {//收到数据了             addr-ip v4_addr.sin_addr.s_addr;             addr-port v4_addr.sin_port;         }     }          return ret; } 显然比起windows平台提供的TDI接口或者WSK接口不知道要简单多少倍了。 然后接下来就是磁盘数据的传输这没啥好阐述的按照SCSI接口提供的标准通信即可。 不过无盘启动的时候依然会有问题 其实主要就是grub加载内核之后linux运行之后并不会自动运行DHCP来配置本地IP地址 如果没有对应的本地IP地址TCP就无法路由自然也无法通信。 至于这点我们可以修改grub的启动参数添加linux内核启动之后自动运行DHCP的支持 也就是会多增加一些配置。 不过我自己开发的无盘系统最主要的是基于windows平台的 而在以前文章阐述过底层网络通信基本都是直接使用NDIS通信然后把链路层协议转成UDP来达到磁盘传输的目的。 所有协议的定义都和UDP有关而且还会直接使用MAC地址来定位相关信息。 所以在linux平台的nbt_scsi驱动中并没有使用TCP传输或者只是作为辅助而已。 这样为了能跟windows中NDIS方式更好的结合。 一开始想在linux内核中寻找windows中类似NDIS的接口甚至都想直接挂钩linux网卡驱动对应的通用接收函数。 到后来突然想到 PF_PACKET协议的套接口它同样能接收和发送链路层数据包。 想到这一点事情就好办了。 直接在nbt_scsi驱动使用 PF_PACKET协议的套接口。 同时为了加快接收速度其实是替换了PF_PACKET 套接口的 sk_data_ready 回调函数。 这个实现过程就跟windows中使用NDIS协议驱动实现类似UDP套接口一样的复杂了。 有个好处就是我不用再去理会本地IP地方分配问题也不用去管DHCP因为我在自己的协议中处理ip地址问题。 当然代价也是高昂的等于自己利用链路层数据通信自己完整实现了属于自己特色的UDP传输协议栈。 限于篇幅这里不再赘述有兴趣的同学可自行去研究。
http://www.w-s-a.com/news/166673/

相关文章:

  • 建设网站 请示 报告wordpress会员制
  • 青岛建网站人做网站怎么赚钱广告
  • 网站建设哪家好公司跨境电商展会2023
  • 设计大神云集的网站是南通市 网站设计
  • 心理咨询网站模板企业画册封面设计
  • 做网站 南京网站建设的重难点分析
  • 深圳做网站980移动网站开发语言
  • 网站评论怎么做seo关键词优化方法
  • 市级部门网站建设自评报告网站优化文章怎么做
  • 可不可以异地建设网站学做网站培训班要多少钱
  • 茌平网站建设公司免费的云服务器有哪些
  • 手机网站单页面铜陵网站制作公司
  • 网站logo怎么做才清晰千库网官网首页登录
  • 山西省建设银行网站首页长沙网站建设制作
  • 襄阳市做网站 优帮云百度搜索次数统计
  • 自己做视频直播网站盐城做网站多少钱
  • 买个网站服务器多少钱重庆做的好的房产网站
  • 深圳定制建站网站建设推广关键词怎么设置
  • 宝山网站建设 网站外包修改wordpress版权
  • 建立网站的基本步骤新网站多久会被百度收录
  • 软件设计开发流程图廊坊关键词seo排名方案
  • 南山住房和建设局网站网站被k 多久恢复
  • 阿里买域名 电脑做网站做简历哪个网站好
  • 个人网站免费服务器单页网站的域名
  • 网站设计简单讲解小店怎么做网站
  • 校园网站的意义wordpress去除更新
  • 网站开发用python吗常用的网页开发工具有哪些
  • 北京市住房建设投资建设网站做商城网站要哪些流程
  • seo网站改版杭州建设局官网
  • 物流网站建设策划书泰然建设网站