diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-06-15 13:50:00 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-06-15 13:50:00 -0400 |
commit | 9ebefb180bad4914a31c4e1748ba187a30e1e990 (patch) | |
tree | 68d4833889fac64b1b69e6212afa9584cc88f2ff /fs/btrfs/file.c | |
parent | f1ace244c8c1e16eaa5c8b3b5339849651e31ede (diff) |
Btrfs: patch queue: page_mkwrite
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 176 |
1 files changed, 26 insertions, 150 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 83836fb3d4e9..de8d47b44e12 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -103,10 +103,6 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
103 | this_write = min((size_t)PAGE_CACHE_SIZE - offset, write_bytes); | 103 | this_write = min((size_t)PAGE_CACHE_SIZE - offset, write_bytes); |
104 | /* FIXME, one block at a time */ | 104 | /* FIXME, one block at a time */ |
105 | 105 | ||
106 | mutex_lock(&root->fs_info->fs_mutex); | ||
107 | trans = btrfs_start_transaction(root, 1); | ||
108 | btrfs_set_trans_block_group(trans, inode); | ||
109 | |||
110 | bh = page_buffers(pages[i]); | 106 | bh = page_buffers(pages[i]); |
111 | 107 | ||
112 | if (buffer_mapped(bh) && bh->b_blocknr == 0) { | 108 | if (buffer_mapped(bh) && bh->b_blocknr == 0) { |
@@ -115,6 +111,10 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
115 | char *ptr, *kaddr; | 111 | char *ptr, *kaddr; |
116 | u32 datasize; | 112 | u32 datasize; |
117 | 113 | ||
114 | mutex_lock(&root->fs_info->fs_mutex); | ||
115 | trans = btrfs_start_transaction(root, 1); | ||
116 | btrfs_set_trans_block_group(trans, inode); | ||
117 | |||
118 | /* create an inline extent, and copy the data in */ | 118 | /* create an inline extent, and copy the data in */ |
119 | path = btrfs_alloc_path(); | 119 | path = btrfs_alloc_path(); |
120 | BUG_ON(!path); | 120 | BUG_ON(!path); |
@@ -135,24 +135,19 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
135 | btrfs_set_file_extent_type(ei, | 135 | btrfs_set_file_extent_type(ei, |
136 | BTRFS_FILE_EXTENT_INLINE); | 136 | BTRFS_FILE_EXTENT_INLINE); |
137 | ptr = btrfs_file_extent_inline_start(ei); | 137 | ptr = btrfs_file_extent_inline_start(ei); |
138 | |||
138 | kaddr = kmap_atomic(bh->b_page, KM_USER0); | 139 | kaddr = kmap_atomic(bh->b_page, KM_USER0); |
139 | btrfs_memcpy(root, path->nodes[0]->b_data, | 140 | btrfs_memcpy(root, path->nodes[0]->b_data, |
140 | ptr, kaddr + bh_offset(bh), | 141 | ptr, kaddr + bh_offset(bh), |
141 | offset + write_bytes); | 142 | offset + write_bytes); |
142 | kunmap_atomic(kaddr, KM_USER0); | 143 | kunmap_atomic(kaddr, KM_USER0); |
144 | |||
143 | mark_buffer_dirty(path->nodes[0]); | 145 | mark_buffer_dirty(path->nodes[0]); |
144 | btrfs_free_path(path); | 146 | btrfs_free_path(path); |
145 | } else if (buffer_mapped(bh)) { | 147 | ret = btrfs_end_transaction(trans, root); |
146 | /* csum the file data */ | 148 | BUG_ON(ret); |
147 | btrfs_csum_file_block(trans, root, inode->i_ino, | 149 | mutex_unlock(&root->fs_info->fs_mutex); |
148 | pages[i]->index << PAGE_CACHE_SHIFT, | ||
149 | kmap(pages[i]), PAGE_CACHE_SIZE); | ||
150 | kunmap(pages[i]); | ||
151 | } | 150 | } |
152 | SetPageChecked(pages[i]); | ||
153 | ret = btrfs_end_transaction(trans, root); | ||
154 | BUG_ON(ret); | ||
155 | mutex_unlock(&root->fs_info->fs_mutex); | ||
156 | 151 | ||
157 | ret = btrfs_commit_write(file, pages[i], offset, | 152 | ret = btrfs_commit_write(file, pages[i], offset, |
158 | offset + this_write); | 153 | offset + this_write); |
@@ -503,7 +498,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
503 | if ((pos & (PAGE_CACHE_SIZE - 1))) { | 498 | if ((pos & (PAGE_CACHE_SIZE - 1))) { |
504 | pinned[0] = grab_cache_page(inode->i_mapping, first_index); | 499 | pinned[0] = grab_cache_page(inode->i_mapping, first_index); |
505 | if (!PageUptodate(pinned[0])) { | 500 | if (!PageUptodate(pinned[0])) { |
506 | ret = mpage_readpage(pinned[0], btrfs_get_block); | 501 | ret = btrfs_readpage(NULL, pinned[0]); |
507 | BUG_ON(ret); | 502 | BUG_ON(ret); |
508 | wait_on_page_locked(pinned[0]); | 503 | wait_on_page_locked(pinned[0]); |
509 | } else { | 504 | } else { |
@@ -513,7 +508,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
513 | if ((pos + count) & (PAGE_CACHE_SIZE - 1)) { | 508 | if ((pos + count) & (PAGE_CACHE_SIZE - 1)) { |
514 | pinned[1] = grab_cache_page(inode->i_mapping, last_index); | 509 | pinned[1] = grab_cache_page(inode->i_mapping, last_index); |
515 | if (!PageUptodate(pinned[1])) { | 510 | if (!PageUptodate(pinned[1])) { |
516 | ret = mpage_readpage(pinned[1], btrfs_get_block); | 511 | ret = btrfs_readpage(NULL, pinned[1]); |
517 | BUG_ON(ret); | 512 | BUG_ON(ret); |
518 | wait_on_page_locked(pinned[1]); | 513 | wait_on_page_locked(pinned[1]); |
519 | } else { | 514 | } else { |
@@ -633,138 +628,6 @@ out: | |||
633 | return num_written ? num_written : err; | 628 | return num_written ? num_written : err; |
634 | } | 629 | } |
635 | 630 | ||
636 | /* | ||
637 | * FIXME, do this by stuffing the csum we want in the info hanging off | ||
638 | * page->private. For now, verify file csums on read | ||
639 | */ | ||
640 | static int btrfs_read_actor(read_descriptor_t *desc, struct page *page, | ||
641 | unsigned long offset, unsigned long size) | ||
642 | { | ||
643 | char *kaddr; | ||
644 | unsigned long left, count = desc->count; | ||
645 | struct inode *inode = page->mapping->host; | ||
646 | |||
647 | if (size > count) | ||
648 | size = count; | ||
649 | |||
650 | if (!PageChecked(page)) { | ||
651 | /* FIXME, do it per block */ | ||
652 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
653 | int ret; | ||
654 | struct buffer_head *bh; | ||
655 | |||
656 | if (page_has_buffers(page)) { | ||
657 | bh = page_buffers(page); | ||
658 | if (!buffer_mapped(bh)) { | ||
659 | SetPageChecked(page); | ||
660 | goto checked; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | ret = btrfs_csum_verify_file_block(root, | ||
665 | page->mapping->host->i_ino, | ||
666 | page->index << PAGE_CACHE_SHIFT, | ||
667 | kmap(page), PAGE_CACHE_SIZE); | ||
668 | if (ret) { | ||
669 | if (ret != -ENOENT) { | ||
670 | printk("failed to verify ino %lu page %lu ret %d\n", | ||
671 | page->mapping->host->i_ino, | ||
672 | page->index, ret); | ||
673 | memset(page_address(page), 1, PAGE_CACHE_SIZE); | ||
674 | flush_dcache_page(page); | ||
675 | } | ||
676 | } | ||
677 | SetPageChecked(page); | ||
678 | kunmap(page); | ||
679 | } | ||
680 | checked: | ||
681 | /* | ||
682 | * Faults on the destination of a read are common, so do it before | ||
683 | * taking the kmap. | ||
684 | */ | ||
685 | if (!fault_in_pages_writeable(desc->arg.buf, size)) { | ||
686 | kaddr = kmap_atomic(page, KM_USER0); | ||
687 | left = __copy_to_user_inatomic(desc->arg.buf, | ||
688 | kaddr + offset, size); | ||
689 | kunmap_atomic(kaddr, KM_USER0); | ||
690 | if (left == 0) | ||
691 | goto success; | ||
692 | } | ||
693 | |||
694 | /* Do it the slow way */ | ||
695 | kaddr = kmap(page); | ||
696 | left = __copy_to_user(desc->arg.buf, kaddr + offset, size); | ||
697 | kunmap(page); | ||
698 | |||
699 | if (left) { | ||
700 | size -= left; | ||
701 | desc->error = -EFAULT; | ||
702 | } | ||
703 | success: | ||
704 | desc->count = count - size; | ||
705 | desc->written += size; | ||
706 | desc->arg.buf += size; | ||
707 | return size; | ||
708 | } | ||
709 | |||
710 | /** | ||
711 | * btrfs_file_aio_read - filesystem read routine, with a mod to csum verify | ||
712 | * @iocb: kernel I/O control block | ||
713 | * @iov: io vector request | ||
714 | * @nr_segs: number of segments in the iovec | ||
715 | * @pos: current file position | ||
716 | */ | ||
717 | static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | ||
718 | unsigned long nr_segs, loff_t pos) | ||
719 | { | ||
720 | struct file *filp = iocb->ki_filp; | ||
721 | ssize_t retval; | ||
722 | unsigned long seg; | ||
723 | size_t count; | ||
724 | loff_t *ppos = &iocb->ki_pos; | ||
725 | |||
726 | count = 0; | ||
727 | for (seg = 0; seg < nr_segs; seg++) { | ||
728 | const struct iovec *iv = &iov[seg]; | ||
729 | |||
730 | /* | ||
731 | * If any segment has a negative length, or the cumulative | ||
732 | * length ever wraps negative then return -EINVAL. | ||
733 | */ | ||
734 | count += iv->iov_len; | ||
735 | if (unlikely((ssize_t)(count|iv->iov_len) < 0)) | ||
736 | return -EINVAL; | ||
737 | if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len)) | ||
738 | continue; | ||
739 | if (seg == 0) | ||
740 | return -EFAULT; | ||
741 | nr_segs = seg; | ||
742 | count -= iv->iov_len; /* This segment is no good */ | ||
743 | break; | ||
744 | } | ||
745 | retval = 0; | ||
746 | if (count) { | ||
747 | for (seg = 0; seg < nr_segs; seg++) { | ||
748 | read_descriptor_t desc; | ||
749 | |||
750 | desc.written = 0; | ||
751 | desc.arg.buf = iov[seg].iov_base; | ||
752 | desc.count = iov[seg].iov_len; | ||
753 | if (desc.count == 0) | ||
754 | continue; | ||
755 | desc.error = 0; | ||
756 | do_generic_file_read(filp, ppos, &desc, | ||
757 | btrfs_read_actor); | ||
758 | retval += desc.written; | ||
759 | if (desc.error) { | ||
760 | retval = retval ?: desc.error; | ||
761 | break; | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | return retval; | ||
766 | } | ||
767 | |||
768 | static int btrfs_sync_file(struct file *file, | 631 | static int btrfs_sync_file(struct file *file, |
769 | struct dentry *dentry, int datasync) | 632 | struct dentry *dentry, int datasync) |
770 | { | 633 | { |
@@ -789,12 +652,25 @@ out: | |||
789 | return ret > 0 ? EIO : ret; | 652 | return ret > 0 ? EIO : ret; |
790 | } | 653 | } |
791 | 654 | ||
655 | static struct vm_operations_struct btrfs_file_vm_ops = { | ||
656 | .nopage = filemap_nopage, | ||
657 | .populate = filemap_populate, | ||
658 | .page_mkwrite = btrfs_page_mkwrite, | ||
659 | }; | ||
660 | |||
661 | static int btrfs_file_mmap(struct file *filp, struct vm_area_struct *vma) | ||
662 | { | ||
663 | vma->vm_ops = &btrfs_file_vm_ops; | ||
664 | file_accessed(filp); | ||
665 | return 0; | ||
666 | } | ||
667 | |||
792 | struct file_operations btrfs_file_operations = { | 668 | struct file_operations btrfs_file_operations = { |
793 | .llseek = generic_file_llseek, | 669 | .llseek = generic_file_llseek, |
794 | .read = do_sync_read, | 670 | .read = do_sync_read, |
795 | .aio_read = btrfs_file_aio_read, | 671 | .aio_read = generic_file_aio_read, |
796 | .write = btrfs_file_write, | 672 | .write = btrfs_file_write, |
797 | .mmap = generic_file_mmap, | 673 | .mmap = btrfs_file_mmap, |
798 | .open = generic_file_open, | 674 | .open = generic_file_open, |
799 | .ioctl = btrfs_ioctl, | 675 | .ioctl = btrfs_ioctl, |
800 | .fsync = btrfs_sync_file, | 676 | .fsync = btrfs_sync_file, |