缓冲区头¶
Linux 使用缓冲区头来维护关于单个文件系统块的状态。缓冲区头已被弃用,新的文件系统应该使用 iomap 代替。
函数¶
-
void brelse(struct buffer_head *bh)¶
释放缓冲区。
参数
struct buffer_head *bh
要释放的缓冲区。
描述
减少 buffer_head 的引用计数。 如果 bh 为 NULL,则此函数不执行任何操作。
如果一个 folio 上的所有缓冲区都具有零引用计数,是干净且未锁定的,并且如果该 folio 是未锁定且未处于写回状态,则 try_to_free_buffers()
可能会从 folio 中剥离缓冲区,以准备释放它(有时,很少情况下,缓冲区会从 folio 中移除,但最终不会被释放,并且缓冲区可能会稍后重新附加)。
上下文
任何上下文。
-
void bforget(struct buffer_head *bh)¶
丢弃缓冲区中的任何脏数据。
参数
struct buffer_head *bh
要忘记的缓冲区。
描述
如果写入缓冲区的数据不再需要写回,则调用此函数而不是 brelse()
。 它将清除缓冲区的脏标志,因此将跳过此缓冲区的写回。
上下文
任何上下文。
-
struct buffer_head *__bread(struct block_device *bdev, sector_t block, unsigned size)¶
读取一个块。
参数
struct block_device *bdev
要读取的块设备。
sector_t block
块号,以块大小为单位。
unsigned size
此设备的块大小(以字节为单位)。
描述
读取指定的块,并返回引用它的缓冲区头。内存从可移动区域分配,因此可以迁移。返回的缓冲区头的引用计数已增加。调用者应在完成缓冲区操作后调用 brelse()
。
上下文
可能会睡眠等待 I/O。
返回值
如果块不可读,则返回 NULL。
-
struct buffer_head *get_nth_bh(struct buffer_head *bh, unsigned int count)¶
获取此缓冲区之后的第 n 个缓冲区的引用。
参数
struct buffer_head *bh
开始计数的缓冲区。
unsigned int count
要跳过多少个缓冲区。
描述
这主要用于查找 folio 中的第 n 个缓冲区; 在这种情况下,您传递头部缓冲区和 folio 中的字节偏移量除以块大小。 它可用于其他目的,但它将在 folio 的末尾环绕,而不是返回 NULL 或继续到下一个 folio。
返回值
请求的缓冲区,引用计数已提升。
-
int sync_mapping_buffers(struct address_space *mapping)¶
写出并等待映射的“关联”缓冲区
参数
struct address_space *mapping
想要写入这些缓冲区的映射
描述
针对 mapping->i_private_list 中的缓冲区启动 I/O,并等待该 I/O。
基本上,这是 fsync() 的一个方便函数。 mapping 是一个文件或目录,需要写入这些缓冲区才能成功执行 fsync()。
-
int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end, bool datasync)¶
用于简单文件系统的通用缓冲区 fsync 实现,没有 inode 锁
参数
struct file *file
要同步的文件
loff_t start
起始偏移量(以字节为单位)
loff_t end
结束偏移量(以字节为单位)(包含)
bool datasync
如果为 true,则仅同步必要的元数据
描述
这是 fsync 方法的通用实现,适用于在挂在 address_space 结构上的缓冲区列表中跟踪所有非 inode 元数据的简单文件系统。
-
int generic_buffers_fsync(struct file *file, loff_t start, loff_t end, bool datasync)¶
用于简单文件系统的通用缓冲区 fsync 实现,没有 inode 锁
参数
struct file *file
要同步的文件
loff_t start
起始偏移量(以字节为单位)
loff_t end
结束偏移量(以字节为单位)(包含)
bool datasync
如果为 true,则仅同步必要的元数据
描述
这是 fsync 方法的通用实现,适用于在挂在 address_space 结构上的缓冲区列表中跟踪所有非 inode 元数据的简单文件系统。 这也确保在最后调用设备缓存刷新操作。
-
bool block_dirty_folio(struct address_space *mapping, struct folio *folio)¶
将 folio 标记为脏。
参数
struct address_space *mapping
包含此 folio 的地址空间。
struct folio *folio
要标记为脏的 folio。
描述
使用 buffer_heads 的文件系统可以使用此函数作为其 ->dirty_folio 实现。 某些文件系统需要在调用此函数之前做一些工作。 不使用 buffer_heads 的文件系统应改为调用 filemap_dirty_folio()
。
如果 folio 有缓冲区,则更新的缓冲区将设置为脏,以保持 folio 和缓冲区之间的脏状态一致性。 添加到脏 folio 的缓冲区会被创建为脏缓冲区。
缓冲区在 folio 被标记为脏之前被标记为脏。 存在一个小的竞争窗口,其中写回可能会看到 folio 的干净状态,但看不到缓冲区的脏状态。 这没关系。 如果此代码要在缓冲区之前设置 folio 脏标志,写回可能会清除 folio 脏标志,看到一堆干净的缓冲区,最终我们会在脏 folio 列表中得到脏缓冲区/干净 folio。
我们使用 i_private_lock 来锁定 try_to_free_buffers()
,同时使用 folio 的缓冲区列表。 这也防止在 folio 设置为脏后将干净的缓冲区添加到 folio。
上下文
只能从进程上下文中调用。 不会睡眠。 调用者必须确保在此调用期间无法截断 folio,通常是通过持有 folio 锁或在 folio 中映射一个页面并持有页表锁。
返回值
如果 folio 被标记为脏,则为 True; 如果已标记为脏,则为 false。
-
void mark_buffer_dirty(struct buffer_head *bh)¶
将 buffer_head 标记为需要写出
参数
struct buffer_head *bh
要标记为脏的 buffer_head
描述
mark_buffer_dirty()
将针对缓冲区设置脏位,然后将它的支持页面设置为脏,然后在页面缓存中将页面标记为脏,然后将 address_space 的 inode 附加到其超级块的脏 inode 列表。
mark_buffer_dirty()
是原子的。 它采用 bh->b_folio->mapping->i_private_lock、i_pages 锁和 mapping->host->i_lock。
-
void __brelse(struct buffer_head *bh)¶
释放缓冲区。
-
void __bforget(struct buffer_head *bh)¶
丢弃缓冲区中的任何脏数据。
-
struct buffer_head *bdev_getblk(struct block_device *bdev, sector_t block, unsigned size, gfp_t gfp)¶
在块设备的缓冲区缓存中获取 buffer_head。
参数
struct block_device *bdev
块设备。
sector_t block
块号。
unsigned size
此 bdev 的 buffer_heads 的大小。
gfp_t gfp
要使用的内存分配标志。
描述
返回的缓冲区头的引用计数已递增,但未锁定。 调用者应在完成缓冲区操作后调用 brelse()
。 缓冲区可能不是最新的。 如果需要,调用者可以通过读取它或覆盖它来使其保持最新。
返回值
缓冲区头,如果无法分配内存,则为 NULL。
-
struct buffer_head *__bread_gfp(struct block_device *bdev, sector_t block, unsigned size, gfp_t gfp)¶
读取一个块。
参数
struct block_device *bdev
要读取的块设备。
sector_t block
块号,以块大小为单位。
unsigned size
此设备的块大小(以字节为单位)。
gfp_t gfp
不是页面分配标志; 请参阅下文。
描述
您不应调用此函数。 您应该使用 sb_bread()、sb_bread_unmovable() 或 __bread()
之一。
读取指定的块,并返回引用它的缓冲区头。 如果 gfp 为 0,则将使用块设备的默认 GFP 标志分配内存。 如果 gfp 为 __GFP_MOVABLE,则可以从可移动区域分配内存。 不要传入完整的 GFP 标志集。
返回的缓冲区头的引用计数已增加。 调用者应在完成缓冲区操作后调用 brelse()
。
上下文
可能会睡眠等待 I/O。
返回值
如果块不可读,则返回 NULL。
-
void block_invalidate_folio(struct folio *folio, size_t offset, size_t length)¶
使缓冲区支持的 folio 的部分或全部失效。
参数
struct folio *folio
受影响的 folio。
size_t offset
要失效的范围的开始
size_t length
要失效的范围的长度
描述
当 folio 的全部或部分被截断操作失效时,将调用 block_invalidate_folio()
。
block_invalidate_folio()
不必释放所有缓冲区,但它必须确保在 offset 之外没有留下任何脏缓冲区,并且没有针对截断点之外的任何块进行 I/O。 因为调用者将要释放(并可能重用)磁盘上的那些块。
-
void clean_bdev_aliases(struct block_device *bdev, sector_t block, sector_t len)¶
清理块设备中的一系列缓冲区
参数
struct block_device *bdev
要在其中清理缓冲区的块设备
sector_t block
要清理的块范围的开始
sector_t len
要清理的块数
描述
我们正在获取一系列块用于数据,并且我们不希望从该函数返回开始,直到显式将缓冲区标记为脏的时刻(希望在我们释放该块之前不会发生这种情况 ;-) 我们甚至不需要将其标记为非最新的 - 无论如何,没有人可以对新分配的缓冲区有任何期望。 我们过去使用 unmap_buffer() 进行这种失效,但这是不正确的。 例如,我们绝对不想将别名标记为未映射 - 这会混淆任何可能使用 bread() 拾取它的人...
此外.. 请注意 bforget()
不会锁定缓冲区。 因此,可能会针对最近释放的缓冲区进行写出 I/O。 我们不会在 bforget()
中等待该 I/O - 仅在我们真正需要时才等待 I/O 更有效。 这就是这里发生的事情。
参数
struct folio *folio
该 folio。
描述
如果有任何缓冲区正在使用中(脏、处于写回状态、引用计数已提升),则不会释放任何缓冲区。
如果 folio 是脏的,但所有缓冲区都是干净的,那么我们需要确保也将 folio 标记为干净的。 这是因为 folio 可能是针对块设备的,并且稍后将缓冲区重新附加到脏 folio 将设置所有缓冲区为脏。 这会损坏同一设备上的文件系统数据。
这同样适用于常规文件系统 folio:如果所有缓冲区都是干净的,那么我们将 folio 设置为干净并继续。 为此,我们需要完全排除 block_dirty_folio()
。 这是通过 i_private_lock 获得的。
可以通过锁定 folio 或持有其映射的 i_private_lock 来获得针对 try_to_free_buffers 的排除。
上下文
进程上下文。 folio 必须被锁定。 不会睡眠。
返回值
如果附加到此 folio 的所有缓冲区都被释放,则为 true。
-
int bh_uptodate_or_lock(struct buffer_head *bh)¶
测试缓冲区是否是最新的
参数
struct buffer_head *bh
struct buffer_head
描述
如果缓冲区是最新的,则返回 true; 如果不是,则返回 false,并且缓冲区被锁定。
-
int __bh_read(struct buffer_head *bh, blk_opf_t op_flags, bool wait)¶
提交已锁定缓冲区的读取
参数
struct buffer_head *bh
struct buffer_head
blk_opf_t op_flags
除了 REQ_OP_READ 之外,还附加 REQ_OP_* 标志
bool wait
等待直到读取完成
描述
成功或不等待时返回零,错误时返回 -EIO。
-
void __bh_read_batch(int nr, struct buffer_head *bhs[], blk_opf_t op_flags, bool force_lock)¶
提交一批未锁定缓冲区的读取
参数
int nr
缓冲区批次的条目数
struct buffer_head *bhs[]
一批 struct buffer_head
blk_opf_t op_flags
除了 REQ_OP_READ 之外,还附加 REQ_OP_* 标志
bool force_lock
如果设置,则强制获取缓冲区的锁,否则将丢弃任何无法锁定的缓冲区。
描述
成功或不等待时返回零,错误时返回 -EIO。