aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2007-10-16 04:25:01 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:42:55 -0400
commitafddba49d18f346e5cc2938b6ed7c512db18ca68 (patch)
tree4726e3d3b0e9e8e5b5d3b2b0cccb36446bbdf3ca /fs/namei.c
parent637aff46f94a754207c80c8c64bf1b74f24b967d (diff)
fs: introduce write_begin, write_end, and perform_write aops
These are intended to replace prepare_write and commit_write with more flexible alternatives that are also able to avoid the buffered write deadlock problems efficiently (which prepare_write is unable to do). [mark.fasheh@oracle.com: API design contributions, code review and fixes] [akpm@linux-foundation.org: various fixes] [dmonakhov@sw.ru: new aop block_write_begin fix] Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com> Signed-off-by: Dmitriy Monakhov <dmonakhov@openvz.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c46
1 files changed, 11 insertions, 35 deletions
diff --git a/fs/namei.c b/fs/namei.c
index a83160acd748..b40b8084eefc 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2729,53 +2729,29 @@ int __page_symlink(struct inode *inode, const char *symname, int len,
2729{ 2729{
2730 struct address_space *mapping = inode->i_mapping; 2730 struct address_space *mapping = inode->i_mapping;
2731 struct page *page; 2731 struct page *page;
2732 void *fsdata;
2732 int err; 2733 int err;
2733 char *kaddr; 2734 char *kaddr;
2734 2735
2735retry: 2736retry:
2736 err = -ENOMEM; 2737 err = pagecache_write_begin(NULL, mapping, 0, len-1,
2737 page = find_or_create_page(mapping, 0, gfp_mask); 2738 AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata);
2738 if (!page)
2739 goto fail;
2740 err = mapping->a_ops->prepare_write(NULL, page, 0, len-1);
2741 if (err == AOP_TRUNCATED_PAGE) {
2742 page_cache_release(page);
2743 goto retry;
2744 }
2745 if (err) 2739 if (err)
2746 goto fail_map; 2740 goto fail;
2741
2747 kaddr = kmap_atomic(page, KM_USER0); 2742 kaddr = kmap_atomic(page, KM_USER0);
2748 memcpy(kaddr, symname, len-1); 2743 memcpy(kaddr, symname, len-1);
2749 kunmap_atomic(kaddr, KM_USER0); 2744 kunmap_atomic(kaddr, KM_USER0);
2750 err = mapping->a_ops->commit_write(NULL, page, 0, len-1); 2745
2751 if (err == AOP_TRUNCATED_PAGE) { 2746 err = pagecache_write_end(NULL, mapping, 0, len-1, len-1,
2752 page_cache_release(page); 2747 page, fsdata);
2753 goto retry;
2754 }
2755 if (err)
2756 goto fail_map;
2757 /*
2758 * Notice that we are _not_ going to block here - end of page is
2759 * unmapped, so this will only try to map the rest of page, see
2760 * that it is unmapped (typically even will not look into inode -
2761 * ->i_size will be enough for everything) and zero it out.
2762 * OTOH it's obviously correct and should make the page up-to-date.
2763 */
2764 if (!PageUptodate(page)) {
2765 err = mapping->a_ops->readpage(NULL, page);
2766 if (err != AOP_TRUNCATED_PAGE)
2767 wait_on_page_locked(page);
2768 } else {
2769 unlock_page(page);
2770 }
2771 page_cache_release(page);
2772 if (err < 0) 2748 if (err < 0)
2773 goto fail; 2749 goto fail;
2750 if (err < len-1)
2751 goto retry;
2752
2774 mark_inode_dirty(inode); 2753 mark_inode_dirty(inode);
2775 return 0; 2754 return 0;
2776fail_map:
2777 unlock_page(page);
2778 page_cache_release(page);
2779fail: 2755fail:
2780 return err; 2756 return err;
2781} 2757}