Commit 479f40c44ae30e02642ce0391be707a53852d545
1 parent
d928bfbfe7
Exists in
master
and in
13 other branches
f2fs: skip unnecessary node writes during fsync
If multiple redundant fsync calls are triggered, we don't need to write its node pages with fsync mark continuously. So, this patch adds FI_NEED_FSYNC to track whether the latest node block is written with the fsync mark or not. If the mark was set, a new fsync doesn't need to write a node block. Otherwise, we should do a new node block with the mark for roll-forward recovery. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Showing 4 changed files with 32 additions and 9 deletions Side-by-side Diff
fs/f2fs/f2fs.h
... | ... | @@ -1126,6 +1126,7 @@ |
1126 | 1126 | struct node_info; |
1127 | 1127 | |
1128 | 1128 | int is_checkpointed_node(struct f2fs_sb_info *, nid_t); |
1129 | +bool fsync_mark_done(struct f2fs_sb_info *, nid_t); | |
1129 | 1130 | void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); |
1130 | 1131 | int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); |
1131 | 1132 | int truncate_inode_blocks(struct inode *, pgoff_t); |
fs/f2fs/file.c
... | ... | @@ -176,6 +176,8 @@ |
176 | 176 | } else { |
177 | 177 | /* if there is no written node page, write its inode page */ |
178 | 178 | while (!sync_node_pages(sbi, inode->i_ino, &wbc)) { |
179 | + if (fsync_mark_done(sbi, inode->i_ino)) | |
180 | + goto out; | |
179 | 181 | mark_inode_dirty_sync(inode); |
180 | 182 | ret = f2fs_write_inode(inode, NULL); |
181 | 183 | if (ret) |
fs/f2fs/node.c
... | ... | @@ -133,6 +133,20 @@ |
133 | 133 | return is_cp; |
134 | 134 | } |
135 | 135 | |
136 | +bool fsync_mark_done(struct f2fs_sb_info *sbi, nid_t nid) | |
137 | +{ | |
138 | + struct f2fs_nm_info *nm_i = NM_I(sbi); | |
139 | + struct nat_entry *e; | |
140 | + bool fsync_done = false; | |
141 | + | |
142 | + read_lock(&nm_i->nat_tree_lock); | |
143 | + e = __lookup_nat_cache(nm_i, nid); | |
144 | + if (e) | |
145 | + fsync_done = e->fsync_done; | |
146 | + read_unlock(&nm_i->nat_tree_lock); | |
147 | + return fsync_done; | |
148 | +} | |
149 | + | |
136 | 150 | static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid) |
137 | 151 | { |
138 | 152 | struct nat_entry *new; |
... | ... | @@ -173,7 +187,7 @@ |
173 | 187 | } |
174 | 188 | |
175 | 189 | static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, |
176 | - block_t new_blkaddr) | |
190 | + block_t new_blkaddr, bool fsync_done) | |
177 | 191 | { |
178 | 192 | struct f2fs_nm_info *nm_i = NM_I(sbi); |
179 | 193 | struct nat_entry *e; |
... | ... | @@ -217,6 +231,11 @@ |
217 | 231 | /* change address */ |
218 | 232 | nat_set_blkaddr(e, new_blkaddr); |
219 | 233 | __set_nat_cache_dirty(nm_i, e); |
234 | + | |
235 | + /* update fsync_mark if its inode nat entry is still alive */ | |
236 | + e = __lookup_nat_cache(nm_i, ni->ino); | |
237 | + if (e) | |
238 | + e->fsync_done = fsync_done; | |
220 | 239 | write_unlock(&nm_i->nat_tree_lock); |
221 | 240 | } |
222 | 241 | |
... | ... | @@ -483,7 +502,7 @@ |
483 | 502 | /* Deallocate node address */ |
484 | 503 | invalidate_blocks(sbi, ni.blk_addr); |
485 | 504 | dec_valid_node_count(sbi, dn->inode); |
486 | - set_node_addr(sbi, &ni, NULL_ADDR); | |
505 | + set_node_addr(sbi, &ni, NULL_ADDR, false); | |
487 | 506 | |
488 | 507 | if (dn->nid == dn->inode->i_ino) { |
489 | 508 | remove_orphan_inode(sbi, dn->nid); |
... | ... | @@ -846,7 +865,7 @@ |
846 | 865 | f2fs_bug_on(old_ni.blk_addr != NULL_ADDR); |
847 | 866 | new_ni = old_ni; |
848 | 867 | new_ni.ino = dn->inode->i_ino; |
849 | - set_node_addr(sbi, &new_ni, NEW_ADDR); | |
868 | + set_node_addr(sbi, &new_ni, NEW_ADDR, false); | |
850 | 869 | |
851 | 870 | fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true); |
852 | 871 | set_cold_node(dn->inode, page); |
... | ... | @@ -1202,7 +1221,7 @@ |
1202 | 1221 | mutex_lock(&sbi->node_write); |
1203 | 1222 | set_page_writeback(page); |
1204 | 1223 | write_node_page(sbi, page, &fio, nid, ni.blk_addr, &new_addr); |
1205 | - set_node_addr(sbi, &ni, new_addr); | |
1224 | + set_node_addr(sbi, &ni, new_addr, is_fsync_dnode(page)); | |
1206 | 1225 | dec_page_count(sbi, F2FS_DIRTY_NODES); |
1207 | 1226 | mutex_unlock(&sbi->node_write); |
1208 | 1227 | unlock_page(page); |
... | ... | @@ -1503,7 +1522,7 @@ |
1503 | 1522 | block_t new_blkaddr) |
1504 | 1523 | { |
1505 | 1524 | rewrite_node_page(sbi, page, sum, ni->blk_addr, new_blkaddr); |
1506 | - set_node_addr(sbi, ni, new_blkaddr); | |
1525 | + set_node_addr(sbi, ni, new_blkaddr, false); | |
1507 | 1526 | clear_node_page_dirty(page); |
1508 | 1527 | } |
1509 | 1528 | |
... | ... | @@ -1559,7 +1578,7 @@ |
1559 | 1578 | f2fs_bug_on(ni.blk_addr == NULL_ADDR); |
1560 | 1579 | invalidate_blocks(sbi, ni.blk_addr); |
1561 | 1580 | dec_valid_node_count(sbi, inode); |
1562 | - set_node_addr(sbi, &ni, NULL_ADDR); | |
1581 | + set_node_addr(sbi, &ni, NULL_ADDR, false); | |
1563 | 1582 | |
1564 | 1583 | recover_xnid: |
1565 | 1584 | /* 2: allocate new xattr nid */ |
1566 | 1585 | |
... | ... | @@ -1569,12 +1588,12 @@ |
1569 | 1588 | remove_free_nid(NM_I(sbi), new_xnid); |
1570 | 1589 | get_node_info(sbi, new_xnid, &ni); |
1571 | 1590 | ni.ino = inode->i_ino; |
1572 | - set_node_addr(sbi, &ni, NEW_ADDR); | |
1591 | + set_node_addr(sbi, &ni, NEW_ADDR, false); | |
1573 | 1592 | F2FS_I(inode)->i_xattr_nid = new_xnid; |
1574 | 1593 | |
1575 | 1594 | /* 3: update xattr blkaddr */ |
1576 | 1595 | refresh_sit_entry(sbi, NEW_ADDR, blkaddr); |
1577 | - set_node_addr(sbi, &ni, blkaddr); | |
1596 | + set_node_addr(sbi, &ni, blkaddr, false); | |
1578 | 1597 | |
1579 | 1598 | update_inode_page(inode); |
1580 | 1599 | return true; |
... | ... | @@ -1612,7 +1631,7 @@ |
1612 | 1631 | |
1613 | 1632 | if (unlikely(!inc_valid_node_count(sbi, NULL))) |
1614 | 1633 | WARN_ON(1); |
1615 | - set_node_addr(sbi, &new_ni, NEW_ADDR); | |
1634 | + set_node_addr(sbi, &new_ni, NEW_ADDR, false); | |
1616 | 1635 | inc_valid_inode_count(sbi); |
1617 | 1636 | f2fs_put_page(ipage, 1); |
1618 | 1637 | return 0; |
fs/f2fs/node.h
... | ... | @@ -42,6 +42,7 @@ |
42 | 42 | struct nat_entry { |
43 | 43 | struct list_head list; /* for clean or dirty nat list */ |
44 | 44 | bool checkpointed; /* whether it is checkpointed or not */ |
45 | + bool fsync_done; /* whether the latest node has fsync mark */ | |
45 | 46 | struct node_info ni; /* in-memory node information */ |
46 | 47 | }; |
47 | 48 |