内核维护了3 个数据结构:
• 进程级的文件描述符表。(为单个进程进行维护)
• 系统级的打开文件表。(为所有打开的文件维护,表名:open file descri)
• 文件系统的i-node 表。(inode---index node)
内核对所有打开的文件维护有一个系统级的描述表格(open file description table)。
有时, 也称之为打开文件表(open file table), 并将表中各条目称为打开文件句柄(open file handle)。

内核为每个进程维护一个打开文件的列表,该表被称为文件表(file table);
该表的每一条目都记录了单个文件描述符的相关信息;
• 控制文件描述符操作的一组标志;
• 对打开文件句柄的引用;
文件表通过非负整数fds(file descriptors)进行索引;
https://elixir.bootlin.com/linux/v5.7.8/source/include/linux/fdtable.h#L48
/* * 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];//表示内核为进程维护的文件表;NR_OPEN_DEFAULT表示一个进程可以打开文件的最大个数;该数组的索引项对应fd(file descriptors),通过fd索引对应的打开的文件的信息;所谓的表本质是个结构体指针数组 };
为什么进程能够通过file结构体来找到磁盘上相应文件的位置来进行文件读写?
文件表中每项---文件表项(“struct file”指针)均包含一个打开文件的信息,其中包括一个指向文件备份inode内存拷贝的指针和元数据;
进程每打开一个文件(这里指不同的文件),内存中均会有一个“struct file”结构体生成;
内核为每个进程维护的文件表本质是一个“struct file”指针数组,“struct file”见https://elixir.bootlin.com/linux/v5.7.8/source/include/linux/fs.h#L941
struct file { union { struct llist_node fu_llist; struct rcu_head fu_rcuhead; } f_u; struct path f_path; //文件路径 struct inode *f_inode; /* cached value */指向文件备份inode内存拷贝的指针和元数据 const struct file_operations *f_op; //对文件的操作方法 /* * Protects f_ep_links, f_flags. * Must not be taken from IRQ context. */ spinlock_t f_lock; enum rw_hint f_write_hint; atomic_long_t f_count; unsigned int f_flags; fmode_t f_mode; struct mutex f_pos_lock; loff_t f_pos; struct fown_struct f_owner; const struct cred *f_cred; struct file_ra_state f_ra; u64 f_version; #ifdef CONFIG_SECURITY void *f_security; #endif /* needed for tty driver, and maybe others */ void *private_data; #ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ struct list_head f_ep_links; struct list_head f_tfile_llink; #endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping; errseq_t f_wb_err; } __randomize_layout __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
“struct inode”结构体,https://elixir.bootlin.com/linux/v5.7.8/source/include/linux/fs.h#L633
通过“struct inode”结构体,获取文件数据块的在磁盘上的位置以及文件大小等信息;
/* * Keep mostly read-only and often accessed (especially for * the RCU path lookup and 'stat' data) fields at the beginning * of the 'struct inode' */ struct inode { umode_t i_mode; unsigned short i_opflags; kuid_t i_uid; kgid_t i_gid; unsigned int i_flags; #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif const struct inode_operations *i_op; struct super_block *i_sb; struct address_space *i_mapping; #ifdef CONFIG_SECURITY void *i_security; #endif /* Stat data, not accessed from path walking */ unsigned long i_ino; /* * Filesystems may only read i_nlink directly. They shall use the * following functions for modification: * * (set|clear|inc|drop)_nlink * inode_(inc|dec)_link_count */ union { const unsigned int i_nlink; unsigned int __i_nlink; }; dev_t i_rdev; loff_t i_size; struct timespec64 i_atime; struct timespec64 i_mtime; struct timespec64 i_ctime; spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ unsigned short i_bytes; u8 i_blkbits; u8 i_write_hint; blkcnt_t i_blocks; #ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount; #endif /* Misc */ unsigned long i_state; struct rw_semaphore i_rwsem; unsigned long dirtied_when; /* jiffies of first dirtying */ unsigned long dirtied_time_when; struct hlist_node i_hash; struct list_head i_io_list; /* backing dev IO list */ #ifdef CONFIG_CGROUP_WRITEBACK struct bdi_writeback *i_wb; /* the associated cgroup wb */ /* foreign inode detection, see wbc_detach_inode() */ int i_wb_frn_winner; u16 i_wb_frn_avg_time; u16 i_wb_frn_history; #endif struct list_head i_lru; /* inode LRU list */ struct list_head i_sb_list; struct list_head i_wb_list; /* backing dev writeback list */ union { struct hlist_head i_dentry; struct rcu_head i_rcu; }; atomic64_t i_version; atomic64_t i_sequence; /* see futex */ atomic_t i_count; atomic_t i_dio_count; atomic_t i_writecount; #if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING) atomic_t i_readcount; /* struct files open RO */ #endif union { const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ void (*free_inode)(struct inode *); };//对inode的操作 struct file_lock_context *i_flctx; struct address_space i_data; struct list_head i_devices; union { struct pipe_inode_info *i_pipe; struct block_device *i_bdev; struct cdev *i_cdev; char *i_link; unsigned i_dir_seq; }; __u32 i_generation; #ifdef CONFIG_FSNOTIFY __u32 i_fsnotify_mask; /* all events this inode cares about */ struct fsnotify_mark_connector __rcu *i_fsnotify_marks; #endif #ifdef CONFIG_FS_ENCRYPTION struct fscrypt_info *i_crypt_info; #endif #ifdef CONFIG_FS_VERITY struct fsverity_info *i_verity_info; #endif void *i_private; /* fs or device private pointer */ } __randomize_layout;
参考书籍:Linux/Unix系统编程手册
内核维护了进程级的文件描述符表、系统级的打开文件表和文件系统的i-node表。文件描述符用于索引文件表,其中包含文件的相关信息,如打开文件句柄和文件元数据。结构体`struct file`和`struct inode`分别保存文件描述符和磁盘文件位置的详细信息,使得进程能进行文件读写操作。
1359

被折叠的 条评论
为什么被折叠?



