Skip to content

Commit

Permalink
f2fs: fix to set PageUptodate in f2fs_write_end correctly
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Jaegeuk Kim <[email protected]>
  • Loading branch information
Jaegeuk Kim authored and TheScarastic committed May 21, 2017
1 parent f98bde4 commit d0e04f6
Showing 1 changed file with 19 additions and 10 deletions.
29 changes: 19 additions & 10 deletions fs/f2fs/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -1643,13 +1643,12 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr);

if (len == PAGE_SIZE)
goto out_update;
if (PageUptodate(page))
goto out_clear;
if (len == PAGE_SIZE || PageUptodate(page))
return 0;

if (blkaddr == NEW_ADDR) {
zero_user_segment(page, 0, PAGE_SIZE);
SetPageUptodate(page);
} else {
struct bio *bio;

Expand Down Expand Up @@ -1677,11 +1676,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
goto fail;
}
}
out_update:
if (!PageUptodate(page))
SetPageUptodate(page);
out_clear:
clear_cold_data(page);
return 0;

fail:
Expand All @@ -1699,11 +1693,26 @@ static int f2fs_write_end(struct file *file,

trace_f2fs_write_end(inode, pos, len, copied);

/*
* This should be come from len == PAGE_SIZE, and we expect copied
* should be PAGE_SIZE. Otherwise, we treat it with zero copied and
* let generic_perform_write() try to copy data again through copied=0.
*/
if (!PageUptodate(page)) {
if (unlikely(copied != PAGE_SIZE))
copied = 0;
else
SetPageUptodate(page);
}
if (!copied)
goto unlock_out;

set_page_dirty(page);
clear_cold_data(page);

if (pos + copied > i_size_read(inode))
f2fs_i_size_write(inode, pos + copied);

unlock_out:
f2fs_put_page(page, 1);
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
return copied;
Expand Down

0 comments on commit d0e04f6

Please sign in to comment.