針對linux page cache的操做主要體如今struct address_space_operations數據結構中,cephfs處理linux page cache的函數集合以下:node
const struct address_space_operations ceph_aops = {linux
.readpage = ceph_readpage,數組
.readpages = ceph_readpages,數據結構
.writepage = ceph_writepage,app
.writepages = ceph_writepages_start,函數
.write_begin = ceph_write_begin,spa
.write_end = ceph_write_end,隊列
.set_page_dirty = ceph_set_page_dirty,進程
.invalidatepage = ceph_invalidatepage,內存
.releasepage = ceph_releasepage,
.direct_IO = ceph_direct_io,
};
ceph_readpage(struct file *filp, struct page *page)
|__調用readpage_nounlock(filep, page) 在加鎖的狀況下讀取一個物理內存頁的數據
|__肯定page的offset沒有超出inode的總長度
|__調用ceph_readpage_from_fscache()函數嘗試從fscache中讀取一個物理內存頁的數據
|__若讀取成功則直接返回
|__調用ceph_osdc_readpages()函數從ceph集羣中讀取一個物理內存頁的數據
|__調用ceph_osdc_new_reqeust()函數建立一個讀請求
|__調用osd_req_op_extent_osd_data_pages()函數爲讀請求的返回內容分配內存空間
|__調用ceph_osdc_start_request()函數將讀請求同步發送給ceph集羣
|__調用flush_dcache_page()函數刷page到dcache中
|__調用SetPageUptodate()函數設置物理內存頁的狀態是update的
|__調用ceph_readpage_to_fscache()函數將新讀到的物理內存頁更新到fscache中
|__調用unlock_page(page)
|__調用clear_bit_unlock()函數爲page解鎖
|__調用wake_up_page()函數喚醒等待該page的相關進程
ceph_readpages(struct file *file, struct address_space *mapping, struct list_head *page_list, unsigned nr_pages) 讀取多個頁
|__調用ceph_readpages_from_fscache()函數嘗試從fscache中讀取多個物理內存頁的數據
|__若讀取成功則直接返回
|__遍歷page_list
|__調用start_read()函數讀取數據到page_list所包含的物理內存頁
|__調用ceph_osdc_new_reqeust()函數建立一個讀請求
|__調用calc_pages_for(0, len)函數獲得讀取指定長度len的數據須要的物理內存頁數
|__從page_list中摘下指定數量的物理內存頁
|__調用osd_req_op_extent_osd_data_pages()函數將從page_list中摘下的物理內存頁做爲讀請求的接收緩衝
|__設置讀請求完成後的回調函數爲finish_read()
|__調用ceph_osdc_start_request()函數將讀請求同步發送給ceph集羣
finish_read(struct ceph_osd_request *req) 從ceph集羣中讀操做結束後的回調函數
|__遍歷讀取到的全部物理內存頁
|__調用flush_dcache_page()函數將page中的內存刷到dcache中
|__調用SetPageUptodate()函數設置page的狀態是uptodate的
|__調用ceph_readpage_to_fscache()函數將讀取到的page內存同步到fscache中
ceph_writepage(struct page *page, struct writeback_control *wbc)
|__調用writepage_nounlock(page,wbc)函數同步page信息到ceph集羣
|__調用page_snap_context()函數獲得page的snap context信息(page將CephSnapContext信息寫入到page的private中)
|__調用set_page_writeback(page)函數設置page writeback標識
|__調用ceph_osdc_writepages()函數將page信息同步寫到ceph集羣
|__調用ceph_osdc_new_reqeust()函數建立一個寫請求
|__調用osd_req_op_extent_osd_data_pages()函數爲寫請求設置寫內容物理內存頁
|__調用ceph_osdc_start_request()函數將寫請求同步發送給ceph集羣
|__設置page->private=0,即:刪除page的CephSnapContext信息
|__調用ClearPagePrivate(page)函數清空page的private
|__調用end_page_writeback()函數
|__調用wake_up_page(page, PG_writeback)函數喚醒在page上等待writeback完成的進程
ceph_writepages_start(struct address_space *mapping, struct writeback_control *wbc)
|__調用pagevec_init(&pvec, 0)函數初始化struct pagevec實例pvec
|__從wbc的range_start和range_end中獲得start和end
|__調用pagevec_lookup_tag(&pvec, mapping, PAGECACHE_TAG_DIRTY…)函數從mapping中radix tree中找到tags==PAGECACHE_TAG_DIRTY的全部pages且將全部pages寫入到pvec中
|__遍歷全部PAGECACHE_TAG_DIRTY的pages
|__調用page_offset()函數獲得page所在的offset值
|__調用ceph_calc_file_object_mapping()函數獲得從offset開始,長度是len的文件所佔用的objects個數以及在object中的偏移
|__將page添加到pages數組中
|__從pages數組中獲得offset值,即:offset=page_offset(pages[0])
|__調用ceph_osdc_new_request()函數建立一個寫數據請求
|__設置寫數據請求的回調函數爲writepages_finish
|__調用osd_req_op_extent_osd_data_pages()函數添加寫請求額外的數據
|__調用ceph_osdc_start_request()函數將寫請求同步發送到ceph集羣
writepages_finish(struct ceph_osd_request *req)
|__清除全部在發送寫請求過程當中產生的內存
ceph_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigend flags, staruct page **pagep, void **fsdata)
|__獲得pos所在的page位置,即:index=pos >> PAGE_SHIFT
|__調用grab_cache_page_write_begin(mapping, index, flags)函數在pagecache中指定位置index出獲取或建立一個物理內存頁page
|__調用pagecache_get_page()函數在pagecache中指定位置index出獲取或建立一個物理內存頁page
|__調用wait_for_stable_page(page)函數等待該page上的writeback函數返回
|__調用ceph_update_writeable_page(file, pos, len, page)函數只容許往clean page裏寫入數據或者已經dirty的snap context裏寫入數據
|__調用wait_on_page_writeback(page)函數等待page的writeback完成
|__調用page_snap_context(page)函數獲得該page的snap context
|__若snap context的seq > oldest->seq
|__調用ceph_queue_writeback(inode)函數將inode放入到writeback隊列中
|__調用clear_page_dirty_for_io(page)函數清除page上的dirty標識
|__調用writepage_nounlock(page, NULL)函數將page數據同步的寫入到ceph集羣
|__調用PageUptodate(page)檢查page是不是uptodate的
|__是則直接返回
|__若page已經滿了
|__直接返回
|__調用i_size_read(inode)函數獲得inode的讀數據的大小
|__調用readpage_nounlock(file, page)函數從ceph集羣中讀取數據到page中
ceph_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page **page, void *fsdata)
|__若copied < len
|__調用zero_user_segment(page, from+copied, len)函數將page中從from+copied一直到from+copied+len的內存空間置0
|__若pos+copied > i_size_read(inode)
|__調用ceph_inode_set_size()函數設置inode的size爲pos+copied
|__若Page不是uptodate的
|__調用SetPageUptodate(page)函數設置page是uptodate的
|__調用set_page_dirty(page)函數設置page是dirty的
ceph_set_page_dirty(struct page *page)
|__若PageDirty(page)
|__直接返回
|__經過mapping的到struct ceph_inode_info結構
|__調用__ceph_have_pending_cap_snap()函數檢查cephfs是否有snaps
|__從struct ceph_inode_info結構中的i_cap_snaps列表中獲得struct ceph_cap_snap結構
|__從struct ceph_cap_snap結構中獲得struct ceph_snap_context結構
|__若cephfs沒有snaps
|__調用ceph_get_snap_context()函數從struct ceph_inode_info的i_head_spapc中獲得struct ceph_snap_context結構
|__將struct ceph_snap_context結構設置到page的private中,即:page->private=snapc
|__調用__set_page_dirty_nobuffers()函數將page在address_spaces中的radix tree中設置成dirty
ceph_invalidatepage(struct page *page, unsigned int offset, unsigned int length)
|__調用ceph_invalidate_fscache_page()函數使得page在fscache中無效
|__若page沒有private
|__直接返回
|__設置page->private=0清除page的snaps
|__調用ClearPagePriavte(page)
ceph_releasepage(struct page *page, gfp_t g)
|__調用ceph_release_fscache_page()函數在fscache中刪除page
|__返回!PagePrivate(page)
ceph_direct_io(struct kiocb *iocb, struct iov_iter *iter)
|__返回-EINVAL