linux 0.11 内核学习 -- file_dev.c

/*

 *  linux/fs/file_dev.c

 *

 *  (C) 1991  Linus Torvalds

 */

#include <errno.h>

#include <fcntl.h>

#include <linux/sched.h>

#include <linux/kernel.h>

#include <asm/segment.h>

#define MIN(a,b) (((a)<(b))?(a):(b))

#define MAX(a,b) (((a)>(b))?(a):(b))

/* 根据i 节点和文件结构,读设备数据,为上层的read函数提供函数 */

int file_read(struct m_inode * inode, struct file * filp, char * buf, int count)

{

// 由i 节点可以知道设备号,由filp 结构可以知道文件中当前读写指针位置。buf 指定用户态中

// 缓冲区的位置,count 为需要读取的字节数。返回值是实际读取的字节数,或出错号(小于0)

int left,chars,nr;

struct buffer_head * bh;

// 若需要读取的字节计数值小于等于零,则返回

if ((left=count)<=0)

return 0;

while (left) 

{

// 根据i 节点和文件表结构信息,取数据块文件当前读写位置在设备上对应的逻辑块号nr。若nr 不

// 为0,则从i 节点指定的设备上读取该逻辑块

if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) // 得到逻辑块号

{

if (!(bh=bread(inode->i_dev,nr)))

break;

} else

bh = NULL;

// 计算文件读写指针在数据块中的偏移值nr

nr = filp->f_pos % BLOCK_SIZE;

// 然后与还需读取的字节数left 作比较,其中小值即为本次需读的字节数chars

chars = MIN( BLOCK_SIZE-nr , left );

// 调整读写文件指针

filp->f_pos += chars;

// 剩余字节计数相应减去chars

left -= chars;

if (bh) // 如果读出了数据

{

char * p = nr + bh->b_data; // 将p 指向读出数据块缓冲区中开始读取的位置

// 复制chars字节到用户的缓冲区

while (chars-->0)

put_fs_byte(*(p++),buf++);

brelse(bh);

// 否则将用户的缓冲区全部设置成0

else

{

/*************************************/

while (chars-->0)

put_fs_byte(0,buf++);

/**************************************/

}

}

// 修改该i 节点的访问时间为当前时间。返回读取的字节数

inode->i_atime = CURRENT_TIME;

return (count-left)?(count-left):-ERROR;

/*

* 该函数实现的是根据i节点和文件的struct file来读取实际设备

* 上的数据到用户的缓冲区。调用的函数bread来读取设备上的数据。

* bread函数的参数设备号是有参数inode得到,而文件的偏移量是

* 由struct file结构中的f_pos计算出来,有这两个参数将设备上的

* 数据得到,然后复制到用户区域中

*/

}

/* 根据i 节点和文件结构信息,将用户数据写入指定设备,只是将数据写入 */

/* 缓冲区,然后由内核在合适的时候将数据刷新到设备文件上             */

int file_write(struct m_inode * inode, struct file * filp, char * buf, int count)

{

off_t pos;

int block,c;

struct buffer_head * bh;

char * p;

int i=0;

/*

 * ok, append may not work when many processes are writing at the same time

 * but so what. That way leads to madness anyway.

 */

// 如果是要向文件后添加数据,则将文件读写指针移到文件尾部

if (filp->f_flags & O_APPEND)

pos = inode->i_size;

// 否则就将在文件读写指针处写入

else

pos = filp->f_pos;

while (i<count) 

{

// 创建数据块号(pos/BLOCK_SIZE)在设备上对应的逻辑块,并返回在设备上的逻辑块号。如果逻辑

// 块号=0,则表示创建失败,退出循环

if (!(block = create_block(inode,pos/BLOCK_SIZE)))

break;

// 根据该逻辑块号读取设备上的相应数据块

if (!(bh=bread(inode->i_dev,block)))

break;

// 求出文件读写指针在数据块中的偏移值c

c = pos % BLOCK_SIZE;

// 将p 指向读出数据块缓冲区中开始读取的位置

p = c + bh->b_data;

// 缓冲区已修改标志

bh->b_dirt = 1;

// 从开始读写位置到块末共可写入c=(BLOCK_SIZE-c)个字节。若c 大于剩余还需写入的字节数

// (count-i),则此次只需再写入c=(count-i)即可

c = BLOCK_SIZE-c;

if (c > count-i) c = count-i;

// 文件读写指针前移此次需写入的字节数。如果当前文件读写指针位置值超过了文件的大小,则

// 修改i 节点中文件大小字段,并置i 节点已修改标志

pos += c;

if (pos > inode->i_size) {

inode->i_size = pos;

inode->i_dirt = 1;

}

// 已写入字节计数累加此次写入的字节数c

i += c;

// 从用户缓冲区buf 中复制c 个字节到高速缓冲区中p指向开始的位置处

/***********************************/

while (c-->0)

*(p++) = get_fs_byte(buf++);

/***********************************/

// 然后释放该缓冲区

brelse(bh);

}

inode->i_mtime = CURRENT_TIME; // // 更改文件修改时间为当前时间

// 如果此次操作不是在文件尾添加数据,则把文件读写指针调整到当前读写位置,并更改i 节点修改

// 时间为当前时间

if (!(filp->f_flags & O_APPEND)) 

{

filp->f_pos = pos;

inode->i_ctime = CURRENT_TIME;

}

// 返回写入的字节数,若写入字节数为0,则返回出错号-1

return (i?i:-1);

/*

* 该函数实现的是将用户程序区的数据复制到设备文件上。函数的做法是

* 首先建立一个block(调用函数create_block在磁盘上建立一个逻辑块),

* 然后调用函数bread将新申请到的逻辑块读入到缓冲区中,然后将数据

* 写入到该缓冲区中,设置该缓冲区的i_dirt,然后释放该缓冲区,内核在

* 合适的时候将数据刷新到设备上

*/

}

参考《linux内核完全注释》和网上相关资料

你可能感兴趣的:(linux)