专栏首页原创分享文件系统之file结构体管理源码分析(基于linux1.2.13)

文件系统之file结构体管理源码分析(基于linux1.2.13)

操作系统为进程维护了打开的文件列表,每个进程维护了一个file数组字段(struct file * fd[NR_OPEN]);每个元素指向一个file结构体。每个file结构体有一个字段指向inode结构体,inode管理这个文件的内容、权限等信息。这里分析的是file结构体的管理。

下面是file结构体的定义

struct file {
  mode_t f_mode;
  loff_t f_pos;
  unsigned short f_flags;
  unsigned short f_count;
  off_t f_reada;
  struct file *f_next, *f_prev;
  int f_owner;    /* pid or -pgrp where SIGIO should be sent */
  struct inode * f_inode;
  struct file_operations * f_op;
  unsigned long f_version;
  void *private_data;  /* needed for tty driver, and maybe others */
};

下面是对file结构体的管理,当进程打开一个文件的时候,就可能需要从中申请一个file结构体。

/*
 *  linux/fs/file_table.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mm.h>

struct file * first_file;
int nr_files = 0;

// 双向循环链表,first_file指向头指针,头插法插入一个节点
static void insert_file_free(struct file *file)
{
  file->f_next = first_file;
  file->f_prev = first_file->f_prev;
  file->f_next->f_prev = file;
  file->f_prev->f_next = file;
  first_file = file;
}
// 删除一个节点
static void remove_file_free(struct file *file)
{  
  // 如果要删除的节点是第一个节点,则更新头指针,指向下一个节点
  if (first_file == file)
    first_file = first_file->f_next;
  // 如果被删除的节点后面还有节点,则需要更新下一个节点的prev指针,指向当前节点的上一个节点
  if (file->f_next)
    file->f_next->f_prev = file->f_prev;
  // 同理,更新上一个节点的next指针,指向被删除节点的下一个节点
  if (file->f_prev)
    file->f_prev->f_next = file->f_next;
  // 置空
  file->f_next = file->f_prev = NULL;
}

// file插入链表,成为最后一个节点
static void put_last_free(struct file *file)
{  
  // 保证file脱离了原来的链表
  remove_file_free(file);
  // 插入链表,但是不更新头指针first_file,所以file成为最后一个节点
  file->f_prev = first_file->f_prev;
  file->f_prev->f_next = file;
  file->f_next = first_file;
  file->f_next->f_prev = file;
}

void grow_files(void)
{
  struct file * file;
  int i;
  // 申请一页内存
  file = (struct file *) get_free_page(GFP_KERNEL);

  if (!file)
    return;
  // i=PAGE_SIZE/sizeof(struct file),即一页可以存多少个节点,更新最大节点数
  nr_files+=i= PAGE_SIZE/sizeof(struct file);
  /*
   当前是初始化的时候,先初始化一个节点,需要初始化的节点数减一,执行insert_file_free
   前需要保证first_file非空,见insert_file_free中的first_file
  */
  if (!first_file)
    file->f_next = file->f_prev = first_file = file++, i--;
  // 形成一个链表
  for (; i ; i--)
    insert_file_free(file++);
}
// file链表初始化
unsigned long file_table_init(unsigned long start, unsigned long end)
{
  first_file = NULL;
  return start;
}

// 获取一个可以的file结构体
struct file * get_empty_filp(void)
{
  int i;
  struct file * f;

  if (!first_file)
    grow_files();
repeat:
  // nr_files是链表的总节点数
  for (f = first_file, i=0; i < nr_files; i++, f = f->f_next)
    // 找到空闲的节点
    if (!f->f_count) {
      // 脱离链表
      remove_file_free(f);
      // 清空内存
      memset(f,0,sizeof(*f));
      // 插入链表末尾
      put_last_free(f);
      // 标记已使用
      f->f_count = 1;
      f->f_version = ++event;
      return f;
    }
  // 没有找到空闲节点,扩容,再找
  if (nr_files < NR_FILE) {
    grow_files();
    goto repeat;
  }
  return NULL;
}
  

从图中我们可以看出,系统维护了一个双向循环的链表,保存了一系列已使用和未使用的file结构体。first_file指针执行第一个空闲的节点,进程申请file结构体的时候就把该节点放到链表结尾。first_file指针指向下一个空闲节点。如果没有空闲节点了,就会自动扩容。

本文分享自微信公众号 - 编程杂技(theanarkh),作者:theanarkh

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 深入理解TCP/IP协议的实现之connect(基于linux1.2.13)

    分析完了服务器端,我们继续分析客户端,在socket编程中,客户端的流程是比较简单的,申请一个socket,然后调connect去发起连接就行。我们先看一下co...

    theanarkh
  • redis0.1源码解析之基本原理

    本文分析redis的基础原理,暂不做深入分析,后续再详细分析。我们从main函数开始。

    theanarkh
  • js中的变量声明问题

    从1,,2中我们可以看出js引擎是先对var声明的变量进行注册,再对函数类型的变量进行注册。 而3和4是一样的原理,js引擎执行到这段代码时,首先注册var a...

    theanarkh
  • Cocos Creator开发hello World

    若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。

    达达前端
  • uni app 零基础小白到项目实战

    若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。

    达达前端
  • 前端零基础入门:页面结构层HTML(2)

    达达前端
  • Cocos CreatorUI系统上

    若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。

    达达前端
  • Cocos Creator打包发布

    若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。

    达达前端
  • python3第七天(输入和输出)

    输出值的方式:1,表达式。2,print()函数。3,文件对象的write()函数

    py3study
  • Cocos CreatorUI系统下

    若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。

    达达前端

扫码关注云+社区

领取腾讯云代金券