首页 / LINUX / Linux块设备驱动详解
Linux块设备驱动详解
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Linux块设备驱动详解,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含12296字,纯文字阅读大概需要18分钟。
内容图文
![Linux块设备驱动详解](/upload/InfoBanner/zyjiaocheng/1119/40daa29955654c55af5d610f4e2dfec5.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011002655.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011004032.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011004334.jpg)
<基本概念>
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011004758.jpg)
1 struct bio { 2 sector _ t bi _ sector; / * 要传输的第一个扇区 * / 3 struct bio * bi _ next; / * 下一个 bio * / 4 struct block _ device * bi _ bdev; 5 unsigned long bi _ flags; / * 状态、命令等 * / 6 unsigned long bi _ rw; / * 低位表示 READ/WRITE ,高位表示优先级 * / 7 8 unsigned short bi _ vcnt; / * bio _ vec 数量 * / 9 unsigned short bi _ idx; / * 当前 bvl _ vec 索引 * / 10 11 / * 执行物理地址合并后 sgement 的数目 * / 12 unsigned short bi _ phys _ segments; 13 14 unsigned int bi _ size; 15 16 / * 为了明了最大的 segment 尺寸,我们考虑这个 bio 中第一个和最后一个 17 可合并的 segment 的尺寸 * / 18 unsigned int bi _ hw _ front _ size; 19 unsigned int bi _ hw _ back _ size; 20 21 unsigned int bi _ max _ vecs; / * 我们能持有的最大 bvl _ vecs 数 * / 22 unsigned int bi _ comp _ cpu; / * completion CPU * / 23 24 struct bio _ vec * bi _ io _ vec; / * 实际的 vec 列表 * / 25 26 bio _ end _ io _ t * bi _ end _ io; 27 atomic _ t bi _ cnt; 28 29 void * bi _ private; 30 #if defined(CONFIG _ BLK _ DEV _ INTEGRITY) 31 struct bio _ integrity _ payload * bi _ integrity; / * 数据完整性 * / 32 #endif 33 34 bio _ destructor _ t * bi _ destructor; / * 析构 * / 35 }; |
1 struct bio_vec { 2 struct page *bv_page; /* 页指针 */ 3 unsigned int bv_len; /* 传输的字节数 */ 4 unsigned int bv_offset; /* 偏移位置 */ 5 }; |
- struct buffer_head {
- unsigned long b_state ; / * buffer state bitmap ( see above ) * /
-
struct buffer_head
*
b_this_page
;
/
*
circular list of page
‘
s buffers
*
/
-
struct page
*
b_page
;
/
*
the page this bh
is
mapped
to
*
/
-
sector_t b_blocknr
;
/
*
start block number
*
/
-
size_t b_size
;
/
*
size of mapping
*
/
-
char
*
b_data
;
/
*
pointer
to
data within the page
*
/
-
struct block_device
*
b_bdev
;
-
bh_end_io_t
*
b_end_io
;
/
*
I
/
O completion
*
/
-
void
*
b_private
;
/
*
reserved
for
b_end_io
*
/
-
struct list_head b_assoc_buffers
;
/
*
associated with another mapping
*
/
-
struct address_space
*
b_assoc_map
;
/
*
mapping this buffer
is
-
associated with
*
/
- atomic_t b_count ; / * users using this buffer_head * /
- } ;
-
void ll_rw_block
(
int
rw
,
int
nr
,
struct buffer_head
*
bhs
[
]
)
-
{
-
int
i
;
-
for
(
i
=
0
;
i
<
nr
;
i
)
{
-
struct buffer_head
*
bh
=
bhs
[
i
]
;
-
if
(
!
trylock_buffer
(
bh
)
)
-
continue
;
-
if
(
rw
=
=
WRITE
)
{
-
if
(
test_clear_buffer_dirty
(
bh
)
)
{
-
bh
-
>
b_end_io
=
end_buffer_write_sync
;
-
get_bh
(
bh
)
;
-
submit_bh
(
WRITE
,
bh
)
;
-
continue
;
-
}
-
}
else
{
-
if
(
!
buffer_uptodate
(
bh
)
)
{
-
bh
-
>
b_end_io
=
end_buffer_read_sync
;
-
get_bh
(
bh
)
;
-
submit_bh
(
rw
,
bh
)
;
-
continue
;
-
}
-
}
-
unlock_buffer
(
bh
)
;
-
}
-
}
-
int
submit_bh
(
int
rw
,
struct buffer_head
*
bh
)
-
{
-
struct bio
*
bio
;
-
int
ret
=
0
;
-
BUG_ON
(
!
buffer_locked
(
bh
)
)
;
-
BUG_ON
(
!
buffer_mapped
(
bh
)
)
;
-
BUG_ON
(
!
bh
-
>
b_end_io
)
;
-
BUG_ON
(
buffer_delay
(
bh
)
)
;
-
BUG_ON
(
buffer_unwritten
(
bh
)
)
;
-
/
*
-
*
Only clear out a write
error
when rewriting
-
*
/
-
if
(
test_set_buffer_req
(
bh
)
&
&
(
rw
&
WRITE
)
)
-
clear_buffer_write_io_error
(
bh
)
;
-
/
*
-
*
from here
on
down
,
it
‘
s all bio
-
-
do
the initial mapping
,
-
*
submit_bio
-
>
generic_make_request may further map this bio around
-
*
/
-
bio
=
bio_alloc
(
GFP_NOIO
,
1
)
;
-
bio
-
>
bi_sector
=
bh
-
>
b_blocknr
*
(
bh
-
>
b_size
>
>
9
)
;
-
bio
-
>
bi_bdev
=
bh
-
>
b_bdev
;
-
bio
-
>
bi_io_vec
[
0
]
.
bv_page
=
bh
-
>
b_page
;
-
bio
-
>
bi_io_vec
[
0
]
.
bv_len
=
bh
-
>
b_size
;
-
bio
-
>
bi_io_vec
[
0
]
.
bv_offset
=
bh_offset
(
bh
)
;
-
bio
-
>
bi_vcnt
=
1
;
-
bio
-
>
bi_idx
=
0
;
-
bio
-
>
bi_size
=
bh
-
>
b_size
;
-
bio
-
>
bi_end_io
=
end_bio_bh_io_sync
;
-
bio
-
>
bi_private
=
bh
;
-
bio_get
(
bio
)
;
-
submit_bio
(
rw
,
bio
)
;
-
if
(
bio_flagged
(
bio
,
BIO_EOPNOTSUPP
)
)
-
ret
=
-
EOPNOTSUPP
;
-
bio_put
(
bio
)
;
- return ret ;
- }
-
void generic_make_request
(
struct bio
*
bio
)
-
{
-
struct bio_list bio_list_on_stack
;
-
if
(
!
generic_make_request_checks
(
bio
)
)
-
return
;
-
if
(
current
-
>
bio_list
)
{
-
bio_list_add
(
current
-
>
bio_list
,
bio
)
;
-
return
;
-
}
-
BUG_ON
(
bio
-
>
bi_next
)
;
-
bio_list_init
(
&
bio_list_on_stack
)
;
-
current
-
>
bio_list
=
&
bio_list_on_stack
;
-
do
{
-
struct request_queue
*
q
=
bdev_get_queue
(
bio
-
>
bi_bdev
)
;
-
q
-
>
make_request_fn
(
q
,
bio
)
;
-
bio
=
bio_list_pop
(
current
-
>
bio_list
)
;
-
}
while
(
bio
)
;
-
current
-
>
bio_list
=
NULL
;
/
*
deactivate
*
/
-
}
1 struct request { 2 struct list _ head queuelist; 3 struct call _ single _ data csd; 4 int cpu; 5 6 struct request _ queue * q; 7 8 unsigned int cmd _ flags; 9 enum rq _ cmd _ type _ bits cmd _ type; 10 unsigned long atomic _ flags; 11 12 / * 维护 I/O submission 的 BIO 遍历状态 13 * hard _开头的成员仅用于块层内部,驱动不应该改变它们 14 * / 15 16 sector _ t sector; / * 要提交的下一个 sector * / 17 sector _ t hard _ sector; / * 要完成的下一个 sector * / 18 unsigned long nr _ sectors; / * 剩余需要提交的 sector 数 * / 19 unsigned long hard _ nr _ sectors; / * 剩余需要完成的 sector 数 * / 20 / * 在当前 segment 中剩余的需提交的 sector 数 * / 21 unsigned int current _ nr _ sectors; 22 23 / * 在当前 segment 中剩余的需完成的 sector 数 * / 24 unsigned int hard _ cur _ sectors; 25 26 struct bio * bio; 27 struct bio * biotail; 28 29 struct hlist _ node hash; 30 union { 31 struct rb _ node rb _ node; / * sort/lookup * / 32 void * completion _ data; 33 }; 34 35 / * 36 * I/O 调度器可获得的两个指针,如果需要更多,请动态分配 |
37
*
/ 38 void * elevator _ private; 39 void * elevator _ private2; 40 41 struct gendisk * rq _ disk; 42 unsigned long start _ time; 43 44 / * scatter-gather DMA 方式下 addr+len 对的数量 ( 执行物理地址合并后 ) 45 * / 46 unsigned short nr _ phys _ segments; 47 48 unsigned short ioprio; 49 50 void * special; 51 char * buffer; 52 53 int tag; 54 int errors; 55 56 int ref _ count; 57 58 unsigned short cmd _ len; 59 unsigned char __ cmd[BLK _ MAX _ CDB]; 60 unsigned char * cmd; 61 62 unsigned int data _ len; 63 unsigned int extra _ len; 64 unsigned int sense _ len; 65 void * data; 66 void * sense; 67 68 unsigned long deadline; 69 struct list _ head timeout _ list; 70 unsigned int timeout; 71 int retries; 72 73 / * 74 * 完成回调函数 75 * / 76 rq _ end _ io _ fn * end _ io; 77 void * end _ io _ data; 78 79 struct request * next _ rq; 80 }; |
30 return 0; 31 out _ queue: unregister _ blkdev(XXX _ MAJOR, "xxx"); 32 out: put _ disk(xxx _ disks); 33 blk _ cleanup _ queue(xxx _ queue); 34 35 return -ENOMEM; 36 } |
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011005190.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011005536.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011005721.jpg)
第一种,调用请求队列中自己定义的make_request_fn()函数,那问题来了,系统怎么知道这个自己定义函数在哪里呢?由内核函数blk_queue_make_request()函数指定,函数原形:
void blk_queue_make_request(struct request_queue *q,make_request_fn *mfn);
static int __make_request(struct request_queue *q,struct bio *bio);
static int Virtual_blkdev_make_request(struct requset_queue *q,structb bio *bio) { //因为不使用I/O调度算法,直接在该函数中完成数据在内存和硬盘之间的数据传输,该函数 //代替了request_fn_proc()函数的功能 ............ } Virtual_blkdev_queue = blk_alloc_queue(GFP_KERNEL) if(!Virtual_blkdev_queue) { ret=-ENOMEN; goto err_alloc_queue; } blk_queue_make_request(Virtual_blkdev_queue,Virtual_blkdev_make_request); |
struct request_queue* blk_inti_queue(request_fn_proc *rfn,spinlock_t *lock) |
<总结驱动框架>
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011006157.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011006447.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011006581.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011006881.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011007187.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011007358.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011007535.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011007711.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011008252.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011008433.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011009111.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011009415.jpg)
![技术分享图片](/upload/getfiles/default/2022/11/7/20221107011009717.jpg)
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">
原文:https://www.cnblogs.com/big-devil/p/8590007.html
内容总结
以上是互联网集市为您收集整理的Linux块设备驱动详解全部内容,希望文章能够帮你解决Linux块设备驱动详解所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。