I was learning how to write an operating system (IX): File System

Foreword

This should be the end of this series, a complete operating system may be the most important of which is divided into several modules: process management, memory management and file system. Computer to process scheduling and allocation of resources as the basic unit; and interaction with the user, the basic unit is the file

Health Disk

File is the abstraction of raw disk

Composition disk

A disk formed by a plurality of disk series, and has been divided into a disk track, the track is sectors.

Disk access unit is a sector, a sector is 512 bytes

Use Disk

  • The CPU issues a command to the disk controller
  • The controller starts the seek, rotation and transfer
  • Finally, send an interrupt to the CPU after completion

Information is transmitted to the controller Cylinder Head Sector the like, and then waits for a reply

Disk block

Disk sector is an abstract block

Block is responsible for improving disk block, and magnetic disk drive is responsible for calculating from the cyl block, head, sec (CHS), and finally transmitted to the disk controller

磁盘访问时间 = 写入控制器时间 + 寻道时间 + 旋转时间 + 传输时间

In which the main time seek time and rotational time, so that the sector plate blocks can be abstracted into a plurality of sectors to save access time of disk access

Disk Scheduling

Since multiple processes are performed alternately, there may be multiple processes simultaneously access the same disk situation, we need a request queue to process all requests, it will involve the scheduling algorithm

FCFS scheduling

FCFS is the most fair and most intuitive algorithm, which is in accordance with the order of the queue to access the disk, but in efficiency is very low, the head will track long-range attacks in irregular

SSTF scheduling

SSTF algorithm is similar to the short operating priority algorithm, first look for a closer track, but SSTF algorithm may cause hunger, over long-distance track may have been unaddressed

SCAN scheduling

SSTF SCAN algorithm is a modified version of the algorithm, which is carried out SSTF, but not in the middle of the track reentry to find a shorter distance, thus avoiding the problem of hunger

C-SCAN schedule (elevator algorithm)

In a direction of the scanning is defined, when the last access to a certain direction of the track, the track direction of the track opposite end returns the disk, and start scanning again.

Files and file systems

The third file is the abstraction layer of the disk, and the disk sectors before the two blocks are abstract. The reason why there is file this layer of abstraction for the convenience of users, in the eyes of the user, the information on the disk can be viewed as a stream of characters. So abstract nine files can be viewed as a set of mapping between block flow plate characters

The logical structure of the document

From the document tray to the block map view, generally these types of organization

  • Sequential file

    Record length is fixed and arranged in order by key. Or can be stored in order to list the storage situation, you need to search for files in order to access. There are two sequential file structure:

    1. The first structure is a string, independent of order of the keywords between the recording. The usual approach is determined by time, i.e. the time according to the order of precedence is stored, is stored in the first record as the first record, followed by deposit of the second record, and so on.

    2. The second is a sequential structure, all records in the file means arranged in order by key.
      When recording batch operation, that every time you want to read or write a large number of records, the efficiency of the order of the files are all logical files in the highest; in addition, only on tape, and can effectively work order file to store. However, sequential file to search, modify, add or delete individual records of the operation more difficult.

  • Index file

    For variable-length records document only sequential search, a large overhead, for which you can build a table to speed up the retrieval speed index, the index table itself is a sequential file. Many high or recording file access requirements, need to be introduced to provide efficient access to the index, in practice, by an index can increase the speed of hundreds of times.

  • Index order table

    Table index order index is a combination of the two tissues and order situation. All records indexed sequential file sequential file is divided into several groups, establishing an indexed sequential file table, build an index entry for each group of the first record in the index table, which contains the record key value and a pointer to the record.

In the actual operating system implementation, generally multi-level index

Directories and file systems

File system disk or directory is the fourth abstract, that is, abstract entire disk

In order to realize the operating system file directory, it referred to the introduction of the file control block data structure.

File control block.

File control block (the FCB) data structure is used to store various types of information required for the control file, in order to achieve "access by name." FCB ordered set is called a file directory, a FCB is a file directory entry. To create a new file, the system will assign a FCB and stored in files in a directory called directory entry.

FCB mainly contains the following information:

  1. Basic information, such as file name, the physical location of the file, the logical structure of the file, the physical structure of the file and the like.
  2. Access control information, such as access to files and the like.
  3. Use of information, such as file creation time, modification time and so on.

File directory tree

In general multi-level directory of the disk can be abstracted as

  • FCB array

    FCB FCB is to array the disc information of all blocks are concentrated into an array

  • Data disk block set

    在每个数据盘块里都包含一些目录项用来找到子目录,目录项也就是文件名+对应的FCB的“地址”,也就是去之前的FCB数组中找到相应的FCB

在磁盘进行格式化的时候,会存放一些信息用来知道一些磁盘信息和找到根目录

fx.png

  • inode位图: 哪些inode空闲,哪些被占用

  • 超级块:记录两个位图有多大等信息

  • 盘块位图: 哪些盘块是空闲的,硬盘大小不同这个位图的大小也不同

文件的实现

在我之前实现的FragileOS里文件系统非常简陋,基本没有什么好说的。这其实也是为什么之前把这个系列改了一个方向来结合的看Linux0.11的代码。所以来看一下Linux0.11里是怎么使用和实现文件系统的,

读取文件

  • 这是读取文件的系统调用
  • 函数首先对参数有效性进行判断
  • 之后对文件的类型进行判断
  • 如果是目录文件或者是常规文件就执行读取操作
int sys_read(unsigned int fd,char * buf,int count)
{
    struct file * file;
    struct m_inode * inode;

    if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd]))
        return -EINVAL;
    if (!count)
        return 0;
    verify_area(buf,count);
    inode = file->f_inode;
    if (inode->i_pipe)
        return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO;
    if (S_ISCHR(inode->i_mode))
        return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
    if (S_ISBLK(inode->i_mode))
        return block_read(inode->i_zone[0],&file->f_pos,buf,count);
    if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
        if (count+file->f_pos > inode->i_size)
            count = inode->i_size - file->f_pos;
        if (count<=0)
            return 0;
        return file_read(inode,file,buf,count);
    }
    printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
    return -EINVAL;
}
  • 根据i节点和文件结构,读取文件中数据。
  • 首先判断参数的有效性
  • 之后循环的调用bread来读取数据
  • 之后复制chars字节到用户缓冲区buf中
  • 最后是修改该i节点的访问时间为当前时间和返回读取的字节数
int file_read(struct m_inode * inode, struct file * filp, char * buf, int count)
{
    int left,chars,nr;
    struct buffer_head * bh;

    if ((left=count)<=0)
        return 0;
    while (left) {
        if ((nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE))) {
            if (!(bh=bread(inode->i_dev,nr)))
                break;
        } else
            bh = NULL;
        nr = filp->f_pos % BLOCK_SIZE;
        chars = MIN( BLOCK_SIZE-nr , left );
        filp->f_pos += chars;
        left -= chars;
        if (bh) {
            char * p = nr + bh->b_data;
            while (chars-->0)
                put_fs_byte(*(p++),buf++);
            brelse(bh);
        } else {
            while (chars-->0)
                put_fs_byte(0,buf++);
        }
    }
    inode->i_atime = CURRENT_TIME;
    return (count-left)?(count-left):-ERROR;
}

文件写入

  • 根据i节点和文件结构信息,将用户数据写入文件中
  • 首先确定数据写入文件的位置
  • 然后算出对应的盘块
  • 然后用户缓冲区buf中复制c个字节到告诉缓冲块中p指向的开始位置处
  • 最后是修改该i节点的访问时间为当前时间和返回读取的字节数
int file_write(struct m_inode * inode, struct file * filp, char * buf, int count)
{
    off_t pos;
    int block,c;
    struct buffer_head * bh;
    char * p;
    int i=0;

/*
 * ok, append may not work when many processes are writing at the same time
 * but so what. That way leads to madness anyway.
 */
    if (filp->f_flags & O_APPEND)
        pos = inode->i_size;
    else
        pos = filp->f_pos;
    while (i<count) {
        if (!(block = create_block(inode,pos/BLOCK_SIZE)))
            break;
        if (!(bh=bread(inode->i_dev,block)))
            break;
        c = pos % BLOCK_SIZE;
        p = c + bh->b_data;
        bh->b_dirt = 1;
        c = BLOCK_SIZE-c;
        if (c > count-i) c = count-i;
        pos += c;
        if (pos > inode->i_size) {
            inode->i_size = pos;
            inode->i_dirt = 1;
        }
        i += c;
        while (c-->0)
            *(p++) = get_fs_byte(buf++);
        brelse(bh);
    }
    inode->i_mtime = CURRENT_TIME;
    if (!(filp->f_flags & O_APPEND)) {
        filp->f_pos = pos;
        inode->i_ctime = CURRENT_TIME;
    }
    return (i?i:-1);
}

文件目录的实现

打开创建文件

  • 首先对参数进行处理,然后搜索进程结构中文件结构指针数组一个空闲的文件句柄
  • 接着为打开文件在文件表中寻找一个空闲结构项
  • 然后调用函数open_namei()执行打开操作,若返回值小于0,则说明出错,就释放刚申请到的文件结构
  • 然后为不同的文件类型做一些特殊的处理
  • 最后初始化打开文件的文件结构,然后返回文件句柄
int sys_open(const char * filename,int flag,int mode)
{
    struct m_inode * inode;
    struct file * f;
    int i,fd;

    mode &= 0777 & ~current->umask;
    for(fd=0 ; fd<NR_OPEN ; fd++)
        if (!current->filp[fd])
            break;
    if (fd>=NR_OPEN)
        return -EINVAL;
    current->close_on_exec &= ~(1<<fd);
    f=0+file_table;
    for (i=0 ; i<NR_FILE ; i++,f++)
        if (!f->f_count) break;
    if (i>=NR_FILE)
        return -EINVAL;
    (current->filp[fd]=f)->f_count++;
    if ((i=open_namei(filename,flag,mode,&inode))<0) {
        current->filp[fd]=NULL;
        f->f_count=0;
        return i;
    }
/* ttys are somewhat special (ttyxx major==4, tty major==5) */
    if (S_ISCHR(inode->i_mode)) {
        if (MAJOR(inode->i_zone[0])==4) {
            if (current->leader && current->tty<0) {
                current->tty = MINOR(inode->i_zone[0]);
                tty_table[current->tty].pgrp = current->pgrp;
            }
        } else if (MAJOR(inode->i_zone[0])==5)
            if (current->tty<0) {
                iput(inode);
                current->filp[fd]=NULL;
                f->f_count=0;
                return -EPERM;
            }
    }
/* Likewise with block-devices: check for floppy_change */
    if (S_ISBLK(inode->i_mode))
        check_disk_change(inode->i_zone[0]);
    f->f_mode = inode->i_mode;
    f->f_flags = flag;
    f->f_count = 1;
    f->f_inode = inode;
    f->f_pos = 0;
    return (fd);
}

解析目录

  • 先根据当前路径的第一个字符来判断当前路径是绝对路径还是相对路径
  • 然后进循环处理过程,分割每个目录名
  • 得到这个目录名后,调用查找目录项函数find_entry()在当前处理的目录中寻找指定名称的目录
  • 如果找到这个目录,就设置一些信息,然后继续以该目录项为当前目录继续循环处理路径名中的下一目录名部分(或文件名)
static struct m_inode * get_dir(const char * pathname)
{
    char c;
    const char * thisname;
    struct m_inode * inode;
    struct buffer_head * bh;
    int namelen,inr,idev;
    struct dir_entry * de;

    if (!current->root || !current->root->i_count)
        panic("No root inode");
    if (!current->pwd || !current->pwd->i_count)
        panic("No cwd inode");
    if ((c=get_fs_byte(pathname))=='/') {
        inode = current->root;
        pathname++;
    } else if (c)
        inode = current->pwd;
    else
        return NULL;    /* empty name is bad */
    inode->i_count++;
    while (1) {
        thisname = pathname;
        if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
            iput(inode);
            return NULL;
        }
        for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
            /* nothing */ ;
        if (!c)
            return inode;
        if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
            iput(inode);
            return NULL;
        }
        inr = de->inode;
        idev = inode->i_dev;
        brelse(bh);
        iput(inode);
        if (!(inode = iget(idev,inr)))
            return NULL;
    }
}

Guess you like

Origin www.cnblogs.com/secoding/p/11442659.html