diff options
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r-- | fs/f2fs/segment.c | 386 |
1 files changed, 234 insertions, 152 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 5904a411c86f..6f16b39f0b52 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c | |||
@@ -191,70 +191,145 @@ void register_inmem_page(struct inode *inode, struct page *page) | |||
191 | trace_f2fs_register_inmem_page(page, INMEM); | 191 | trace_f2fs_register_inmem_page(page, INMEM); |
192 | } | 192 | } |
193 | 193 | ||
194 | int commit_inmem_pages(struct inode *inode, bool abort) | 194 | static int __revoke_inmem_pages(struct inode *inode, |
195 | struct list_head *head, bool drop, bool recover) | ||
196 | { | ||
197 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | ||
198 | struct inmem_pages *cur, *tmp; | ||
199 | int err = 0; | ||
200 | |||
201 | list_for_each_entry_safe(cur, tmp, head, list) { | ||
202 | struct page *page = cur->page; | ||
203 | |||
204 | if (drop) | ||
205 | trace_f2fs_commit_inmem_page(page, INMEM_DROP); | ||
206 | |||
207 | lock_page(page); | ||
208 | |||
209 | if (recover) { | ||
210 | struct dnode_of_data dn; | ||
211 | struct node_info ni; | ||
212 | |||
213 | trace_f2fs_commit_inmem_page(page, INMEM_REVOKE); | ||
214 | |||
215 | set_new_dnode(&dn, inode, NULL, NULL, 0); | ||
216 | if (get_dnode_of_data(&dn, page->index, LOOKUP_NODE)) { | ||
217 | err = -EAGAIN; | ||
218 | goto next; | ||
219 | } | ||
220 | get_node_info(sbi, dn.nid, &ni); | ||
221 | f2fs_replace_block(sbi, &dn, dn.data_blkaddr, | ||
222 | cur->old_addr, ni.version, true, true); | ||
223 | f2fs_put_dnode(&dn); | ||
224 | } | ||
225 | next: | ||
226 | ClearPageUptodate(page); | ||
227 | set_page_private(page, 0); | ||
228 | ClearPageUptodate(page); | ||
229 | f2fs_put_page(page, 1); | ||
230 | |||
231 | list_del(&cur->list); | ||
232 | kmem_cache_free(inmem_entry_slab, cur); | ||
233 | dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); | ||
234 | } | ||
235 | return err; | ||
236 | } | ||
237 | |||
238 | void drop_inmem_pages(struct inode *inode) | ||
239 | { | ||
240 | struct f2fs_inode_info *fi = F2FS_I(inode); | ||
241 | |||
242 | mutex_lock(&fi->inmem_lock); | ||
243 | __revoke_inmem_pages(inode, &fi->inmem_pages, true, false); | ||
244 | mutex_unlock(&fi->inmem_lock); | ||
245 | } | ||
246 | |||
247 | static int __commit_inmem_pages(struct inode *inode, | ||
248 | struct list_head *revoke_list) | ||
195 | { | 249 | { |
196 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 250 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
197 | struct f2fs_inode_info *fi = F2FS_I(inode); | 251 | struct f2fs_inode_info *fi = F2FS_I(inode); |
198 | struct inmem_pages *cur, *tmp; | 252 | struct inmem_pages *cur, *tmp; |
199 | bool submit_bio = false; | ||
200 | struct f2fs_io_info fio = { | 253 | struct f2fs_io_info fio = { |
201 | .sbi = sbi, | 254 | .sbi = sbi, |
202 | .type = DATA, | 255 | .type = DATA, |
203 | .rw = WRITE_SYNC | REQ_PRIO, | 256 | .rw = WRITE_SYNC | REQ_PRIO, |
204 | .encrypted_page = NULL, | 257 | .encrypted_page = NULL, |
205 | }; | 258 | }; |
259 | bool submit_bio = false; | ||
206 | int err = 0; | 260 | int err = 0; |
207 | 261 | ||
208 | /* | ||
209 | * The abort is true only when f2fs_evict_inode is called. | ||
210 | * Basically, the f2fs_evict_inode doesn't produce any data writes, so | ||
211 | * that we don't need to call f2fs_balance_fs. | ||
212 | * Otherwise, f2fs_gc in f2fs_balance_fs can wait forever until this | ||
213 | * inode becomes free by iget_locked in f2fs_iget. | ||
214 | */ | ||
215 | if (!abort) { | ||
216 | f2fs_balance_fs(sbi, true); | ||
217 | f2fs_lock_op(sbi); | ||
218 | } | ||
219 | |||
220 | mutex_lock(&fi->inmem_lock); | ||
221 | list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) { | 262 | list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) { |
222 | lock_page(cur->page); | 263 | struct page *page = cur->page; |
223 | if (!abort) { | 264 | |
224 | if (cur->page->mapping == inode->i_mapping) { | 265 | lock_page(page); |
225 | set_page_dirty(cur->page); | 266 | if (page->mapping == inode->i_mapping) { |
226 | f2fs_wait_on_page_writeback(cur->page, DATA); | 267 | trace_f2fs_commit_inmem_page(page, INMEM); |
227 | if (clear_page_dirty_for_io(cur->page)) | 268 | |
228 | inode_dec_dirty_pages(inode); | 269 | set_page_dirty(page); |
229 | trace_f2fs_commit_inmem_page(cur->page, INMEM); | 270 | f2fs_wait_on_page_writeback(page, DATA, true); |
230 | fio.page = cur->page; | 271 | if (clear_page_dirty_for_io(page)) |
231 | err = do_write_data_page(&fio); | 272 | inode_dec_dirty_pages(inode); |
232 | if (err) { | 273 | |
233 | unlock_page(cur->page); | 274 | fio.page = page; |
234 | break; | 275 | err = do_write_data_page(&fio); |
235 | } | 276 | if (err) { |
236 | clear_cold_data(cur->page); | 277 | unlock_page(page); |
237 | submit_bio = true; | 278 | break; |
238 | } | 279 | } |
239 | } else { | 280 | |
240 | ClearPageUptodate(cur->page); | 281 | /* record old blkaddr for revoking */ |
241 | trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP); | 282 | cur->old_addr = fio.old_blkaddr; |
283 | |||
284 | clear_cold_data(page); | ||
285 | submit_bio = true; | ||
242 | } | 286 | } |
243 | set_page_private(cur->page, 0); | 287 | unlock_page(page); |
244 | ClearPagePrivate(cur->page); | 288 | list_move_tail(&cur->list, revoke_list); |
245 | f2fs_put_page(cur->page, 1); | 289 | } |
246 | 290 | ||
247 | list_del(&cur->list); | 291 | if (submit_bio) |
248 | kmem_cache_free(inmem_entry_slab, cur); | 292 | f2fs_submit_merged_bio_cond(sbi, inode, NULL, 0, DATA, WRITE); |
249 | dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); | 293 | |
294 | if (!err) | ||
295 | __revoke_inmem_pages(inode, revoke_list, false, false); | ||
296 | |||
297 | return err; | ||
298 | } | ||
299 | |||
300 | int commit_inmem_pages(struct inode *inode) | ||
301 | { | ||
302 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | ||
303 | struct f2fs_inode_info *fi = F2FS_I(inode); | ||
304 | struct list_head revoke_list; | ||
305 | int err; | ||
306 | |||
307 | INIT_LIST_HEAD(&revoke_list); | ||
308 | f2fs_balance_fs(sbi, true); | ||
309 | f2fs_lock_op(sbi); | ||
310 | |||
311 | mutex_lock(&fi->inmem_lock); | ||
312 | err = __commit_inmem_pages(inode, &revoke_list); | ||
313 | if (err) { | ||
314 | int ret; | ||
315 | /* | ||
316 | * try to revoke all committed pages, but still we could fail | ||
317 | * due to no memory or other reason, if that happened, EAGAIN | ||
318 | * will be returned, which means in such case, transaction is | ||
319 | * already not integrity, caller should use journal to do the | ||
320 | * recovery or rewrite & commit last transaction. For other | ||
321 | * error number, revoking was done by filesystem itself. | ||
322 | */ | ||
323 | ret = __revoke_inmem_pages(inode, &revoke_list, false, true); | ||
324 | if (ret) | ||
325 | err = ret; | ||
326 | |||
327 | /* drop all uncommitted pages */ | ||
328 | __revoke_inmem_pages(inode, &fi->inmem_pages, true, false); | ||
250 | } | 329 | } |
251 | mutex_unlock(&fi->inmem_lock); | 330 | mutex_unlock(&fi->inmem_lock); |
252 | 331 | ||
253 | if (!abort) { | 332 | f2fs_unlock_op(sbi); |
254 | f2fs_unlock_op(sbi); | ||
255 | if (submit_bio) | ||
256 | f2fs_submit_merged_bio(sbi, DATA, WRITE); | ||
257 | } | ||
258 | return err; | 333 | return err; |
259 | } | 334 | } |
260 | 335 | ||
@@ -291,11 +366,17 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) | |||
291 | 366 | ||
292 | /* checkpoint is the only way to shrink partial cached entries */ | 367 | /* checkpoint is the only way to shrink partial cached entries */ |
293 | if (!available_free_memory(sbi, NAT_ENTRIES) || | 368 | if (!available_free_memory(sbi, NAT_ENTRIES) || |
294 | excess_prefree_segs(sbi) || | ||
295 | !available_free_memory(sbi, INO_ENTRIES) || | 369 | !available_free_memory(sbi, INO_ENTRIES) || |
370 | excess_prefree_segs(sbi) || | ||
371 | excess_dirty_nats(sbi) || | ||
296 | (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) { | 372 | (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) { |
297 | if (test_opt(sbi, DATA_FLUSH)) | 373 | if (test_opt(sbi, DATA_FLUSH)) { |
374 | struct blk_plug plug; | ||
375 | |||
376 | blk_start_plug(&plug); | ||
298 | sync_dirty_inodes(sbi, FILE_INODE); | 377 | sync_dirty_inodes(sbi, FILE_INODE); |
378 | blk_finish_plug(&plug); | ||
379 | } | ||
299 | f2fs_sync_fs(sbi->sb, true); | 380 | f2fs_sync_fs(sbi->sb, true); |
300 | stat_inc_bg_cp_count(sbi->stat_info); | 381 | stat_inc_bg_cp_count(sbi->stat_info); |
301 | } | 382 | } |
@@ -502,7 +583,7 @@ static int f2fs_issue_discard(struct f2fs_sb_info *sbi, | |||
502 | 583 | ||
503 | bool discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr) | 584 | bool discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr) |
504 | { | 585 | { |
505 | int err = -ENOTSUPP; | 586 | int err = -EOPNOTSUPP; |
506 | 587 | ||
507 | if (test_opt(sbi, DISCARD)) { | 588 | if (test_opt(sbi, DISCARD)) { |
508 | struct seg_entry *se = get_seg_entry(sbi, | 589 | struct seg_entry *se = get_seg_entry(sbi, |
@@ -841,6 +922,31 @@ static void write_sum_page(struct f2fs_sb_info *sbi, | |||
841 | update_meta_page(sbi, (void *)sum_blk, blk_addr); | 922 | update_meta_page(sbi, (void *)sum_blk, blk_addr); |
842 | } | 923 | } |
843 | 924 | ||
925 | static void write_current_sum_page(struct f2fs_sb_info *sbi, | ||
926 | int type, block_t blk_addr) | ||
927 | { | ||
928 | struct curseg_info *curseg = CURSEG_I(sbi, type); | ||
929 | struct page *page = grab_meta_page(sbi, blk_addr); | ||
930 | struct f2fs_summary_block *src = curseg->sum_blk; | ||
931 | struct f2fs_summary_block *dst; | ||
932 | |||
933 | dst = (struct f2fs_summary_block *)page_address(page); | ||
934 | |||
935 | mutex_lock(&curseg->curseg_mutex); | ||
936 | |||
937 | down_read(&curseg->journal_rwsem); | ||
938 | memcpy(&dst->journal, curseg->journal, SUM_JOURNAL_SIZE); | ||
939 | up_read(&curseg->journal_rwsem); | ||
940 | |||
941 | memcpy(dst->entries, src->entries, SUM_ENTRY_SIZE); | ||
942 | memcpy(&dst->footer, &src->footer, SUM_FOOTER_SIZE); | ||
943 | |||
944 | mutex_unlock(&curseg->curseg_mutex); | ||
945 | |||
946 | set_page_dirty(page); | ||
947 | f2fs_put_page(page, 1); | ||
948 | } | ||
949 | |||
844 | static int is_next_segment_free(struct f2fs_sb_info *sbi, int type) | 950 | static int is_next_segment_free(struct f2fs_sb_info *sbi, int type) |
845 | { | 951 | { |
846 | struct curseg_info *curseg = CURSEG_I(sbi, type); | 952 | struct curseg_info *curseg = CURSEG_I(sbi, type); |
@@ -873,9 +979,8 @@ static void get_new_segment(struct f2fs_sb_info *sbi, | |||
873 | 979 | ||
874 | if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { | 980 | if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { |
875 | segno = find_next_zero_bit(free_i->free_segmap, | 981 | segno = find_next_zero_bit(free_i->free_segmap, |
876 | MAIN_SEGS(sbi), *newseg + 1); | 982 | (hint + 1) * sbi->segs_per_sec, *newseg + 1); |
877 | if (segno - *newseg < sbi->segs_per_sec - | 983 | if (segno < (hint + 1) * sbi->segs_per_sec) |
878 | (*newseg % sbi->segs_per_sec)) | ||
879 | goto got_it; | 984 | goto got_it; |
880 | } | 985 | } |
881 | find_other_zone: | 986 | find_other_zone: |
@@ -1280,8 +1385,8 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) | |||
1280 | { | 1385 | { |
1281 | int type = __get_segment_type(fio->page, fio->type); | 1386 | int type = __get_segment_type(fio->page, fio->type); |
1282 | 1387 | ||
1283 | allocate_data_block(fio->sbi, fio->page, fio->blk_addr, | 1388 | allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, |
1284 | &fio->blk_addr, sum, type); | 1389 | &fio->new_blkaddr, sum, type); |
1285 | 1390 | ||
1286 | /* writeout dirty page into bdev */ | 1391 | /* writeout dirty page into bdev */ |
1287 | f2fs_submit_page_mbio(fio); | 1392 | f2fs_submit_page_mbio(fio); |
@@ -1293,7 +1398,8 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page) | |||
1293 | .sbi = sbi, | 1398 | .sbi = sbi, |
1294 | .type = META, | 1399 | .type = META, |
1295 | .rw = WRITE_SYNC | REQ_META | REQ_PRIO, | 1400 | .rw = WRITE_SYNC | REQ_META | REQ_PRIO, |
1296 | .blk_addr = page->index, | 1401 | .old_blkaddr = page->index, |
1402 | .new_blkaddr = page->index, | ||
1297 | .page = page, | 1403 | .page = page, |
1298 | .encrypted_page = NULL, | 1404 | .encrypted_page = NULL, |
1299 | }; | 1405 | }; |
@@ -1323,19 +1429,19 @@ void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio) | |||
1323 | get_node_info(sbi, dn->nid, &ni); | 1429 | get_node_info(sbi, dn->nid, &ni); |
1324 | set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); | 1430 | set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); |
1325 | do_write_page(&sum, fio); | 1431 | do_write_page(&sum, fio); |
1326 | dn->data_blkaddr = fio->blk_addr; | 1432 | f2fs_update_data_blkaddr(dn, fio->new_blkaddr); |
1327 | } | 1433 | } |
1328 | 1434 | ||
1329 | void rewrite_data_page(struct f2fs_io_info *fio) | 1435 | void rewrite_data_page(struct f2fs_io_info *fio) |
1330 | { | 1436 | { |
1437 | fio->new_blkaddr = fio->old_blkaddr; | ||
1331 | stat_inc_inplace_blocks(fio->sbi); | 1438 | stat_inc_inplace_blocks(fio->sbi); |
1332 | f2fs_submit_page_mbio(fio); | 1439 | f2fs_submit_page_mbio(fio); |
1333 | } | 1440 | } |
1334 | 1441 | ||
1335 | static void __f2fs_replace_block(struct f2fs_sb_info *sbi, | 1442 | void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, |
1336 | struct f2fs_summary *sum, | ||
1337 | block_t old_blkaddr, block_t new_blkaddr, | 1443 | block_t old_blkaddr, block_t new_blkaddr, |
1338 | bool recover_curseg) | 1444 | bool recover_curseg, bool recover_newaddr) |
1339 | { | 1445 | { |
1340 | struct sit_info *sit_i = SIT_I(sbi); | 1446 | struct sit_info *sit_i = SIT_I(sbi); |
1341 | struct curseg_info *curseg; | 1447 | struct curseg_info *curseg; |
@@ -1378,7 +1484,7 @@ static void __f2fs_replace_block(struct f2fs_sb_info *sbi, | |||
1378 | curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); | 1484 | curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); |
1379 | __add_sum_entry(sbi, type, sum); | 1485 | __add_sum_entry(sbi, type, sum); |
1380 | 1486 | ||
1381 | if (!recover_curseg) | 1487 | if (!recover_curseg || recover_newaddr) |
1382 | update_sit_entry(sbi, new_blkaddr, 1); | 1488 | update_sit_entry(sbi, new_blkaddr, 1); |
1383 | if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) | 1489 | if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) |
1384 | update_sit_entry(sbi, old_blkaddr, -1); | 1490 | update_sit_entry(sbi, old_blkaddr, -1); |
@@ -1402,66 +1508,30 @@ static void __f2fs_replace_block(struct f2fs_sb_info *sbi, | |||
1402 | 1508 | ||
1403 | void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, | 1509 | void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, |
1404 | block_t old_addr, block_t new_addr, | 1510 | block_t old_addr, block_t new_addr, |
1405 | unsigned char version, bool recover_curseg) | 1511 | unsigned char version, bool recover_curseg, |
1512 | bool recover_newaddr) | ||
1406 | { | 1513 | { |
1407 | struct f2fs_summary sum; | 1514 | struct f2fs_summary sum; |
1408 | 1515 | ||
1409 | set_summary(&sum, dn->nid, dn->ofs_in_node, version); | 1516 | set_summary(&sum, dn->nid, dn->ofs_in_node, version); |
1410 | 1517 | ||
1411 | __f2fs_replace_block(sbi, &sum, old_addr, new_addr, recover_curseg); | 1518 | __f2fs_replace_block(sbi, &sum, old_addr, new_addr, |
1519 | recover_curseg, recover_newaddr); | ||
1412 | 1520 | ||
1413 | dn->data_blkaddr = new_addr; | 1521 | f2fs_update_data_blkaddr(dn, new_addr); |
1414 | set_data_blkaddr(dn); | ||
1415 | f2fs_update_extent_cache(dn); | ||
1416 | } | ||
1417 | |||
1418 | static inline bool is_merged_page(struct f2fs_sb_info *sbi, | ||
1419 | struct page *page, enum page_type type) | ||
1420 | { | ||
1421 | enum page_type btype = PAGE_TYPE_OF_BIO(type); | ||
1422 | struct f2fs_bio_info *io = &sbi->write_io[btype]; | ||
1423 | struct bio_vec *bvec; | ||
1424 | struct page *target; | ||
1425 | int i; | ||
1426 | |||
1427 | down_read(&io->io_rwsem); | ||
1428 | if (!io->bio) { | ||
1429 | up_read(&io->io_rwsem); | ||
1430 | return false; | ||
1431 | } | ||
1432 | |||
1433 | bio_for_each_segment_all(bvec, io->bio, i) { | ||
1434 | |||
1435 | if (bvec->bv_page->mapping) { | ||
1436 | target = bvec->bv_page; | ||
1437 | } else { | ||
1438 | struct f2fs_crypto_ctx *ctx; | ||
1439 | |||
1440 | /* encrypted page */ | ||
1441 | ctx = (struct f2fs_crypto_ctx *)page_private( | ||
1442 | bvec->bv_page); | ||
1443 | target = ctx->w.control_page; | ||
1444 | } | ||
1445 | |||
1446 | if (page == target) { | ||
1447 | up_read(&io->io_rwsem); | ||
1448 | return true; | ||
1449 | } | ||
1450 | } | ||
1451 | |||
1452 | up_read(&io->io_rwsem); | ||
1453 | return false; | ||
1454 | } | 1522 | } |
1455 | 1523 | ||
1456 | void f2fs_wait_on_page_writeback(struct page *page, | 1524 | void f2fs_wait_on_page_writeback(struct page *page, |
1457 | enum page_type type) | 1525 | enum page_type type, bool ordered) |
1458 | { | 1526 | { |
1459 | if (PageWriteback(page)) { | 1527 | if (PageWriteback(page)) { |
1460 | struct f2fs_sb_info *sbi = F2FS_P_SB(page); | 1528 | struct f2fs_sb_info *sbi = F2FS_P_SB(page); |
1461 | 1529 | ||
1462 | if (is_merged_page(sbi, page, type)) | 1530 | f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, type, WRITE); |
1463 | f2fs_submit_merged_bio(sbi, type, WRITE); | 1531 | if (ordered) |
1464 | wait_on_page_writeback(page); | 1532 | wait_on_page_writeback(page); |
1533 | else | ||
1534 | wait_for_stable_page(page); | ||
1465 | } | 1535 | } |
1466 | } | 1536 | } |
1467 | 1537 | ||
@@ -1477,7 +1547,7 @@ void f2fs_wait_on_encrypted_page_writeback(struct f2fs_sb_info *sbi, | |||
1477 | 1547 | ||
1478 | cpage = find_lock_page(META_MAPPING(sbi), blkaddr); | 1548 | cpage = find_lock_page(META_MAPPING(sbi), blkaddr); |
1479 | if (cpage) { | 1549 | if (cpage) { |
1480 | f2fs_wait_on_page_writeback(cpage, DATA); | 1550 | f2fs_wait_on_page_writeback(cpage, DATA, true); |
1481 | f2fs_put_page(cpage, 1); | 1551 | f2fs_put_page(cpage, 1); |
1482 | } | 1552 | } |
1483 | } | 1553 | } |
@@ -1498,12 +1568,11 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi) | |||
1498 | 1568 | ||
1499 | /* Step 1: restore nat cache */ | 1569 | /* Step 1: restore nat cache */ |
1500 | seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); | 1570 | seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); |
1501 | memcpy(&seg_i->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE); | 1571 | memcpy(seg_i->journal, kaddr, SUM_JOURNAL_SIZE); |
1502 | 1572 | ||
1503 | /* Step 2: restore sit cache */ | 1573 | /* Step 2: restore sit cache */ |
1504 | seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); | 1574 | seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); |
1505 | memcpy(&seg_i->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, | 1575 | memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); |
1506 | SUM_JOURNAL_SIZE); | ||
1507 | offset = 2 * SUM_JOURNAL_SIZE; | 1576 | offset = 2 * SUM_JOURNAL_SIZE; |
1508 | 1577 | ||
1509 | /* Step 3: restore summary entries */ | 1578 | /* Step 3: restore summary entries */ |
@@ -1599,7 +1668,14 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) | |||
1599 | /* set uncompleted segment to curseg */ | 1668 | /* set uncompleted segment to curseg */ |
1600 | curseg = CURSEG_I(sbi, type); | 1669 | curseg = CURSEG_I(sbi, type); |
1601 | mutex_lock(&curseg->curseg_mutex); | 1670 | mutex_lock(&curseg->curseg_mutex); |
1602 | memcpy(curseg->sum_blk, sum, PAGE_CACHE_SIZE); | 1671 | |
1672 | /* update journal info */ | ||
1673 | down_write(&curseg->journal_rwsem); | ||
1674 | memcpy(curseg->journal, &sum->journal, SUM_JOURNAL_SIZE); | ||
1675 | up_write(&curseg->journal_rwsem); | ||
1676 | |||
1677 | memcpy(curseg->sum_blk->entries, sum->entries, SUM_ENTRY_SIZE); | ||
1678 | memcpy(&curseg->sum_blk->footer, &sum->footer, SUM_FOOTER_SIZE); | ||
1603 | curseg->next_segno = segno; | 1679 | curseg->next_segno = segno; |
1604 | reset_curseg(sbi, type, 0); | 1680 | reset_curseg(sbi, type, 0); |
1605 | curseg->alloc_type = ckpt->alloc_type[type]; | 1681 | curseg->alloc_type = ckpt->alloc_type[type]; |
@@ -1654,13 +1730,12 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) | |||
1654 | 1730 | ||
1655 | /* Step 1: write nat cache */ | 1731 | /* Step 1: write nat cache */ |
1656 | seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); | 1732 | seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); |
1657 | memcpy(kaddr, &seg_i->sum_blk->n_nats, SUM_JOURNAL_SIZE); | 1733 | memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE); |
1658 | written_size += SUM_JOURNAL_SIZE; | 1734 | written_size += SUM_JOURNAL_SIZE; |
1659 | 1735 | ||
1660 | /* Step 2: write sit cache */ | 1736 | /* Step 2: write sit cache */ |
1661 | seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); | 1737 | seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); |
1662 | memcpy(kaddr + written_size, &seg_i->sum_blk->n_sits, | 1738 | memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE); |
1663 | SUM_JOURNAL_SIZE); | ||
1664 | written_size += SUM_JOURNAL_SIZE; | 1739 | written_size += SUM_JOURNAL_SIZE; |
1665 | 1740 | ||
1666 | /* Step 3: write summary entries */ | 1741 | /* Step 3: write summary entries */ |
@@ -1706,12 +1781,8 @@ static void write_normal_summaries(struct f2fs_sb_info *sbi, | |||
1706 | else | 1781 | else |
1707 | end = type + NR_CURSEG_NODE_TYPE; | 1782 | end = type + NR_CURSEG_NODE_TYPE; |
1708 | 1783 | ||
1709 | for (i = type; i < end; i++) { | 1784 | for (i = type; i < end; i++) |
1710 | struct curseg_info *sum = CURSEG_I(sbi, i); | 1785 | write_current_sum_page(sbi, i, blkaddr + (i - type)); |
1711 | mutex_lock(&sum->curseg_mutex); | ||
1712 | write_sum_page(sbi, sum->sum_blk, blkaddr + (i - type)); | ||
1713 | mutex_unlock(&sum->curseg_mutex); | ||
1714 | } | ||
1715 | } | 1786 | } |
1716 | 1787 | ||
1717 | void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) | 1788 | void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) |
@@ -1727,24 +1798,24 @@ void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) | |||
1727 | write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); | 1798 | write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); |
1728 | } | 1799 | } |
1729 | 1800 | ||
1730 | int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, | 1801 | int lookup_journal_in_cursum(struct f2fs_journal *journal, int type, |
1731 | unsigned int val, int alloc) | 1802 | unsigned int val, int alloc) |
1732 | { | 1803 | { |
1733 | int i; | 1804 | int i; |
1734 | 1805 | ||
1735 | if (type == NAT_JOURNAL) { | 1806 | if (type == NAT_JOURNAL) { |
1736 | for (i = 0; i < nats_in_cursum(sum); i++) { | 1807 | for (i = 0; i < nats_in_cursum(journal); i++) { |
1737 | if (le32_to_cpu(nid_in_journal(sum, i)) == val) | 1808 | if (le32_to_cpu(nid_in_journal(journal, i)) == val) |
1738 | return i; | 1809 | return i; |
1739 | } | 1810 | } |
1740 | if (alloc && __has_cursum_space(sum, 1, NAT_JOURNAL)) | 1811 | if (alloc && __has_cursum_space(journal, 1, NAT_JOURNAL)) |
1741 | return update_nats_in_cursum(sum, 1); | 1812 | return update_nats_in_cursum(journal, 1); |
1742 | } else if (type == SIT_JOURNAL) { | 1813 | } else if (type == SIT_JOURNAL) { |
1743 | for (i = 0; i < sits_in_cursum(sum); i++) | 1814 | for (i = 0; i < sits_in_cursum(journal); i++) |
1744 | if (le32_to_cpu(segno_in_journal(sum, i)) == val) | 1815 | if (le32_to_cpu(segno_in_journal(journal, i)) == val) |
1745 | return i; | 1816 | return i; |
1746 | if (alloc && __has_cursum_space(sum, 1, SIT_JOURNAL)) | 1817 | if (alloc && __has_cursum_space(journal, 1, SIT_JOURNAL)) |
1747 | return update_sits_in_cursum(sum, 1); | 1818 | return update_sits_in_cursum(journal, 1); |
1748 | } | 1819 | } |
1749 | return -1; | 1820 | return -1; |
1750 | } | 1821 | } |
@@ -1848,20 +1919,22 @@ static void add_sits_in_set(struct f2fs_sb_info *sbi) | |||
1848 | static void remove_sits_in_journal(struct f2fs_sb_info *sbi) | 1919 | static void remove_sits_in_journal(struct f2fs_sb_info *sbi) |
1849 | { | 1920 | { |
1850 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); | 1921 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); |
1851 | struct f2fs_summary_block *sum = curseg->sum_blk; | 1922 | struct f2fs_journal *journal = curseg->journal; |
1852 | int i; | 1923 | int i; |
1853 | 1924 | ||
1854 | for (i = sits_in_cursum(sum) - 1; i >= 0; i--) { | 1925 | down_write(&curseg->journal_rwsem); |
1926 | for (i = 0; i < sits_in_cursum(journal); i++) { | ||
1855 | unsigned int segno; | 1927 | unsigned int segno; |
1856 | bool dirtied; | 1928 | bool dirtied; |
1857 | 1929 | ||
1858 | segno = le32_to_cpu(segno_in_journal(sum, i)); | 1930 | segno = le32_to_cpu(segno_in_journal(journal, i)); |
1859 | dirtied = __mark_sit_entry_dirty(sbi, segno); | 1931 | dirtied = __mark_sit_entry_dirty(sbi, segno); |
1860 | 1932 | ||
1861 | if (!dirtied) | 1933 | if (!dirtied) |
1862 | add_sit_entry(segno, &SM_I(sbi)->sit_entry_set); | 1934 | add_sit_entry(segno, &SM_I(sbi)->sit_entry_set); |
1863 | } | 1935 | } |
1864 | update_sits_in_cursum(sum, -sits_in_cursum(sum)); | 1936 | update_sits_in_cursum(journal, -i); |
1937 | up_write(&curseg->journal_rwsem); | ||
1865 | } | 1938 | } |
1866 | 1939 | ||
1867 | /* | 1940 | /* |
@@ -1873,13 +1946,12 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
1873 | struct sit_info *sit_i = SIT_I(sbi); | 1946 | struct sit_info *sit_i = SIT_I(sbi); |
1874 | unsigned long *bitmap = sit_i->dirty_sentries_bitmap; | 1947 | unsigned long *bitmap = sit_i->dirty_sentries_bitmap; |
1875 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); | 1948 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); |
1876 | struct f2fs_summary_block *sum = curseg->sum_blk; | 1949 | struct f2fs_journal *journal = curseg->journal; |
1877 | struct sit_entry_set *ses, *tmp; | 1950 | struct sit_entry_set *ses, *tmp; |
1878 | struct list_head *head = &SM_I(sbi)->sit_entry_set; | 1951 | struct list_head *head = &SM_I(sbi)->sit_entry_set; |
1879 | bool to_journal = true; | 1952 | bool to_journal = true; |
1880 | struct seg_entry *se; | 1953 | struct seg_entry *se; |
1881 | 1954 | ||
1882 | mutex_lock(&curseg->curseg_mutex); | ||
1883 | mutex_lock(&sit_i->sentry_lock); | 1955 | mutex_lock(&sit_i->sentry_lock); |
1884 | 1956 | ||
1885 | if (!sit_i->dirty_sentries) | 1957 | if (!sit_i->dirty_sentries) |
@@ -1896,7 +1968,7 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
1896 | * entries, remove all entries from journal and add and account | 1968 | * entries, remove all entries from journal and add and account |
1897 | * them in sit entry set. | 1969 | * them in sit entry set. |
1898 | */ | 1970 | */ |
1899 | if (!__has_cursum_space(sum, sit_i->dirty_sentries, SIT_JOURNAL)) | 1971 | if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL)) |
1900 | remove_sits_in_journal(sbi); | 1972 | remove_sits_in_journal(sbi); |
1901 | 1973 | ||
1902 | /* | 1974 | /* |
@@ -1913,10 +1985,12 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
1913 | unsigned int segno = start_segno; | 1985 | unsigned int segno = start_segno; |
1914 | 1986 | ||
1915 | if (to_journal && | 1987 | if (to_journal && |
1916 | !__has_cursum_space(sum, ses->entry_cnt, SIT_JOURNAL)) | 1988 | !__has_cursum_space(journal, ses->entry_cnt, SIT_JOURNAL)) |
1917 | to_journal = false; | 1989 | to_journal = false; |
1918 | 1990 | ||
1919 | if (!to_journal) { | 1991 | if (to_journal) { |
1992 | down_write(&curseg->journal_rwsem); | ||
1993 | } else { | ||
1920 | page = get_next_sit_page(sbi, start_segno); | 1994 | page = get_next_sit_page(sbi, start_segno); |
1921 | raw_sit = page_address(page); | 1995 | raw_sit = page_address(page); |
1922 | } | 1996 | } |
@@ -1934,13 +2008,13 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
1934 | } | 2008 | } |
1935 | 2009 | ||
1936 | if (to_journal) { | 2010 | if (to_journal) { |
1937 | offset = lookup_journal_in_cursum(sum, | 2011 | offset = lookup_journal_in_cursum(journal, |
1938 | SIT_JOURNAL, segno, 1); | 2012 | SIT_JOURNAL, segno, 1); |
1939 | f2fs_bug_on(sbi, offset < 0); | 2013 | f2fs_bug_on(sbi, offset < 0); |
1940 | segno_in_journal(sum, offset) = | 2014 | segno_in_journal(journal, offset) = |
1941 | cpu_to_le32(segno); | 2015 | cpu_to_le32(segno); |
1942 | seg_info_to_raw_sit(se, | 2016 | seg_info_to_raw_sit(se, |
1943 | &sit_in_journal(sum, offset)); | 2017 | &sit_in_journal(journal, offset)); |
1944 | } else { | 2018 | } else { |
1945 | sit_offset = SIT_ENTRY_OFFSET(sit_i, segno); | 2019 | sit_offset = SIT_ENTRY_OFFSET(sit_i, segno); |
1946 | seg_info_to_raw_sit(se, | 2020 | seg_info_to_raw_sit(se, |
@@ -1952,7 +2026,9 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
1952 | ses->entry_cnt--; | 2026 | ses->entry_cnt--; |
1953 | } | 2027 | } |
1954 | 2028 | ||
1955 | if (!to_journal) | 2029 | if (to_journal) |
2030 | up_write(&curseg->journal_rwsem); | ||
2031 | else | ||
1956 | f2fs_put_page(page, 1); | 2032 | f2fs_put_page(page, 1); |
1957 | 2033 | ||
1958 | f2fs_bug_on(sbi, ses->entry_cnt); | 2034 | f2fs_bug_on(sbi, ses->entry_cnt); |
@@ -1967,7 +2043,6 @@ out: | |||
1967 | add_discard_addrs(sbi, cpc); | 2043 | add_discard_addrs(sbi, cpc); |
1968 | } | 2044 | } |
1969 | mutex_unlock(&sit_i->sentry_lock); | 2045 | mutex_unlock(&sit_i->sentry_lock); |
1970 | mutex_unlock(&curseg->curseg_mutex); | ||
1971 | 2046 | ||
1972 | set_prefree_as_free_segments(sbi); | 2047 | set_prefree_as_free_segments(sbi); |
1973 | } | 2048 | } |
@@ -2099,6 +2174,11 @@ static int build_curseg(struct f2fs_sb_info *sbi) | |||
2099 | array[i].sum_blk = kzalloc(PAGE_CACHE_SIZE, GFP_KERNEL); | 2174 | array[i].sum_blk = kzalloc(PAGE_CACHE_SIZE, GFP_KERNEL); |
2100 | if (!array[i].sum_blk) | 2175 | if (!array[i].sum_blk) |
2101 | return -ENOMEM; | 2176 | return -ENOMEM; |
2177 | init_rwsem(&array[i].journal_rwsem); | ||
2178 | array[i].journal = kzalloc(sizeof(struct f2fs_journal), | ||
2179 | GFP_KERNEL); | ||
2180 | if (!array[i].journal) | ||
2181 | return -ENOMEM; | ||
2102 | array[i].segno = NULL_SEGNO; | 2182 | array[i].segno = NULL_SEGNO; |
2103 | array[i].next_blkoff = 0; | 2183 | array[i].next_blkoff = 0; |
2104 | } | 2184 | } |
@@ -2109,11 +2189,11 @@ static void build_sit_entries(struct f2fs_sb_info *sbi) | |||
2109 | { | 2189 | { |
2110 | struct sit_info *sit_i = SIT_I(sbi); | 2190 | struct sit_info *sit_i = SIT_I(sbi); |
2111 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); | 2191 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); |
2112 | struct f2fs_summary_block *sum = curseg->sum_blk; | 2192 | struct f2fs_journal *journal = curseg->journal; |
2113 | int sit_blk_cnt = SIT_BLK_CNT(sbi); | 2193 | int sit_blk_cnt = SIT_BLK_CNT(sbi); |
2114 | unsigned int i, start, end; | 2194 | unsigned int i, start, end; |
2115 | unsigned int readed, start_blk = 0; | 2195 | unsigned int readed, start_blk = 0; |
2116 | int nrpages = MAX_BIO_BLOCKS(sbi); | 2196 | int nrpages = MAX_BIO_BLOCKS(sbi) * 8; |
2117 | 2197 | ||
2118 | do { | 2198 | do { |
2119 | readed = ra_meta_pages(sbi, start_blk, nrpages, META_SIT, true); | 2199 | readed = ra_meta_pages(sbi, start_blk, nrpages, META_SIT, true); |
@@ -2127,16 +2207,16 @@ static void build_sit_entries(struct f2fs_sb_info *sbi) | |||
2127 | struct f2fs_sit_entry sit; | 2207 | struct f2fs_sit_entry sit; |
2128 | struct page *page; | 2208 | struct page *page; |
2129 | 2209 | ||
2130 | mutex_lock(&curseg->curseg_mutex); | 2210 | down_read(&curseg->journal_rwsem); |
2131 | for (i = 0; i < sits_in_cursum(sum); i++) { | 2211 | for (i = 0; i < sits_in_cursum(journal); i++) { |
2132 | if (le32_to_cpu(segno_in_journal(sum, i)) | 2212 | if (le32_to_cpu(segno_in_journal(journal, i)) |
2133 | == start) { | 2213 | == start) { |
2134 | sit = sit_in_journal(sum, i); | 2214 | sit = sit_in_journal(journal, i); |
2135 | mutex_unlock(&curseg->curseg_mutex); | 2215 | up_read(&curseg->journal_rwsem); |
2136 | goto got_it; | 2216 | goto got_it; |
2137 | } | 2217 | } |
2138 | } | 2218 | } |
2139 | mutex_unlock(&curseg->curseg_mutex); | 2219 | up_read(&curseg->journal_rwsem); |
2140 | 2220 | ||
2141 | page = get_current_sit_page(sbi, start); | 2221 | page = get_current_sit_page(sbi, start); |
2142 | sit_blk = (struct f2fs_sit_block *)page_address(page); | 2222 | sit_blk = (struct f2fs_sit_block *)page_address(page); |
@@ -2371,8 +2451,10 @@ static void destroy_curseg(struct f2fs_sb_info *sbi) | |||
2371 | if (!array) | 2451 | if (!array) |
2372 | return; | 2452 | return; |
2373 | SM_I(sbi)->curseg_array = NULL; | 2453 | SM_I(sbi)->curseg_array = NULL; |
2374 | for (i = 0; i < NR_CURSEG_TYPE; i++) | 2454 | for (i = 0; i < NR_CURSEG_TYPE; i++) { |
2375 | kfree(array[i].sum_blk); | 2455 | kfree(array[i].sum_blk); |
2456 | kfree(array[i].journal); | ||
2457 | } | ||
2376 | kfree(array); | 2458 | kfree(array); |
2377 | } | 2459 | } |
2378 | 2460 | ||