当用户空间程序调用open打开文件,或调用socket创建一个套接字时,都会返回一个int类型的句柄,这个句柄在内核中是怎么存储的,怎么根据句柄找到相应的文件对象或套接字对象呢,这篇文章来分析下这块内容。
进程对象task_struct中的files用来保存此类信息,其定义如下:
/*
* Open file table structure
*/
struct files_struct {
/*
* read mostly part
*/
atomic_t count;
bool resize_in_progress;
wait_queue_head_t resize_wait;
struct fdtable __rcu *fdt;
struct fdtable fdtab;
/*
* written part on a separate cache line in SMP
*/
spinlock_t file_lock ____cacheline_aligned_in_smp;
unsigned int next_fd;
unsigned long close_on_exec_init[1];
unsigned long open_fds_init[1];
unsigned long full_fds_bits_init[1];
struct file __rcu * fd_array[NR_OPEN_DEFAULT];
};
句柄相关的大部分信息,保存在files_struct的fdt中,下面是fdtable的定义:
struct fdtable {
unsigned int max_fds;
struct file __rcu **fd; // current fd array
unsigned long *close_on_exec;
unsigned long *open_fds;
unsigned long *full_fds_bits;
struct rcu_head rcu;
};
max_fds 是指当前最多能保存多少个句柄
fd 如果文件句柄为3,则fd[3]保存了与文件相关的file指针对象
open_fds 从最低位开始,某位为1,则表示相应位置句柄已被占用
full_fds_bits 用来表示open_fds有多少个long型缓存区
用表格来对上面几个字段,进行下说明:
序号 | next_fd | max_fds | full_fds_bits | open_fds |
1 | 4 | 64 | 0 | 0xf |
2 | 5 | 64 | 0 | 0x1f |
3 | 6 | 64 | 0 | 0x3f |
4 | 64 | 64 | 1 | 0xffffffffffffffff |
5 | 65 | 128 | 1 | 0x1,ffffffffffffffff |
6 | 66 | 128 | 1 | 0x3,ffffffffffffffff |
7 | 127 | 128 | 1 | 0x7fffffffffffffff,ffffffffffffffff |
8 | 128 | 128 | 3 | 0xffffffffffffffff,ffffffffffffffff |
9 | 129 | 256 | 3 | 0x1,ffffffffffffffff,ffffffffffffffff |
表格中的next_fd是files_struct中的字段,为下一个可用的句柄,从0开始计数。next_fd只是起辅助作用,句柄是否可用,以open_fds中的数据为准;
表格中的第一行,open_fds为0xf,对应的二进制表示为1111b,表示前4个句柄已被占用,下一个可用的句柄(next_fd)为4;
max_fds表示当前最多可保存多少个句柄,如缓存区被占满后,会调用expand_files进行扩展。默认情况下open_fds指向保有1个long类型长度的缓存区,最多保存64个句柄;扩展后open_fds指向有2个long类型长度的缓存区,可保存128个句柄;再次扩展后,则有4个long类型长度,保存256个句柄。
full_fds_bits用来表示open_fds的前多少个long类型缓存区被用完,用来辅助快速查找空闲的句柄位置。前3行full_fds_bits为0,表示open_fds第1个long缓存区还有空闲位置;第4到7行,full_fds_bits为1,表示open_fds第1个long缓存区(低64位)被用完;最后两行,full_fds_bits为3(二进制为11b),表示open_fds前两个long缓存区(低128位)被占用完。
总结一下:
文件或套接字,在内核中都有一个file对象与之一一对应,通过查找open_fds,获取下一个可用的句柄x,fdtable->fd[x]保存file对象的指针。