📄 mmap.c
字号:
/* * Copyright (c) 1997-2003 Erez Zadok * Copyright (c) 2001-2003 Stony Brook University * Copyright (c) 1997-2000 Columbia University * * For specific licensing information, see the COPYING file distributed with * this package, or get one from ftp://ftp.filesystems.org/pub/fist/COPYING. * * This Copyright notice must be kept intact and distributed with all * fistgen sources INCLUDING sources generated by fistgen. *//* * $Id: mmap.c,v 1.19 2003/02/10 04:08:02 cwright Exp $ */#ifdef HAVE_CONFIG_H# include <config.h>#endif /* HAVE_CONFIG_H */#ifdef FISTGEN# include "fist_wrapfs.h"#endif /* FISTGEN */#include "fist.h"#include "wrapfs.h"#ifdef FIST_COUNT_WRITES/* for counting writes in the middle vs. regular writes */unsigned long count_writes = 0, count_writes_middle = 0;#endif /* FIST_COUNT_WRITES *//* forward declaration of commit write and prepare write */STATIC int wrapfs_commit_write(file_t *file, page_t *page, unsigned from, unsigned to);STATIC int wrapfs_prepare_write(file_t *file, page_t *page, unsigned from, unsigned to);/* * Function for handling creation of holes when lseek-ing past the * end of the file and then writing some data. */intwrapfs_fill_zeros(file_t* file, page_t *page, unsigned from){ int err = 0; dentry_t *dentry = file->f_dentry; inode_t *inode = dentry->d_inode; page_t *tmp_page; int index; for (index = inode->i_size >> PAGE_CACHE_SHIFT; index < page->index; index++) { tmp_page = wrapfs_get1page(file, index); if (IS_ERR(tmp_page)) { err = PTR_ERR(tmp_page); goto out; } /* * zero out rest of the contents of the page between the appropriate * offsets. */ memset((char*)page_address(tmp_page) + (inode->i_size & ~PAGE_CACHE_MASK), 0, PAGE_CACHE_SIZE - (inode->i_size & ~PAGE_CACHE_MASK)); if (! (err = wrapfs_prepare_write(file, tmp_page, 0, PAGE_CACHE_SIZE))) err = wrapfs_commit_write(file, tmp_page, 0, PAGE_CACHE_SIZE); page_cache_release(tmp_page); if (err < 0) goto out; if (current->need_resched) schedule(); } /* zero out appropriate parts of last page */#ifdef FIST_ENCODING_TYPE_BLOCK /* * if the encoding type is block, then adjust the 'from' (where the * zeroing will start) offset appropriately */ from = from & (~(FIST_ENCODING_BLOCKSIZE - 1));#endif /* FIST_ENCODING_TYPE_BLOCK */ if ((from - (inode->i_size & ~PAGE_CACHE_MASK)) > 0) { memset((char*)page_address(page) + (inode->i_size & ~PAGE_CACHE_MASK), 0, from - (inode->i_size & ~PAGE_CACHE_MASK)); if (! (err = wrapfs_prepare_write(file, page, 0, PAGE_CACHE_SIZE))) err = wrapfs_commit_write(file, page, 0, PAGE_CACHE_SIZE); if (err < 0) goto out; if (current->need_resched) schedule(); }out: return err;}/* * Currently there is no way to make writepage() work with the SCA code, * because we need access to a dentry and writepage only gives us an inode. */#ifndef FIST_FILTER_SCASTATIC intwrapfs_writepage(page_t *page){ int err = -EIO; inode_t *inode; inode_t *hidden_inode; page_t *hidden_page; char *kaddr, *hidden_kaddr; print_entry_location(); inode = page->mapping->host;/* CPW: Moved below print_entry_location */ hidden_inode = itohi(inode); printk("Entering writepage\n"); /* * writepage is called when shared mmap'ed files need to write * their pages, while prepare/commit_write are called from the * non-paged write() interface. (However, in 2.3 the two interfaces * share the same cache, while in 2.2 they didn't.) * * So we pretty much have to duplicate much of what commit_write does. */ /* find lower page (returns a locked page) */ hidden_page = grab_cache_page(hidden_inode->i_mapping, page->index); if (!hidden_page) goto out; /* get page address, and encode it */ kaddr = (char *) kmap(page); hidden_kaddr = (char*) kmap(hidden_page); wrapfs_encode_block(kaddr, hidden_kaddr, PAGE_CACHE_SIZE, inode, inode->i_sb, page->index); /* if encode_block could fail, then return error */ kunmap(page); kunmap(hidden_page); /* call lower writepage (expects locked page) */ err = hidden_inode->i_mapping->a_ops->writepage(hidden_page); /* * update mtime and ctime of lower level file system * wrapfs' mtime and ctime are updated by generic_file_write */ hidden_inode->i_mtime = hidden_inode->i_ctime = CURRENT_TIME;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,1) UnlockPage(hidden_page); /* b/c grab_cache_page locked it */#endif /* kernel older than 2.4.1 */ page_cache_release(hidden_page); /* b/c grab_cache_page increased refcnt */ if (err) ClearPageUptodate(page); else SetPageUptodate(page);out:#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,1) UnlockPage(page);#endif /* kernel 2.4.1 and newer */ print_exit_status(err); return err;}#endif /* not FIST_FILTER_SCA *//* * get one page from cache or lower f/s, return error otherwise. * returns unlocked, up-to-date page (if ok), with increased refcnt. */page_t *wrapfs_get1page(file_t *file, int index){ page_t *page; dentry_t *dentry; inode_t *inode; struct address_space *mapping; int err; print_entry_location(); dentry = file->f_dentry; /* CPW: Moved below print_entry_location */ inode = dentry->d_inode; mapping = inode->i_mapping; fist_dprint(8, "%s: read page index %d\n", __FUNCTION__, index); if (index < 0) { printk("%s BUG: index=%d\n", __FUNCTION__, index); page = ERR_PTR(-EIO); goto out; } page = read_cache_page(mapping, index, (filler_t *) mapping->a_ops->readpage, (void *) file); if (IS_ERR(page)) goto out; wait_on_page(page); if (!Page_Uptodate(page)) { lock_page(page); err = mapping->a_ops->readpage(file, page); if (err) { page = ERR_PTR(err); goto out; } wait_on_page(page); if (!Page_Uptodate(page)) { page = ERR_PTR(-EIO); goto out; } } out: print_exit_pointer(page); return page;}/* * readpage is called from generic_page_read and the fault handler. * If your file system uses generic_page_read for the read op, it * must implement readpage. * * Readpage expects a locked page, and must unlock it. */STATIC intwrapfs_do_readpage(file_t *file, page_t *page){ int err = -EIO; dentry_t *dentry; file_t *hidden_file; dentry_t *hidden_dentry; inode_t *inode; inode_t *hidden_inode; char *page_data;#ifdef FIST_FILTER_SCA int i; int num_hidden_pages; int hidden_page_index; page_t **hidden_pages; char **hidden_pages_data; void *opaque;#else /* not FIST_FILTER_SCA */ page_t *hidden_page; char *hidden_page_data; int real_size;#endif /* not FIST_FILTER_SCA */ print_entry_location(); dentry = file->f_dentry; /* CPW: Moved below print_entry_location */ hidden_file = ftohf(file); hidden_dentry = dtohd(dentry); inode = dentry->d_inode; hidden_inode = itohi(inode); fist_dprint(7, "%s: requesting page %d from file %s\n", __FUNCTION__, page->index, dentry->d_name.name);#ifdef FIST_FILTER_SCA num_hidden_pages = wrapfs_count_hidden_pages(page->index, inode, &hidden_page_index, &opaque); if (num_hidden_pages <= 0) { err = num_hidden_pages; if (err == 0) { page_data = (char *) kmap(page); memset(page_data, 0, PAGE_CACHE_SIZE); kunmap(page); } goto out; }#endif /* FIST_FILTER_SCA */ MALLOC_PAGE_POINTERS(hidden_pages, num_hidden_pages); MALLOC_PAGEDATA_POINTERS(hidden_pages_data, num_hidden_pages); FOR_EACH_PAGE CURRENT_HIDDEN_PAGE = NULL; /* find lower page (returns a locked page) */ FOR_EACH_PAGE { fist_dprint(8, "%s: Current page index = %d\n", __FUNCTION__, CURRENT_HIDDEN_PAGEINDEX); CURRENT_HIDDEN_PAGE = read_cache_page(hidden_inode->i_mapping, CURRENT_HIDDEN_PAGEINDEX, (filler_t *) hidden_inode->i_mapping->a_ops->readpage, (void *) hidden_file); if (IS_ERR(CURRENT_HIDDEN_PAGE)) { err = PTR_ERR(CURRENT_HIDDEN_PAGE); CURRENT_HIDDEN_PAGE = NULL; goto out_release; } } /* * wait for the page data to show up * (signaled by readpage as unlocking the page) */ FOR_EACH_PAGE { wait_on_page(CURRENT_HIDDEN_PAGE); if (!Page_Uptodate(CURRENT_HIDDEN_PAGE)) { /* * call readpage() again if we returned from wait_on_page with a * page that's not up-to-date; that can happen when a partial * page has a few buffers which are ok, but not the whole * page. */ lock_page(CURRENT_HIDDEN_PAGE); err = hidden_inode->i_mapping->a_ops->readpage(hidden_file, CURRENT_HIDDEN_PAGE); if (err) { CURRENT_HIDDEN_PAGE = NULL; goto out_release; } wait_on_page(CURRENT_HIDDEN_PAGE); if (!Page_Uptodate(CURRENT_HIDDEN_PAGE)) { err = -EIO; goto out_release; } } } /* map pages, get their addresses */ page_data = (char *) kmap(page); FOR_EACH_PAGE CURRENT_HIDDEN_PAGEDATA = (char *) kmap(CURRENT_HIDDEN_PAGE);#ifdef FIST_FILTER_SCA# ifdef FIST_FAST_TAILS /* * If this is a fast tail (page we were asked for is * the last page of the file), then we don't need to * decode this buffer, just stick it into page_data */ if (IS_FASTTAIL_PAGE(page->index, inode)) { int offset, len, len0; offset = HIDDEN_PAGE_STARTING_OFFSET(page->index, inode) & ~PAGE_CACHE_MASK; len = HIDDEN_PAGE_LENGTH(page->index, inode); if (offset + len <= PAGE_CACHE_SIZE) { /* copy one page */ ASSERT(num_hidden_pages == 1); memcpy(page_data, hidden_pages_data[0] + offset, len); } else { /* copy two pages */ ASSERT(num_hidden_pages == 2); len0 = PAGE_CACHE_SIZE - offset; memcpy(page_data, hidden_pages_data[0] + offset, len0); memcpy(page_data + len0, hidden_pages_data[1], len - len0); } memset(page_data + len, 0, PAGE_CACHE_SIZE - len); err = 0; } else# endif /* FIST_FAST_TAILS */ err = wrapfs_decode_buffers(num_hidden_pages, hidden_pages_data, page_data, inode, inode->i_sb, opaque); if (err > 0) err = 0;#else /* not FIST_FILTER_SCA */ /* if decode_block could fail, then return error */ err = 0; real_size = hidden_inode->i_size - (page->index << PAGE_CACHE_SHIFT); if (real_size <= 0) memset(page_data, 0, PAGE_CACHE_SIZE); else if (real_size < PAGE_CACHE_SIZE) { wrapfs_decode_block(hidden_page_data, page_data, real_size, inode, inode->i_sb, page->index); memset(page_data + real_size, 0, PAGE_CACHE_SIZE - real_size); } else wrapfs_decode_block(hidden_page_data, page_data, PAGE_CACHE_SIZE, inode, inode->i_sb, page->index);#endif /* not FIST_FILTER_SCA */ FOR_EACH_PAGE kunmap(CURRENT_HIDDEN_PAGE); kunmap(page);out_release: FOR_EACH_PAGE if (CURRENT_HIDDEN_PAGE) page_cache_release(CURRENT_HIDDEN_PAGE); /* undo read_cache_page */ FREE_PAGE_POINTERS(hidden_pages, num_hidden_pages); FREE_PAGEDATA_POINTERS(hidden_pages_data, num_hidden_pages);out: if (err == 0) SetPageUptodate(page); else ClearPageUptodate(page); print_exit_status(err); return err;}STATIC intwrapfs_readpage(file_t *file, page_t *page){ int err; print_entry_location(); err = wrapfs_do_readpage(file, page); /* * we have to unlock our page, b/c we _might_ have gotten a locked page. * but we no longer have to wakeup on our page here, b/c UnlockPage does * it */ UnlockPage(page); print_exit_status(err); return err;}STATIC intwrapfs_prepare_write(file_t *file, page_t *page, unsigned from, unsigned to){ int err = 0; print_entry_location(); /* * we call kmap(page) only here, and do the kunmap * and the actual downcalls, including unlockpage and uncache * in commit_write. */ kmap(page); /* fast path for whole page writes */ if (from == 0 && to == PAGE_CACHE_SIZE) goto out; /* read the page to "revalidate" our data */ /* call the helper function which doesn't unlock the page */ if (!Page_Uptodate(page)) err = wrapfs_do_readpage(file, page); out: print_exit_status(err); return err;}#ifdef FIST_FILTER_SCA/* * shift data inwards; return 0 if ok or -errno */int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -