文件系统之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指针指向下一个空闲节点。如果没有空闲节点了,就会自动扩容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值