FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

mkfs.cによりファイルシステムが作られる仕組み(まだ勉強中3)

github.com

ビルドプロセスの中に、mkfsによりファイルシステムfs.imgを作る工程がある。

./mkfs fs.img README _cat _echo _forktest _grep _init _kill _ln _ls _mkdir _rm _sh _stressfs _usertests _wc _zombie

fs.imgはどのような仕組みで作られているんだろうか。まずは、こちらの解説が詳しい。

tondol.hatenablog.jp

ブロックは1ブロック512バイトで構成されている。

  1. 0ブロック目は利用されていない。これは前回ブログで1ブロック分ブートに使用するので入っていないのかな?(でも向こうはxv6.imgだしなあ。。。)
  2. 1ブロック目はスーパーブロックとなっている。スーパーブロックの構成は、
struct superblock {
  uint size;         // Size of file system image (blocks)
  uint nblocks;      // Number of data blocks
  uint ninodes;      // Number of inodes.
  uint nlog;         // Number of log blocks
  uint logstart;     // Block number of first log block
  uint inodestart;   // Block number of first inode block
  uint bmapstart;    // Block number of first free map block
};

ファイルシステムメタデータの情報が入っているようだ。

まずは、FSSIZE分のセクタのフォーマットをする。

  for(i = 0; i < FSSIZE; i++)
    wsect(i, zeroes);

...

void
wsect(uint sec, void *buf)
{
  if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){
    perror("lseek");
    exit(1);
  }
  if(write(fsfd, buf, BSIZE) != BSIZE){
    perror("write");
    exit(1);
  }
}

fsfdファイルポインタに対して、セクタ分の情報を書き込んでいる。 次に、セクタ1にsuperblockの情報を書き込む。

  memset(buf, 0, sizeof(buf));
  memmove(buf, &sb, sizeof(sb));
  wsect(1, buf);

iallocで新しいinodeを割り当て、それをルートディレクトリとする。iappendの構造はちょっと複雑ですぐには読めない。でも、必要ブロック分、wsectを呼び出している感じがする。

  rootino = ialloc(T_DIR);
  assert(rootino == ROOTINO);

  bzero(&de, sizeof(de));
  de.inum = xshort(rootino);
  strcpy(de.name, ".");
  iappend(rootino, &de, sizeof(de));

さらに、必要なファイルやディレクトリを追加していっている。

  for(i = 2; i < argc; i++){
    assert(index(argv[i], '/') == 0);

    if((fd = open(argv[i], 0)) < 0){
      perror(argv[i]);
      exit(1);
    }

    // Skip leading _ in name when writing to file system.
    // The binaries are named _rm, _cat, etc. to keep the
    // build operating system from trying to execute them
    // in place of system binaries like rm and cat.
    if(argv[i][0] == '_')
      ++argv[i];

    inum = ialloc(T_FILE);

    bzero(&de, sizeof(de));
    de.inum = xshort(inum);
    strncpy(de.name, argv[i], DIRSIZ);
    iappend(rootino, &de, sizeof(de));

    while((cc = read(fd, buf, sizeof(buf))) > 0)
      iappend(inum, buf, cc);

    close(fd);
  }

最後に、ブロックを調整して終わりかな。

  // fix size of root inode dir
  rinode(rootino, &din);
  off = xint(din.size);
  off = ((off/BSIZE) + 1) * BSIZE;
  din.size = xint(off);
  winode(rootino, &din);

  balloc(freeblock);

  exit(0);