diff options
Diffstat (limited to 'fs/reiserfs/inode.c')
-rw-r--r-- | fs/reiserfs/inode.c | 176 |
1 files changed, 166 insertions, 10 deletions
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index ddde489f1cb2..21db3a705f1e 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -17,11 +17,12 @@ | |||
17 | #include <linux/mpage.h> | 17 | #include <linux/mpage.h> |
18 | #include <linux/writeback.h> | 18 | #include <linux/writeback.h> |
19 | #include <linux/quotaops.h> | 19 | #include <linux/quotaops.h> |
20 | #include <linux/swap.h> | ||
20 | 21 | ||
21 | static int reiserfs_commit_write(struct file *f, struct page *page, | 22 | int reiserfs_commit_write(struct file *f, struct page *page, |
22 | unsigned from, unsigned to); | 23 | unsigned from, unsigned to); |
23 | static int reiserfs_prepare_write(struct file *f, struct page *page, | 24 | int reiserfs_prepare_write(struct file *f, struct page *page, |
24 | unsigned from, unsigned to); | 25 | unsigned from, unsigned to); |
25 | 26 | ||
26 | void reiserfs_delete_inode(struct inode *inode) | 27 | void reiserfs_delete_inode(struct inode *inode) |
27 | { | 28 | { |
@@ -2550,8 +2551,71 @@ static int reiserfs_writepage(struct page *page, struct writeback_control *wbc) | |||
2550 | return reiserfs_write_full_page(page, wbc); | 2551 | return reiserfs_write_full_page(page, wbc); |
2551 | } | 2552 | } |
2552 | 2553 | ||
2553 | static int reiserfs_prepare_write(struct file *f, struct page *page, | 2554 | static int reiserfs_write_begin(struct file *file, |
2554 | unsigned from, unsigned to) | 2555 | struct address_space *mapping, |
2556 | loff_t pos, unsigned len, unsigned flags, | ||
2557 | struct page **pagep, void **fsdata) | ||
2558 | { | ||
2559 | struct inode *inode; | ||
2560 | struct page *page; | ||
2561 | pgoff_t index; | ||
2562 | int ret; | ||
2563 | int old_ref = 0; | ||
2564 | |||
2565 | index = pos >> PAGE_CACHE_SHIFT; | ||
2566 | page = __grab_cache_page(mapping, index); | ||
2567 | if (!page) | ||
2568 | return -ENOMEM; | ||
2569 | *pagep = page; | ||
2570 | |||
2571 | inode = mapping->host; | ||
2572 | reiserfs_wait_on_write_block(inode->i_sb); | ||
2573 | fix_tail_page_for_writing(page); | ||
2574 | if (reiserfs_transaction_running(inode->i_sb)) { | ||
2575 | struct reiserfs_transaction_handle *th; | ||
2576 | th = (struct reiserfs_transaction_handle *)current-> | ||
2577 | journal_info; | ||
2578 | BUG_ON(!th->t_refcount); | ||
2579 | BUG_ON(!th->t_trans_id); | ||
2580 | old_ref = th->t_refcount; | ||
2581 | th->t_refcount++; | ||
2582 | } | ||
2583 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | ||
2584 | reiserfs_get_block); | ||
2585 | if (ret && reiserfs_transaction_running(inode->i_sb)) { | ||
2586 | struct reiserfs_transaction_handle *th = current->journal_info; | ||
2587 | /* this gets a little ugly. If reiserfs_get_block returned an | ||
2588 | * error and left a transacstion running, we've got to close it, | ||
2589 | * and we've got to free handle if it was a persistent transaction. | ||
2590 | * | ||
2591 | * But, if we had nested into an existing transaction, we need | ||
2592 | * to just drop the ref count on the handle. | ||
2593 | * | ||
2594 | * If old_ref == 0, the transaction is from reiserfs_get_block, | ||
2595 | * and it was a persistent trans. Otherwise, it was nested above. | ||
2596 | */ | ||
2597 | if (th->t_refcount > old_ref) { | ||
2598 | if (old_ref) | ||
2599 | th->t_refcount--; | ||
2600 | else { | ||
2601 | int err; | ||
2602 | reiserfs_write_lock(inode->i_sb); | ||
2603 | err = reiserfs_end_persistent_transaction(th); | ||
2604 | reiserfs_write_unlock(inode->i_sb); | ||
2605 | if (err) | ||
2606 | ret = err; | ||
2607 | } | ||
2608 | } | ||
2609 | } | ||
2610 | if (ret) { | ||
2611 | unlock_page(page); | ||
2612 | page_cache_release(page); | ||
2613 | } | ||
2614 | return ret; | ||
2615 | } | ||
2616 | |||
2617 | int reiserfs_prepare_write(struct file *f, struct page *page, | ||
2618 | unsigned from, unsigned to) | ||
2555 | { | 2619 | { |
2556 | struct inode *inode = page->mapping->host; | 2620 | struct inode *inode = page->mapping->host; |
2557 | int ret; | 2621 | int ret; |
@@ -2604,8 +2668,100 @@ static sector_t reiserfs_aop_bmap(struct address_space *as, sector_t block) | |||
2604 | return generic_block_bmap(as, block, reiserfs_bmap); | 2668 | return generic_block_bmap(as, block, reiserfs_bmap); |
2605 | } | 2669 | } |
2606 | 2670 | ||
2607 | static int reiserfs_commit_write(struct file *f, struct page *page, | 2671 | static int reiserfs_write_end(struct file *file, struct address_space *mapping, |
2608 | unsigned from, unsigned to) | 2672 | loff_t pos, unsigned len, unsigned copied, |
2673 | struct page *page, void *fsdata) | ||
2674 | { | ||
2675 | struct inode *inode = page->mapping->host; | ||
2676 | int ret = 0; | ||
2677 | int update_sd = 0; | ||
2678 | struct reiserfs_transaction_handle *th; | ||
2679 | unsigned start; | ||
2680 | |||
2681 | |||
2682 | reiserfs_wait_on_write_block(inode->i_sb); | ||
2683 | if (reiserfs_transaction_running(inode->i_sb)) | ||
2684 | th = current->journal_info; | ||
2685 | else | ||
2686 | th = NULL; | ||
2687 | |||
2688 | start = pos & (PAGE_CACHE_SIZE - 1); | ||
2689 | if (unlikely(copied < len)) { | ||
2690 | if (!PageUptodate(page)) | ||
2691 | copied = 0; | ||
2692 | |||
2693 | page_zero_new_buffers(page, start + copied, start + len); | ||
2694 | } | ||
2695 | flush_dcache_page(page); | ||
2696 | |||
2697 | reiserfs_commit_page(inode, page, start, start + copied); | ||
2698 | |||
2699 | /* generic_commit_write does this for us, but does not update the | ||
2700 | ** transaction tracking stuff when the size changes. So, we have | ||
2701 | ** to do the i_size updates here. | ||
2702 | */ | ||
2703 | pos += copied; | ||
2704 | if (pos > inode->i_size) { | ||
2705 | struct reiserfs_transaction_handle myth; | ||
2706 | reiserfs_write_lock(inode->i_sb); | ||
2707 | /* If the file have grown beyond the border where it | ||
2708 | can have a tail, unmark it as needing a tail | ||
2709 | packing */ | ||
2710 | if ((have_large_tails(inode->i_sb) | ||
2711 | && inode->i_size > i_block_size(inode) * 4) | ||
2712 | || (have_small_tails(inode->i_sb) | ||
2713 | && inode->i_size > i_block_size(inode))) | ||
2714 | REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; | ||
2715 | |||
2716 | ret = journal_begin(&myth, inode->i_sb, 1); | ||
2717 | if (ret) { | ||
2718 | reiserfs_write_unlock(inode->i_sb); | ||
2719 | goto journal_error; | ||
2720 | } | ||
2721 | reiserfs_update_inode_transaction(inode); | ||
2722 | inode->i_size = pos; | ||
2723 | /* | ||
2724 | * this will just nest into our transaction. It's important | ||
2725 | * to use mark_inode_dirty so the inode gets pushed around on the | ||
2726 | * dirty lists, and so that O_SYNC works as expected | ||
2727 | */ | ||
2728 | mark_inode_dirty(inode); | ||
2729 | reiserfs_update_sd(&myth, inode); | ||
2730 | update_sd = 1; | ||
2731 | ret = journal_end(&myth, inode->i_sb, 1); | ||
2732 | reiserfs_write_unlock(inode->i_sb); | ||
2733 | if (ret) | ||
2734 | goto journal_error; | ||
2735 | } | ||
2736 | if (th) { | ||
2737 | reiserfs_write_lock(inode->i_sb); | ||
2738 | if (!update_sd) | ||
2739 | mark_inode_dirty(inode); | ||
2740 | ret = reiserfs_end_persistent_transaction(th); | ||
2741 | reiserfs_write_unlock(inode->i_sb); | ||
2742 | if (ret) | ||
2743 | goto out; | ||
2744 | } | ||
2745 | |||
2746 | out: | ||
2747 | unlock_page(page); | ||
2748 | page_cache_release(page); | ||
2749 | return ret == 0 ? copied : ret; | ||
2750 | |||
2751 | journal_error: | ||
2752 | if (th) { | ||
2753 | reiserfs_write_lock(inode->i_sb); | ||
2754 | if (!update_sd) | ||
2755 | reiserfs_update_sd(th, inode); | ||
2756 | ret = reiserfs_end_persistent_transaction(th); | ||
2757 | reiserfs_write_unlock(inode->i_sb); | ||
2758 | } | ||
2759 | |||
2760 | goto out; | ||
2761 | } | ||
2762 | |||
2763 | int reiserfs_commit_write(struct file *f, struct page *page, | ||
2764 | unsigned from, unsigned to) | ||
2609 | { | 2765 | { |
2610 | struct inode *inode = page->mapping->host; | 2766 | struct inode *inode = page->mapping->host; |
2611 | loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to; | 2767 | loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to; |
@@ -2999,8 +3155,8 @@ const struct address_space_operations reiserfs_address_space_operations = { | |||
2999 | .releasepage = reiserfs_releasepage, | 3155 | .releasepage = reiserfs_releasepage, |
3000 | .invalidatepage = reiserfs_invalidatepage, | 3156 | .invalidatepage = reiserfs_invalidatepage, |
3001 | .sync_page = block_sync_page, | 3157 | .sync_page = block_sync_page, |
3002 | .prepare_write = reiserfs_prepare_write, | 3158 | .write_begin = reiserfs_write_begin, |
3003 | .commit_write = reiserfs_commit_write, | 3159 | .write_end = reiserfs_write_end, |
3004 | .bmap = reiserfs_aop_bmap, | 3160 | .bmap = reiserfs_aop_bmap, |
3005 | .direct_IO = reiserfs_direct_IO, | 3161 | .direct_IO = reiserfs_direct_IO, |
3006 | .set_page_dirty = reiserfs_set_page_dirty, | 3162 | .set_page_dirty = reiserfs_set_page_dirty, |