Linux内核源码分析-页高速缓存-address_space
来源:互联网 发布:新淘宝店铺转让价格表 编辑:程序博客网 时间:2024/05/18 01:52
本文主要参考《深入理解Linux内核》,结合2.6.11版的内核代码,分析内核文件子系统中的页高速缓存处理函数。
注意:
1、 不描述内核同步、错误处理、参数合法性验证相关的内容
2、 源码摘自Linux内核2.6.11 stable版,获取命令:
git clone
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
cd ./linux-stable/
git checkout linux-2.6.11.y
3、 阅读本文请结合《深入理解Linux内核》第三版相关章节
4、 本文会不定时更新
函数调用结构
公共函数
1、find_get_page
功能:
调用函数radix_tree_lookup在address_space 的radix_tree_root中查找页,找到则增加页的引用计数并返回,未找到返回NULL
源码:
/* * a rather lightweight function, finding and getting a reference to a * hashed page atomically. */struct page * find_get_page(struct address_space *mapping, unsigned long offset){ struct page *page; spin_lock_irq(&mapping->tree_lock); page = radix_tree_lookup(&mapping->page_tree, offset); if (page) page_cache_get(page); spin_unlock_irq(&mapping->tree_lock); return page;}
2、find_get_pages
功能:
调用函数radix_tree_gang_lookup从树中查找nr_pages个非空页,并增加找到页的引用计数
源码:
/** * find_get_pages - gang pagecache lookup * @mapping: The address_space to search * @start: The starting page index * @nr_pages: The maximum number of pages * @pages: Where the resulting pages are placed * * find_get_pages() will search for and return a group of up to * @nr_pages pages in the mapping. The pages are placed at @pages. * find_get_pages() takes a reference against the returned pages. * * The search returns a group of mapping-contiguous pages with ascending * indexes. There may be holes in the indices due to not-present pages. * * find_get_pages() returns the number of pages which were found. */unsigned find_get_pages(struct address_space *mapping, pgoff_t start, unsigned int nr_pages, struct page **pages){ unsigned int i; unsigned int ret; spin_lock_irq(&mapping->tree_lock); ret = radix_tree_gang_lookup(&mapping->page_tree, (void **)pages, start, nr_pages); for (i = 0; i < ret; i++) page_cache_get(pages[i]); spin_unlock_irq(&mapping->tree_lock); return ret;}
3、find_lock_page
功能:
调用函数radix_tree_lookup在address_space 的radix_tree_root中查找页,找到则增加页的引用计数、锁定页并返回,未找到返回NULL
源码:
/** * find_lock_page - locate, pin and lock a pagecache page * * @mapping - the address_space to search * @offset - the page index * * Locates the desired pagecache page, locks it, increments its reference * count and returns its address. * * Returns zero if the page was not present. find_lock_page() may sleep. */struct page *find_lock_page(struct address_space *mapping, unsigned long offset){ struct page *page; spin_lock_irq(&mapping->tree_lock);repeat: page = radix_tree_lookup(&mapping->page_tree, offset); if (page) { page_cache_get(page); if (TestSetPageLocked(page)) { spin_unlock_irq(&mapping->tree_lock); lock_page(page); spin_lock_irq(&mapping->tree_lock); /* Has the page been truncated while we slept? */ if (page->mapping != mapping || page->index != offset) { unlock_page(page); page_cache_release(page); goto repeat; } } } spin_unlock_irq(&mapping->tree_lock); return page;}
4、find_trylock_page
功能:
和find_get_page功能类似,但试着锁定页,锁定失败返回NULL;不增加页的引用计数器
源码:
/* * Same as find_get_page, but trylock it instead of incrementing the count. */struct page *find_trylock_page(struct address_space *mapping, unsigned long offset){ struct page *page; spin_lock_irq(&mapping->tree_lock); page = radix_tree_lookup(&mapping->page_tree, offset); if (page && TestSetPageLocked(page)) page = NULL; spin_unlock_irq(&mapping->tree_lock); return page;}
5、find_or_create_page
源码:
/** * find_or_create_page - locate or add a pagecache page * * @mapping - the page's address_space * @index - the page's index into the mapping * @gfp_mask - page allocation mode * * Locates a page in the pagecache. If the page is not present, a new page * is allocated using @gfp_mask and is added to the pagecache and to the VM's * LRU list. The returned page is locked and has its reference count * incremented. * * find_or_create_page() may sleep, even if @gfp_flags specifies an atomic * allocation! * * find_or_create_page() returns the desired page's address, or zero on * memory exhaustion. */struct page *find_or_create_page(struct address_space *mapping, unsigned long index, unsigned int gfp_mask){ struct page *page, *cached_page = NULL; int err;repeat: page = find_lock_page(mapping, index); if (!page) { if (!cached_page) { cached_page = alloc_page(gfp_mask); if (!cached_page) return NULL; } err = add_to_page_cache_lru(cached_page, mapping, index, gfp_mask); if (!err) { page = cached_page; cached_page = NULL; } else if (err == -EEXIST) goto repeat; } if (cached_page) page_cache_release(cached_page); return page;}
处理流程:
1、 调用函数find_lock_page在mapping中查找页,找到则返回该页地址
2、 未找到调用函数alloc_page分配一页,调用函数add_to_page_cache_lru把页插入mapping中
6、add_to_page_cache
源码:
/* * This function is used to add newly allocated pagecache pages: * the page is new, so we can just run SetPageLocked() against it. * The other page state flags were set by rmqueue(). * * This function does not add the page to the LRU. The caller must do that. */int add_to_page_cache(struct page *page, struct address_space *mapping, pgoff_t offset, int gfp_mask){ int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); if (error == 0) { spin_lock_irq(&mapping->tree_lock); error = radix_tree_insert(&mapping->page_tree, offset, page); if (!error) { page_cache_get(page); SetPageLocked(page); page->mapping = mapping; page->index = offset; mapping->nrpages++; pagecache_acct(1); } spin_unlock_irq(&mapping->tree_lock); radix_tree_preload_end(); } return error;}
处理流程:
1、 调用函数radix_tree_preload补充每cpu变量radix_tree_preloads中的radix_tree_node对象,并禁用内核抢占
2、 调用函数radix_tree_insert把页插入mapping->page_tree中
3、 插入成功则增加页引用计数器、锁定页,初始化page和mapping相关字段
4、 调用函数radix_tree_preload_end启动内核抢占
7、remove_from_page_cache
功能:
调用函数__remove_from_page_cache从mapping中删除页
源码:
void remove_from_page_cache(struct page *page){ struct address_space *mapping = page->mapping; if (unlikely(!PageLocked(page))) PAGE_BUG(page); spin_lock_irq(&mapping->tree_lock); __remove_from_page_cache(page); spin_unlock_irq(&mapping->tree_lock);}
8、read_cache_page
源码:
/* * Read into the page cache. If a page already exists, * and PageUptodate() is not set, try to fill the page. */struct page *read_cache_page(struct address_space *mapping, unsigned long index, int (*filler)(void *,struct page*), void *data){ struct page *page; int err;retry: page = __read_cache_page(mapping, index, filler, data); if (IS_ERR(page)) goto out; mark_page_accessed(page); if (PageUptodate(page)) goto out; lock_page(page); if (!page->mapping) { unlock_page(page); page_cache_release(page); goto retry; } if (PageUptodate(page)) { unlock_page(page); goto out; } err = filler(data, page); if (err < 0) { page_cache_release(page); page = ERR_PTR(err); } out: return page;}
处理流程:
1、 调用函数__read_cache_page查找或分配新页
2、 调用函数mark_page_accessed记录也被访问标志
3、 调用函数PageUptodate检查页内容是否最新,是则返回页地址
4、 如果页内容不是最新,锁定页并调用函数mapping->a_ops->readpage读取页的内容,然后返回页地址
文件私有函数
1、add_to_page_cache_lru
功能:
调用函数add_to_page_cache把页插入mapping缓存中,插入成功调用函数lru_cache_add把页插入每cpu变量lru_add_pvecs中
源码:
int add_to_page_cache_lru(struct page *page, struct address_space *mapping, pgoff_t offset, int gfp_mask){ int ret = add_to_page_cache(page, mapping, offset, gfp_mask); if (ret == 0) lru_cache_add(page); return ret;}
2、__read_cache_page
源码:
static inline struct page *__read_cache_page(struct address_space *mapping, unsigned long index, int (*filler)(void *,struct page*), void *data){ struct page *page, *cached_page = NULL; int err;repeat: page = find_get_page(mapping, index); if (!page) { if (!cached_page) { cached_page = page_cache_alloc_cold(mapping); if (!cached_page) return ERR_PTR(-ENOMEM); } err = add_to_page_cache_lru(cached_page, mapping, index, GFP_KERNEL); if (err == -EEXIST) goto repeat; if (err < 0) { /* Presumably ENOMEM for radix tree node */ page_cache_release(cached_page); return ERR_PTR(err); } page = cached_page; cached_page = NULL; err = filler(data, page); if (err < 0) { page_cache_release(page); page = ERR_PTR(err); } } if (cached_page) page_cache_release(cached_page); return page;}
处理流程:
1、 调用函数find_get_page在mapping中查找页,找到则返回该页的地址
2、 未找到则调用函数page_cache_alloc_cold分页一页,调用函数add_to_page_cache_lru把页插入mapping缓存中,调用函数mapping->a_ops->readpage读取页的内容,然后返回页地址
- Linux内核源码分析-页高速缓存-address_space
- linux内核 address_space 结构
- linux内核 address_space 结构
- linux内核 address_space 结构
- linux内核 address_space 结构
- linux内核 address_space 结构
- Linux内核源码分析--文件系统(二、高速缓存区)
- linux内核分析笔记----页高速缓存和页回写
- linux内核分析笔记----页高速缓存和页回写
- linux内核分析笔记----页高速缓存和页回写
- Linux内核-文件系统-页高速缓存
- linux内核之页高速缓存
- linux内核研究-9-页高速缓存(cache)
- Linux 内核之页高速缓存与页回写
- Linux 内核之页高速缓存与页回写
- Linux内核源码分析
- 内核struct address_space
- LINUX内核设计与实现之页高速缓存和页回写
- Java学习2:基于Intellij IDEA开发一个简单的Web Application
- ActionMode 操作模式
- 必备15大技能
- 关于 iOS 程序调试 及腾讯 Bugly 的演练
- ros.launch 文件学习
- Linux内核源码分析-页高速缓存-address_space
- 投票系统UML图
- codevs 1060 搞笑世界杯(DP)
- C#小练习08
- 001 Python Test
- WPF 构建自定义控件 模板Template
- JDBC的再学习
- 七步通过python学习机器学习
- Runtime结合Category给工程中所有控制器替换背景颜色