创建块设备并自动挂载
1. 概述
从本小节开始,我们以一个虚拟磁盘块设备驱动为例来讲解如何编写一个基础的块设备驱动。说是虚拟的磁盘也就是分配一段内存来当做磁盘来使用,对磁盘的读写也就是访问内存的不同位置来实现。
2. 块设备注册
SylixOS中的块设备是通过LW_BLK_DEV 这个数据结构来描述的,这个结构就是一个实际磁盘控制器的抽象:
typedef struct { PCHAR BLKD_pcName; /* 可以为 NULL 或者 "\0" */ /* nfs romfs 文件系统使用 */ FUNCPTR BLKD_pfuncBlkRd; /* function to read blocks */ FUNCPTR BLKD_pfuncBlkWrt; /* function to write blocks */ FUNCPTR BLKD_pfuncBlkIoctl; /* function to ioctl device */ FUNCPTR BLKD_pfuncBlkReset; /* function to reset device */ FUNCPTR BLKD_pfuncBlkStatusChk; /* function to check status */ ULONG BLKD_ulNSector; /* number of sectors */ ULONG BLKD_ulBytesPerSector; /* bytes per sector */ ULONG BLKD_ulBytesPerBlock; /* bytes per block */ BOOL BLKD_bRemovable; /* removable medium flag */ BOOL BLKD_bDiskChange; /* media change flag */ INT BLKD_iRetry; /* retry count for I/O errors */ INT BLKD_iFlag; /* O_RDONLY or O_RDWR */ /* * 以下参数操作系统使用, 必须初始化为 0. */ INT BLKD_iLogic; /* if this is a logic disk */ UINT BLKD_uiLinkCounter; /* must be 0 */ PVOID BLKD_pvLink; /* must be NULL */ UINT BLKD_uiPowerCounter; /* must be 0 */ UINT BLKD_uiInitCounter; /* must be 0 */ } LW_BLK_DEV;
一个块设备通常都会有自己的磁盘缓冲,在SylixOS中,块设备缓冲是通过 LW_DISKCACHE_ATTR 数据结构来描述的:
typedef struct { PVOID DCATTR_pvCacheMem; /* 扇区缓存地址 */ size_t DCATTR_stMemSize; /* 扇区缓存大小 */ INT DCATTR_iBurstOpt; /* 缓存属性 */ INT DCATTR_iMaxRBurstSector; /* 磁盘猝发读的最大扇区数 */ INT DCATTR_iMaxWBurstSector; /* 磁盘猝发写的最大扇区数 */ INT DCATTR_iMsgCount; /* 管线消息队列缓存个数 */ INT DCATTR_iPipeline; /* 处理管线线程数量 */ BOOL DCATTR_bParallel; /* 是否支持并行读写 */ ULONG DCATTR_ulReserved[8]; /* 保留 */ } LW_DISKCACHE_ATTR;
在对上述两个数据结构初始化之后,就可以调用 API_OemDiskMount2 来创建块设备并自动尝试挂载相应的分区:
PLW_OEMDISK_CB API_OemDiskMount2(CPCHAR pcVolName, PLW_BLK_DEV pblkdDisk, PLW_DISKCACHE_ATTR pdcattrl);
成功调用后,接口返回一个磁盘控制块句柄:
typedef struct { PLW_BLK_DEV OEMDISK_pblkdDisk; /* 物理磁盘驱动 */ PLW_BLK_DEV OEMDISK_pblkdCache; /* CACHE 驱动块 */ PLW_BLK_DEV OEMDISK_pblkdPart[LW_CFG_MAX_DISKPARTS]; /* 各分区驱动块 */ INT OEMDISK_iVolSeq[LW_CFG_MAX_DISKPARTS]; /* 对应个分区的卷序号 */ PLW_DEV_HDR OEMDISK_pdevhdr[LW_CFG_MAX_DISKPARTS]; /* 安装后的设备头 */ PVOID OEMDISK_pvCache; /* 自动分配内存地址 */ UINT OEMDISK_uiNPart; /* 分区数 */ INT OEMDISK_iBlkNo; /* /dev/blk/? 设备号 */ CHAR OEMDISK_cVolName[1]; /* 磁盘根挂载节点名 */ } LW_OEMDISK_CB;
一般的做法是定义一个全局的块设备数据结构变量,块缓冲数据结构可以定义为局部变量,初始化后进行块设备创建:
static LW_BLK_DEV vdisk_dev; static PLW_OEMDISK_CB *vdisk_oemcb; int module_init (void) { PLW_BLK_DEV pdev = &vdisk_dev; LW_DISKCACHE_ATTR dcattrl; /* * 配置块设备参数 */ pdev->BLKD_pcName = "VirtualDisk"; pdev->BLKD_ulNSector = VIRTUAL_DISK_SIZE / SECTOR_BYTES; pdev->BLKD_ulBytesPerSector = SECTOR_BYTES; pdev->BLKD_ulBytesPerBlock = SECTOR_BYTES; pdev->BLKD_bRemovable = LW_TRUE; pdev->BLKD_iRetry = 1; pdev->BLKD_iFlag = O_RDWR; pdev->BLKD_bDiskChange = LW_TRUE; pdev->BLKD_pfuncBlkRd = vdisk_read; pdev->BLKD_pfuncBlkWrt = vdisk_write; pdev->BLKD_pfuncBlkIoctl = vdisk_ioctl; pdev->BLKD_pfuncBlkReset = vdisk_reset; pdev->BLKD_pfuncBlkStatusChk = vdisk_status_chk; pdev->BLKD_iLogic = 0; pdev->BLKD_uiLinkCounter = 0; pdev->BLKD_pvLink = LW_NULL; pdev->BLKD_uiPowerCounter = 0; pdev->BLKD_uiInitCounter = 0; dcattrl.DCATTR_pvCacheMem = LW_NULL; dcattrl.DCATTR_stMemSize = (size_t)(DISK_CACHE_SIZE); dcattrl.DCATTR_iBurstOpt = LW_DCATTR_BOPT_CACHE_COHERENCE; dcattrl.DCATTR_iMaxRBurstSector = (INT)BUSTOR_SECTOR; dcattrl.DCATTR_iMaxWBurstSector = (INT)BUSTOR_SECTOR; dcattrl.DCATTR_iMsgCount = 4; dcattrl.DCATTR_bParallel = LW_TRUE; dcattrl.DCATTR_iPipeline = 1; vdisk_oemcb = API_OemDiskMount2("/media/vdisk", pdev, &dcattrl); if (!vdisk_oemcb) { printk("oem disk mount fail.\r\n"); free(vdisk_start); return (PX_ERROR); } return (ERROR_NONE); } void module_exit (void) { if (vdisk_oemcb) { API_OemDiskUnmount(vdisk_oemcb); } }
具体的初始化参数会在下面章节讲解,API_OemDiskMount2 第一个参数表示块设备要挂载的位置,系统会自动截取最后一个'/'后面的字符串加上块设备序号或者分区号组成最终的设备名和挂载目录。
同时还要定义一个全局变量用来保存虚拟磁盘的内存起始地址:
#define VIRTUAL_DISK_SIZE 20 * LW_CFG_MB_SIZE static void *vdisk_start; int module_init (void) { vdisk_start = malloc(VIRTUAL_DISK_SIZE); if (!vdisk_start) { printk("create virtual disk fail.\n"); return (PX_ERROR); } return (ERROR_NONE); }
在驱动中使用malloc接口申请内存当做虚拟磁盘空间,默认的大小为20MB。
2022年2月11日 11:27 1F
打卡