diff options
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r-- | fs/f2fs/segment.c | 80 |
1 files changed, 57 insertions, 23 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 9b79056d705d..aa7fe79b62b2 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c | |||
@@ -191,8 +191,7 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page) | |||
191 | 191 | ||
192 | f2fs_trace_pid(page); | 192 | f2fs_trace_pid(page); |
193 | 193 | ||
194 | set_page_private(page, (unsigned long)ATOMIC_WRITTEN_PAGE); | 194 | f2fs_set_page_private(page, (unsigned long)ATOMIC_WRITTEN_PAGE); |
195 | SetPagePrivate(page); | ||
196 | 195 | ||
197 | new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); | 196 | new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); |
198 | 197 | ||
@@ -215,7 +214,8 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page) | |||
215 | } | 214 | } |
216 | 215 | ||
217 | static int __revoke_inmem_pages(struct inode *inode, | 216 | static int __revoke_inmem_pages(struct inode *inode, |
218 | struct list_head *head, bool drop, bool recover) | 217 | struct list_head *head, bool drop, bool recover, |
218 | bool trylock) | ||
219 | { | 219 | { |
220 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 220 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
221 | struct inmem_pages *cur, *tmp; | 221 | struct inmem_pages *cur, *tmp; |
@@ -227,7 +227,16 @@ static int __revoke_inmem_pages(struct inode *inode, | |||
227 | if (drop) | 227 | if (drop) |
228 | trace_f2fs_commit_inmem_page(page, INMEM_DROP); | 228 | trace_f2fs_commit_inmem_page(page, INMEM_DROP); |
229 | 229 | ||
230 | lock_page(page); | 230 | if (trylock) { |
231 | /* | ||
232 | * to avoid deadlock in between page lock and | ||
233 | * inmem_lock. | ||
234 | */ | ||
235 | if (!trylock_page(page)) | ||
236 | continue; | ||
237 | } else { | ||
238 | lock_page(page); | ||
239 | } | ||
231 | 240 | ||
232 | f2fs_wait_on_page_writeback(page, DATA, true, true); | 241 | f2fs_wait_on_page_writeback(page, DATA, true, true); |
233 | 242 | ||
@@ -270,8 +279,7 @@ next: | |||
270 | ClearPageUptodate(page); | 279 | ClearPageUptodate(page); |
271 | clear_cold_data(page); | 280 | clear_cold_data(page); |
272 | } | 281 | } |
273 | set_page_private(page, 0); | 282 | f2fs_clear_page_private(page); |
274 | ClearPagePrivate(page); | ||
275 | f2fs_put_page(page, 1); | 283 | f2fs_put_page(page, 1); |
276 | 284 | ||
277 | list_del(&cur->list); | 285 | list_del(&cur->list); |
@@ -318,13 +326,19 @@ void f2fs_drop_inmem_pages(struct inode *inode) | |||
318 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 326 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
319 | struct f2fs_inode_info *fi = F2FS_I(inode); | 327 | struct f2fs_inode_info *fi = F2FS_I(inode); |
320 | 328 | ||
321 | mutex_lock(&fi->inmem_lock); | 329 | while (!list_empty(&fi->inmem_pages)) { |
322 | __revoke_inmem_pages(inode, &fi->inmem_pages, true, false); | 330 | mutex_lock(&fi->inmem_lock); |
323 | spin_lock(&sbi->inode_lock[ATOMIC_FILE]); | 331 | __revoke_inmem_pages(inode, &fi->inmem_pages, |
324 | if (!list_empty(&fi->inmem_ilist)) | 332 | true, false, true); |
325 | list_del_init(&fi->inmem_ilist); | 333 | |
326 | spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); | 334 | if (list_empty(&fi->inmem_pages)) { |
327 | mutex_unlock(&fi->inmem_lock); | 335 | spin_lock(&sbi->inode_lock[ATOMIC_FILE]); |
336 | if (!list_empty(&fi->inmem_ilist)) | ||
337 | list_del_init(&fi->inmem_ilist); | ||
338 | spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); | ||
339 | } | ||
340 | mutex_unlock(&fi->inmem_lock); | ||
341 | } | ||
328 | 342 | ||
329 | clear_inode_flag(inode, FI_ATOMIC_FILE); | 343 | clear_inode_flag(inode, FI_ATOMIC_FILE); |
330 | fi->i_gc_failures[GC_FAILURE_ATOMIC] = 0; | 344 | fi->i_gc_failures[GC_FAILURE_ATOMIC] = 0; |
@@ -354,8 +368,7 @@ void f2fs_drop_inmem_page(struct inode *inode, struct page *page) | |||
354 | kmem_cache_free(inmem_entry_slab, cur); | 368 | kmem_cache_free(inmem_entry_slab, cur); |
355 | 369 | ||
356 | ClearPageUptodate(page); | 370 | ClearPageUptodate(page); |
357 | set_page_private(page, 0); | 371 | f2fs_clear_page_private(page); |
358 | ClearPagePrivate(page); | ||
359 | f2fs_put_page(page, 0); | 372 | f2fs_put_page(page, 0); |
360 | 373 | ||
361 | trace_f2fs_commit_inmem_page(page, INMEM_INVALIDATE); | 374 | trace_f2fs_commit_inmem_page(page, INMEM_INVALIDATE); |
@@ -429,12 +442,15 @@ retry: | |||
429 | * recovery or rewrite & commit last transaction. For other | 442 | * recovery or rewrite & commit last transaction. For other |
430 | * error number, revoking was done by filesystem itself. | 443 | * error number, revoking was done by filesystem itself. |
431 | */ | 444 | */ |
432 | err = __revoke_inmem_pages(inode, &revoke_list, false, true); | 445 | err = __revoke_inmem_pages(inode, &revoke_list, |
446 | false, true, false); | ||
433 | 447 | ||
434 | /* drop all uncommitted pages */ | 448 | /* drop all uncommitted pages */ |
435 | __revoke_inmem_pages(inode, &fi->inmem_pages, true, false); | 449 | __revoke_inmem_pages(inode, &fi->inmem_pages, |
450 | true, false, false); | ||
436 | } else { | 451 | } else { |
437 | __revoke_inmem_pages(inode, &revoke_list, false, false); | 452 | __revoke_inmem_pages(inode, &revoke_list, |
453 | false, false, false); | ||
438 | } | 454 | } |
439 | 455 | ||
440 | return err; | 456 | return err; |
@@ -542,9 +558,13 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) | |||
542 | static int __submit_flush_wait(struct f2fs_sb_info *sbi, | 558 | static int __submit_flush_wait(struct f2fs_sb_info *sbi, |
543 | struct block_device *bdev) | 559 | struct block_device *bdev) |
544 | { | 560 | { |
545 | struct bio *bio = f2fs_bio_alloc(sbi, 0, true); | 561 | struct bio *bio; |
546 | int ret; | 562 | int ret; |
547 | 563 | ||
564 | bio = f2fs_bio_alloc(sbi, 0, false); | ||
565 | if (!bio) | ||
566 | return -ENOMEM; | ||
567 | |||
548 | bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH; | 568 | bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH; |
549 | bio_set_dev(bio, bdev); | 569 | bio_set_dev(bio, bdev); |
550 | ret = submit_bio_wait(bio); | 570 | ret = submit_bio_wait(bio); |
@@ -868,6 +888,9 @@ int f2fs_disable_cp_again(struct f2fs_sb_info *sbi) | |||
868 | 888 | ||
869 | if (holes[DATA] > ovp || holes[NODE] > ovp) | 889 | if (holes[DATA] > ovp || holes[NODE] > ovp) |
870 | return -EAGAIN; | 890 | return -EAGAIN; |
891 | if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) && | ||
892 | dirty_segments(sbi) > overprovision_segments(sbi)) | ||
893 | return -EAGAIN; | ||
871 | return 0; | 894 | return 0; |
872 | } | 895 | } |
873 | 896 | ||
@@ -1037,6 +1060,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, | |||
1037 | 1060 | ||
1038 | dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST; | 1061 | dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST; |
1039 | dpolicy->io_aware_gran = MAX_PLIST_NUM; | 1062 | dpolicy->io_aware_gran = MAX_PLIST_NUM; |
1063 | dpolicy->timeout = 0; | ||
1040 | 1064 | ||
1041 | if (discard_type == DPOLICY_BG) { | 1065 | if (discard_type == DPOLICY_BG) { |
1042 | dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; | 1066 | dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; |
@@ -1059,6 +1083,8 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, | |||
1059 | } else if (discard_type == DPOLICY_UMOUNT) { | 1083 | } else if (discard_type == DPOLICY_UMOUNT) { |
1060 | dpolicy->max_requests = UINT_MAX; | 1084 | dpolicy->max_requests = UINT_MAX; |
1061 | dpolicy->io_aware = false; | 1085 | dpolicy->io_aware = false; |
1086 | /* we need to issue all to keep CP_TRIMMED_FLAG */ | ||
1087 | dpolicy->granularity = 1; | ||
1062 | } | 1088 | } |
1063 | } | 1089 | } |
1064 | 1090 | ||
@@ -1424,7 +1450,14 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, | |||
1424 | int i, issued = 0; | 1450 | int i, issued = 0; |
1425 | bool io_interrupted = false; | 1451 | bool io_interrupted = false; |
1426 | 1452 | ||
1453 | if (dpolicy->timeout != 0) | ||
1454 | f2fs_update_time(sbi, dpolicy->timeout); | ||
1455 | |||
1427 | for (i = MAX_PLIST_NUM - 1; i >= 0; i--) { | 1456 | for (i = MAX_PLIST_NUM - 1; i >= 0; i--) { |
1457 | if (dpolicy->timeout != 0 && | ||
1458 | f2fs_time_over(sbi, dpolicy->timeout)) | ||
1459 | break; | ||
1460 | |||
1428 | if (i + 1 < dpolicy->granularity) | 1461 | if (i + 1 < dpolicy->granularity) |
1429 | break; | 1462 | break; |
1430 | 1463 | ||
@@ -1611,7 +1644,7 @@ void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi) | |||
1611 | } | 1644 | } |
1612 | 1645 | ||
1613 | /* This comes from f2fs_put_super */ | 1646 | /* This comes from f2fs_put_super */ |
1614 | bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi) | 1647 | bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) |
1615 | { | 1648 | { |
1616 | struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; | 1649 | struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; |
1617 | struct discard_policy dpolicy; | 1650 | struct discard_policy dpolicy; |
@@ -1619,6 +1652,7 @@ bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi) | |||
1619 | 1652 | ||
1620 | __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT, | 1653 | __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT, |
1621 | dcc->discard_granularity); | 1654 | dcc->discard_granularity); |
1655 | dpolicy.timeout = UMOUNT_DISCARD_TIMEOUT; | ||
1622 | __issue_discard_cmd(sbi, &dpolicy); | 1656 | __issue_discard_cmd(sbi, &dpolicy); |
1623 | dropped = __drop_discard_cmd(sbi); | 1657 | dropped = __drop_discard_cmd(sbi); |
1624 | 1658 | ||
@@ -3164,10 +3198,10 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio) | |||
3164 | stat_inc_inplace_blocks(fio->sbi); | 3198 | stat_inc_inplace_blocks(fio->sbi); |
3165 | 3199 | ||
3166 | err = f2fs_submit_page_bio(fio); | 3200 | err = f2fs_submit_page_bio(fio); |
3167 | if (!err) | 3201 | if (!err) { |
3168 | update_device_state(fio); | 3202 | update_device_state(fio); |
3169 | 3203 | f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE); | |
3170 | f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE); | 3204 | } |
3171 | 3205 | ||
3172 | return err; | 3206 | return err; |
3173 | } | 3207 | } |