📄 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.64 2002/12/27 20:19:02 ezk 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 */STATIC intwrapfs_writepage(file_t *file, page_t *page){ int err = -EIO; dentry_t *dentry = file->f_dentry; dentry_t *hidden_dentry = dtohd(dentry); inode_t *inode = dentry->d_inode; inode_t *hidden_inode = itohi(inode); file_t *hidden_file = ftohf(file); page_t *hidden_page; char *kaddr, *hidden_kaddr; print_entry_location(); 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);#ifdef FIST_FILTER_SCA /* XXX Do we need to do anything here? XXX This is never called...*/#else /* not FIST_FILTER_SCA */ wrapfs_encode_block(kaddr, hidden_kaddr, PAGE_SIZE, inode, inode->i_sb);#endif /* not FIST_FILTER_SCA */ /* 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_file, hidden_page); UnlockPage(hidden_page); /* b/c grab_cache_page locked it */ page_cache_release(hidden_page); /* b/c grab_cache_page increased refcnt */ if (err) ClearPageUptodate(page); else SetPageUptodate(page);out: print_exit_status(err); return err;}/* * 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->f_dentry; file_t *hidden_file = ftohf(file); dentry_t *hidden_dentry = dtohd(dentry); inode_t *inode = dentry->d_inode; inode_t *hidden_inode = itohi(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;#endif /* not FIST_FILTER_SCA */ print_entry_location(); fist_dprint(7, "requesting page %d from file %s\n", 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, "Current page index = %d\n", 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; wrapfs_decode_block(hidden_page_data, page_data, PAGE_SIZE, inode, inode->i_sb);#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 "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 */intwrapfs_shift_inward(file_t *file, /* hidden file we're shifting */ off_t dst_offset, /* where to shift to (abs offset) */ off_t src_offset, /* where to shift from (abs offset) */ off_t total_bytes_to_shift){ int dst_page_index, src_page_index; unsigned int dst_page_offset, src_page_offset; page_t *dst_page, *src_page; off_t bytes_to_copy; int dst_page_bytes_left, src_page_bytes_left; char *dst_kaddr, *src_kaddr; int err = 0; struct address_space_operations *a_ops; print_entry_location(); if (total_bytes_to_shift <= 0) { printk("wrapfs_shift_inward asked to shift %ld bytes\n", total_bytes_to_shift); goto out; } /* compute page indices */ dst_page_index = dst_offset >> PAGE_CACHE_SHIFT; src_page_index = src_offset >> PAGE_CACHE_SHIFT; /* compute offsets within pages */ dst_page_offset = dst_offset & ~PAGE_CACHE_MASK; src_page_offset = src_offset & ~PAGE_CACHE_MASK; /* compute number of bytes left in pages */ dst_page_bytes_left = PAGE_CACHE_SIZE - dst_page_offset; src_page_bytes_left = PAGE_CACHE_SIZE - src_page_offset; /* get pages */ dst_page = wrapfs_get1page(file, dst_page_index); if (IS_ERR(dst_page)) { err = PTR_ERR(dst_page); goto out; } src_page = wrapfs_get1page(file, src_page_index); if (IS_ERR(src_page)) { page_cache_release(dst_page); err = PTR_ERR(src_page); goto out; } src_kaddr = (char *) kmap(src_page); a_ops = file->f_dentry->d_inode->i_mapping->a_ops; while (1) { src_page_bytes_left = MIN(src_page_bytes_left, total_bytes_to_shift); bytes_to_copy = MIN(src_page_bytes_left, dst_page_bytes_left); /* lock destination page */ lock_page(dst_page); err = a_ops->prepare_write(file, dst_page, dst_page_offset, dst_page_offset+bytes_to_copy); if (err < 0) { /* XXX: what about partial writes */ UnlockPage(dst_page); goto out_release; } dst_kaddr = (char *) page_address(dst_page); /* actually copy some bytes */ memmove(dst_kaddr + dst_page_offset, src_kaddr + src_page_offset, bytes_to_copy); err = a_ops->commit_write(file, dst_page, dst_page_offset, dst_page_offset+bytes_to_copy); UnlockPage(dst_page); if (err) { goto out_release; } total_bytes_to_shift -= bytes_to_copy; if (total_bytes_to_shift == 0) break; /* adjust destinations as needed */ dst_page_bytes_left -= bytes_to_copy; if (dst_page_bytes_left == 0) { /* get new page */ page_cache_release(dst_page); dst_page_index++; dst_page_offset = 0; dst_page_bytes_left = PAGE_CACHE_SIZE; dst_page = wrapfs_get1page(file, dst_page_index); if (IS_ERR(dst_page)) { page_cache_release(src_page); err = PTR_ERR(dst_page); goto out; } } else { dst_page_offset += bytes_to_copy; } /* adjust sources as needed */ src_page_bytes_left -= bytes_to_copy; if (src_page_bytes_left == 0) { /* get new page */ kunmap(src_page); page_cache_release(src_page); src_page_index++; src_page_offset = 0; src_page_bytes_left = PAGE_CACHE_SIZE; src_page = wrapfs_get1page(file, src_page_index); if (IS_ERR(src_page)) { page_cache_release(dst_page); err = PTR_ERR(src_page); goto out; } src_kaddr = (char *) kmap(src_page); } else { src_page_offset += bytes_to_copy; } } /* end of "while (1)" */ out_release: page_cache_release(dst_page); page_cache_release(src_page); out: print_exit_status(err); return err;}/* * shift data inwards; return 0 if ok or -errno */intwrapfs_shift_outward(file_t *file, /* hidden file we're shifting */ off_t dst_offset, /* where to shift to (abs offset) */ off_t src_offset, /* where to shift from (abs offset) */ off_t total_bytes_to_shift){ int dst_page_index, src_page_index; unsigned int dst_page_offset, src_page_offset; page_t *dst_page, *src_page; off_t bytes_to_copy; int dst_page_bytes_left, src_page_bytes_left; char *dst_kaddr, *src_kaddr; int err = 0; struct address_space_operations *a_ops; print_entry_location(); fist_dprint(8, __FUNCTION__ " args: dst_off=%d, src_off=%d, bytes=%d\n", dst_offset, src_offset, total_bytes_to_shift); if (total_bytes_to_shift <= 0) { printk("wrapfs_shift_outward asked to shift %ld bytes\n", total_bytes_to_shift); goto out; } /* compute page indices */ dst_page_index = (dst_offset + total_bytes_to_shift) >> PAGE_CACHE_SHIFT; src_page_index = (src_offset + total_bytes_to_shift) >> PAGE_CACHE_SHIFT; /* compute offsets within pages */ dst_page_offset = (dst_offset + total_bytes_to_shift) & ~PAGE_CACHE_MASK; src_page_offset = (src_offset + total_bytes_to_shift) & ~PAGE_CACHE_MASK; /* compute number of bytes left in pages */ dst_page_bytes_left = dst_page_offset; src_page_bytes_left = src_page_offset; fist_dprint(8, __FUNCTION__ " dst: index=%d, offset=%d, bytesleft=%d\n", dst_page_index, dst_page_offset, dst_page_bytes_left); fist_dprint(8, __FUNCTION__ " src: index=%d, offset=%d, bytesleft=%d\n", src_page_index, src_page_offset, src_page_bytes_left); /* get pages */ dst_page = wrapfs_get1page(file, dst_page_index); if (IS_ERR(dst_page)) { err = PTR_ERR(dst_page); goto out; } src_page = wrapfs_get1page(file, src_page_index); if (IS_ERR(src_page)) { page_cache_release(dst_page); err = PTR_ERR(src_page); goto out; } src_kaddr = (char *) kmap(src_page); a_ops = file->f_dentry->d_inode->i_mapping->a_ops; while (1) { src_page_bytes_left = MIN(src_page_bytes_left, total_bytes_to_shift); bytes_to_copy = MIN(src_page_bytes_left, dst_page_bytes_left); dst_page_offset -= bytes_to_copy; src_page_offset -= bytes_to_copy; /* lock destination page */ lock_page(dst_page); err = a_ops->prepare_write(file, dst_page, dst_page_offset, dst_page_offset+bytes_to_copy); if (err < 0) { /* XXX: what about partial writes */ UnlockPage(dst_page); goto out_release; } dst_kaddr = (char *) page_address(dst_page); /* actually copy some bytes */ memmove(dst_kaddr + dst_page_offset, src_kaddr + src_page_offset, bytes_to_copy); err = a_ops->commit_write(file, dst_page, dst_page_offset, dst_page_offset+bytes_to_copy); UnlockPage(dst_page); if (err) { goto out_release; } total_bytes_to_shift -= bytes_to_copy; if (total_bytes_to_shift == 0) break; /* adjust destinations as needed */ dst_page_bytes_left -= bytes_to_copy; if (dst_page_bytes_left == 0) { /* get new page */ page_cache_release(dst_page); dst_page_index--; dst_page_offset = PAGE_CACHE_SIZE; dst_page_bytes_left = PAGE_CACHE_SIZE; fist_dprint(8, __FUNCTION__ " dst: index=%d, offset=%d, bytesleft=%d\n", dst_page_index, dst_page_offset, dst_page_bytes_left); dst_page = wrapfs_get1page(file, dst_page_index); if (IS_ERR(dst_page)) { page_cache_release(src_page); err = PTR_ERR(dst_page); goto out; } } /* adjust sources as needed */ src_page_bytes_left -= bytes_to_copy; if (src_page_bytes_left == 0) { /* get new page */ page_cache_release(src_page);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -