日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

块设备驱动介绍

發(fā)布時(shí)間:2023/12/20 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 块设备驱动介绍 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

以下內(nèi)容源于朱有鵬《物聯(lián)網(wǎng)大講堂》課程的學(xué)習(xí),如有侵權(quán),請(qǐng)告知?jiǎng)h除。


一、正確理解塊設(shè)備驅(qū)動(dòng)的概念

1、塊設(shè)備和字符設(shè)備的差異

  • 塊和字符是兩種不同的訪問設(shè)備的策略
  • 同一個(gè)設(shè)備可以同時(shí)支持塊和字符兩種訪問策略;
  • 設(shè)備本身的物理特性決定了哪一種訪問策略更適合;
  • 塊設(shè)備本身驅(qū)動(dòng)層支持緩沖區(qū),而字符設(shè)備驅(qū)動(dòng)層沒有緩沖;
  • 塊設(shè)備驅(qū)動(dòng)最適合存儲(chǔ)設(shè)備。

2、塊設(shè)備驅(qū)動(dòng)的特點(diǎn)

  • 字符設(shè)備只能順序訪問(如串口發(fā)送數(shù)據(jù)順序),而塊設(shè)備可以隨機(jī)訪問(不連續(xù)塊訪問);
  • 傳統(tǒng)的機(jī)械式塊設(shè)備(如硬盤、DVD)可以隨機(jī)訪問,但是連續(xù)訪問效率更高,因此塊設(shè)備驅(qū)動(dòng)中有排序邏輯將用戶的隨機(jī)訪問重新調(diào)整成盡量連續(xù)訪問以提升效率;
  • 電磁設(shè)備Nand、SD卡等隨機(jī)訪問效率等同于順序訪問;
  • 塊設(shè)備驅(qū)動(dòng)和字符設(shè)備驅(qū)動(dòng)不同,應(yīng)用層對(duì)塊設(shè)備驅(qū)動(dòng)的訪問一般不是直接操作設(shè)備文件(/dev/block/xxx,或者/dev/sdax),而是通過文件系統(tǒng)來簡(jiǎn)潔操作。(思考裸機(jī)階段時(shí)刷機(jī)燒錄SD卡時(shí)說過的對(duì)SD卡的2種訪問:文件系統(tǒng)下訪問和扇區(qū)級(jí)訪問)

3、塊設(shè)備相關(guān)的幾個(gè)單位

(1)扇區(qū)(Sector)

  • 概念來自于早期磁盤,在硬盤、DVD中還有用,在Nand/SD中已經(jīng)沒意義了。
  • 扇區(qū)是塊設(shè)備本身的特性,大小一般為512的整數(shù)倍,因?yàn)闅v史原因很多時(shí)候都向前兼容定義為512。

(2)塊(block)

  • 概念來自于文件系統(tǒng),是內(nèi)核對(duì)文件系統(tǒng)數(shù)據(jù)處理的基本單位,大小為若干個(gè)扇區(qū),常見有512B、1KB、4KB等

(3)段(Section)

  • 概念來自于內(nèi)核,是內(nèi)核的內(nèi)存管理中一個(gè)頁或者部分頁,由若干個(gè)連續(xù)為塊組成。

(4)頁(Page)

  • 概念來自于內(nèi)核,是內(nèi)核內(nèi)存映射管理的基本單位。linux內(nèi)核的頁式內(nèi)存映射名稱來源于此。

(5)總結(jié):塊設(shè)備驅(qū)動(dòng)對(duì)下以Sector為單位管理塊設(shè)備,對(duì)上以Block為單位和文件系統(tǒng)交互。


二、塊設(shè)備驅(qū)動(dòng)框架簡(jiǎn)介

1、塊設(shè)備驅(qū)動(dòng)框圖


(1)VFS

  • 虛擬文件系統(tǒng),是文件系統(tǒng)的抽象,對(duì)上可以接各種文件系統(tǒng),是一對(duì)多的關(guān)系,是分層理論。

(2)通用塊層

  • 對(duì)所有塊設(shè)備都適用,屏蔽了不同硬件的差異。類似于字符設(shè)備驅(qū)動(dòng)框架的第一部分。

(3)IO調(diào)度層(電梯算法)

  • 有別于其他設(shè)備的地方。這里提供了合并、排序等機(jī)制。
  • 讀寫相當(dāng)于電梯上、下的操作。

(4)塊設(shè)備驅(qū)動(dòng)層(真正硬件操作部分)

2、重點(diǎn)結(jié)構(gòu)體

(1)struct request對(duì)設(shè)備的每一次操作(譬如讀或者寫一個(gè)扇區(qū))

(2)struct request_queuerequest,隊(duì)列

(3)struct bio通用塊層用bio來管理一個(gè)請(qǐng)求

(4)struct gendisk表示一個(gè)磁盤設(shè)備或一個(gè)分區(qū)


三、塊設(shè)備驅(qū)動(dòng)案例分析

1、塊設(shè)備驅(qū)動(dòng)案例演示

(1)驅(qū)動(dòng)簡(jiǎn)單介紹

(2)編譯

(3)模塊安裝

(4)查看信息cat /proc/devices(查看字符和塊設(shè)備),cat /proc/partitions(查看磁盤及分區(qū)),ls /dev/,lsmod

(5)掛載測(cè)試

2、塊設(shè)備驅(qū)動(dòng)簡(jiǎn)單分析

(1)如何證明塊設(shè)備驅(qū)動(dòng)真的工作了:格式化、掛載

  • 格式化:mkfs.ext2 /dev/my_ramblock
  • 掛載:mount -t ext2 /dev/my_ramblcok /tmp,之后在/tmp進(jìn)行的操作(創(chuàng)建文件,寫內(nèi)容),都是在此塊設(shè)備進(jìn)行操作
  • 卸載:umount /tmp,卸載之后,/tmp沒有之前的文件

(2)注意各種打印信息

(3)體會(huì)塊設(shè)備驅(qū)動(dòng)的整體工作框架

3、源碼分析

(1)register_blkdev(kernel/block/genhd.c)

  • 內(nèi)核提供的注冊(cè)塊設(shè)備驅(qū)動(dòng)的注冊(cè)接口,在塊設(shè)備驅(qū)動(dòng)框架中的地位,等同于register_chrdev在字符設(shè)備驅(qū)動(dòng)框架中的地位。

(2)blk_init_queue?

  • 用來實(shí)例化產(chǎn)生一個(gè)等待隊(duì)列,將來應(yīng)用層對(duì)本塊設(shè)備所做的所有的讀寫操作,都會(huì)生成一個(gè)request然后被加到這個(gè)等待隊(duì)列中來。

(3)blk_init_queue

  • 函數(shù)接收2個(gè)參數(shù),第一個(gè)是等待隊(duì)列的回調(diào)函數(shù),這個(gè)函數(shù)是驅(qū)動(dòng)提供的用來處理等待隊(duì)列中的request的函數(shù)(IO調(diào)度層通過電梯算法從等待隊(duì)列中取出一個(gè)request,就會(huì)調(diào)用這個(gè)回調(diào)函數(shù)來處理這個(gè)請(qǐng)求),第二個(gè)參數(shù)是一個(gè)自旋鎖,這個(gè)自旋鎖是要求我們驅(qū)動(dòng)提供給等待隊(duì)列去使用的。

(4)blk_fetch_request

  • 函數(shù)是IO調(diào)度層提供的接口,作用是從request_queue中(按照電梯算法)取出一個(gè)(算法認(rèn)為當(dāng)前最應(yīng)該去被執(zhí)行的一個(gè)請(qǐng)求,是被算法排序、合并后的)請(qǐng)求,取出的請(qǐng)求其實(shí)就是當(dāng)前硬件(塊設(shè)備)最應(yīng)該去執(zhí)行的那個(gè)讀寫操作。


#include <linux/module.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/timer.h> #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/wait.h> #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/delay.h> #include <linux/io.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/dma.h>#define RAMBLOCK_SIZE (1024*1024) // 1MB,2048扇區(qū)static struct gendisk *my_ramblock_disk; // 磁盤設(shè)備的結(jié)構(gòu)體 static struct request_queue *my_ramblock_queue; // 等待隊(duì)列 static DEFINE_SPINLOCK(my_ramblock_lock); static int major; static unsigned char *my_ramblock_buf; // 虛擬塊設(shè)備的內(nèi)存指針static void do_my_ramblock_request(struct request_queue *q) {struct request *req;static int r_cnt = 0; //實(shí)驗(yàn)用,打印出驅(qū)動(dòng)讀與寫的調(diào)度方法static int w_cnt = 0;req = blk_fetch_request(q);while (NULL != req){unsigned long start = blk_rq_pos(req) *512;unsigned long len = blk_rq_cur_bytes(req);if(rq_data_dir(req) == READ){// 讀請(qǐng)求memcpy(req->buffer, my_ramblock_buf + start, len); //讀操作,printk("do_my_ramblock-request read %d times\n", r_cnt++);}else{// 寫請(qǐng)求memcpy( my_ramblock_buf+start, req->buffer, len); //寫操作printk("do_my_ramblock request write %d times\n", w_cnt++);}if(!__blk_end_request_cur(req, 0)) {req = blk_fetch_request(q);}} }static int blk_ioctl(struct block_device *dev, fmode_t no, unsigned cmd, unsigned long arg) {return -ENOTTY; }static int blk_open (struct block_device *dev , fmode_t no) {printk("11111blk mount succeed\n");return 0; } static int blk_release(struct gendisk *gd , fmode_t no) {printk("11111blk umount succeed\n");return 0; }static const struct block_device_operations my_ramblock_fops = {.owner = THIS_MODULE,.open = blk_open,.release = blk_release,.ioctl = blk_ioctl, };static int my_ramblock_init(void) {major = register_blkdev(0, "my_ramblock");if (major < 0){printk("fail to regiser my_ramblock\n");return -EBUSY;}// 實(shí)例化my_ramblock_disk = alloc_disk(1); //次設(shè)備個(gè)數(shù) ,分區(qū)個(gè)數(shù) +1//分配設(shè)置請(qǐng)求隊(duì)列,提供讀寫能力my_ramblock_queue = blk_init_queue(do_my_ramblock_request, &my_ramblock_lock);//設(shè)置硬盤屬性 my_ramblock_disk->major = major;my_ramblock_disk->first_minor = 0;my_ramblock_disk->fops = &my_ramblock_fops;sprintf(my_ramblock_disk->disk_name, "my_ramblcok"); // /dev/namemy_ramblock_disk->queue = my_ramblock_queue;set_capacity(my_ramblock_disk, RAMBLOCK_SIZE / 512);/* 硬件相關(guān)操作 */my_ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);add_disk(my_ramblock_disk); // 向驅(qū)動(dòng)框架注冊(cè)一個(gè)disk或者一個(gè)partation的接口return 0; }static void my_ramblock_exit(void) {unregister_blkdev(major, "my_ramblock");del_gendisk(my_ramblock_disk);put_disk(my_ramblock_disk);blk_cleanup_queue(my_ramblock_queue);kfree(my_ramblock_buf); }module_init(my_ramblock_init); module_exit(my_ramblock_exit);MODULE_LICENSE("GPL");


總結(jié)

以上是生活随笔為你收集整理的块设备驱动介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。