aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/affs/file.c101
1 files changed, 59 insertions, 42 deletions
diff --git a/fs/affs/file.c b/fs/affs/file.c
index c314a35f0918..6e0c9399200e 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -395,25 +395,33 @@ static int affs_writepage(struct page *page, struct writeback_control *wbc)
395{ 395{
396 return block_write_full_page(page, affs_get_block, wbc); 396 return block_write_full_page(page, affs_get_block, wbc);
397} 397}
398
398static int affs_readpage(struct file *file, struct page *page) 399static int affs_readpage(struct file *file, struct page *page)
399{ 400{
400 return block_read_full_page(page, affs_get_block); 401 return block_read_full_page(page, affs_get_block);
401} 402}
402static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) 403
404static int affs_write_begin(struct file *file, struct address_space *mapping,
405 loff_t pos, unsigned len, unsigned flags,
406 struct page **pagep, void **fsdata)
403{ 407{
404 return cont_prepare_write(page, from, to, affs_get_block, 408 *pagep = NULL;
405 &AFFS_I(page->mapping->host)->mmu_private); 409 return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
410 affs_get_block,
411 &AFFS_I(mapping->host)->mmu_private);
406} 412}
413
407static sector_t _affs_bmap(struct address_space *mapping, sector_t block) 414static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
408{ 415{
409 return generic_block_bmap(mapping,block,affs_get_block); 416 return generic_block_bmap(mapping,block,affs_get_block);
410} 417}
418
411const struct address_space_operations affs_aops = { 419const struct address_space_operations affs_aops = {
412 .readpage = affs_readpage, 420 .readpage = affs_readpage,
413 .writepage = affs_writepage, 421 .writepage = affs_writepage,
414 .sync_page = block_sync_page, 422 .sync_page = block_sync_page,
415 .prepare_write = affs_prepare_write, 423 .write_begin = affs_write_begin,
416 .commit_write = generic_commit_write, 424 .write_end = generic_write_end,
417 .bmap = _affs_bmap 425 .bmap = _affs_bmap
418}; 426};
419 427
@@ -603,54 +611,65 @@ affs_readpage_ofs(struct file *file, struct page *page)
603 return err; 611 return err;
604} 612}
605 613
606static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to) 614static int affs_write_begin_ofs(struct file *file, struct address_space *mapping,
615 loff_t pos, unsigned len, unsigned flags,
616 struct page **pagep, void **fsdata)
607{ 617{
608 struct inode *inode = page->mapping->host; 618 struct inode *inode = mapping->host;
609 u32 size, offset; 619 struct page *page;
610 u32 tmp; 620 pgoff_t index;
611 int err = 0; 621 int err = 0;
612 622
613 pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); 623 pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len);
614 offset = page->index << PAGE_CACHE_SHIFT; 624 if (pos > AFFS_I(inode)->mmu_private) {
615 if (offset + from > AFFS_I(inode)->mmu_private) { 625 /* XXX: this probably leaves a too-big i_size in case of
616 err = affs_extent_file_ofs(inode, offset + from); 626 * failure. Should really be updating i_size at write_end time
627 */
628 err = affs_extent_file_ofs(inode, pos);
617 if (err) 629 if (err)
618 return err; 630 return err;
619 } 631 }
620 size = inode->i_size; 632
633 index = pos >> PAGE_CACHE_SHIFT;
634 page = __grab_cache_page(mapping, index);
635 if (!page)
636 return -ENOMEM;
637 *pagep = page;
621 638
622 if (PageUptodate(page)) 639 if (PageUptodate(page))
623 return 0; 640 return 0;
624 641
625 if (from) { 642 /* XXX: inefficient but safe in the face of short writes */
626 err = affs_do_readpage_ofs(file, page, 0, from); 643 err = affs_do_readpage_ofs(file, page, 0, PAGE_CACHE_SIZE);
627 if (err) 644 if (err) {
628 return err; 645 unlock_page(page);
629 } 646 page_cache_release(page);
630 if (to < PAGE_CACHE_SIZE) {
631 zero_user_page(page, to, PAGE_CACHE_SIZE - to, KM_USER0);
632 if (size > offset + to) {
633 if (size < offset + PAGE_CACHE_SIZE)
634 tmp = size & ~PAGE_CACHE_MASK;
635 else
636 tmp = PAGE_CACHE_SIZE;
637 err = affs_do_readpage_ofs(file, page, to, tmp);
638 }
639 } 647 }
640 return err; 648 return err;
641} 649}
642 650
643static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to) 651static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
652 loff_t pos, unsigned len, unsigned copied,
653 struct page *page, void *fsdata)
644{ 654{
645 struct inode *inode = page->mapping->host; 655 struct inode *inode = mapping->host;
646 struct super_block *sb = inode->i_sb; 656 struct super_block *sb = inode->i_sb;
647 struct buffer_head *bh, *prev_bh; 657 struct buffer_head *bh, *prev_bh;
648 char *data; 658 char *data;
649 u32 bidx, boff, bsize; 659 u32 bidx, boff, bsize;
660 unsigned from, to;
650 u32 tmp; 661 u32 tmp;
651 int written; 662 int written;
652 663
653 pr_debug("AFFS: commit_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); 664 from = pos & (PAGE_CACHE_SIZE - 1);
665 to = pos + len;
666 /*
667 * XXX: not sure if this can handle short copies (len < copied), but
668 * we don't have to, because the page should always be uptodate here,
669 * due to write_begin.
670 */
671
672 pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len);
654 bsize = AFFS_SB(sb)->s_data_blksize; 673 bsize = AFFS_SB(sb)->s_data_blksize;
655 data = page_address(page); 674 data = page_address(page);
656 675
@@ -748,6 +767,9 @@ done:
748 if (tmp > inode->i_size) 767 if (tmp > inode->i_size)
749 inode->i_size = AFFS_I(inode)->mmu_private = tmp; 768 inode->i_size = AFFS_I(inode)->mmu_private = tmp;
750 769
770 unlock_page(page);
771 page_cache_release(page);
772
751 return written; 773 return written;
752 774
753out: 775out:
@@ -761,8 +783,8 @@ const struct address_space_operations affs_aops_ofs = {
761 .readpage = affs_readpage_ofs, 783 .readpage = affs_readpage_ofs,
762 //.writepage = affs_writepage_ofs, 784 //.writepage = affs_writepage_ofs,
763 //.sync_page = affs_sync_page_ofs, 785 //.sync_page = affs_sync_page_ofs,
764 .prepare_write = affs_prepare_write_ofs, 786 .write_begin = affs_write_begin_ofs,
765 .commit_write = affs_commit_write_ofs 787 .write_end = affs_write_end_ofs
766}; 788};
767 789
768/* Free any preallocated blocks. */ 790/* Free any preallocated blocks. */
@@ -805,18 +827,13 @@ affs_truncate(struct inode *inode)
805 if (inode->i_size > AFFS_I(inode)->mmu_private) { 827 if (inode->i_size > AFFS_I(inode)->mmu_private) {
806 struct address_space *mapping = inode->i_mapping; 828 struct address_space *mapping = inode->i_mapping;
807 struct page *page; 829 struct page *page;
808 u32 size = inode->i_size - 1; 830 void *fsdata;
831 u32 size = inode->i_size;
809 int res; 832 int res;
810 833
811 page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT); 834 res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata);
812 if (!page)
813 return;
814 size = (size & (PAGE_CACHE_SIZE - 1)) + 1;
815 res = mapping->a_ops->prepare_write(NULL, page, size, size);
816 if (!res) 835 if (!res)
817 res = mapping->a_ops->commit_write(NULL, page, size, size); 836 res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata);
818 unlock_page(page);
819 page_cache_release(page);
820 mark_inode_dirty(inode); 837 mark_inode_dirty(inode);
821 return; 838 return;
822 } else if (inode->i_size == AFFS_I(inode)->mmu_private) 839 } else if (inode->i_size == AFFS_I(inode)->mmu_private)