二,与进程联系的文件系统相关结构

文件描述符用于在一个进程中唯一标识打开的文件。假定内核能够在用户进程中和内核内部使用的结构之间,建立一种关联。每个进程的task_struct中包含了用于完成该工作的成员。

struct task_struct {

......

//用于查找环形链表时防止无限循环。

int link_count, total_link_count;

......

struct fs_struct *fs;

struct files_struct *files;

struct nsproxy *nsproxy;

......

};

 

struct fs_struct {

int users;

spinlock_t lock;

seqcount_t seq;

int umask;

int in_exec;

struct path root, pwd;

};

Umask:表示标准的掩码,用于设置新文件的权限。

rootpwd:指定了进程的根目录和当前工作目录。

 

结构files_struct是用户打开文件描述表,它给出了所有文件描述符的使用情况。

struct files_struct {

atomic_t count;

struct fdtable __rcu *fdt;

struct fdtable fdtab;

spinlock_t file_lock ____cacheline_aligned_in_smp;

int next_fd;

struct embedded_fd_set close_on_exec_init;

struct embedded_fd_set open_fds_init;

struct file __rcu * fd_array[NR_OPEN_DEFAULT];

};

next_fd:下一个文件描述符。

close_on_exec_init;:对执行exec时将关闭的所有文件描述符,在该 位图中对应的比特位都将置为。

open_fds_init:文件描述符集合。

fd_array:存储所有打开文件的file结构。

struct fdtable {

unsigned int max_fds;//进程可以处理的最大文件描述符数目。

struct file __rcu **fd;   

fd_set *close_on_exec;

fd_set *open_fds;

struct rcu_head rcu;

struct fdtable *next;

};

Fdtable结构中fdclose_on_execopen_fds分别指向files_struct 结构中的fd_arrayclose_on_exec_initopen_fds_init。在files_struct结构中能够处理的描述符是有限的,如果要打开更多的文件,内核会分配更大存储空间的字段,让fdtable中的指针指向新值。

struct file {

union {

struct list_head fu_list;

struct rcu_head  fu_rcuhead;

} f_u;

struct path f_path;

#define f_dentry f_path.dentry

#define f_vfsmnt f_path.mnt

const struct file_operations *f_op;

spinlock_t f_lock;

......

atomic_long_t f_count;

unsigned int  f_flags;

fmode_t f_mode;

loff_t f_pos;

struct fown_struct f_owner;

......

struct address_space *f_mapping;

.....

};

fu_list:超级块提供了一个s_files成员作表头,以建立file对象的链 表,链表元素是fu_list,该链表包含超级块表示的文件系统的所有打开的文件。

f_op:指向文件操作结构。

f_flags:指定了在open系统调用时传递的额外的标志。

f_mode:文件的打开模式。

f_pos:文件操作指针在文件中的当前位置。

f_owner:包含了处理文件的进程有关的信息(也确定了SIGIO信号 的目标PID,以实现异步输入输出)。

f_mapping:指向所属文件相关inode实例的地址空间映射。

 

三,系统有关的操作函数集

结构super_operations是对文件系统超级块进行操作的函数集。操作的实现必须由底层文件系统提供。

struct super_operations {

    struct inode *(*alloc_inode)(struct super_block *sb);

void (*destroy_inode)(struct inode *);

    void (*dirty_inode) (struct inode *, int flags);

int (*write_inode) (struct inode *, struct writeback_control *wbc);

int (*drop_inode) (struct inode *);

void (*evict_inode) (struct inode *);

void (*put_super) (struct super_block *);

void (*write_super) (struct super_block *);

int (*sync_fs)(struct super_block *sb, int wait);

int (*freeze_fs) (struct super_block *);

int (*unfreeze_fs) (struct super_block *);

int (*statfs) (struct dentry *, struct kstatfs *);

int (*remount_fs) (struct super_block *, int *, char *);

void (*umount_begin) (struct super_block *);

int (*show_options)(struct seq_file *, struct vfsmount *);

int (*show_devname)(struct seq_file *, struct vfsmount *);

int (*show_path)(struct seq_file *, struct vfsmount *);

int (*show_stats)(struct seq_file *, struct vfsmount *);

......

};

alloc_inode:在给定的超级块下创建并初始化一个新的索引节点。

destroy_inode:释放给定的索引节点。

dirty_inode:索引节点被修改时调用该函数。

write_inode:将指定的索引节点写回磁盘。

drop_inode:在最后一个索引节点被释放后,VFS调用该函数。

put_super:在卸载文件系统时VFS调用,用于释放超级块。

write_super:更新磁盘上的超级块。

sync_fs:使文件系统的数据元素与磁盘上的文件系统同步,wait参数 指定操作是否同步。

 StatfsVFS调用该函数获取文件系统状态,文件系统信息放置在 kstatfs中。

remount_fs:当制定新的安装选项重新安装文件系统时VFS调用该函 数。

umount_begin:仅用于网络文件系统和用户空间文件系统,仅在文件 系统强制卸载时调用该方法。

show_options:用于proc文件系统,用于显示文件系统装载的选项。

show_stats:提供了文件系统的统计信息,同样用于proc文件系统。

 

结构inode_operations中操作函数主要负责结构性操作,(例如删除一个文件)和文件相关元数据操作(例如属性)。

struct inode_operations {

struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);

void * (*follow_link) (struct dentry *, struct nameidata *);

int (*permission) (struct inode *, int);

struct posix_acl * (*get_acl)(struct inode *, int);

int (*readlink) (struct dentry *, char __user *,int);

void (*put_link) (struct dentry *, struct nameidata *, void *);

int (*create) (struct inode *,struct dentry *,int, struct nameidata *);

int (*link) (struct dentry *,struct inode *,struct dentry *);

int (*unlink) (struct inode *,struct dentry *);

int (*symlink) (struct inode *,struct dentry *,const char *);

int (*mkdir) (struct inode *,struct dentry *,int);

int (*rmdir) (struct inode *,struct dentry *);

int (*mknod) (struct inode *,struct dentry *,int,dev_t);

int (*rename) (struct inode *, struct dentry *,

struct inode *, struct dentry *);

void (*truncate) (struct inode *);

......

void (*truncate_range)(struct inode *, loff_t, loff_t);

int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,

      u64 len);

} ____cacheline_aligned; 

Lookup:在父目录中查找指定文件的dentry

follow_link:通过一个符号链接查找它实际指向的索引节点。

readlink:读符号链接。

Permission:得到节点权限。

Create:创建节点,代表目录的节点才提供这个函数。

Link:用于在指定目录下创建一个硬链接。这个link函数最终会被系 统调用link()调用。该函数的第一个参数是原始文件的dentry,第二个参数为上述指定目录的inode,第三个参数是链接文件的dentry

Symlink:在某个目录下创建符号链接。

mkdir:在指定目录下创建一个子目录,当前目录的inode会调用 i_op->mkdir()。该函数会被系统调用mkdir()调用。第一个参数即为指定目录的inode,第二个参数为子目录的dentry,第三个参数为子目录权限。

Mknod:在指定的目录下创建一个特殊文件,比如管道、设备文件或 套接字等。

Rename:文件或目录重命名。

Truncate:将文件长度剪短。

truncate_range:用于截断一个范围内的块。

 

dentry_operations结构保存了一些指向各种特定于文件系统可以对dentry对象执行的操作的函数指针。

struct dentry_operations {

int (*d_revalidate)(struct dentry *, struct nameidata *);

int (*d_hash)(const struct dentry *, const struct inode *,

struct qstr *);

int (*d_compare)(const struct dentry *, const struct inode *,

const struct dentry *, const struct inode *,

unsigned int, const char *, const struct qstr *);

int (*d_delete)(const struct dentry *);

void (*d_release)(struct dentry *);

void (*d_prune)(struct dentry *);

void (*d_iput)(struct dentry *, struct inode *);

char *(*d_dname)(struct dentry *, char *, int);

struct vfsmount *(*d_automount)(struct path *);

int (*d_manage)(struct dentry *, bool);

} ____cacheline_aligned;

d_revalidate:对于网络文件系统特别重要。它检查内存中的各个dentry 对象构成的结构是否仍然能够反映当前文件系统中的情况。因为网络文件系统并不直接关联到内核/VFS,所有信息都必须通过网络连接收集,可能由于文件系统在存储端的改变,致使某些dentry不再有效。该函数用于确保一致性。

d_hash:计算散列值,该值用于将对象放置到dentry散列表中。

d_compare:比较两个dentry对象的文件名。尽管VFS只执行简单的 字符串比较,但文件系统可以替换默认实现,以适合自身的需求。

d_delete:在确认dentry对象仍然包含在全局dentry散列表中之后, 使用__d_drop将其移出。如果该对象此时只剩下一个使用者,还会调用dentry_iput将相关inode的使用计数减1

d_iput:从一个不再使用的dentry对象中释放inode

 

各个file实例都包含一个指向struct file_operations实例的指针,该结构保存了所有可能文件操作的函数指针。

struct file_operations {

struct module *owner;

loff_t (*llseek) (struct file *, loff_t, int);

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

int (*readdir) (struct file *, void *, filldir_t);

unsigned int (*poll) (struct file *, struct poll_table_struct *);

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

int (*mmap) (struct file *, struct vm_area_struct *);

int (*open) (struct inode *, struct file *);

int (*flush) (struct file *, fl_owner_t id);

int (*release) (struct inode *, struct file *);

int (*fsync) (struct file *, loff_t, loff_t, int datasync);

int (*aio_fsync) (struct kiocb *, int datasync);

int (*fasync) (int, struct file *, int);

int (*lock) (struct file *, int, struct file_lock *);

ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);

unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);

int (*check_flags)(int);

int (*flock) (struct file *, int, struct file_lock *);

ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);

ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);

int (*setlease)(struct file *, long, struct file_lock **);

long (*fallocate)(struct file *file, int mode, loff_t offset,

  loff_t len);

};

Llseek:文件操作指针在文件中定位。

aio_read:用于异步读取操作。

Readdir:读取目录内容,只对目录对象适用。

Poll:用于pollselect系统调用,以便实现同步的I/O多路复用。

Mmap:用来请求将设备内存映射到进程的地址空间。

Flush:操作在进程关闭它的设备文件描述符的拷贝时调用,它应当 执行设备的任何未完成的操作。

Release:在文件结构被释放时调用这个操作。

Fsync:这个方法是fsync系统调用的后端,用户调用来刷新任何挂着 的数据。

Fasync:用于启用/停用有信号控制的输入和输出。

Lock:用于锁定文件,对多个进程的并发文件访问进行同步。

Sendpage:它由内核调用来发送数据,一次一页,到对应的文件。设 备驱动实际上不实现sendpage

get_unmapped_area:这个方法的目的是在进程的地址空间找一个合适 的位置来映射在底层设备上的内存段,这个任务通常由内存管理代码进行。

check_flags:这个方法允许模块检查传递给fcntl(F_SETFL...)调用的 标志。

splice_write:用于从管道向文件传输数据。