文件的内存映射可以认为是两个不同的地址空间之间的映射,以简化程序员的工作。一个地址空间是用户进程的虚拟地址空间,另一个是文件系统所在的地址空间。
在内核创建一个映射时,必须建立两个地址空间之间的关联,以支持二者以读写请求的形式通信。vm_operations_struct结构即用于完成此项工作,它提供了一个操作,读取已经映射到虚拟地址空间,但是内容尚未进入物理内存的页。
但是该结构不了解映射类型,或性质的相关信息,只能算是一个通用接口,具体实现还需要内核描述打开文件的file结构体当中的成员变量address_space结构体来详细说明数据源。
-
struct address_space {
-
struct inode *host; /* owner: inode, block_device */
-
struct radix_tree_root page_tree; /* radix tree of all pages */
-
spinlock_t tree_lock; /* and lock protecting it */
-
atomic_t i_mmap_writable;/* count VM_SHARED mappings */
-
struct rb_root_cached i_mmap; /* tree of private and shared mappings */
-
struct rw_semaphore i_mmap_rwsem; /* protect tree, count, list */
-
/* Protected by tree_lock together with the radix tree */
-
unsigned long nrpages; /* number of total pages */
-
/* number of shadow or DAX exceptional entries */
-
unsigned long nrexceptional;
-
pgoff_t writeback_index;/* writeback starts here */
-
const struct address_space_operations *a_ops; /* methods */
-
unsigned long flags; /* error bits */
-
spinlock_t private_lock; /* for use by the address_space */
-
gfp_t gfp_mask; /* implicit gfp mask for allocations */
-
struct list_head private_list; /* for use by the address_space */
-
void *private_data; /* ditto */
-
errseq_t wb_err;
-
} __attribute__((aligned(sizeof(long)))) __randomize_layout;
-
-
struct address_space_operations {
-
int (*writepage)(struct page *page, struct writeback_control *wbc);
-
int (*readpage)(struct file *, struct page *);
-
-
/* Write back some dirty pages from this mapping. */
-
int (*writepages)(struct address_space *, struct writeback_control *);
-
-
/* Set a page dirty. Return true if this dirtied it */
-
int (*set_page_dirty)(struct page *page);
-
-
int (*readpages)(struct file *filp, struct address_space *mapping,
-
struct list_head *pages, unsigned nr_pages);
-
-
int (*write_begin)(struct file *, struct address_space *mapping,
-
loff_t pos, unsigned len, unsigned flags,
-
struct page **pagep, void **fsdata);
-
int (*write_end)(struct file *, struct address_space *mapping,
-
loff_t pos, unsigned len, unsigned copied,
-
struct page *page, void *fsdata);
-
-
/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
-
sector_t (*bmap)(struct address_space *, sector_t);
-
void (*invalidatepage) (struct page *, unsigned int, unsigned int);
-
int (*releasepage) (struct page *, gfp_t);
-
void (*freepage)(struct page *);
-
ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter);
-
/*
-
* migrate the contents of a page to the specified target. If
-
* migrate_mode is MIGRATE_ASYNC, it must not block.
-
*/
-
int (*migratepage) (struct address_space *,
-
struct page *, struct page *, enum migrate_mode);
-
bool (*isolate_page)(struct page *, isolate_mode_t);
-
void (*putback_page)(struct page *);
-
int (*launder_page) (struct page *);
-
int (*is_partially_uptodate) (struct page *, unsigned long,
-
unsigned long);
-
void (*is_dirty_writeback) (struct page *, bool *, bool *);
-
int (*error_remove_page)(struct address_space *, struct page *);
-
-
/* swapfile support */
-
int (*swap_activate)(struct swap_info_struct *sis, struct file *file,
-
sector_t *span);
-
void (*swap_deactivate)(struct file *file);
-
};
这样每个address_space都有一组相关操作,保存在自己的a_ops指针当中
当建立内存映射的时候,内核分配完新的vm_area_struct实例之后,就会用特定于文件的函数file->f_op->mmap创建映射,vm_area_struct当中的vm_operations_struct和address_space之间就会建立联系(vm_operations_struct 的指针最后指向的是generic_file_vm_ops,里面的fault函数指向filemap_fault,这个函数就会调用上
-
address_space_operations当中的readpage函数)
-
const struct vm_operations_struct generic_file_vm_ops = {
-
.fault = filemap_fault,
-
.map_pages = filemap_map_pages,
-
.page_mkwrite = filemap_page_mkwrite,
-
};
-
int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
-
{
-
struct address_space *mapping = file->f_mapping;
-
-
if (!mapping->a_ops->readpage)
-
return -ENOEXEC;
-
file_accessed(file);
-
vma->vm_ops = &generic_file_vm_ops;
-
return 0;
-
}
阅读(7716) | 评论(0) | 转发(1) |