📄 mmap.c
字号:
cur_ep = &(*cur_ep)->next; *cur_ep = NULL; if (err < 0) goto out_free; hidden_size += err; if (current->need_resched) schedule(); } old_hidden_size = HIDDEN_PAGE_LENGTH(page->index, inode); hidden_offset = HIDDEN_PAGE_STARTING_OFFSET(page->index, inode); delta = old_hidden_size - hidden_size; if (delta != 0) { /* * update hidden size by delta * * Note! we take a snapshot of the i_size *before* we go * into shift_* as those functions can change it; however, * we only actually *write* it to disk after all is done */ attr.ia_size = hidden_inode->i_size - delta; if (inode->i_size > page_offset + PAGE_CACHE_SIZE) { /* this is write-in-the-middle */ if (delta > 0) {# ifdef FIST_COUNT_WRITES count_writes_middle++; printk("WITM:%lu:%lu:%lu:%lu:\n", (unsigned long) page_offset, (unsigned long) inode->i_size, count_writes, count_writes_middle);# endif /* FIST_COUNT_WRITES */ /* shift inwards */ err = wrapfs_shift_inward(hidden_file, hidden_offset + hidden_size, hidden_offset + old_hidden_size, hidden_inode->i_size - (hidden_offset + old_hidden_size)); if (err < 0) goto out_free; } else { /* shift outwards from the end */ err = wrapfs_shift_outward(hidden_file, hidden_offset + hidden_size, hidden_offset + old_hidden_size, hidden_inode->i_size - (hidden_offset + old_hidden_size)); if (err < 0) goto out_free; } } else { /* this is append and/or extend */ if (page->index >= hdr->num_chunks && hdr->num_chunks > 0 && (hdr->real_size & ~PAGE_CACHE_MASK) != 0) { /* we need to encode the former incomplete tail */ page_t *old_last_page; char *old_last_page_data; int temp_size; struct encoded_page *temp_ep = NULL; old_last_page = wrapfs_get1page(file, hdr->num_chunks - 1); if (IS_ERR(old_last_page)) { err = PTR_ERR(old_last_page); goto out_free; } old_last_page_data = (char *) kmap(old_last_page); temp_size = 0; need_to_call = 1; cur_ep = &temp_ep; opaque = NULL; while (need_to_call) { *cur_ep = kmalloc(sizeof(struct encoded_page), GFP_KERNEL); if (!*cur_ep) { err = -ENOMEM; goto out_free; } (*cur_ep)->data = (char *) __get_free_page(GFP_KERNEL); err = wrapfs_encode_buffers((*cur_ep)->data, old_last_page_data, &need_to_call, PAGE_CACHE_SIZE, inode, inode->i_sb, &opaque); cur_ep = &(*cur_ep)->next; *cur_ep = NULL; if (err < 0) goto encode_error; temp_size += err; if (current->need_resched) schedule(); } old_hidden_offset = HIDDEN_PAGE_STARTING_OFFSET(old_last_page->index, inode); err = wrapfs_copy_encoded_data(hidden_file, old_hidden_offset, temp_ep, temp_size); if (err < 0) goto encode_error; /* adjust hidden_offset */ hidden_offset = old_hidden_offset + temp_size; wrapfs_idx_set_entry(hdr, hdr->num_chunks - 1, hidden_offset); /* Calculate new hidden file size */ attr.ia_size = hidden_offset + hidden_size; encode_error: /* free encoded_pages */ while (temp_ep) { next_ep = temp_ep->next; free_page((unsigned long) temp_ep->data); kfree(temp_ep); temp_ep = next_ep; } kunmap(old_last_page); page_cache_release(old_last_page); if (err < 0) goto out_free; } } /* update index table structure */ err = wrapfs_idx_set_entry(hdr, page->index, hidden_offset + hidden_size); if (err < 0) goto out_free; attr.ia_valid = ATTR_SIZE; err = notify_change(hidden_dentry, &attr); if (err < 0) goto out_free; /* update header information by delta */ wrapfs_idx_update(hdr, page->index + 1, -delta); } /* * copy chunk of modified bytes, now that we've * potentially shifted and made space */ err = wrapfs_copy_encoded_data(hidden_file, hidden_offset, ep, hidden_size); if (err < 0) goto out; /* we return number of bytes written */ err = to - from; /* we may have to update the header size */ pos = (page->index << PAGE_CACHE_SHIFT) + to; if (pos > hdr->real_size) hdr->real_size = pos; /* update our file size */ copy_inode_size(inode, hidden_inode); /* * 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;out_free: /* free encoded_pages */ while (ep) { next_ep = ep->next; free_page((unsigned long) ep->data); kfree(ep); ep = next_ep; }out: /* final cleanups */ kunmap(page); /* kmap was done in prepare_write */ if (err < 0) ClearPageUptodate(page); else SetPageUptodate(page); up(&hidden_inode->i_sem); print_exit_status(err); return err; /* assume all is ok */}#else /* not FIST_FILTER_SCA */STATIC intwrapfs_commit_write(file_t *file, page_t *page, unsigned from, unsigned to){ int err = -ENOMEM; inode_t *inode; inode_t *hidden_inode; page_t *hidden_page; file_t *hidden_file = NULL; loff_t pos; unsigned bytes = to - from; unsigned hidden_from, hidden_to, hidden_bytes; print_entry_location(); inode = page->mapping->host; /* CPW: Moved below print_entry_location */ hidden_inode = itohi(inode); ASSERT(file != NULL); /* * here we have a kmapped page, with data from the user copied * into it. we need to encode_block it, and then call the lower * commit_write. We also need to simulate same behavior of * generic_file_write, and call prepare_write on the lower f/s first. */# ifdef FIST_COUNT_WRITES count_writes++;# endif /* FIST_COUNT_WRITES */ /* this is append and/or extend -- we can't have holes so fill them in */ if (page->index > (hidden_inode->i_size >> PAGE_CACHE_SHIFT)) { page_t *tmp_page; int index; for (index = hidden_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 the contents of the page at 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(); } } hidden_file = ftohf(file); down(&hidden_inode->i_sem); /* find lower page (returns a locked page) */ hidden_page = grab_cache_page(hidden_inode->i_mapping, page->index); if (!hidden_page) goto out;#if FIST_ENCODING_BLOCKSIZE > 1#error encoding_blocksize greater than 1 is not yet supported#endif /* FIST_ENCODING_BLOCKSIZE > 1 */#ifdef FIST_ENCODING_TYPE_NONE hidden_from = from; hidden_to = to; if ((page->index << PAGE_CACHE_SHIFT) + to > hidden_inode->i_size) { /* * If this call to commit_write had introduced holes and the code * for handling holes was invoked, then the beginning of this page * must be zeroed out as well: * zero out bytes from 'size_of_file%pagesize' to 'from'. */ 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)); }#endif /* FIST_ENCODING_TYPE_NONE */#ifdef FIST_ENCODING_TYPE_STREAM hidden_from = 0; if ((page->index << PAGE_CACHE_SHIFT) + to > hidden_inode->i_size) { /* * If this call to commit_write had introduced holes and the code * for handling holes was invoked, then the beginning of this page * must be zeroed out as well: * zero out bytes from 'size_of_file%pagesize' to 'from'. */ 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)); hidden_to = to; } else if (((page->index + 1) << PAGE_CACHE_SHIFT) <= hidden_inode->i_size) hidden_to = PAGE_CACHE_SIZE; else hidden_to = hidden_inode->i_size & ~PAGE_CACHE_MASK;#endif /* FIST_ENCODING_TYPE_STREAM */#ifdef FIST_ENCODING_TYPE_BLOCK hidden_from = from & (~(FIST_ENCODING_BLOCKSIZE - 1)); hidden_to = ((to + FIST_ENCODING_BLOCKSIZE - 1) & (~(FIST_ENCODING_BLOCKSIZE - 1))); if ((page->index << PAGE_CACHE_SHIFT) + to > hidden_inode->i_size) { /* * if this call to commit_write had introduced holes and the code * for handling holes was invoked, then the beginning of this page * must be zeroed out * zero out bytes from 'size_of_file%pagesize' to 'from'. */ if ((hidden_from - (inode->i_size & ~PAGE_CACHE_MASK)) > 0) memset((char*)page_address(page) + (inode->i_size & ~PAGE_CACHE_MASK), 0, hidden_from - (inode->i_size & ~PAGE_CACHE_MASK)); }#endif /* FIST_ENCODING_TYPE_NONE */ hidden_bytes = hidden_to - hidden_from; /* call lower prepare_write */ err = -EINVAL; if (hidden_inode->i_mapping && hidden_inode->i_mapping->a_ops && hidden_inode->i_mapping->a_ops->prepare_write) err = hidden_inode->i_mapping->a_ops->prepare_write(hidden_file, hidden_page, hidden_from, hidden_to); if (err) /* don't leave locked pages behind, esp. on an ENOSPC */ goto out_unlock; fist_dprint(8, "%s: encoding %d bytes\n", __FUNCTION__, hidden_bytes); wrapfs_encode_block((char *) page_address(page) + hidden_from, (char*) page_address(hidden_page) + hidden_from, hidden_bytes, inode, inode->i_sb, page->index); /* if encode_block could fail, then goto unlock and return error */ /* call lower commit_write */ err = hidden_inode->i_mapping->a_ops->commit_write(hidden_file, hidden_page, hidden_from, hidden_to); if (err < 0) goto out_unlock; err = bytes; /* convert error to no. of bytes */ inode->i_blocks = hidden_inode->i_blocks; /* we may have to update i_size */ pos = (page->index << PAGE_CACHE_SHIFT) + to; if (pos > inode->i_size) inode->i_size = pos; /* * 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; mark_inode_dirty_sync(inode);out_unlock: UnlockPage(hidden_page); page_cache_release(hidden_page); kunmap(page); /* kmap was done in prepare_write */out: /* we must set our page as up-to-date */ if (err < 0) ClearPageUptodate(page); else SetPageUptodate(page); up(&hidden_inode->i_sem); print_exit_status(err); return err; /* assume all is ok */}#endif /* not FIST_FILTER_SCA */STATIC intwrapfs_bmap(struct address_space *mapping, long block){ int err = 0; inode_t *inode; inode_t *hidden_inode; print_entry_location(); inode = (inode_t *) mapping->host; hidden_inode = itohi(inode); if (hidden_inode->i_mapping->a_ops->bmap) err = hidden_inode->i_mapping->a_ops->bmap(hidden_inode->i_mapping, block); print_exit_location(); return err;}/* * This function is copied verbatim from mm/filemap.c. * XXX: It should be simply moved to some header file instead -- bug Al about it! */static inline int sync_page(struct page *page){ struct address_space *mapping = page->mapping; if (mapping && mapping->a_ops && mapping->a_ops->sync_page) return mapping->a_ops->sync_page(page); return 0;}/* * XXX: we may not need this function if not FIST_FILTER_DATA. * FIXME: for FIST_FILTER_SCA, get all lower pages and sync them each. */STATIC intwrapfs_sync_page(page_t *page){ int err = 0; inode_t *inode; inode_t *hidden_inode; page_t *hidden_page; print_entry_location(); inode = page->mapping->host; /* CPW: Moved below print_entry_location */ hidden_inode = itohi(inode); /* find lower page (returns a locked page) */ hidden_page = grab_cache_page(hidden_inode->i_mapping, page->index); if (!hidden_page) goto out; err = sync_page(hidden_page); UnlockPage(hidden_page); /* b/c grab_cache_page locked it */ page_cache_release(hidden_page); /* b/c grab_cache_page increased refcnt */out: print_exit_location(); return err;}#ifdef FIST_FILTER_DATAstruct address_space_operations wrapfs_aops ={#ifndef FIST_FILTER_SCA writepage: wrapfs_writepage,#endif /* not FIST_FILTER_SCA */ readpage: wrapfs_readpage, prepare_write: wrapfs_prepare_write, commit_write: wrapfs_commit_write, bmap: wrapfs_bmap, sync_page: wrapfs_sync_page,};#endif /* FIST_FILTER_DATA *//* * Local variables: * c-basic-offset: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -