forked from Minki/linux
f2fs: avoid f2fs_lock_op for IPU writes
Currently, if we do get_node_of_data before f2fs_lock_op, there may be dead lock as follows, where process A would be in infinite loop, and B will NOT be awaked. Process A(cp): Process B: f2fs_lock_all(sbi) get_dnode_of_data <---- lock dn.node_page flush_nodes f2fs_lock_op So, this patch adds f2fs_trylock_op to avoid f2fs_lock_op done by IPU. Signed-off-by: Hou Pengyang <houpengyang@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
a912b54d3a
commit
cc15620bc8
@ -1383,12 +1383,12 @@ int do_write_data_page(struct f2fs_io_info *fio)
|
||||
|
||||
if (valid_ipu_blkaddr(fio)) {
|
||||
ipu_force = true;
|
||||
fio->need_lock = false;
|
||||
fio->need_lock = LOCK_DONE;
|
||||
goto got_it;
|
||||
}
|
||||
}
|
||||
|
||||
if (fio->need_lock)
|
||||
if (fio->need_lock == LOCK_REQ)
|
||||
f2fs_lock_op(fio->sbi);
|
||||
|
||||
err = get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
|
||||
@ -1403,19 +1403,18 @@ int do_write_data_page(struct f2fs_io_info *fio)
|
||||
goto out_writepage;
|
||||
}
|
||||
got_it:
|
||||
err = encrypt_one_page(fio);
|
||||
if (err)
|
||||
goto out_writepage;
|
||||
|
||||
set_page_writeback(page);
|
||||
|
||||
/*
|
||||
* If current allocation needs SSR,
|
||||
* it had better in-place writes for updated data.
|
||||
*/
|
||||
if (ipu_force || (valid_ipu_blkaddr(fio) && need_inplace_update(fio))) {
|
||||
err = encrypt_one_page(fio);
|
||||
if (err)
|
||||
goto out_writepage;
|
||||
|
||||
set_page_writeback(page);
|
||||
f2fs_put_dnode(&dn);
|
||||
if (fio->need_lock)
|
||||
if (fio->need_lock == LOCK_REQ)
|
||||
f2fs_unlock_op(fio->sbi);
|
||||
err = rewrite_data_page(fio);
|
||||
trace_f2fs_do_write_data_page(fio->page, IPU);
|
||||
@ -1423,6 +1422,20 @@ got_it:
|
||||
return err;
|
||||
}
|
||||
|
||||
if (fio->need_lock == LOCK_RETRY) {
|
||||
if (!f2fs_trylock_op(fio->sbi)) {
|
||||
err = -EAGAIN;
|
||||
goto out_writepage;
|
||||
}
|
||||
fio->need_lock = LOCK_REQ;
|
||||
}
|
||||
|
||||
err = encrypt_one_page(fio);
|
||||
if (err)
|
||||
goto out_writepage;
|
||||
|
||||
set_page_writeback(page);
|
||||
|
||||
/* LFS mode write path */
|
||||
write_data_page(&dn, fio);
|
||||
trace_f2fs_do_write_data_page(page, OPU);
|
||||
@ -1432,7 +1445,7 @@ got_it:
|
||||
out_writepage:
|
||||
f2fs_put_dnode(&dn);
|
||||
out:
|
||||
if (fio->need_lock)
|
||||
if (fio->need_lock == LOCK_REQ)
|
||||
f2fs_unlock_op(fio->sbi);
|
||||
return err;
|
||||
}
|
||||
@ -1458,7 +1471,7 @@ static int __write_data_page(struct page *page, bool *submitted,
|
||||
.page = page,
|
||||
.encrypted_page = NULL,
|
||||
.submitted = false,
|
||||
.need_lock = true,
|
||||
.need_lock = LOCK_RETRY,
|
||||
};
|
||||
|
||||
trace_f2fs_writepage(page, DATA);
|
||||
@ -1494,7 +1507,7 @@ write:
|
||||
|
||||
/* Dentry blocks are controlled by checkpoint */
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
fio.need_lock = false;
|
||||
fio.need_lock = LOCK_DONE;
|
||||
err = do_write_data_page(&fio);
|
||||
goto done;
|
||||
}
|
||||
@ -1513,8 +1526,13 @@ write:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (err == -EAGAIN)
|
||||
if (err == -EAGAIN) {
|
||||
err = do_write_data_page(&fio);
|
||||
if (err == -EAGAIN) {
|
||||
fio.need_lock = LOCK_REQ;
|
||||
err = do_write_data_page(&fio);
|
||||
}
|
||||
}
|
||||
if (F2FS_I(inode)->last_disk_size < psize)
|
||||
F2FS_I(inode)->last_disk_size = psize;
|
||||
|
||||
|
@ -799,6 +799,12 @@ enum temp_type {
|
||||
NR_TEMP_TYPE,
|
||||
};
|
||||
|
||||
enum need_lock_type {
|
||||
LOCK_REQ = 0,
|
||||
LOCK_DONE,
|
||||
LOCK_RETRY,
|
||||
};
|
||||
|
||||
struct f2fs_io_info {
|
||||
struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */
|
||||
enum page_type type; /* contains DATA/NODE/META/META_FLUSH */
|
||||
@ -810,7 +816,7 @@ struct f2fs_io_info {
|
||||
struct page *page; /* page to be written */
|
||||
struct page *encrypted_page; /* encrypted page */
|
||||
bool submitted; /* indicate IO submission */
|
||||
bool need_lock; /* indicate we need to lock cp_rwsem */
|
||||
int need_lock; /* indicate we need to lock cp_rwsem */
|
||||
};
|
||||
|
||||
#define is_read_io(rw) ((rw) == READ)
|
||||
@ -1279,6 +1285,11 @@ static inline void f2fs_lock_op(struct f2fs_sb_info *sbi)
|
||||
down_read(&sbi->cp_rwsem);
|
||||
}
|
||||
|
||||
static inline int f2fs_trylock_op(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
return down_read_trylock(&sbi->cp_rwsem);
|
||||
}
|
||||
|
||||
static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
up_read(&sbi->cp_rwsem);
|
||||
|
@ -719,7 +719,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
|
||||
.old_blkaddr = NULL_ADDR,
|
||||
.page = page,
|
||||
.encrypted_page = NULL,
|
||||
.need_lock = true,
|
||||
.need_lock = LOCK_REQ,
|
||||
};
|
||||
bool is_dirty = PageDirty(page);
|
||||
int err;
|
||||
|
@ -312,7 +312,7 @@ static int __commit_inmem_pages(struct inode *inode,
|
||||
fio.page = page;
|
||||
fio.old_blkaddr = NULL_ADDR;
|
||||
fio.encrypted_page = NULL;
|
||||
fio.need_lock = false,
|
||||
fio.need_lock = LOCK_DONE;
|
||||
err = do_write_data_page(&fio);
|
||||
if (err) {
|
||||
unlock_page(page);
|
||||
|
Loading…
Reference in New Issue
Block a user