aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2016-09-06 14:02:03 -0400
committerJaegeuk Kim <jaegeuk@kernel.org>2016-09-13 16:02:34 -0400
commit649d7df29ca83b2c9e81a4a305a8de8ab02b5e9d (patch)
tree5cd2b805dff2b6659ab15fd2142383ddba8f8aea
parent61e4da1172d18f5277be847a40559eacd3169ce7 (diff)
f2fs: fix to set PageUptodate in f2fs_write_end correctly
Previously, f2fs_write_begin sets PageUptodate all the time. But, when user tries to update the entire page (i.e., len == PAGE_SIZE), we need to consider that the page is able to be copied partially afterwards. In such the case, we will lose the remaing region in the page. This patch fixes this by setting PageUptodate in f2fs_write_end as given copied result. In the short copy case, it returns zero to let generic_perform_write retry copying user data again. As a result, f2fs_write_end() works: PageUptodate len copied return retry 1. no 4096 4096 4096 false -> return 4096 2. no 4096 1024 0 true -> goto #1 case 3. yes 2048 2048 2048 false -> return 2048 4. yes 2048 1024 1024 false -> return 1024 Suggested-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/data.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 357a4235dde8..528c3c0d55a2 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1642,13 +1642,12 @@ repeat:
1642 if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) 1642 if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
1643 f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr); 1643 f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr);
1644 1644
1645 if (len == PAGE_SIZE) 1645 if (len == PAGE_SIZE || PageUptodate(page))
1646 goto out_update; 1646 return 0;
1647 if (PageUptodate(page))
1648 goto out_clear;
1649 1647
1650 if (blkaddr == NEW_ADDR) { 1648 if (blkaddr == NEW_ADDR) {
1651 zero_user_segment(page, 0, PAGE_SIZE); 1649 zero_user_segment(page, 0, PAGE_SIZE);
1650 SetPageUptodate(page);
1652 } else { 1651 } else {
1653 struct bio *bio; 1652 struct bio *bio;
1654 1653
@@ -1676,11 +1675,6 @@ repeat:
1676 goto fail; 1675 goto fail;
1677 } 1676 }
1678 } 1677 }
1679out_update:
1680 if (!PageUptodate(page))
1681 SetPageUptodate(page);
1682out_clear:
1683 clear_cold_data(page);
1684 return 0; 1678 return 0;
1685 1679
1686fail: 1680fail:
@@ -1698,11 +1692,26 @@ static int f2fs_write_end(struct file *file,
1698 1692
1699 trace_f2fs_write_end(inode, pos, len, copied); 1693 trace_f2fs_write_end(inode, pos, len, copied);
1700 1694
1695 /*
1696 * This should be come from len == PAGE_SIZE, and we expect copied
1697 * should be PAGE_SIZE. Otherwise, we treat it with zero copied and
1698 * let generic_perform_write() try to copy data again through copied=0.
1699 */
1700 if (!PageUptodate(page)) {
1701 if (unlikely(copied != PAGE_SIZE))
1702 copied = 0;
1703 else
1704 SetPageUptodate(page);
1705 }
1706 if (!copied)
1707 goto unlock_out;
1708
1701 set_page_dirty(page); 1709 set_page_dirty(page);
1710 clear_cold_data(page);
1702 1711
1703 if (pos + copied > i_size_read(inode)) 1712 if (pos + copied > i_size_read(inode))
1704 f2fs_i_size_write(inode, pos + copied); 1713 f2fs_i_size_write(inode, pos + copied);
1705 1714unlock_out:
1706 f2fs_put_page(page, 1); 1715 f2fs_put_page(page, 1);
1707 f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); 1716 f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
1708 return copied; 1717 return copied;