Linux0.11内核源码解析-block_dev.c

目录

block_dev.c 文件的作用

 int block_write(int dev, long * pos, char * buf, int count)

int block_read(int dev, unsigned long * pos, char * buf, int count)


block_dev.c 文件的作用

block_dev.c 文件就包含两个函数,分别是block_read和block_write函数,提供给read和write系统调用

Linux0.11内核源码解析-block_dev.c_第1张图片

块读写数据是操作指针图

Linux0.11内核源码解析-block_dev.c_第2张图片

 int block_write(int dev, long * pos, char * buf, int count)

代码首先根据位置指针将其右移 BLOCK_SIZE_BITS 位,得到块号(block),然后使用与运算将其与 (BLOCK_SIZE-1) 进行按位与操作,以获取在块内的偏移量(offset)。

进入循环,只要还有待写入的字节数(count>0),就执行以下步骤:

将 chars 设置为当前块剩余的字符数(BLOCK_SIZE - offset)。如果 chars 大于 count,则将 chars 设置为 count,以确保不会写入超过指定字节数的数据。

根据 chars 的值选择不同的读取策略:

如果 chars 等于块大小(BLOCK_SIZE),则调用 getblk 函数从设备上获取单个块,并将返回的缓冲头结构体赋给 bh。

如果 chars 不等于块大小,则调用 breada 函数异步地读取多个块,并将返回的缓冲头结构体赋给 bh。

增加块号的值,将 p 设置为偏移量加上缓冲区数据的地址,并将偏移量 offset 重置为 0。

更新位置指针(*pos)的值,增加已写入的字节数(written),减少待写入的字节数(count)。

使用 get_fs_byte 函数从用户空间的缓冲区(buf)逐个字符地读取数据,并将其写入内核空间的缓冲区(p)。循环会自减 chars 直到为 0。

将缓冲头结构体(bh)的 b_dirt 标志设置为 1,表示该块已被修改。

调用 brelse 函数释放之前获取的缓冲头结构体(bh)。

最后,函数返回已写入的总字节数(written)

int block_write(int dev, long * pos, char * buf, int count)
{
	int block = *pos >> BLOCK_SIZE_BITS;//右移10bit获取获取block号
	int offset = *pos & (BLOCK_SIZE-1);//与运算获取块内偏移量
	int chars;
	int written = 0;
	struct buffer_head * bh;
	register char * p;

	while (count>0) {
		chars = BLOCK_SIZE - offset;
		if (chars > count)
			chars=count;
		if (chars == BLOCK_SIZE)
			bh = getblk(dev,block);//完整的块
		else
			bh = breada(dev,block,block+1,block+2,-1);//读取设备上的多个块,预读后续几个block提高性能,并返回缓冲头结构体
		block++;
		if (!bh)
			return written?written:-EIO;
		p = offset + bh->b_data;
		offset = 0;
		*pos += chars;
		written += chars;
		count -= chars;
		while (chars-->0)
			*(p++) = get_fs_byte(buf++);
		bh->b_dirt = 1;
		brelse(bh);
	}
	return written;
}

int block_read(int dev, unsigned long * pos, char * buf, int count)

首先将位置指针右移 BLOCK_SIZE_BITS 位,以获取块号(block),然后使用与运算获取在块内的偏移量(offset)。

进入循环,只要还有待读取的字节数(count>0),就会执行以下步骤:

将 chars 设置为当前块剩余的字符数(BLOCK_SIZE - offset),如果此值大于 count,则将其设置为 count。

调用 breada 函数以异步地读取设备上的多个块,并将返回的缓冲头结构体赋给 bh。如果读取失败,则根据 read 的值判断是否已经读取过数据,如果是则返回 read,否则返回 -EIO 表示 I/O 错误。

增加 block 的值,将 p 指向缓冲区起始位置加上偏移量(offset)的地址,并将 offset 重置为 0。

更新位置指针(*pos)的值,增加已读取的字节数(read),减少待读取的字节数(count)。

使用 put_fs_byte 函数将内核空间的字符复制到用户空间的缓冲区(buf)。这个过程会逐个字符地从 p 指向的地址复制到 buf 指向的地址,并同时自增 p 和 buf 的指针。循环将重复执行 chars 次。

调用 brelse 函数释放之前获取的缓冲头结构体(bh)。

最后,函数返回已读取的总字节数(read)。

int block_read(int dev, unsigned long * pos, char * buf, int count)
{
	int block = *pos >> BLOCK_SIZE_BITS;
	int offset = *pos & (BLOCK_SIZE-1);
	int chars;
	int read = 0;
	struct buffer_head * bh;
	register char * p;

	while (count>0) {
		chars = BLOCK_SIZE-offset;
		if (chars > count)
			chars = count;
		if (!(bh = breada(dev,block,block+1,block+2,-1)))
			return read?read:-EIO;
		block++;
		p = offset + bh->b_data;
		offset = 0;
		*pos += chars;
		read += chars;
		count -= chars;
		while (chars-->0)
			put_fs_byte(*(p++),buf++);
		brelse(bh);
	}
	return read;
}

你可能感兴趣的:(linux0.11内核源码,c语言,开发语言)