(莱昂氏unix源代码分析导读-40)inode“指向文件的内容”的读写

                                              by cszhao1980

前面已经说过,inode指向文件的内容是通过i_addr[]数组来组织和记录的。

本章讨论一下文件内容的读写。

在进行文件读写时,使用了进程u空间的若干变量,先介绍如下:

 

       0418:      char u_segflg;       /* flag for IO; user or kernel space */

0425:      char *u_base;       /* base address for IO */

0426:      char *u_count;      /* bytes remaining for IO */

0427:      char *u_offset[2];    /* offset in file for IO */

 

(1)         u_segflg Kernel/user标志, 0—— user 1——kernel

(2)         u_base 起始地址

这两个变量用来确定文件内容要读入的内存的起始地址:

(3)         u_count:要读入的长度;

(4)         u_offset[2]:文件当前offset(即从该offset处开始读写,读写过程会更新该offset);

                    offset数组使用2word模拟一个32位数,offset[0]为高16 bitoffset[1]为高16 bit

 

由于文件长度可能超出1word的限制,故在保存长度相关变量时,往往使用2word来模拟

32 bit数,如u中的u_offset数组,inode中的i_size0i_size1等等。unix v6还提供了一套“双字”

操作函数,如:

(1)         lshift()  双字移位;

(2)         dmadd() 双字加法;

(3)         dmcmp():双字减法;

等等。

 

现在让我们看看readi(ip) ——该函数用来读取文件内容。read(ip)仅有一个参数,即inode指针,其

他的参数都通过进程u结构传递进来。下面我们来看看这个函数:

(1)         6232 行将i_flagIACC标志置位,这会导致iupdat函数在更新inode时,会更新的access time

(2)         6233~6235是对特殊字符设备(IFCHR)的特殊处理,将来会详细介绍;

(3)         6238 ~ 6262行的do while循环是程序的主体,结束循环的情况有:

i.           读到文件结尾;

ii.          读够要求的字节数(u_count);

 

6239~6240行用于确定要读取的逻辑块和块内偏移;

6243~6244行的dpcmp调用用于获取文件剩余的字节数;

6255~6258行使用块读取函数bread/breada将块读入缓冲区;

6260行:使用iomove函数将缓冲区内有效字符拷贝至用户指定地址。

 

【注】:对特殊块设备(IFBLK置位)有特殊的处理,在此不讨论。

 

下面我们看一下iomove函数,它有两种用途:

(1)         读:即将缓冲区内内容移入用户数据区;

(2)         写:即将用户数据区内容移入缓冲区。

 

它有四个参数:

(1)         bp ——缓冲区指针;

(2)         o ——块内偏移(读、写的起始地址);

(3)         an ——读、写字符数;

(4)         flag ——读/flagB_READ/B_WRITE

 

iomove使用两套函数来完成数据转移工作:

(1)         copyin/ copyout

(2)         passc/cpass

 

1套函数只能用于kernel地址与user地址间的数据转移;

2套函数既可以用于kernelkernel又可以用于kerneluser间的数据转移。

 

之所以分两套函数,是因为在执行kernelkernel数据传递时,第1套函数按word进行传递,

效率较高。但也正因如此,当数据传递中遇到byte疆界时,该套函数就不适用了。

 

最后,我们看一下writei函数,与readi正好相反,它的目的是将内存内的数据写回磁盘。

writei函数的实现同readi非常相似,比较难理解的是:

6303: if(n == 512)

6304: bp = getblk(dn, bn); else

6305: bp = bread(dn, bn);

6306: iomove(bp, on, n, B_WRITE);

 

n512时,表示要写一整块盘块,因此,盘块原有的内容就不重要了,所以只需调用

getblk获取一块缓冲区,然后将要写的内容拷入缓冲区即可。

 

博客地址:http://blog.csdn.net/cszhao1980

博客专栏地址:http://blog.csdn.net/column/details/lions-unix.html

 

你可能感兴趣的:((莱昂氏unix源代码分析导读-40)inode“指向文件的内容”的读写)