Lab 9_1 Large files

在这个实验中,你会拓展文件系统中文件的最大大小,其中一开始文件是12个直接连接块,1个一级索引块,一共16*16+12=268个块,这个时候我们要修改一下改成11个直接相连,1个一级索引块,1个二级索引块,一共256*256+256+11=65536+256+11个块.

其中xv6把文件系统映射到fs.img中,这个一共有二十万个块,其中70个保存块信息的meta块,剩下的都是数据.完成这个实验你需要关注磁盘 inode 的格式,这个由 fs.h 中的 struct dinode 定义。 您对 NDIRECT、NINDIRECT、MAXFILE 和结构 dinode 的 addrs[] 元素特别感兴趣。 查看 xv6 文本中的图 8.3 以了解标准 xv6 inode 的图表。
在磁盘上查找文件数据的代码在 fs.c 的 bmap() 中。 看看它,确保你明白它在做什么。 bmap() 在读取和写入文件时都会被调用。 写入时,bmap() 会根据需要分配新块来保存文件内容,并在需要时分配间接块来保存块地址。
bmap() 处理两种块号。 bn 参数是一个“逻辑块号”——文件中的块号,相对于文件的开头。 ip->addrs[] 中的块号和 bread() 的参数是磁盘块号。 您可以将 bmap() 视为将文件的逻辑块号映射到磁盘块号。

修改 bmap() ,使其除了直接块和单间接块外,还实现双重间接块。 你只需要 11 个直接块,而不是 12 个,就可以为新的双重间接块腾出空间; 您不能更改磁盘 inode 的大小。 ip->addrs[] 的前 11 个元素应该是直接块; 第 12 个应该是一个单独的间接块(就像现在的块一样); 第 13 个应该是你新的双重间接块。

1) 修改直接映射的数量.
#define NDIRECT 11#define NDIRECT 11
uint addrs[NDIRECT+2];
#define MAXFILE (NDIRECT + NINDIRECT + NDOUBLE)//文件最大值也要改变

其中直接映射的数量由原来的12个改为11个.

2) 对应的file.h的inode结构体也要进行更改
struct inode {
  uint dev;           // Device number
  uint inum;          // Inode number
  int ref;            // Reference count
  struct sleeplock lock; // protects everything below here
  int valid;          // inode has been read from disk?

  short type;         // copy of disk inode
  short major;
  short minor;
  short nlink;
  uint size;
  uint addrs[NDIRECT+2];
};
3) 阅读bmap的代码: 0-NDIRECT-1 :直接 ,NDIRECT,NDIRECT+NINDIRECT-1:一级间接
//bn:the number the blocks.
  if(bn < NDIRECT){
    if((addr = ip->addrs[bn]) == 0)
      ip->addrs[bn] = addr = balloc(ip->dev);
    return addr;
  }
  bn -= NDIRECT;

  if(bn < NINDIRECT){
    // Load indirect block, allocating if necessary.
    if((addr = ip->addrs[NDIRECT]) == 0)
      ip->addrs[NDIRECT] = addr = balloc(ip->dev);
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if((addr = a[bn]) == 0){
      a[bn] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    return addr;
  }

有个大前提,就是如果索引为0就代表这个磁盘为空,需要申请一个返回一个磁盘块号

首先第一部分,就是直接映射的部分,如果寻找的逻辑地址是在NDIRECT以内的,就可以直接访问磁盘块.

第二部分就是一级间接映射,首先先把一级映射的映射表找到,读出来,如果没有映射表就新建一个.映射表我们之前在操作系统学过就是一个int类型数组,这个时候我们就可以把映射表解释称int类型数组,然后根据索引值,也就是bn-NDIRECT来寻找,寻找就是寻找数组里面的东西.

4) 依葫芦画瓢作出二级索引.
  bn -= NINDIRECT;

  if(bn < NDOUBLE){
    if((addr = ip->addrs[NDIRECT+1]) == 0)
      ip->addrs[NDIRECT+1] = addr = balloc(ip->dev);
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    int bn1 = bn / NINDIRECT,bn2 = bn % NINDIRECT;
    //first suoyin
    if((addr = a[bn1]) == 0){
     a[bn1] = addr = balloc(ip->dev);
     log_write(bp);
    }
    //second suoyin
    brelse(bp);
    bp=bread(ip->dev,addr);
    a=(uint*)bp->data;
    if((addr=a[bn2])==0)
    {
        a[bn2]=addr=balloc(ip->dev);
        log_write(bp);
    }
    brelse(bp);
    return addr;
  }

二级索引需要两个索引值,一个是除得来的结果,一个是%得来的结果,首先先读一次,获得一级索引表,做法和上面是一样的,接着再读,根据一级索引表得来的结果就是对应二级索引表的位置,所以说根据一级索引表的结果打开二级索引表,找到最后属于我们的索引值.

5) 完成索引的释放.
  if(ip->addrs[NDIRECT+1]) {
    bp = bread(ip->dev, ip->addrs[NDIRECT+1]);
    a = (uint*)bp->data;
    for(j = 0; j < NINDIRECT; j++) {
      if(a[j]) {
        bp2 = bread(ip->dev, a[j]);
        a2 = (uint*)bp2->data;
        for(i = 0; i < NINDIRECT; i++) {
          if(a2[i]) bfree(ip->dev, a2[i]);
        }
        brelse(bp2);
        bfree(ip->dev, a[j]);
        a[j] = 0;
      }
    }
    brelse(bp);
    bfree(ip->dev, ip->addrs[NDIRECT+1]);
    ip->addrs[NDIRECT] = 0;
  }

就是先读取数组的第13项,构造一个二重循环,先进入到第一个一级索引的第一个二级索引陆续地释放所有的块.再进入到第一个一级索引的第二个二级索引…第一个一级索引的第256个二级索引….第256个二级索引的第256个一级索引…

Lab9_2 Symbolic links

您将实现 symlink(char *target, char *path) 系统调用,它会在 path 处创建一个新的符号链接,该链接引用由 target 命名的文件。

首先,为symlink创建一个新的系统调用号,在user/usys.pl,user/user.h中添加一个入口,在kernel/sysfile.c中实现一个空的sys_symlink。
将新文件类型 (T_SYMLINK) 添加到 kernel/stat.h 以表示符号链接。
向 kernel/fcntl.h 添加一个新标志 (O_NOFOLLOW),可与 open 系统调用一起使用。请注意,传递给 open 的标志是使用按位 OR 运算符组合的,因此您的新标志不应与任何现有标志重叠。这将让您在将 user/symlinktest.c 添加到 Makefile 后编译它。
实现 symlink(target, path) 系统调用以在指向目标的路径上创建一个新的符号链接。请注意,系统调用成功时不需要存在目标。您将需要选择某个位置来存储符号链接的目标路径,例如,在 inode 的数据块中。 symlink 应该返回一个表示成功 (0) 或失败 (-1) 的整数,类似于链接和取消链接。
修改 open 系统调用以处理路径引用符号链接的情况。如果文件不存在,则打开必须失败。当进程在要打开的标志中指定 O_NOFOLLOW 时, open 应该打开符号链接(而不是跟随符号链接)。
如果链接文件也是符号链接,则必须递归地跟随它,直到到达非链接文件。如果链接形成循环,则必须返回错误代码。如果链接的深度达到某个阈值(例如,10),您可以通过返回错误代码来近似此值。
其他系统调用(例如,链接和取消链接)不得遵循符号链接;这些系统调用对符号链接本身进行操作。
对于本实验,您不必处理指向目录的符号链接。

1) 添加系统调用.(略)
2) 按照实验提示的信息,添加两个新的宏.(略)
3) 完成symlink系统调用.

首先第一点,我们发现,在sysfile.c的系统调用是需要提交事务的,我们也模仿这一点进行更改,处理的思路就是获取参数,创建一个新的inode,把符号连接的文件路径写进inode里面,然后提交即可.

uint64
sys_symlink(void)
{  
  char path[MAXPATH], target[MAXPATH];
  struct inode *ip;
  // get parameter
  if(argstr(0, target, MAXPATH) < 0)
    return -1;
  if(argstr(1, path, MAXPATH) < 0)
    return -1;
  begin_op();
  // create a inode
  if((ip = create(path, T_SYMLINK, 0, 0)) == 0) {
    end_op();
    return -1;
  }
  // write the path of the file to the inode.
  if(writei(ip, 0, (uint64)target, 0, MAXPATH) < MAXPATH) {
    iunlockput(ip);
    end_op();
    return -1;
  }
  iunlockput(ip);
  end_op();
  return 0;
}

0 条评论

发表评论

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用*标注

隐藏