/* * linux/fs/block_dev.c * * (C) 1991 Linus Torvalds */
#include <errno.h>
#include <linux/sched.h> #include <linux/kernel.h> #include <asm/segment.h> #include <asm/system.h> //是以“块”为单位读写的
int block_write(int dev, long * pos, char * buf, int count)// 数据块写函数 - 从高速缓冲区向指定设备(块设备,如硬盘)从给定偏移处写入指定长度字节数据
{//参数:dev - 设备号;pos - 设备文件中偏移量指针;buf - 用户地址空间中缓冲区地址,count - 要传送的字节数
int block = *pos >> BLOCK_SIZE_BITS;//pos 所在文件数据块号,记住这种方法
int offset = *pos & (BLOCK_SIZE-1);//pos在数据块中的偏移值,记住这种方法
int chars; int written = 0; struct buffer_head * bh; register char * p;
while (count>0) {// 针对要写入的字节数count,循环执行以下操作,直到全部写入
chars = BLOCK_SIZE - offset;// 计算在该块中可写入的字节数。
if (chars > count)//如果需要写入的字节数填不满一块
chars=count; if (chars == BLOCK_SIZE)//如果正好要写1 块数据,则直接申请1 块高速缓冲块
bh = getblk(dev,block); else//否则需要读入将被写入的数据块,并预读下两块数据块,然后将块号递增1
bh = breada(dev,block,block+1,block+2,-1); block++; if (!bh)// 如果缓冲块操作失败,则返回已写字节数,如果没有写入任何字节,则返回出错号
return written?written:-EIO; p = offset + bh->b_data;//在这一块中指定要写入的位置
offset = 0;//写数据是按块写入的,如果要写入 的数据大于1块,则第2次循环从下一块的开始写入,所以offset置0
*pos += chars;//更新文件的当前指针,它的值直接反映到被调用函数sys_write中来,pos变量是按“址”传递参数的
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)// 数据块读函数 - 从指定设备和位置读入指定字节数的数据到高速缓冲中
{ int block = *pos >> BLOCK_SIZE_BITS;//pos 所在文件数据块号,记住这种方法
int offset = *pos & (BLOCK_SIZE-1);//pos在数据块中的偏移值,记住这种方法
int chars; int read = 0; struct buffer_head * bh; register char * p;
while (count>0) { chars = BLOCK_SIZE-offset;// 计算在该块中要读出的的字节数。
if (chars > count)//如果需要读出的字节数不满一块,则只需读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; }
|