diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 46 |
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 | ||
2735 | retry: | 2736 | retry: |
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; |
2776 | fail_map: | ||
2777 | unlock_page(page); | ||
2778 | page_cache_release(page); | ||
2779 | fail: | 2755 | fail: |
2780 | return err; | 2756 | return err; |
2781 | } | 2757 | } |