前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入浅出文件系统原理之基础数据结构(基于linux0.11)

深入浅出文件系统原理之基础数据结构(基于linux0.11)

作者头像
theanarkh
发布2019-07-30 18:50:58
8050
发布2019-07-30 18:50:58
举报
文章被收录于专栏:原创分享

想写一个系列的文章,逐步介绍文件系统的实现原理。采用的是linux0.11版本。这是第一篇文章。首先介绍一下文件系统的基础数据结构。这是后面的基础,需要先熟悉。所谓数据结构决定算法。

下面是文件系统在硬盘的结构图。

代码语言:javascript
复制
/*
 * This file has definitions for some important file table
 * structures etc.
 */

#ifndef _FS_H
#define _FS_H

#include <sys/types.h>

/* devices are as follows: (same as minix, so we can use the minix
 * file system. These are major numbers.)
 *
 * 0 - unused (nodev)
 * 1 - /dev/mem
 * 2 - /dev/fd
 * 3 - /dev/hd
 * 4 - /dev/ttyx
 * 5 - /dev/tty
 * 6 - /dev/lp
 * 7 - unnamed pipes
 */

#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3)

#define READ 0
#define WRITE 1
#define READA 2    /* read-ahead - don't pause */
#define WRITEA 3  /* "write-ahead" - silly, but somewhat useful */

void buffer_init(long buffer_end);
// 设备的主设备号和次设备号,低八位是次设备号,高位是主设备号
#define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff)
// 文件名长度
#define NAME_LEN 14
// 文件系统的根inode节点号
#define ROOT_INO 1
// 块位图和inode位图占据的最大硬盘块数
#define I_MAP_SLOTS 8
#define Z_MAP_SLOTS 8
// 超级块的魔数,说明是有效的超级块
#define SUPER_MAGIC 0x137F
// 一个进程打开文件数的大小
#define NR_OPEN 20
// 系统同时打开的inode数大小,即同时只能打开32个文件
#define NR_INODE 32
// file结构体数,进程间共享的
#define NR_FILE 64
// 超级块数,即文件系统的个数
#define NR_SUPER 8
#define NR_HASH 307
// 缓存文件系统数据的buffer个数,操作系统启动的时候初始化该变量
#define NR_BUFFERS nr_buffers
// 硬盘一块对应的字节数
#define BLOCK_SIZE 1024
// 2 >> 10 即块的大小,用于计算字节数到块数
#define BLOCK_SIZE_BITS 10
#ifndef NULL
#define NULL ((void *) 0)
#endif
// 每个硬盘块有几个inode节点,即块大小除以硬盘中每个inode结构的大小,硬盘里是d_inode,内存是m_inode结构
#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode)))
// 每个硬盘块包含的目录项数
#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry)))

// 下面宏用于匿名管道,可结合管道的实现理解
#define PIPE_HEAD(inode) ((inode).i_zone[0])
#define PIPE_TAIL(inode) ((inode).i_zone[1])
#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1))
#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode))
#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1))
#define INC_PIPE(head) \
__asm__("incl %0\n\tandl $4095,%0"::"m" (head))
// 该版本没有用这个定义
typedef char buffer_block[BLOCK_SIZE];
// 管理文件系统的数据缓存的结构
struct buffer_head {
  char * b_data;      /* pointer to data block (1024 bytes) */
  unsigned long b_blocknr;  /* block number */
  unsigned short b_dev;    /* device (0 = free) */
  unsigned char b_uptodate;
  unsigned char b_dirt;    /* 0-clean,1-dirty */
  unsigned char b_count;    /* users using this block */
  unsigned char b_lock;    /* 0 - ok, 1 -locked */
  struct task_struct * b_wait;
  struct buffer_head * b_prev;
  struct buffer_head * b_next;
  struct buffer_head * b_prev_free;
  struct buffer_head * b_next_free;
};
// 文件系统在硬盘里的inode节点结构
struct d_inode {
  // 各种标记位,读写执行等,我们ls时看到的
  unsigned short i_mode;
  // 文件的用户id
  unsigned short i_uid;
  // 文件大小
  unsigned long i_size;
  unsigned long i_time;
  // 文件的用户组id
  unsigned char i_gid;
  // 文件入度,即有多少个目录指向他
  unsigned char i_nlinks;
  // 存储文件内容对应的硬盘块号
  unsigned short i_zone[9];
};
// 内存中的inode节点结构
struct m_inode {
  // 和d_inode一样
  unsigned short i_mode;
  unsigned short i_uid;
  unsigned long i_size;
  unsigned long i_mtime;
  unsigned char i_gid;
  unsigned char i_nlinks;
  unsigned short i_zone[9];
/* these are in memory also */
  // 在内存中使用的字段
  // 等待该inode节点的进程队列
  struct task_struct * i_wait;
  // access time文件被访问就会修改这个字段
  unsigned long i_atime;
  /*
    change time,修改文件内容和属性就会修改这个字段,
    还有一个是mtime,修改文件内容就会修改这个字段,但是这个版本没有实现
  */
  unsigned long i_ctime;
  // inode所属的设备号
  unsigned short i_dev;
  // 该结构引用的inode在硬盘里的号
  unsigned short i_num;
  // 多少个进程在使用这个inode
  unsigned short i_count;
  // 互斥锁
  unsigned char i_lock;
  // inode内容是否被修改过
  unsigned char i_dirt;
  // 是不是管道文件
  unsigned char i_pipe;
  // 该节点是否挂载了另外的文件系统
  unsigned char i_mount;
  // 这个版本没用到
  unsigned char i_seek;
  /*
    数据是否是最新的,或者说有效的,
    update代表数据的有效性,dirt代表文件是否需要回写,
    比如写入文件的时候,a进程写入的时候,dirt是1,因为需要回写到硬盘,
    但是数据是最新的,update是1,这时候b进程读取这个文件的时候,可以从
    缓存里直接读取。
  */
  unsigned char i_update;
};
// 管理打开文件的内存属性的结构,比如操作位置(inode没有读取操作位置这个概念,),实现系统进程共享inode
struct file {
  unsigned short f_mode;
  unsigned short f_flags;
  unsigned short f_count;
  struct m_inode * f_inode;
  off_t f_pos;
};
// 超级块,管理一个文件系统元数据的结构
struct super_block {
  // inode节点个数
  unsigned short s_ninodes;
  // 文件系统占据的硬盘总块数
  unsigned short s_nzones;
  // inode和数据块位图占据的硬盘块数,位图是记录哪个块或者inode节点被使用了
  unsigned short s_imap_blocks;
  unsigned short s_zmap_blocks;
  /*
    第一块在硬盘的块号,一个硬盘可以有几个文件系统,
    每个文件系统占据一部分,所以要记录开始的块号和总块数
  */
  unsigned short s_firstdatazone;
  /*
    用于计算文件系统块等于多少个硬盘块,硬盘块大小乘以2
    的s_log_zone_size次方等于文件系统的块大小(硬盘块的
    大小和文件系统块的大小不是一回事,比如硬盘块的大小是1kb,
    文件系统是4kb)
  */ 
  unsigned short s_log_zone_size;
  // 文件名最大字节数 
  unsigned long s_max_size;
  // 魔数
  unsigned short s_magic;
/* These are only in memory */
  // 缓存inode位图的内容
  struct buffer_head * s_imap[8];
  // 缓存数据块位图的内容
  struct  buffer_head * s_zmap[8];
  // 设备号
  unsigned short s_dev;
  // 挂载在哪个文件的inode下
  struct m_inode * s_isup;
  struct m_inode * s_imount;
  unsigned long s_time;
  // 等待使用该超级块的进程队列
  struct task_struct * s_wait;
  // 互斥访问变量
  unsigned char s_lock;
  // 文件系统是否只能读不能写
  unsigned char s_rd_only;
  // 是否需要回写到硬盘
  unsigned char s_dirt;
};
// 超级块在硬盘的结构
struct d_super_block {
  // inode节点数量
  unsigned short s_ninodes;
  // 硬盘块数量
  unsigned short s_nzones;
  // inode位图块数量
  unsigned short s_imap_blocks;
  // 数据块位图数量
  unsigned short s_zmap_blocks;
  // 文件系统的第一块块号,不是数据块第一块块号
  unsigned short s_firstdatazone;
  // 参考上面
  unsigned short s_log_zone_size;
  // 最大文件长度
  unsigned long s_max_size;
  // 判断是否是超级块的标记
  unsigned short s_magic;
};
// 目录项结构
struct dir_entry {
  // inode号
  unsigned short inode;
  // 文件名
  char name[NAME_LEN];
};
// 进程共享的inode列表
extern struct m_inode inode_table[NR_INODE];
// 进程共享的file结构列表
extern struct file file_table[NR_FILE];
// 超级块列表
extern struct super_block super_block[NR_SUPER];
// 缓存区管理
extern struct buffer_head * start_buffer;
// 缓冲区个数
extern int nr_buffers;

下面是进程和文件系统的关系图。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程杂技 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档