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: Chao Yu <chao2.yu@samsung.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
eee6160f2e
commit
3aab8f828e
@ -914,6 +914,16 @@ skip_write:
|
|||||||
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,
|
|||||||
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 @@ repeat:
|
|||||||
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 @@ inline_data:
|
|||||||
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 @@ out:
|
|||||||
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,
|
|||||||
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,
|
|||||||
/* 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,
|
||||||
|
Loading…
Reference in New Issue
Block a user