XV6ソースコードリーダ - ファイルシステム

Exercise1ソースコードリーダ

ファイルシステムのセクションbuf.h fcntl.h stat.h fs.hファイル.h ide.c bio.c log.c fs.c FILE.C sysfile.c exec.c

1.buf.h:ディスク・ブロック・データ構造のxv6が定義され、ブロックサイズは512バイトです。

// xv6中磁盘块数据结构,块大小512字节
struct buf {
  int flags; // DIRTY, VALID
  uint dev;
  uint sector; // 对应扇区
  struct buf *prev; // LRU cache list
  struct buf *next; // 链式结构用于连接
  struct buf *qnext; // disk queue
  uchar data[512];
};
#define B_BUSY  0x1  // buffer is locked by some process
#define B_VALID 0x2  // buffer has been read from disk
#define B_DIRTY 0x4  // buffer needs to be written to disk

2.fcntl.h:マクロは、操作権限を定義します。

#define O_RDONLY  0x000 // 只读
#define O_WRONLY  0x001 // 只写
#define O_RDWR    0x002 // 读写
#define O_CREATE  0x200 // 创建

3.stat.h:宣言ファイルまたはディレクトリの属性データ構造。

#define T_DIR  1   // Directory
#define T_FILE 2   // File
#define T_DEV  3   // Device

struct stat {
  short type;  // Type of file
  int dev;     // File system's disk device
  uint ino;    // Inode number
  short nlink; // Number of links to file
  uint size;   // Size of file in bytes
};

4.fs.h / fs.c:文のスーパーブロック、dinode、データファイルやディレクトリ構造、および関連マクロ定義。

#define ROOTINO 1  // root i-number
#define BSIZE 512  // block size

// File system super block
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
};

#define NDIRECT 12
#define NINDIRECT (BSIZE / sizeof(uint))
#define MAXFILE (NDIRECT + NINDIRECT)

// 磁盘上inode节点体现形式
// On-disk inode structure
struct dinode {
  short type;           // File type
  short major;          // Major device number (T_DEV only)
  short minor;          // Minor device number (T_DEV only)
  short nlink;          // Number of links to inode in file system
  uint size;            // Size of file (bytes)
  uint addrs[NDIRECT+1];   // Data block addresses
};

// Inodes per block.
#define IPB           (BSIZE / sizeof(struct dinode))

// Block containing inode i
#define IBLOCK(i)     ((i) / IPB + 2)

// Bitmap bits per block
#define BPB           (BSIZE*8)

// Block containing bit for block b
#define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3)

// Directory is a file containing a sequence of dirent structures.
#define DIRSIZ 14

// 文件或目录据结构,目录本身是以文件的方式存储到磁盘上的,叫做目录文件。
struct dirent {
  ushort inum; // i节点
  char name[DIRSIZ]; // 文件或目录名
};

5.file.h:文のiノード、ファイルのデータ構造。

struct file {
  // 分为管道文件,设备文件,普通文件
  enum { FD_NONE, FD_PIPE, FD_INODE } type; 
  int ref; // reference count
  char readable;
  char writable;
  struct pipe *pipe;
  struct inode *ip; // 指向inode节点
  uint off;
};

// 在内存中inode节点体现形式
// in-memory copy of an inode
struct inode {
  uint dev;           // Device number
  uint inum;          // Inode number
  int ref;            // Reference count
  int flags;          // I_BUSY, I_VALID

      // 下面这些编程都是dinode的拷贝
      // copy of disk inode
  short type;         
  short major;
  short minor;
  short nlink;
  uint size;
  uint addrs[NDIRECT+1];
};
#define I_BUSY 0x1
#define I_VALID 0x2

// table mapping major device number to device functions
struct devsw {
  int (*read)(struct inode*, char*, int);
  int (*write)(struct inode*, char*, int);
};

extern struct devsw devsw[];

#define CONSOLE 1

キュー(idequeue)ディスクIOの具体的な実現、xv6プロセスはディスク操作を要求維持:6.ide.c. ディスクが要求を読み書きするとプロセスが** **無効iderw(構造体BUF * B)を呼び出すと、プロセスがスリープ状態になる一方で、要求は、待ちキューidequeueに追加されます。ディスクは、操作が完了した読み取りおよび書き込みすると、それが割り込み、割り込みハンドラideintrを(トリガする)キューウェイクアップ要求は、プロセスの開始に対応し、待ち行列の先頭の要求を削除します。

// idequeue points to the buf now being read/written to the disk.
// idequeue->qnext points to the next buf to be processed.
// You must hold idelock while manipulating queue.

static struct spinlock idelock; // 保护 idequeue
static struct buf *idequeue; // 磁盘读写操作的请求队列
……
// 等待磁盘进入空闲状态
// Wait for IDE disk to become ready.
static int idewait(int checkerr)
{
  ……
  // 
  while(((r = inb(0x1f7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY);
  ……
}

// 初始化IDE磁盘IO
void ideinit(void)
{
  ……
}

// 开始一个磁盘读写请求
// Start the request for b.  Caller must hold idelock.
static void idestart(struct buf *b)
{
  ……
}

// 当磁盘请求完成后中断处理程序会调用的函数
// Interrupt handler.
void ideintr(void)
{
  …… // 处理完一个磁盘IO请求后,唤醒等待在等待队列头的那个进程
  wakeup(b);
  
  // 如果队列不为空,继续处理下一个磁盘IO任务
  // Start disk on next buf in queue.
  if(idequeue != 0)
    idestart(idequeue);
  ……
}

//PAGEBREAK!  上层文件系统调用的磁盘IO接口
// Sync buf with disk. 
// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
// Else if B_VALID is not set, read buf from disk, set B_VALID.
void iderw(struct buf *b)
{
  …… // 竞争锁
  acquire(&idelock);  //DOC:acquire-lock

  // Append b to idequeue.
  b->qnext = 0;
  for(pp=&idequeue; *pp; pp=&(*pp)->qnext)  //DOC:insert-queue
    ;
  *pp = b;
  
  // Start disk if necessary.  开始处理一个磁盘IO任务
  if(idequeue == b)
    idestart(b);
  
  // Wait for request to finish.  睡眠等待
  while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){
    sleep(b, &idelock);
  }

  release(&idelock);  // 释放锁
}

7.bio.c:バッファ・キャッシュの具体的な実現。ディスクは、ディスクキャッシュが頻繁に最近の記憶でブロックをアクセス局所性の原則によれば、非効率的、時間と空間を読み書き動作ので。主なインタフェースは、構造体BUFを持っている*パン(UINT devのは、 UINT部門)、無効BWRITE(構造体BUF * b)は、パンは読み出し動作が要求されたディスクがない場合は、直接のリターンがあれば最初からキャッシュブロックが、存在するかどうかを見つけることでしょう、キャッシュを読み、その結果を返します。ディスクに書き込まれるキャッシュ内のデータに直接BWRITE。
8.log.c:このモジュールは、ファイルシステムの一貫性を維持することです。ログモジュールの導入後、全ディスク・オペレーティング・システム・ファイルに上位層は、トランザクションに切断されている、各トランザクションは、第1のデータとそれに対応するディスク番号になり、ディスクログ領域に書き込まれ、そしてのみ成功ログ書き込み領域の後にあります、実際のストレージのデータブロック領域を書き込む前にログデータ。したがって、存在しないログ領域に書き込まれたログはダウンゾーン時間の実領域から書き込まれた場合のダウンタイムは、ファイルシステムを再起動する書き込みログは、あなたがデータログ領域を復元することができます。
9.sysfile.c:メインの定義ファイル関連のシステムコール。次のように主要インターフェースと意味は以下の通りであります:

// Allocate a file descriptor for the given file.
// Takes over file reference from caller on success.
static int fdalloc(struct file *f)
{
  …… // 申请一个未使用的文件句柄
}

int sys_dup(void)
{
  …… // 调用filedup对文件句柄的引用计数+1
  filedup(f);
  return fd;
}

int sys_read(void)
{
  …… // 读取文件数据
  return fileread(f, p, n);
}

int sys_write(void)
{
  …… // 向文件写数据
  return filewrite(f, p, n);
}

int sys_close(void)
{
  …… // 释放文件句柄资源
  fileclose(f);
  return 0;
}

int sys_fstat(void)
{
  …… // 修改文件统计信息
  return filestat(f, st);
}

// Create the path new as a link to the same inode as old.
int sys_link(void)
{
  …… // 为已有的inode创建一个新名字
}

//PAGEBREAK!
int sys_unlink(void)
{
  …… // 解除inode中的某个名字, 若名字全被移除, inode回被释放
}

static struct inode* create(char *path, short type, 
        short major, short minor)
{
  …… // 
}

int sys_mkdir(void)
{
  …… // 创建一个目录
}

int sys_mknod(void)
{
  …… // 创建一个新文件
}

int sys_chdir(void)
{
  …… // 切换目录
}

int sys_pipe(void)
{
  …… // 创建一个管道文件
}

10.exec.c:唯一の本質的にEXECインターフェース、ELF着信実行ファイルフォーマット、メモリにロードされ、メモリページを割り当て、ARGVパラメータを運ぶために使用されるポインタの配列です。

int exec(char *path, char **argv)
{
  …… // 判断文件是否存在
  if((ip = namei(path)) == 0)
    return -1;
  ilock(ip);
  pgdir = 0;

  // Check ELF header  检查elf头是否合法
  if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
    goto bad;
  ……
  
  // Load program into memory.
  sz = 0;
  for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
    if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))
      goto bad;
    if(ph.type != ELF_PROG_LOAD)
      continue;
    if(ph.memsz < ph.filesz)
      goto bad;
    if((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0)
      goto bad;
    if(loaduvm(pgdir, (char*)ph.vaddr, ip, ph.off, ph.filesz) < 0)
      goto bad;
  }
  iunlockput(ip);
  ip = 0;

  // Allocate two pages at the next page boundary.
  // Make the first inaccessible.  Use the second as the user stack.
  sz = PGROUNDUP(sz);
  if((sz = allocuvm(pgdir, sz, sz + 2*PGSIZE)) == 0)
    goto bad;
  clearpteu(pgdir, (char*)(sz - 2*PGSIZE));
  sp = sz;

  // Push argument strings, prepare rest of stack in ustack.
  for(argc = 0; argv[argc]; argc++) {
    if(argc >= MAXARG)
      goto bad;
    sp = (sp - (strlen(argv[argc]) + 1)) & ~3;
    if(copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
      goto bad;
    ustack[3+argc] = sp;
  }
  ……

 bad:
  if(pgdir)
    freevm(pgdir);
  if(ip)
    iunlockput(ip);
  return -1;
}

読書とExercise2問題

1. UNIXファイル・システムの主要なコンポーネントを理解するには、次のスーパーブロック(スーパーブロック)、ノードi(iノード)、データブロック(データブロック)、ディレクトリブロック(directoryblock)、間接ブロック(indirectionblock)。それぞれ、自分の役割を説明。

ブート スーパーブロック dinode 無料のビットマップ・ブロック データ・ブロック ブロックを記録
ブロック0 まずブロック superblock.ninodesブロック ビットマップは、空きブロックを管理します superblock.nblocks块 superblock.nlog块
  • ブートローダのブート(ブロック0):ブートプログラムを格納するために使用される、システムはここから始まります。
  • このようなファイル・システム、データKuaikuaiの数、I、ログ;:スーパーブロックのスーパーブロック(ブロック1)ノードとファイルシステムブロックレコードのメタ情報内のブロックの総数
  • ノードi(iノード):iはノードIの複数を記憶する各可能な、二つのストレージノードから開始。
  • 管理領域空きブロックビットマップ:システムはどこのブロックが割り当てられていないブロックが出て配分されているファイルシステム、知っておく必要があるため、フリーブロックビットマップを保存します。
  • データブロック(データブロック):データブロックは、コンテンツファイルに格納し、真されます。
  • ディレクトリブロック(directoryblock):ファイルシステム内のファイルと同様に、ディレクトリに加えて、ディレクトリがファイル・ディレクトリ(番号で構成さFCB)自体で、ディスクに保存されているディレクトリのファイルは、ファイルの形式にする必要があり、ファイルがディスク上に保存されていますディレクトリ・ファイルと呼ばれる、ディレクトリのファイルは、ディレクトリ・ブロックに格納されています。
  • 間接ブロック(indirectionblock):xv6は、本明細書にファイルシステムのディスク入出力操作を実行する中間層であるログブロックを、ログ意味するものは、主な目的は、ファイルシステムの一貫性を維持することです。

2.ファイルを読むide.c. これは、その内容の概要については、簡単なプログラムのIDEハードドライブです。

  • 次のようにxv6ファイルシステムは、下から上へ、6層に実装します。
システムコール ファイル記述子
パス名 再帰検索
ディレクトリ ディレクトリiノード
ファイル iノードとブロックアロケータ
取引 ロギング
ブロック バッファ・キャッシュ
  • 一つのプロセスがカーネル・ディスク・ブロックを修正することができることを確実にするために、ディスクへの同期アクセスであるブロックバッファバッファキャッシュ書き込みIDEハードディスク、によってボトム。
  • 上位インタフェースは、これらの操作がアトミックである(または適用されていることを保証するためにセッションを介して、セッションがディスクパッケージを更新するようにロギンスは、ファイルシステムの一貫性を達成するために、上部層にサービスを提供する第二の層または適用されません)。
  • 第3の層は、名前ドキュメント、このような各文書ノードiとデータブロックの系列を提供します。
  • 第四層は、特別なディレクトリiノードとして実装され、その内容は、各ディレクトリエントリは、ファイル名と対応するノードIを含み、ディレクトリエントリのシリーズです。
  • 第5層は、この層は、再帰的に、クエリファイルパスに対応する、(例えば/usr/rtm/xv6/fs.cなど)階層パス名を提供します。
  • (などの配管、機器、文書、など)多くのUNIXリソースが大幅プログラマの作業を簡素化し、ファイル・システム・インターフェース、など抽象の最後の層。

3.ドキュメントbuf.h、bio.c.を読みます XV6は、ファイル・システムのバッファ・キャッシュ層と実装の内容を理解しています。説明バッファとダブルリンクリストのデータ構造の初期化。バッファの状態を知っています。バッファのさまざまな操作を理解します。

  • Bcacheデータ構造はbcache.lockユーザー排他的アクセスしながら、構成構造体BUFの二重連結リストを維持します。
  • まず、システムは、キャッシュを初期化するためにBINIT()を呼び出し、その後、初期化initlockのbcache.lockを呼び出し、BUFは、次いで、アレイを通してbcache.headを用いた補間によって最初のものへのリンクをループ。
  • 上側のディスクファイルシステムの読み取り、(パンを呼び出す)、そしてヒットした場合、キャッシュ内に要求されたディスクブロックするかどうかをチェックするために)(bgetを呼び出して、キャッシュが結果にヒット返します。基本となるiderw()関数のミスは、ディスクからキャッシュにこのディスクブロックをロードし、ディスクブロックを返却する場合は、
  • ディスクに上位のファイルシステムの書き込みは、ディスクに書き込まれ、キャッシュ内のデータに直接)BWRITEを(呼び出します。バッファ・キャッシュ層は、場合BWRITE(コールする)ファイル・システムの上位レイヤによって制御されるディスクに書き込まれるすべての操作に遅延書き込みを実行しようとしません。
  • 上部のファイルシステムはbrelse()を呼び出すことによって、使用されなくなっバッファを解放しないことがあります。
// buf.h
struct buf {
  int flags;
  uint dev;
  uint sector;
  struct buf *prev; // LRU cache list
  struct buf *next;
  struct buf *qnext; // disk queue
  uchar data[512];
};

// bio.c
struct {
  struct spinlock lock;
  struct buf buf[NBUF];

  // Linked list of all buffers, through prev/next.
  // head.next is most recently used.
  struct buf head;
} bcache;

void binit(void)
{
  struct buf *b;

  initlock(&bcache.lock, "bcache");

  //PAGEBREAK!  头插法,每次都是插入到bcache.head的后面
  // Create linked list of buffers
  bcache.head.prev = &bcache.head;
  bcache.head.next = &bcache.head;
  for(b = bcache.buf; b < bcache.buf+NBUF; b++){
    b->next = bcache.head.next;
    b->prev = &bcache.head;
    b->dev = -1;
    bcache.head.next->prev = b;
    bcache.head.next = b;
  }
}

// Return a B_BUSY buf with the contents of the indicated disk sector.
struct buf* bread(uint dev, uint sector)
{
  struct buf *b;
  // 优先查找缓存
  b = bget(dev, sector);
  if(!(b->flags & B_VALID))
    iderw(b);  // 命中失败时调用下一次接口真真实实读磁盘
  return b;
}

// Write b's contents to disk.  Must be B_BUSY.
void bwrite(struct buf *b)
{
  if((b->flags & B_BUSY) == 0)
    panic("bwrite");
  b->flags |= B_DIRTY;
  iderw(b); // 立即写, 未延迟写
}

; 4.ファイルlog.cを読む、XV6は、ファイルシステムおよびトランザクションログメカニズムを理解する
ログは、ディスク領域の既知の固定端が存在します。これは、一連のデータ・ブロックに続いて開始ブロックを、含まれています。ブロックは、配列の開始セクタ番号が含まれ、各データブロックをログに対応する、ブロックは、さらに、カウント開始のログ・データ・ブロックを含みます。xv6は、ログの開始ブロックの提出後に変更はなく、前に、データブロックの後にブロックカウンタがクリアされるログ・ファイル・システムにコピーされます。提出後、クリアカウント値の崩壊前に、非ゼロにつながります。

5.文書のfs.h / fs.c.を読みます ファイルシステムのXV6ハードディスクレイアウトをご覧ください。

// On-disk inode structure
struct dinode {
  short type;           // File type
  short major;          // Major device number (T_DEV only)
  short minor;          // Minor device number (T_DEV only)
  short nlink;          // Number of links to inode in file system
  uint size;            // Size of file (bytes)
  // NDIRECT = 12, 前12个为直接索引, 
  // 第13个为间接索引, 可容纳128个直接索引
  uint addrs[NDIRECT+1];   // Data block addresses  
};

6.文書のファイル.h / file.c.を読みます XV6「文書」だけでなく、文書を学び、私は、デバイス関連のデータ構造をノード。XV6は、どのようなファイルの基本的な動作を理解します。?へのファイルの最大数を開くことができ、各プロセスを支援する文書のXV6番号?

  • パイプファイル、デバイスファイルと一般的なファイルにxv6ファイル。
  • XV6は100のファイルハンドルを割り当てられている、最大100個のファイルを同時に開いてサポートしています。
  • 単一のプロセスは、16個のまでのファイルを開くことができます。
// param.h
#define NOFILE       16  // open files per process
#define NFILE       100  // open files per system

7.ドキュメントsysfile.cをお読みください。理解とファイルシステム関連のシステムは、各システムコールの役割を概説し、呼び出します。
一部を読んで、ソースコードを参照してください、私たちは完全な答えをしました。

リファレンス

[1] xv6中国の文書
[2] xv6ファイルシステムのブログパーク
[3] xv6ファイルシステムCSDN
[4] xv6ファイルシステムCSDN
[5]オペレーティングシステム-ファイルシステムのコースウェア

おすすめ

転載: www.cnblogs.com/icoty23/p/10993891.html