code:writei - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki

Source

  • 该函数处理了两种情况,普通INODE 和 块设备装载INODE(参看文件系统#装载文件系统)
    • 普通INODE,对块的处理:将 逻辑块号 转化为 物理块号
    • 块设备装载INODE,对块的处理:对于块设备来说,逻辑块号=物理块号,不需转换
6265

6266 /*

6267  * Write the file corresponding to

6268  * the inode pointed at by the argument.

6269  * the actual read arguments are found

6270  * in the variables:core address for source

6271  * u_base      core address for source

6272  * u_offset      byte offset in file

6273  * u_count      number of bytes to write

6274  * u_segflg      write to kernel/user

6275  */

6276 writei(aip)

6277 struct inode *aip;

6278 {

6279     int *bp;

6280     int lbn, bn, on;

6281     register dn, n;

6282     register struct inode *ip;

6283

6284     ip=aip;

6285     ip->i_flag =| IACC|IUPD;

  • 标志 该INODE块已被修改与存取
6286     if((ip->i_mode&IFMT) == IFCHR) {

6287          (*cdevsw[ip->i_addr[0].d_major].d_write)(ip->i_addr[0]);

  • 处理 字符文件
6288          return;

6289      }

6290     if (u.u_count == 0)

6291          return;

6292

6293     do{

6294          bn = lshift(u.u_offset, -9);

  • u.u_offset右移9位,相当于u.u_offset/512,计算需要读取的逻辑块号
  • u.u_offset值 不改变
  • bn 赋值为逻辑块号
6295          on = u.u_offset[1] & 0777;
  • on 赋值为 块内偏移量
6296          n = min(512-on, u.u_count);
  • n 置为 该块内需写入的字节数 (= 512-块内偏移量 与 需读取字节 的最小值)
6297          if((ip->i_mode&IFMT) != IFBLK) {
  • 若 INODE 不为 特殊块文件,...
6298           if ((bn = bmap(ip, bn)) == 0)
  • bn 置为 需写入块在物理设备对应的块号
6299                return;

6300           dn = ip->i_dev;

  • dn 置为 需写入块的对应物理设备号
6301          } else

6302           dn = ip->i_addr[0];

  • 若 ip 为 块设备装载INODE,则
    • 获取 设备号dn (参看文件系统#装载文件系统)
bn直接作为物理块号(对于设备,逻辑块号=物理块号,不需转换)
6303          if(n == 512)

6304           bp = getblk(dn, bn); else

6305           bp = bread(dn, bn);

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

  • 若需写入的字节数为512(即整个块都要写入)
    • 直接分配一个缓存块,从 指定地址空间 将一整块读入该缓存块
  • 若欲写入的字节数不到一整块
    • 则将磁盘上该块文件的内容读入一个缓存块
    • 然后从 指定地址空间 读入相应字节的内容 到该缓存块的相应位置(即只更新部分内容)
6307          if(u.u_error != 0)

6308           brelse(bp); else

6309          if ((u.u_offset[1]&0777)==0)

6310           bawrite(bp); else

6311           bdwrite(bp);

  • 若文件块已经被全部改写
    • 直接将缓存块异步写回磁盘
  • 若文件块没有被全部改写
    • 采用延迟写策略
6312          if(dpcmp(ip->i_size0&0377, ip->i_size1,

6313           u.u_offset[0], u.u_offset[1]) < 0 &&

6314           (ip->i_mode&(IFBLK&IFCHR)) == 0) {

6315                ip->i_size0 = u.u_offset[0];

6316                ip->i_size1 = u.u_offset[1];

6317          }

  • 若文件小于当前偏移量,表明文件需要扩充,将文件大小改为当前偏移量的值
6318          ip->i_flag =| IUPD;
  • 标志 该INODE块已被存取
6319     } while(u.u_error==0 && u.u_count!=0);
  • 每次循环判断是否出错或者是否写完
  • 若没有写完则继续循环,直到写完为止
6320 }

6321 /* -------------------------*/

Ref

Caller

⚠️ **GitHub.com Fallback** ⚠️