buffer_head数据结构

news2024/11/16 21:37:26

内核版本:5.9.0

数据结构

/*
 * Historically, a buffer_head was used to map a single block
 * within a page, and of course as the unit of I/O through the
 * filesystem and block layers.  Nowadays the basic I/O unit
 * is the bio, and buffer_heads are used for extracting block
 * mappings (via a get_block_t call), for tracking state within
 * a page (via a page_mapping) and for wrapping bio submission
 * for backward compatibility reasons (e.g. submit_bh).
 */
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,等于block size */
	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 */
	spinlock_t b_uptodate_lock;	/* Used by the first bh in a page, to
					 * serialise IO completion of other
					 * buffers in the page */
};

历史上:buffer_head用来将一个单独的block映射到一个page,一般80x86体系结构上,根据block size大小,一个page可以包含1-8个block,比如如果block size = 1K,那么一个缓存page缓存4个block,且buffer_head是文件系统和block layer的io基本单位。

现在:bio取代了buffer_head作为io基本单位。

buffer_head和page关系

假设page size = 4K, block size = 1K

  • 一个4K page可以缓存4个1K的block, 每一个block通过buffer_head描述,这四个buffer_head通过b_this_page单向连接。
  • buffer_head中的b_data指向对应的缓冲区地址。注意:如果page是high mem,b_data存放的缓冲区业内的偏移量,比如第一个缓冲区b_data = 0,第二个是1K,第三个是2K。如果page在非high mem,b_data指向对应缓冲区的虚拟地址。
  • page中的private指向第一个buffer_head

数据结构构建的代码

fs/buffer.c :

//创建page的buffer_head
static struct buffer_head *create_page_buffers(struct page *page, struct inode *inode, unsigned int b_state)
{
	BUG_ON(!PageLocked(page));

    //inode->i_blkbits是用bit表示的块大小,比如block size = 4K, i_blkbits = 12;
    //create_empty_buffers进行真正的创建逻辑。
	if (!page_has_buffers(page))
		create_empty_buffers(page, 1 << READ_ONCE(inode->i_blkbits),
				     b_state);

    //返回page->private,即首个buffer_head
	return page_buffers(page);
}

/* If we *know* page->private refers to buffer_heads */
#define page_buffers(page)                  \                                                                                                                            
    ({                          \
        BUG_ON(!PagePrivate(page));         \
        ((struct buffer_head *)page_private(page)); \
    })
#define page_has_buffers(page)  PagePrivate(page)

/*
 * We attach and possibly dirty the buffers atomically wrt
 * __set_page_dirty_buffers() via private_lock.  try_to_free_buffers
 * is already excluded via the page lock.
 */
void create_empty_buffers(struct page *page,
			unsigned long blocksize, unsigned long b_state)
{
	struct buffer_head *bh, *head, *tail;

    //真正的buffer_head创建函数,返回首个buffer_head
	head = alloc_page_buffers(page, blocksize, true);
	bh = head;

    //tail指向最后一个buffer_head,将首个和最后一个buffer_head连接
	do {
		bh->b_state |= b_state;
		tail = bh;
		bh = bh->b_this_page;
	} while (bh);
	tail->b_this_page = head;

	spin_lock(&page->mapping->private_lock);
	if (PageUptodate(page) || PageDirty(page)) {
		bh = head;
		do {
			if (PageDirty(page))
				set_buffer_dirty(bh);
			if (PageUptodate(page))
				set_buffer_uptodate(bh);
			bh = bh->b_this_page;
		} while (bh != head);
	}
    //设置page->private指向首个buffer_head
	attach_page_private(page, head);
	spin_unlock(&page->mapping->private_lock);
}


struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
		bool retry)
{
	struct buffer_head *bh, *head;
	gfp_t gfp = GFP_NOFS | __GFP_ACCOUNT;
	long offset;
	struct mem_cgroup *memcg;

	if (retry)
		gfp |= __GFP_NOFAIL;

	memcg = get_mem_cgroup_from_page(page);
	memalloc_use_memcg(memcg);

	head = NULL;
	offset = PAGE_SIZE;
    //当前场景offset = 4K size = 1K
	while ((offset -= size) >= 0) {
		bh = alloc_buffer_head(gfp);
		if (!bh)
			goto no_grow;

		bh->b_this_page = head;
		bh->b_blocknr = -1;
		head = bh;

		bh->b_size = size;

		/* Link the buffer to its page */
		set_bh_page(bh, page, offset);
	}
out:
	memalloc_unuse_memcg();
	mem_cgroup_put(memcg);
	return head;
/*
 * In case anything failed, we just free everything we got.
 */
no_grow:
	if (head) {
		do {
			bh = head;
			head = head->b_this_page;
			free_buffer_head(bh);
		} while (head);
	}

	goto out;
}


/**
 * attach_page_private - Attach private data to a page.
 * @page: Page to attach data to.
 * @data: Data to attach to page.
 *
 * Attaching private data to a page increments the page's reference count.
 * The data must be detached before the page will be freed.
 */
static inline void attach_page_private(struct page *page, void *data)
{
	get_page(page);
	set_page_private(page, (unsigned long)data);
	SetPagePrivate(page);
}

   buffer_head的状态b_state

enum bh_state_bits {
    BH_Uptodate,    /* Contains valid data */
    BH_Dirty,   /* Is dirty */
    BH_Lock,    /* Is locked */
    BH_Req,     /* Has been submitted for I/O */

    BH_Mapped,  /* Has a disk mapping */
    BH_New,     /* Disk mapping was newly created by get_block */
    BH_Async_Read,  /* Is under end_buffer_async_read I/O */
    BH_Async_Write, /* Is under end_buffer_async_write I/O */
    BH_Delay,   /* Buffer is not yet allocated on disk */
    BH_Boundary,    /* Block is followed by a discontiguity */
    BH_Write_EIO,   /* I/O error on write */
    BH_Unwritten,   /* Buffer is allocated on disk but not written */
    BH_Quiet,   /* Buffer Error Prinks to be quiet */
    BH_Meta,    /* Buffer contains metadata */
    BH_Prio,    /* Buffer should be submitted with REQ_PRIO */                                                                                                           
    BH_Defer_Completion, /* Defer AIO completion to workqueue */

    BH_PrivateStart,/* not a state bit, but the first bit available
             * for private allocation by other entities
             */
};

BH_Uptodate : 数据有效,磁盘文件已缓存,且两者相同。

BH_Dirty : 缓冲区数据更新,跟磁盘文件不同,必须写回块设备。

BH_Lock : 加锁,通常是缓冲区正在进行磁盘传输。

BH_Req : 提交io请求。

BH_Mapped : 缓冲区和磁盘已映射,即,buffer_head中b_bdev和b_blocknr已设置。

BH_New : 磁盘映射刚刚创建。

b_state相关函数 include/linux/buffer_head.h

/*
 * macro tricks to expand the set_buffer_foo(), clear_buffer_foo()
 * and buffer_foo() functions.
 * To avoid reset buffer flags that are already set, because that causes
 * a costly cache line transition, check the flag first.
 */
#define BUFFER_FNS(bit, name)                       \
static __always_inline void set_buffer_##name(struct buffer_head *bh)   \
{                                   \
    if (!test_bit(BH_##bit, &(bh)->b_state))            \
        set_bit(BH_##bit, &(bh)->b_state);          \
}                                   \
static __always_inline void clear_buffer_##name(struct buffer_head *bh) \
{                                   \
    clear_bit(BH_##bit, &(bh)->b_state);                \
}                                   \
static __always_inline int buffer_##name(const struct buffer_head *bh)  \
{                                   \
    return test_bit(BH_##bit, &(bh)->b_state);          \
}

/*
 * test_set_buffer_foo() and test_clear_buffer_foo()
 */
#define TAS_BUFFER_FNS(bit, name)                   \
static __always_inline int test_set_buffer_##name(struct buffer_head *bh) \
{                                   \
    return test_and_set_bit(BH_##bit, &(bh)->b_state);      \
}                                   \
static __always_inline int test_clear_buffer_##name(struct buffer_head *bh) \
{                                   \
    return test_and_clear_bit(BH_##bit, &(bh)->b_state);        \
}                                   \

/*
 * Emit the buffer bitops functions.   Note that there are also functions
 * of the form "mark_buffer_foo()".  These are higher-level functions which
 * do something in addition to setting a b_state bit.
 */
BUFFER_FNS(Uptodate, uptodate)
BUFFER_FNS(Dirty, dirty)
TAS_BUFFER_FNS(Dirty, dirty)
BUFFER_FNS(Lock, locked)
BUFFER_FNS(Req, req)
TAS_BUFFER_FNS(Req, req)
BUFFER_FNS(Mapped, mapped)
BUFFER_FNS(New, new)
BUFFER_FNS(Async_Read, async_read)
BUFFER_FNS(Async_Write, async_write)
BUFFER_FNS(Delay, delay)
BUFFER_FNS(Boundary, boundary)
BUFFER_FNS(Write_EIO, write_io_error)
BUFFER_FNS(Unwritten, unwritten)
BUFFER_FNS(Meta, meta)
BUFFER_FNS(Prio, prio)
BUFFER_FNS(Defer_Completion, defer_completion)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/707583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

互联网编程之多线程/线程池TCP服务器端程序设计

目录 需求 多线程TCP服务器 线程池TCP服务器 测试 日志模块 需求 多线程TCP服务器&#xff08;30分&#xff09;&#xff1a; 设计编写一个TCP服务器端程序&#xff0c;需使用多线程处理客户端的连接请求。客户端与服务器端之间的通信内容&#xff0c;以及服务器端的处理…

C语言进阶---自定类型详解(结构体+枚举+联合)

结构体 1、结构体类型的声明 1.1、结构的基础知识 结构是一些值得集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量。 1.2、结构体类型的声明 struct tag {member-list; }variable-list;//写法一&#xff1a; struct Stu {char name[20];int age;…

【数据结构与算法】约瑟夫环(C/C++)

实践要求 1. 问题描述 约瑟夫问题的一种描述是&#xff1a;编号为1,2,…,n的n个人按顺时针方向围坐一圈&#xff0c;每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m&#xff0c;从第一个人开始。按顺时针方向自1开始顺序报数&#xff0c;报到m时停止报数。报…

docker镜像fauria/vsftpd dockerfile解析(ENV命令,**占位符**)dockerfile命令、dockerfile指令

文章目录 fauria/vsftpddockerfile原始文件dockerfile解析 fauria/vsftpd fauria/vsftpd是一个由Docker Hub用户"fauria"创建的Docker镜像。这个镜像是基于CentOS 7构建的&#xff0c;包含了vsftpd&#xff08;Very Secure FTP Daemon&#xff09;服务&#xff0c;并…

NASA网站曝严重漏洞,或将沦为黑客钓鱼网站?

美国国家航空航天局&#xff08;NASA&#xff09;天体生物学专用网站存在一个严重的安全漏洞&#xff0c;可能通过伪装带有NASA名称的危险URL来诱骗用户访问恶意网站。 太空旅行无疑是危险的。然而&#xff0c;在访问NASA网站的时候也有可能如此。Cybernews研究团队发现了一个N…

Scala之泛型详解

泛型用于指定类或方法可以接受任意类型参数&#xff0c;参数在实际使用时才被确定&#xff0c;泛型可以有效地增强程序的适用性&#xff0c;使用泛型可以使得类或方法具有更强的通用性。泛型的典型应用场景是集合及集合中的方法参数&#xff0c;可以说同 Java 一样&#xff0c;…

基于粒子群算法的无约束优化问题求解

基于粒子群算法的无约束优化问题求解 1 引言2 粒子群算法2.1 粒子群优化原理2.2 粒子群算法寻优策略与参数控制粒子群算法流程 3 粒子群算法求解无约束优化问题3.1 粒子群算法求解Sphere函数&#xff08;单峰测试函数&#xff09;3.2 Schwefels Problem 2.26&#xff08;多峰测…

chatgpt赋能python:Win7怎么安装Python?

Win7怎么安装Python&#xff1f; 如果你正在使用Windows 7操作系统&#xff0c;想要安装Python&#xff0c;那么你来对了地方。Python是一种利用广泛的编程语言&#xff0c;可用于开发Web应用程序、数据分析和科学计算、机器学习等各种领域。 在此篇文章中&#xff0c;我们会…

MATLAB matlab人脸识别源码+使用说明+操作说明内容清晰适合新手

程序运行界面&#xff1a; 部分代码&#xff1a; function varargout facerecg(varargin) % FACERECG MATLAB code for facerecg.fig % FACERECG, by itself, creates a new FACERECG or raises the existing % singleton*. % % H FACERECG returns the hand…

Revit中如何导入、导出明细表?

Revit中明细表的作用非常大&#xff0c;项目中的数据归类整理及统计都离不开它&#xff0c;今天给大家分享一下如何在Revit中进行明细表标准的导出及导入&#xff0c;减少在实际项目中的重复性工作。 1、首先在Revit中新建一个项目文件&#xff0c;在平面视图中随便画几条管道…

用git下载gitee上的项目资源

目录 用git下载gitee上的项目资源 用git 的clone 命令 然后到gitee上复制相关的下载地址&#xff1a; 粘贴到clone后面即可&#xff08;注意地址与clone之间有空格&#xff01;&#xff01;&#xff01;&#xff09; 运行结果&#xff1a; 用git下载gitee上的项目资源 用git…

学习vue2笔记

学习vue2笔记 文章目录 学习vue2笔记脚手架文件结构关于不同版本的Vuevue.config.js配置文件ref属性props配置项mixin(混入)插件scoped样式总结TodoList案例webStorage组件的自定义事件全局事件总线&#xff08;GlobalEventBus&#xff09;消息订阅与发布&#xff08;pubsub&am…

LeetCoda 打卡day53--动态规划之最长子序列

一个人的朝圣 — LeetCode打卡第52天 知识总结 Leetcode 1143. 最长公共子序列题目说明代码说明 Leetcode 53. 最大子数组和题目说明代码说明 Leetcode 1035. 不相交的线题目说明代码说明 知识总结 今天几道最长子序列的题目, 都可以用一个固定的模版完成. 理解其中递推公式的…

字典序最小回文串

字典序最小回文串 题目解读 给你一个由 小写英文字母 组成的字符串 s &#xff0c;你可以对其执行一些操作。在一步操作中&#xff0c;你可以用其他小写英文字母 替换 s 中的一个字符。 请你执行 尽可能少的操作 &#xff0c;使 s 变成一个 回文串 。如果执行 最少 操作次数…

DAY38——动态规划

步骤&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 题目一. 斐波那契数列 1. 确定dp数组以及下标的含义 dp[i]的定义为&#xff1a;第i个数的斐波那契数值是dp[i] 2. 确定递推公式 状态…

FFmpegFrameGrabber视频抽帧工具类

Bytedeco 通过视频链接进行关键帧抽取图片&#xff0c;利用FFmpegFrameGrabber对视频流进行抽帧处理。 一、引入POM依赖 <dependency><groupId>org.bytedeco</groupId><artifactId>javacv</artifactId><version>1.4.1</version><…

TCP 拥塞状态机演进

下面是 TCP 拥塞状态机&#xff1a; 但它只是冰山一角&#xff0c;这只是 loss-based 状态机&#xff0c;实现一个完全的 delay-based cc 就对不上这个状态机。 该状态机来自 RFC5681&#xff0c;源自 RFC2581&#xff0c;RFC2001&#xff0c;大概在 1990 年代&#xff0c;l…

10分钟内创意爆发,这些头脑风暴技巧让你IDEA满满

当初道叔刚入广告行业&#xff0c;与同事经历了一次困扰的头脑风暴&#xff0c;老板让他们想出一个大集团公司年会的主题口号。我们7-8个团队成员耗费了一个下午的时间&#xff0c;提出了几十个提议&#xff0c;但最终硬是没有一个能满足需求。许多人可能也有过道叔这样的经历。…

Js保留树型数据指定层级

自定义一个树型的数据 const tree [{value: 1, label: "1",children: [{value: 11, label: "1-1",children: [{value: 111, label: "1-1-1"}]}]}, {value: 2, label: "2"}]保留指定层级的方法 function keepNodesAtLevel(data, level…

vue源码阅读之Watcher类

我们上次分析vue源码讲的是收集依赖&#xff0c;数据变化之后我们把依赖收集到dep类中&#xff0c;通过这个管理器进行管理。 里面有一个subs数组&#xff0c;用来存放依赖&#xff0c;并且定义了几个实例方法用来依赖进行添加&#xff0c;删除&#xff0c;通过操作。 比如ad…