Commit 3aab8f82 authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim

f2fs: introduce f2fs_write_failed to handle error case when write

When we fail in ->write_begin()/->direct_IO(), our allocated node block in disk
and page cache are still kept, despite these may not be used again.

This patch introduce f2fs_write_failed() to handle the error case of these two
interfaces, it will truncate page cache and blocks of this file according to
i_size.
Signed-off-by: default avatarChao Yu <chao2.yu@samsung.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent eee6160f
...@@ -914,6 +914,16 @@ static int f2fs_write_data_pages(struct address_space *mapping, ...@@ -914,6 +914,16 @@ static int f2fs_write_data_pages(struct address_space *mapping,
return 0; return 0;
} }
static void f2fs_write_failed(struct address_space *mapping, loff_t to)
{
struct inode *inode = mapping->host;
if (to > inode->i_size) {
truncate_pagecache(inode, inode->i_size);
truncate_blocks(inode, inode->i_size);
}
}
static int f2fs_write_begin(struct file *file, struct address_space *mapping, static int f2fs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata) struct page **pagep, void **fsdata)
...@@ -931,11 +941,13 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -931,11 +941,13 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
repeat: repeat:
err = f2fs_convert_inline_data(inode, pos + len); err = f2fs_convert_inline_data(inode, pos + len);
if (err) if (err)
return err; goto fail;
page = grab_cache_page_write_begin(mapping, index, flags); page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) if (!page) {
return -ENOMEM; err = -ENOMEM;
goto fail;
}
/* to avoid latency during memory pressure */ /* to avoid latency during memory pressure */
unlock_page(page); unlock_page(page);
...@@ -949,10 +961,9 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -949,10 +961,9 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
set_new_dnode(&dn, inode, NULL, NULL, 0); set_new_dnode(&dn, inode, NULL, NULL, 0);
err = f2fs_reserve_block(&dn, index); err = f2fs_reserve_block(&dn, index);
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
if (err) { if (err) {
f2fs_put_page(page, 0); f2fs_put_page(page, 0);
return err; goto fail;
} }
inline_data: inline_data:
lock_page(page); lock_page(page);
...@@ -982,19 +993,20 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -982,19 +993,20 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
err = f2fs_read_inline_data(inode, page); err = f2fs_read_inline_data(inode, page);
if (err) { if (err) {
page_cache_release(page); page_cache_release(page);
return err; goto fail;
} }
} else { } else {
err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr, err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr,
READ_SYNC); READ_SYNC);
if (err) if (err)
return err; goto fail;
} }
lock_page(page); lock_page(page);
if (unlikely(!PageUptodate(page))) { if (unlikely(!PageUptodate(page))) {
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
return -EIO; err = -EIO;
goto fail;
} }
if (unlikely(page->mapping != mapping)) { if (unlikely(page->mapping != mapping)) {
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
...@@ -1005,6 +1017,9 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, ...@@ -1005,6 +1017,9 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
SetPageUptodate(page); SetPageUptodate(page);
clear_cold_data(page); clear_cold_data(page);
return 0; return 0;
fail:
f2fs_write_failed(mapping, pos + len);
return err;
} }
static int f2fs_write_end(struct file *file, static int f2fs_write_end(struct file *file,
...@@ -1049,7 +1064,10 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, ...@@ -1049,7 +1064,10 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
struct iov_iter *iter, loff_t offset) struct iov_iter *iter, loff_t offset)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host; struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
size_t count = iov_iter_count(iter);
int err;
/* Let buffer I/O handle the inline data case. */ /* Let buffer I/O handle the inline data case. */
if (f2fs_has_inline_data(inode)) if (f2fs_has_inline_data(inode))
...@@ -1061,8 +1079,10 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, ...@@ -1061,8 +1079,10 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
/* clear fsync mark to recover these blocks */ /* clear fsync mark to recover these blocks */
fsync_mark_clear(F2FS_SB(inode->i_sb), inode->i_ino); fsync_mark_clear(F2FS_SB(inode->i_sb), inode->i_ino);
return blockdev_direct_IO(rw, iocb, inode, iter, offset, err = blockdev_direct_IO(rw, iocb, inode, iter, offset, get_data_block);
get_data_block); if (err < 0 && (rw & WRITE))
f2fs_write_failed(mapping, offset + count);
return err;
} }
static void f2fs_invalidate_data_page(struct page *page, unsigned int offset, static void f2fs_invalidate_data_page(struct page *page, unsigned int offset,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment