buffer_head的理解

本文深入探讨Linux内核中的Buffer Head机制,解释了在页高速缓存pagecache中,如何利用buffer_head结构管理内存页page中对应的物理块。特别关注了4k页和1k块大小下,buffer_head如何通过链表结构链接同一页的不同缓冲区,并详细解析submit_bh()函数如何将buffer_head信息转换为磁盘IO请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇博客介绍address_space中,我们有提到,内存中一个page所包含的磁盘块在物理上不一定是相邻的。那么page中不同的磁盘块怎么管理呢?这里就涉及到了buffer_head结构。(实际上,我们的epsiode中设定了block大小和page 大小是一样的,都是4k,但buffer_head仍然大量存在,例如sb中的imap zmap,sbh,以及管理blockid的i_zone[10],我们下一步要做的i_index[]可能也得采用它)

把块存放在页高速缓存page cache中就会涉及到块缓存区和缓冲区首部。

每个buffer_head管理的单元是内存页page中对应的一个物理块(对于block大小为1k的情况下,一个page对应磁盘上的4个block,而每个buffer_head对应1个磁盘block),也就是说buffer_head管理单元是 “页”的一个子集。

下面以页的大小为4k,block大小为1k来描述这个问题。在这种情况下,一个页中就会有四个缓冲区对应着四个buffer_head结构管理。页描述符page 中private指针指向其中一个缓冲区首部,缓冲区首部内部通过链表结构(b_this_page)链接该页对应的四个缓冲区。缓冲区首部(buffer_head)的b_page指针指向对应的page结构,b_data指向数据在对应的页中的位置。

如下图:

 

下面部分结合代码内容分析如何将buffer_head所管理的缓冲区转化成下发到磁盘的io请求。

首先submit_bh()函数,其作用:根据缓冲区首部的内容创建一个bio,在该函数中通过buffer_head传进来的信息对bio的信息赋值。如下

1

2

3

4

5

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); //buffer_head指向的缓存区相对于其所在页的偏移

然后submit_hb()调用submit_bio(),把rw数据传输方向赋值。

在submit_bio()中调用generic_make_request()函数。通过generic_make_request()函数把bio递交到通用块层。有关generic_make_request的函数解析,参照:

http://blog.chinaunix.net/uid-9988622-id-1995526.html

http://www.powerlinuxchina.net/club/viewthread.php?action=printable&tid=1239

generic_make_request()函数式递交一个bio的开始。每个进程的task_struct中,都包含两个变量: struct bio *bio_list,**bio_tail,该函数就是通过维护这两个变量来维护待添加的bio链表。generic_make_request函数调用__generic_make_request函数完成。而在__generic_make_request会调用make_request_fn,make_request_fn可能自行实现时递归调用generic_make_request,有了栈的深度有限,英雌通过genenric的设计,是的递归调用深度不超过1,具体是:一旦开始把当前的bio链表下发,则新到的bio不能加入正在下发的链表中。

generic_make_request函数调用__generic_make_request.

__generic_make_request做的事情很简单,先通过blk_partition_remap检查设备是否为磁盘分区,然后把相对于分区的起始扇区号转化为相对于整个磁盘的扇区号,然后调用q->make_request_fn()到达IO调度层,而make_request_fn主要是通过__make_request()函数实现的

 

 

Multi-Headed Attention Layer (MLA). Attributes: dim (int): Dimensionality of the input features. n_heads (int): Number of attention heads. n_local_heads (int): Number of local attention heads for distributed systems. q_lora_rank (int): Rank for low-rank query projection. kv_lora_rank (int): Rank for low-rank key/value projection. qk_nope_head_dim (int): Dimensionality of non-positional query/key projections. qk_rope_head_dim (int): Dimensionality of rotary-positional query/key projections. qk_head_dim (int): Total dimensionality of query/key projections. v_head_dim (int): Dimensionality of value projections. softmax_scale (float): Scaling factor for softmax in attention computation. """ def __init__(self, args: ModelArgs): super().__init__() self.dim = args.dim self.n_heads = args.n_heads self.n_local_heads = args.n_heads // world_size self.q_lora_rank = args.q_lora_rank self.kv_lora_rank = args.kv_lora_rank self.qk_nope_head_dim = args.qk_nope_head_dim self.qk_rope_head_dim = args.qk_rope_head_dim self.qk_head_dim = args.qk_nope_head_dim + args.qk_rope_head_dim self.v_head_dim = args.v_head_dim if self.q_lora_rank == 0: self.wq = ColumnParallelLinear(self.dim, self.n_heads * self.qk_head_dim) else: self.wq_a = Linear(self.dim, self.q_lora_rank) self.q_norm = RMSNorm(self.q_lora_rank) self.wq_b = ColumnParallelLinear(self.q_lora_rank, self.n_heads * self.qk_head_dim) self.wkv_a = Linear(self.dim, self.kv_lora_rank + self.qk_rope_head_dim) self.kv_norm = RMSNorm(self.kv_lora_rank) self.wkv_b = ColumnParallelLinear(self.kv_lora_rank, self.n_heads * (self.qk_nope_head_dim + self.v_head_dim)) self.wo = RowParallelLinear(self.n_heads * self.v_head_dim, self.dim) self.softmax_scale = self.qk_head_dim ** -0.5 if args.max_seq_len > args.original_seq_len: mscale = 0.1 * args.mscale * math.log(args.rope_factor) + 1.0 self.softmax_scale = self.softmax_scale * mscale * mscale if attn_impl == "naive": self.register_buffer("k_cache", torch.zeros(args.max_batch_size, args.max_seq_len, self.n_local_heads, self.qk_head_dim), persistent=False) self.register_buffer("v_cache", torch.zeros(args.max_batch_size, args.max_seq_len, self.n_local_heads, self.v_head_dim), persistent=False) else: self.register_buffer("kv_cache", torch.zeros(args.max_batch_size, args.max_seq_len, self.kv_lora_rank), persistent=False) self.register_buffer("pe_cache", torch.zeros(args.max_batch_size, args.max_seq_len, self.qk_rope_head_dim), persistent=False)
最新发布
04-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值