打开文件:内核做了什么?

2023年 9月 22日 79.1k 0

一.文件描述符本质

文件描述符的是一个非负整数,它是操作系统内核用来标识和管理打开文件的抽象概念。在 Linux 和其他类 Unix 操作系统中,几乎所有与文件相关的操作都是通过文件描述符来进行的。

文件描述符是操作系统内核为每个进程维护的一个表,用于记录和跟踪进程打开的文件。当进程打开一个文件时,内核会分配一个未使用的文件描述符,并将其返回给进程。通常,文件描述符是一个非负整数,其中0、1、2分别是预留给标准输入、标准输出和标准错误的特殊文件描述符。

实际上,文件描述符并不直接表示文件本身,而是一个索引或句柄,用于查找与该文件相关的内核数据结构,如文件结构体(File Structure)。通过文件描述符,进程可以与内核交互,并访问和操作打开的文件。文件描述符允许进程进行文件的读取、写入、关闭等操作,以及其他文件相关的系统调用。

因此,文件描述符可以看作是进程与文件之间的一种间接关联,它提供了一种标识和访问打开文件的方式。它的本质是一个非负整数,由操作系统内核分配和管理,使得进程能够安全地操作文件资源。文件描述符是一个结构体数组的下标。

二.task_struct

struct task_struct 是在 Linux 内核中表示进程的主要数据结构之一。每个运行的进程都有一个对应的 task_struct 结构体。

task_struct 结构体中包含了大量的成员变量,用于记录和管理进程的各种属性和状态。其中一些重要的成员变量包括:

  • pid:进程的唯一标识符(Process ID)。
  • ppid:父进程的进程 ID。
  • state:进程的运行状态,如运行、等待、停止等。
  • mm:进程的内存管理相关信息,包括内存映射、页表等。
  • files:与进程关联的文件描述符表。
  • signal:信号相关的信息,包括信号处理函数和信号屏蔽字。
  • cpu:进程当前所在的 CPU。
  • sched_info:调度相关的信息,用于进程的调度和时间片管理。
  • parent:指向父进程的指针。
  • children:指向子进程的链表。

通过 task_struct,内核能够追踪和管理每个进程的状态和属性,并进行调度、资源管理等操作。它是内核进行进程调度、进程间通信、资源管理等功能的关键数据结构。

需要注意的是,Linux 内核中的进程调度单位是线程(Thread),而一个进程可以包含多个线程。每个线程都有对应的 task_struct 结构体,用于描述线程的属性和状态。因此,task_struct 与进程的关系是,每个运行的线程都有一个对应的 task_struct 结构体,而一个进程可以包含多个线程的 task_struct

总结起来,task_struct 是 Linux 内核中用于描述线程(Thread)的数据结构,包含了线程的属性和状态信息。它在内核中用于管理和调度线程,并与进程相关联,一个进程可以包含多个线程的 task_struct

事实上Linux中本质上没有进程,进程和线程都是通过 task_struct管理状态和属性。本质上没有线程,Linux中线程是一种轻量级的进程

四.files成员

filestask_struct 结构体中的一个成员变量,用于表示与进程相关联的文件描述符表。

文件描述符表是进程在运行过程中打开的文件的记录表。每个进程都有自己的文件描述符表,通过文件描述符表,进程可以访问和操作打开的文件。

files 成员变量的类型是 struct files_struct,它包含一个指向文件描述符表的指针。struct files_struct 结构体还包含了与文件描述符表相关的信息,例如文件描述符的数量、指向文件描述符数组的指针等。

文件描述符表是一个数组,数组中的每个元素是一个 struct file 结构体,用于描述一个打开的文件。每个文件描述符都与一个打开的文件相关联,包括文件的打开模式、文件的位置偏移、访问权限等信息。

通过文件描述符,进程可以进行文件的读取、写入、定位、关闭等操作。通过文件描述符表,进程可以实现文件的共享、管理和资源控制。

总结起来,filestask_struct 结构体中的一个成员变量,用于表示与进程相关联的文件描述符表。文件描述符表是一个数组,每个元素是一个 struct file 结构体,用于描述一个打开的文件。通过文件描述符和文件描述符表,进程可以访问和操作打开的文件。

struct files_struct

files_struct 是 Linux 内核中与进程相关联的文件描述符表的数据结构。

在 Linux 内核中,每个进程都有一个与之关联的 files_struct 结构体,用于管理和跟踪进程打开的文件。

files_struct 结构体包含了多个成员变量,其中一些重要的成员变量包括:

  • count:文件描述符表中已打开文件的数量。
  • fdt:指向文件描述符表数组的指针。
  • max_fds:文件描述符表数组的大小(在内核中的上限)。

文件描述符表是一个由 struct file 结构体组成的数组,每个元素表示一个打开的文件。struct file 结构体包含了与打开文件相关的信息,包括文件的打开模式、位置偏移、文件状态等。

count 用于记录当前进程打开的文件数量,fdt 是一个指向文件描述符表数组的指针,通过它可以访问和操作每个打开的文件。

max_fds 表示文件描述符表数组的大小。在一个进程中,文件描述符的数量不能超过 max_fds 的值,否则无法打开更多的文件。

通过文件描述符表,进程可以实现对打开的文件进行操作,包括读取、写入、定位、关闭等。每个文件都与一个文件描述符相关联,进程可以通过文件描述符来访问和操作对应的文件。

files_struct 结构体是进程在内核中进行文件管理的重要数据结构,它提供了接口和方法,使得进程能够访问和操作其打开的文件。内核通过 files_struct 来追踪进程的文件状态,包括文件打开和关闭的操作。

总结一下,files_struct 是 Linux 内核中与进程相关联的文件描述符表的数据结构。它包含了当前进程打开的文件的相关信息,提供了接口和方法,使得进程能够对打开的文件进行读写和管理。

五.fdt成员

fdtfiles_struct 结构体中的一个成员变量,它指向文件描述符表数组,用于管理和跟踪进程打开的文件。

文件描述符表是一个由 struct file 结构体组成的数组,它记录了进程打开的文件的相关信息。每个元素(struct file 结构体)表示一个打开的文件,包括文件的打开模式、位置偏移、文件状态等。

fdt 是一个指向文件描述符表数组的指针。通过它,可以访问和操作每个打开的文件。例如,可以通过文件描述符来读取、写入、定位和关闭文件。

files_struct 结构体中,fdt 变量的类型是 struct fdtable *,它是一个指向 fdtable 结构体的指针。fdtable 结构体包含了与文件描述符表相关的信息,包括文件描述符的数量、指向文件描述符数组的指针等。

通过 fdtfdtable 结构体,内核可以实现对进程打开的文件的管理和操作。它提供了接口和方法,使得进程能够访问和操作打开的文件。

总结一下,fdtfiles_struct 结构体中的一个成员变量,它是一个指向文件描述符表数组的指针。文件描述符表是一个由 struct file 结构体组成的数组,用于记录进程打开的文件的相关信息。通过 fdt 和文件描述符表,进程可以实现对打开的文件的读写、定位和关闭等操作。

六.文件描述符表

在 Linux 操作系统中,每个进程都有一个文件描述符表(File Descriptor Table),它是一个由文件描述符(File Descriptor)组成的数组。文件描述符表中的每个元素是一个整数,用于标识打开的文件。

具体地说,每个元素是一个索引,它指向进程的文件表(File Table)中的一个项。文件表是进程打开文件的记录,对应每个进程都有独立的文件表。

每个进程默认继承了三个标准的文件描述符:0、1、2 分别表示标准输入(stdin)、标准输出(stdout)和标准错误输出(stderr)。

除了标准文件描述符外,进程还可以通过系统调用(如 open()socket() 等)来打开其他文件,并分配一个新的文件描述符。打开文件时,操作系统会将文件描述符分配给对应的打开文件,并将其记录在进程的文件描述符表中。

文件描述符表中的每个元素只存储一个整数值,用于索引对应的文件表项。文件表项是一个数据结构,记录了打开文件的详细信息,包括文件偏移、文件指针、访问权限等。

通过文件描述符,进程可以对打开的文件进行读取、写入、定位和关闭等操作。进程可以使用系统调用(如 read()write()lseek()close() 等)来直接使用文件描述符进行操作。

需要注意的是,不同进程的文件描述符表是独立的,互不影响。文件描述符在进程间是不共享的,每个进程都有自己独立的文件描述符表和文件表。

总结一下,文件描述符表是每个进程独立维护的,它是一个由文件描述符组成的数组。每个文件描述符表示一个打开的文件,在文件描述符表中存储着对应打开文件的索引。文件描述符表通过索引与进程的文件表关联,文件表中记录了打开文件的详细信息。进程可以使用文件描述符来对打开的文件进行读取、写入、定位和关闭等操作。不同进程的文件描述符表是独立的,互不影响。

struct file

在详细介绍文件描述符表中每个元素的内容之前,我想先澄清一下,文件描述符表中的每个元素本身并不包含文件的详细内容,而是用来标识和管理打开的文件。文件的具体内容和属性是由相应文件表中的条目来记录和维护的。

在 Linux 中,文件描述符表中的每个元素通常是一个指向 struct file 结构体的指针(在内核中的定义为 struct file *),这个结构体用于记录与打开文件相关的信息。下面是 struct file 结构体的一些核心成员:

  • unsigned int f_flags:记录文件的打开标志,例如读写、追加、同步等操作。

  • loff_t f_pos:维护文件的当前读写位置,表示下一次读写操作将从文件的哪个位置开始。

  • const struct file_operations *f_op:指向与文件相关的操作函数的指针,比如读取、写入、定位等函数。

  • struct path f_path:用于存储文件的路径信息,包括文件名、目录等。

  • struct inode *f_inode:指向文件的索引节点(inode),索引节点保存了文件的元数据,如文件大小、权限等。

  • unsigned int f_mode:记录文件的模式,表示文件的类型和访问权限。

  • 除了上述核心成员外,struct file 结构体还可以包含其他用于特定类型文件的成员变量,例如网络套接字文件等。

    文件描述符表中的每个元素是由系统调用(如 open()socket() 等)所创建的打开文件对应的 struct file 结构体。进程可以通过文件描述符来访问和操作打开的文件,例如读取、写入、定位、关闭等操作。内核通过文件描述符来找到对应的 struct file 结构体,从而实现对文件的操作。

    需要注意的是,文件描述符表是每个进程独立维护的,不同进程之间的文件描述符表是相互隔离的,它们互不影响。

    综上所述,文件描述符表中的每个元素(通常是 struct file 结构体的指针)用于标识和管理打开的文件,在其中记录了与文件相关的信息,如打开标志、当前读写位置、文件路径、索引节点等。通过文件描述符表,进程可以使用文件描述符来访问和操作打开的文件。

    七.open函数本质

    file_operations 是在 Linux 内核中定义的一个结构体,它定义了一组对文件进行操作的函数指针,以实现文件的读取、写入、定位、关闭等操作。该结构体通常在文件系统的实现中使用,并由每个文件通过 struct file 结构体中的 f_op 成员引用。

    下面是 file_operations 结构体的一些常见成员函数:

  • read:用于从文件中读取数据。函数原型为 ssize_t (*read) (struct file *file, char __user *buf, size_t size, loff_t *offset)

  • write:用于向文件中写入数据。函数原型为 ssize_t (*write) (struct file *file, const char __user *buf, size_t size, loff_t *offset)

  • llseek:用于更改文件读写位置的函数。函数原型为 loff_t (*llseek) (struct file *file, loff_t offset, int whence)

  • unlocked_ioctl:用于执行特殊的设备控制操作。函数原型为 long (*unlocked_ioctl) (struct file *file, unsigned int cmd, unsigned long arg)

  • open:在打开文件时调用此函数,用于执行打开文件前的准备工作。函数原型为 int (*open) (struct inode *inode, struct file *file)

  • release:在关闭文件时调用此函数,用于执行关闭文件的清理工作。函数原型为 int (*release) (struct inode *inode, struct file *file)

  • flush:用于将缓冲区数据刷新到磁盘。函数原型为 int (*flush) (struct file *file, fl_owner_t id)

  • 除了上述成员函数外,file_operations 结构体还定义了其他一些操作文件的函数指针,如文件的 mmap(内存映射)操作、文件的 fsync(同步文件)操作等。

    当用户对已打开的文件执行读取、写入等操作时,内核会通过 struct file 结构体中的 f_op 成员来调用相应的 file_operations 结构体中的函数指针,以实现具体的文件操作。

    需要注意的是,file_operations 结构体是在文件系统的实现中定义的,每个文件系统可以根据需要定义自己的特定操作。不同文件系统的 file_operations 结构体可能会有所差异。

    综上所述,file_operations 结构体定义了一组用于文件操作的函数指针,通过这些函数指针可以实现对文件的读取、写入、定位、关闭等操作。它是 Linux 内核中文件系统实现的关键部分之一。

    总结:

    每一个进程或者说线程都由一个task_struct结构体维护,task_struct结构体有众多成员,其中有一个成员叫做filesfilesfiles_struct类型。files_struct中含有fdt成员,它是指向文件描述符表数组的指针。文件描述符表数组中仅仅是一个索引,而文件描述符就是文件描述符表的下标。通过索引可以找到文件表项。文件表项是一个数据结构,记录了打开文件的详细信息,包括文件偏移、文件指针、访问权限等。当程序调用open函数时,系统会根据文件地址,通过虚拟文件系统找到inode中的file_operation,复制到程序中的文件表项中。这样就不用通过虚拟文件系统操作要打开的文件。同时返回文件描述的符。通过文件描述符,进程可以对打开的文件进行读取、写入、定位和关闭等操作。进程可以使用系统调用(如 read()write()lseek()close() 等)来直接使用文件描述符进行操作。

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论