Lab: file system

Lab: file system

Large files (moderate)

修改bmap使得inode支持更大的块。Currently xv6 files are limited to 268 blocks, or 268BSIZE bytes (BSIZE is 1024 in xv6). This limit comes from the fact that an xv6 inode contains 12 “direct” block numbers and one “singly-indirect” block number, which refers to a block that holds up to 256 more block numbers, for a total of 12+256=268 blocks.将一个direct block number用作"doubly-indirect" block, containing 256 addresses of singly-indirect blocks, each of which can contain up to 256 addresses of data blocks. The result will be that a file will be able to consist of up to 65803 blocks, or 256256+256+11 blocks (11 instead of 12, because we will sacrifice one of the direct block numbers for the double-indirect block).
Your Job
Modify bmap() so that it implements a doubly-indirect block, in addition to direct blocks and a singly-indirect block. You’ll have to have only 11 direct blocks, rather than 12, to make room for your new doubly-indirect block; you’re not allowed to change the size of an on-disk inode. The first 11 elements of ip->addrs[] should be direct blocks; the 12th should be a singly-indirect block (just like the current one); the 13th should be your new doubly-indirect block. You are done with this exercise when bigfile writes 65803 blocks and usertests -q runs successfully:

修改头文件

fs.h
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
#define SECINDIRECT (NINDIRECT * NINDIRECT)
#define MAXFILE (NDIRECT + NINDIRECT + SECINDIRECT)

// On-disk inode structure
struct dinode {
  short type;           // File type
  short major;          // Major device number (T_DEVICE only)
  short minor;          // Minor device number (T_DEVICE only)
  short nlink;          // Number of links to inode in file system
  uint size;            // Size of file (bytes)
  uint addrs[NDIRECT+2];   // Data block addresses
};

file.h
// in-memory copy of an 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];
};

fs.c

static uint
bmap(struct inode *ip, uint bn)
{
  uint addr, *a;
  struct buf *bp;

  if(bn < NDIRECT){
    if((addr = ip->addrs[bn]) == 0){
      addr = balloc(ip->dev);
      if(addr == 0)
        return 0;
      ip->addrs[bn] = addr;
    }
    return addr;
  }
  bn -= NDIRECT;

  if(bn < NINDIRECT){
    // Load indirect block, allocating if necessary.
    if((addr = ip->addrs[NDIRECT]) == 0){
      addr = balloc(ip->dev);
      if(addr == 0)
        return 0;
      ip->addrs[NDIRECT] = addr;
    }
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if((addr = a[bn]) == 0){
      addr = balloc(ip->dev);
      if(addr){
        a[bn] = addr;
        log_write(bp);
      }
    }
    brelse(bp);
    return addr;
  }
  bn -= NINDIRECT;
  if(bn < SECINDIRECT){
    // Load second indirect block, allocating if necessary.
    int first = bn / NINDIRECT, second = bn % NINDIRECT;
    if((addr = ip->addrs[NDIRECT+1]) == 0){
      addr = balloc(ip->dev);
      if(addr == 0)
        panic("bmap: out of blocks");
      ip->addrs[NDIRECT+1] = addr;
    }
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if((addr = a[first]) == 0){
      addr = balloc(ip->dev);
      if(addr == 0)
        return 0;
      a[first] = addr;
      log_write(bp);
    }
    brelse(bp);
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if((addr = a[second]) == 0){
      addr = balloc(ip->dev);
      if(addr == 0)
        return 0;
      a[second] = addr;
      log_write(bp);
    }
    brelse(bp);
    return addr;
  }
  panic("bmap: out of range");
}

void
itrunc(struct inode *ip)
{
  int i, j;
  struct buf *bp;
  uint *a;

  for(i = 0; i < NDIRECT; i++){
    if(ip->addrs[i]){
      bfree(ip->dev, ip->addrs[i]);
      ip->addrs[i] = 0;
    }
  }

  if(ip->addrs[NDIRECT]){
    bp = bread(ip->dev, ip->addrs[NDIRECT]);
    a = (uint*)bp->data;
    for(j = 0; j < NINDIRECT; j++){
      if(a[j])
        bfree(ip->dev, a[j]);
    }
    brelse(bp);
    bfree(ip->dev, ip->addrs[NDIRECT]);
    ip->addrs[NDIRECT] = 0;
  }

  if(ip->addrs[NDIRECT+1]){
    bp = bread(ip->dev, ip->addrs[NDIRECT+1]);
    a = (uint*)bp->data;
    for(i = 0; i < NINDIRECT; i++){
      if(a[i]){
        struct buf *bp1 = bread(ip->dev, a[i]);
        uint *b = (uint*)bp1->data;
        for(j = 0; j < NINDIRECT; j++){
          if(b[j])
            bfree(ip->dev, b[j]);
        }
        brelse(bp1);
        bfree(ip->dev, a[i]);
      }
    }
    brelse(bp);
    bfree(ip->dev, ip->addrs[NDIRECT+1]);
    ip->addrs[NDIRECT+1] = 0;
  }
  ip->size = 0;
  iupdate(ip);
}

结果在usertests中的textwrite这一项无法通过
查看代码

    volatile int *addr = (int *) 0;
    *addr = 10;
    exit(1);

cpu执行应该会引发中断,但是并没有。同样的代码放在xv6 2024中就正确的引发了中断。

Symbolic links (moderate)

In this exercise you will add symbolic links to xv6. Symbolic links (or soft links) refer to a linked file by pathname; when a symbolic link is opened, the kernel follows the link to the referred file. Symbolic links resembles hard links, but hard links are restricted to pointing to file on the same disk, while symbolic links can cross disk devices. Although xv6 doesn’t support multiple devices, implementing this system call is a good exercise to understand how pathname lookup works.

Your job
You will implement the symlink(char *target, char *path) system call, which creates a new symbolic link at path that refers to file named by target. For further information, see the man page symlink. To test, add symlinktest to the Makefile and run it. Your solution is complete when the tests produce the following output (including usertests succeeding).

struct inode*
follow_symlink(struct inode *ip, int depth) {
  if(depth >= 10) {  // 最大递归深度为10
    return 0;       // 可能存在循环链接
  }
  
  char next[MAXPATH];
  int link_len = readi(ip, 0, (uint64)next, 0, MAXPATH);
  if(link_len <= 0) {
    return 0;
  }
  next[link_len] = 0;
  
  iunlockput(ip);

  if((ip = namei(next))== 0) {
    return 0;
  }
  ilock(ip);

  if(ip->type == T_SYMLINK) {
    return follow_symlink(ip, depth + 1);
  }
  return ip;
}

uint64
sys_open(void)
{
  char path[MAXPATH];
  int fd, omode;
  struct file *f;
  struct inode *ip;
  int n;

  argint(1, &omode);
  if((n = argstr(0, path, MAXPATH)) < 0)
    return -1;

  begin_op();

  if(omode & O_CREATE){
    ip = create(path, T_FILE, 0, 0);
    if(ip == 0){
      end_op();
      return -1;
    }
  } else {
    if((ip = namei(path)) == 0){
      end_op();
      return -1;
    }
    ilock(ip);
    if(ip->type == T_SYMLINK&&!(omode&O_NOFOLLOW)){
      if((ip=follow_symlink(ip, 0))==0){
        end_op();
        return -1;
      }
    }
    if(ip->type == T_DIR && omode != O_RDONLY){
      iunlockput(ip);
      end_op();
      return -1;
    }
  }

  if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
    iunlockput(ip);
    end_op();
    return -1;
  }

  if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
    if(f)
      fileclose(f);
    iunlockput(ip);
    end_op();
    return -1;
  }

  if(ip->type == T_DEVICE){
    f->type = FD_DEVICE;
    f->major = ip->major;
  } else {
    f->type = FD_INODE;
    f->off = 0;
  }
  f->ip = ip;
  f->readable = !(omode & O_WRONLY);
  f->writable = (omode & O_WRONLY) || (omode & O_RDWR);

  if((omode & O_TRUNC) && ip->type == T_FILE){
    itrunc(ip);
  }

  iunlock(ip);
  end_op();

  return fd;
}

//0表示成功 -1表示失败
uint64
sys_symlink(void)
{
  char target[MAXPATH], path[MAXPATH];
  struct inode *ip;

  if(argstr(0, target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0)
    return -1;
  begin_op();
  
  //创建符号链接文件
  if((ip = create(path, T_SYMLINK, 0, 0)) == 0){
    end_op();
    return -1;
  }
  // 将target路径存储在inode的数据块中
  if(writei(ip, 0, (uint64)target, 0, strlen(target)) != strlen(target)){
    iunlockput(ip);
    end_op();
    return -1;
  }
  
  
  iunlockput(ip);
  end_op();
  return 0;
}
### MIT xv6操作系统实验中Lab9文件系统的文档和指南 在MIT的xv6操作系统课程中,Lab 9专注于实现一个简单的日志结构化文件系统(log-structured file system, LFS)。这个实验室的目标是让学生理解并实践如何设计和实现一种高效的文件系统,这种文件系统通过将所有的写操作顺序记录在一个日志中来提高性能。 #### 实验目标 学生需要修改`fs.c`中的函数以支持LFS的功能。这涉及到重写磁盘块分配逻辑以及引入新的机制来处理垃圾回收等问题[^1]。 #### 关键概念 - **Log Structured File System (LFS)**: 日志结构化的文件系统不覆盖已有的数据块而是追加新版本到日志末端。 - **Segment**: 文件系统被划分为多个段(segment),每个段包含若干个连续的数据块。 - **Checkpointing**: 定期保存当前状态的一个快照以便于恢复。 - **Garbage Collection**: 清理不再使用的旧版本数据块以释放空间给未来的写入操作。 #### 主要任务 为了完成此实验,参与者通常会经历以下几个方面的工作: - 修改`balloc()` 和 `bread()` 函数使得它们能够管理基于日志的空间而不是传统的位图(bitmap)方式。 - 更新`iwrite()` 来确保每次更改都先记入日志再提交至最终位置。 - 设计并实施有效的垃圾收集算法用于清理过时的日志条目。 ```c // Example of modifying balloc to support log-based allocation. struct superblock { int size; // Number of blocks. int nblocks; // Total number of data blocks. int ninodes; // Number of inodes. }; int lfs_balloc(struct superblock *sb){ static uint next_block = 0; if(next_block >= sb->nblocks) panic("out of blocks"); struct buf* bp = bread(sb->size + next_block); next_block++; return bp->blockno; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值