Linux VFS (5)

write_begin:由generic_perform_write()调用,用于告知文件系统准备在指定偏移处写len字节的数据。address space应预留一些资源保证完成这次写入操作。如果写入要更新页中的一部分,那么需要将整页块读取到内存中,即读改写。文件系统通过pagep返回page cache中已锁定的page。调用者会将数据写入到该page中。需要支持实际写入的数据长度小于传给write_begin的长度的场景。可通过fsdata保存需要传递给write_end的数据。

write_end:该函数必须在成功调用write_begin和拷贝数据后被调用。len是传递给write_begin的len,copied则是实际拷贝的长度。文件系统必须释放page的锁和引用,并更新struct inode::i_size。失败返回小于0,否则返回实际拷贝到page cache的长度。

bmap:VFS调用该方法将逻辑块偏移映射为物理块序号。该方法用于ioctl(FIBMAP)和swap文件。为了swap一个文件,文件必须固定地映射到一个块设备上。swap系统会通过bmap来找到文件所在的块,然后直接存储,而不通过文件系统。

invalidatepage:如果page设置了PagePrivate,那么当部分或全部的page从address space中被移除时,就会调用invalidatepage。

releasepage:释放标记为PagePrivate的page,该方法需要移除page的私有数据,并清除PagePrivate。如果该方法失败了则返回0。releasepage用于两种场景

VM发现一个没有活动用户的干净page,并向释放该page。如果释放成功,那么该页就会从address space中移除,变为自由的page。

需要让address space中的部分或全部page失效。这种场景由fadvise(POSIX_FADV_DONTNEED)触发,或者文件系统明确请求(比如当nfs和9fs认为cache的数据已经与存储不一致时,会调用invalidate_inode_pages2())

freepage:一旦page在page cache中不可见时,为了允许清除私有数据,就会调用该方法。因为该方法可能被内存回收者调用,所以该方法不能假设原始的address space还存在,也不应当阻塞。

direct_IO:由generic read/write类函数调用来执行direct IO。

isolate_page:VM在需要隔离一个可移动的非LRU的page时调用。如果成功了,VM会通过__SetPageIsolated将该页标记为PG_isolated。

migrate_page:该方法用于压缩物理内存使用量。如果VM想重新放置page(可能是内存卡的故障信号触发的),就会传递一个老page和一个新page给这个方法。该方法需要传输私有数据,并更新所有引用。

putback_page:当已隔离的页迁移失败时,VM会调用该方法。

launder_page:在释放页前调用。该方法将脏页写回存储并避免重新弄脏该页,在整个过程中,都会加锁。

is_partially_uptodate:块大小不等于页大小,一页可能包含多个块。如果VM读取到所需的块数据,那么就无需等待整个页读取完毕。

is_dirty_writeback:当VM想回收page时调用。VM会根据dirty和writeback的值决定是否需要停顿回收页,以便能完成某些IO。通常情况下,VM可以使用PageDirty和PageWriteback,但是某些文件系统会有更复杂的状态(比如NFS的unstable pages需要避免被回收),或者因为锁的问题没有设置这些标志。该方法可以向VM表明该页是脏页或正在写回的页,让VM停止回收该页。

error_remove_page:如果truncation是正常的话,通常设置为generic_error_remove_page()。主要用于处理内存失败。实现该方法,意味着你会处理那些页,除非你已经锁定或者增加了引用计数。

swap_activate:当文件使用了swapon时调用,用于分配空间并将块的查询信息保存在内存中。返回0代表成功,也意味着该文件可以被当做备份的交换空间。

swap_deactivate:当swap_activate成功后,调用该方法使得该文件变为swapoff。

The File Object

一个file对象代表进程打开的一个文件。

struct file_operations

VFS使用struct file_operations操作一个打开的文件。

自v4.18,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 (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); int (*iterate_shared) (struct file *, struct dir_context *); __poll_t (*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 (*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 **, void **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); void (*show_fdinfo)(struct seq_file *m, struct file *f); #ifndef CONFIG_MMU unsigned (*mmap_capabilities)(struct file *); #endif ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t, u64); int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t, u64); int (*fadvise)(struct file *, loff_t, loff_t, int); };

除非额外说明,否则这些函数都不会持锁调用。

read_iter:支持将文件数据读取到非连续的内存中

write_iter:支持将非连续内存中的数据写入到文件中。

iterate:读取目录内容

iterate_shared:当文件系统支持并发的目录迭代时,使用该函数读取目录内容

compat_ioctl:在64位内核上兼容32位的系统调用

open:创建一个新的struct file,并初始化strutc file::private_data

flush:由close(2)调用

release:当文件的引用计数为0时调用

fasync:文件为非阻塞模式时,由fcntl(2)调用

lock:由fcntl(2)调用,执行F_GETLK,F_SETLK,F_SETLKW命令

fallocate:预分配block

Directory Entry Cache (dcache)

dentry属于VFS和单个文件系统,与设备驱动无关。每个dentry都有一个指向其父dentry的指针,以及一个子dentry的hash链表。

struct dentry_operations

struct dentry_operations是可选的,可以设置为NULL,或是使用VFS默认的函数。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzddjg.html