作业地址

Creating a Problem

替换 commit()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include "mmu.h"
#include "proc.h"
void
commit(void)
{
  int pid = myproc()->pid;
  if (log.lh.n > 0) {
    write_log();
    write_head();
    if(pid > 1)            // AAA
      log.lh.block[0] = 0; // BBB  // log 写入扇区
    install_trans();
    if(pid > 1)            // AAA
      panic("commit mimicking crash"); // CCC
    log.lh.n = 0;
    write_head();
  }
}

替换 recover_from_log() 阻止 log 的 recovery

1
2
3
4
5
6
7
8
9
static void
recover_from_log(void)
{
  read_head();
  cprintf("recovery: n=%d but ignoring\n", log.lh.n);
  // install_trans();
  log.lh.n = 0;
  // write_head();
}

最后删除 Makefiole 中 QEMUEXTRA 中的 -snapshot

删除 rm.img 并重新编译后文件抛出异常

1
2
3
$ echo hi >a
lapicid 0: panic: commit mimicking crash
80102e6e 80105186 80104989 8010598d 801057ec 0 0 0 0 0

重新运行后抛出异常

1
2
3
$ cat a
lapicid 0: panic: ilock: no type
80101857 80105138 80104989 8010598d 801057ec 0 0 0 0 0

原因是由于文件 a 对应的 inode 没有写入 log 中,且 commit 时没有写入对应的块,且重启后没有修复

Solving the Problem

把刚才替换的 recover_from_log() 还原,重新运行 cat a

1
2
$ cat a
$

文件 a 为空,原因是 commit() 写入错误的事务(使 log 的位置错误, log.lh.block[0] = 0;)且抛出异常后没有硬盘事务(log.lh.n),在重启后检查到 log 内有完整事务,通过 recover_from_log() 恢复后恢复为错误事务,导致 inode 读取位置错误,读取 0 扇区中内容,0扇区内容为空,所以输出空白

Streamlining Commit

修改下列函数

install_trans()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Copy committed blocks from log to their home location
static void
install_trans(int trans_to_mem_flag)
{
  int tail;

  for (tail = 0; tail < log.lh.n; tail++) {
    struct buf *dbuf = bread(log.dev, log.lh.block[tail]); // read dst

    struct buf *lbuf;

    if (trans_to_mem_flag) {
      lbuf = bread(log.dev, log.start+tail+1);  // read log block
      memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst
    }

    bwrite(dbuf);  // write dst to disk

    if (trans_to_mem_flag) {
      brelse(lbuf);
    }

    brelse(dbuf);
  }
}

commit()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
static void
commit()
{
  if (log.lh.n > 0) {
    write_log();     // Write modified blocks from cache to log
    write_head();    // Write header to disk -- the real commit
    install_trans(0); // Now install writes to home locations
    log.lh.n = 0;
    write_head();    // Erase the transaction from the log
  }
}

recover_from_log()

1
2
3
4
5
6
7
8
static void
recover_from_log(void)
{
  read_head();
  install_trans(1); // if committed, copy from log to disk
  log.lh.n = 0;
  write_head(); // clear the log
}

结果

1
2
3
$ echo hi > a
$ cat a
hi