📄 mmap.c
字号:
src_page_index--; src_page_offset = PAGE_CACHE_SIZE; src_page_bytes_left = PAGE_CACHE_SIZE; fist_dprint(8, __FUNCTION__ " src: index=%d, offset=%d, bytesleft=%d\n", src_page_index, src_page_offset, src_page_bytes_left); 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); } } /* end of "while (1)" */ out_release: page_cache_release(dst_page); page_cache_release(src_page); out: print_exit_status(err); return err;}/* * copy data bytes; return 0 if ok or -errno */intwrapfs_copy_encoded_data(file_t *file, /* hidden file */ off_t dst_offset, /* where to copy to (abs offset) */ encoded_pages_t *encoded_pages, off_t total_bytes_to_copy){ int dst_page_index; unsigned int dst_page_offset, src_page_offset; page_t *dst_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(); // XXX: check errors // printk("EZK0: total_bytes_to_copy 0x%x\n", (int) total_bytes_to_copy); /* compute page indices */ dst_page_index = dst_offset >> PAGE_CACHE_SHIFT; /* compute offsets within pages */ dst_page_offset = dst_offset & ~PAGE_CACHE_MASK; src_page_offset = 0; /* compute number of bytes left in pages */ dst_page_bytes_left = PAGE_CACHE_SIZE - dst_page_offset; src_page_bytes_left = PAGE_CACHE_SIZE; /* adjusted below */ /* get pages */ dst_page = wrapfs_get1page(file, dst_page_index); if (IS_ERR(dst_page)) { err = PTR_ERR(dst_page); goto out; } /* map pages into kernel addresses */ src_kaddr = encoded_pages->data; 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_copy); 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_copy -= bytes_to_copy; // printk("EZK1: total_bytes_to_copy 0x%x\n", (int) total_bytes_to_copy); if (total_bytes_to_copy == 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)) { 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 */ src_page_offset = 0; src_page_bytes_left = PAGE_CACHE_SIZE; encoded_pages = encoded_pages->next; src_kaddr = encoded_pages->data; } else { src_page_offset += bytes_to_copy; } } /* end of "while (1)" */ out_release: page_cache_release(dst_page); out: print_exit_status(err); return err;}STATIC intwrapfs_commit_write(file_t *file, page_t *page, unsigned from, unsigned to){ int err; inode_t *inode = (inode_t *) page->mapping->host; inode_t *hidden_inode = itohi(inode); file_t *hidden_file = NULL; loff_t pos = 0; struct encoded_page *ep = NULL, *next_ep, **cur_ep; unsigned real_to, hidden_size, page_offset; struct iattr attr; void *opaque = NULL; off_t old_hidden_size, hidden_offset, old_hidden_offset, delta; dentry_t *hidden_dentry; struct scafs_header *hdr; int need_to_call = 1; print_entry_location(); ASSERT(file != NULL); hidden_file = ftohf(file); hidden_dentry = hidden_file->f_dentry; down(&hidden_inode->i_sem); /* * 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 */ hdr = &itopd(inode)->hdr; page_offset = page->index << PAGE_CACHE_SHIFT; if (inode->i_size > page_offset + to) if (inode->i_size > page_offset + PAGE_CACHE_SIZE) real_to = PAGE_CACHE_SIZE; else real_to = inode->i_size - page_offset; else real_to = to; hidden_size = 0; cur_ep = &ep; while (need_to_call) { *cur_ep = kmalloc(sizeof(struct encoded_page), GFP_KERNEL); (*cur_ep)->data = (char *) __get_free_page(GFP_KERNEL);#ifdef FIST_FAST_TAILS if (CAN_BE_FASTTAIL_PAGE(real_to, inode) && page->index + 1 >= hdr->num_chunks) { memcpy((*cur_ep)->data, (char *) page_address(page), real_to); need_to_call = 0; err = real_to; hdr->flags |= SCA_FLAG_FASTTAIL; } else#endif /* FIST_FAST_TAILS */ { err = wrapfs_encode_buffers((*cur_ep)->data, (char *) page_address(page), &need_to_call, real_to, inode, inode->i_sb, &opaque); if (page->index + 1 >= hdr->num_chunks) hdr->flags &= ~SCA_FLAG_FASTTAIL; } cur_ep = &(*cur_ep)->next; *cur_ep = NULL; if (err < 0) goto out_free; hidden_size += err; } 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); (*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; } 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_s(temp_ep, sizeof(encoded_pages_t)); 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);out_free: /* free encoded_pages */ while (ep) { next_ep = ep->next; free_page((unsigned long) ep->data); kfree_s(ep, sizeof(encoded_pages_t)); 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 *) page->mapping->host; inode_t *hidden_inode = itohi(inode); page_t *hidden_page; file_t *hidden_file = NULL; char *hidden_kaddr; loff_t pos = 0; unsigned bytes = to - from; print_entry_location(); down(&hidden_inode->i_sem); /* * 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 */ /* find lower page (returns a locked page) */ hidden_page = grab_cache_page(hidden_inode->i_mapping, page->index); if (!hidden_page) goto out; ASSERT(file != NULL); hidden_file = ftohf(file); /* 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, from, to); if (err) { /* don't leave locked pages behind, esp. on an ENOSPC */ goto out_unlock; } /* get page address, and encode it */ hidden_kaddr = (char*) page_address(hidden_page); wrapfs_encode_block((char *) page_address(page), hidden_kaddr, PAGE_SIZE, inode, inode->i_sb); /* 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, from, to); ASSERT(err == 0 || err == bytes); /* disallow partial writes */ if (err == 0) err = bytes; /* convert error to no. of bytes */ /* we may have to update hidden_inode->i_size */ if (err >= 0) { pos = (page->index << PAGE_CACHE_SHIFT) + to; if (pos > hidden_inode->i_size) { hidden_inode->i_size = pos; } } if (hidden_inode->i_size > inode->i_size) { inode->i_size = hidden_inode->i_size; inode->i_blocks = hidden_inode->i_blocks; }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 *) mapping->host; inode_t *hidden_inode = itohi(inode); print_entry_location(); 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;}/* * XXX: we may not need this function if not FIST_FILTER_DATA. * XXX: 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 *) page->mapping->host; inode_t *hidden_inode = itohi(inode); page_t *hidden_page; print_entry_location(); /* 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;}struct address_space_operations wrapfs_aops ={ writepage: wrapfs_writepage, readpage: wrapfs_readpage, prepare_write: wrapfs_prepare_write, commit_write: wrapfs_commit_write, bmap: wrapfs_bmap, sync_page: wrapfs_sync_page,};/* * Local variables: * c-basic-offset: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -