aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2014-09-15 17:50:48 -0400
committerJaegeuk Kim <jaegeuk@kernel.org>2014-09-23 14:10:15 -0400
commit88bd02c9472a166b706284a34a84f1243322d782 (patch)
treea729dceea6c10c86b8c2a1e7b2fa1355d1143ba3 /fs
parent7ef35e3b9e7a99db4930b58b33a94455dbf53276 (diff)
f2fs: fix conditions to remain recovery information in f2fs_sync_file
This patch revisited whole the recovery information during the f2fs_sync_file. In this patch, there are three information to make a decision. a) IS_CHECKPOINTED, /* is it checkpointed before? */ b) HAS_FSYNCED_INODE, /* is the inode fsynced before? */ c) HAS_LAST_FSYNC, /* has the latest node fsync mark? */ And, the scenarios for our rule are based on: [Term] F: fsync_mark, D: dentry_mark 1. inode(x) | CP | inode(x) | dnode(F) 2. inode(x) | CP | inode(F) | dnode(F) 3. inode(x) | CP | dnode(F) | inode(x) | inode(F) 4. inode(x) | CP | dnode(F) | inode(F) 5. CP | inode(x) | dnode(F) | inode(DF) 6. CP | inode(DF) | dnode(F) 7. CP | dnode(F) | inode(DF) 8. CP | dnode(F) | inode(x) | inode(DF) For example, #3, the three conditions should be changed as follows. inode(x) | CP | dnode(F) | inode(x) | inode(F) a) x o o o o b) x x x x o c) x o o x o If f2fs_sync_file stops ------^, it should write inode(F) --------------^ So, the need_inode_block_update should return true, since c) get_nat_flag(e, HAS_LAST_FSYNC), is false. For example, #8, CP | alloc | dnode(F) | inode(x) | inode(DF) a) o x x x x b) x x x o c) o o x o If f2fs_sync_file stops -------^, it should write inode(DF) --------------^ Note that, the roll-forward policy should follow this rule, which means, if there are any missing blocks, we doesn't need to recover that inode. Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/f2fs/data.c3
-rw-r--r--fs/f2fs/f2fs.h6
-rw-r--r--fs/f2fs/file.c10
-rw-r--r--fs/f2fs/node.c56
-rw-r--r--fs/f2fs/node.h21
5 files changed, 56 insertions, 40 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 0e376585e29f..fdc3dbe677a1 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1089,9 +1089,6 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
1089 if (check_direct_IO(inode, rw, iter, offset)) 1089 if (check_direct_IO(inode, rw, iter, offset))
1090 return 0; 1090 return 0;
1091 1091
1092 /* clear fsync mark to recover these blocks */
1093 fsync_mark_clear(F2FS_I_SB(inode), inode->i_ino);
1094
1095 trace_f2fs_direct_IO_enter(inode, offset, count, rw); 1092 trace_f2fs_direct_IO_enter(inode, offset, count, rw);
1096 1093
1097 err = blockdev_direct_IO(rw, iocb, inode, iter, offset, get_data_block); 1094 err = blockdev_direct_IO(rw, iocb, inode, iter, offset, get_data_block);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index b6439c3d1744..dbe5f939b7e7 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1224,9 +1224,9 @@ struct dnode_of_data;
1224struct node_info; 1224struct node_info;
1225 1225
1226bool available_free_memory(struct f2fs_sb_info *, int); 1226bool available_free_memory(struct f2fs_sb_info *, int);
1227int is_checkpointed_node(struct f2fs_sb_info *, nid_t); 1227bool is_checkpointed_node(struct f2fs_sb_info *, nid_t);
1228bool fsync_mark_done(struct f2fs_sb_info *, nid_t); 1228bool has_fsynced_inode(struct f2fs_sb_info *, nid_t);
1229void fsync_mark_clear(struct f2fs_sb_info *, nid_t); 1229bool need_inode_block_update(struct f2fs_sb_info *, nid_t);
1230void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); 1230void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
1231int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); 1231int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
1232int truncate_inode_blocks(struct inode *, pgoff_t); 1232int truncate_inode_blocks(struct inode *, pgoff_t);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index af06e22a0dbd..3035c791d934 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -207,15 +207,17 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
207 up_write(&fi->i_sem); 207 up_write(&fi->i_sem);
208 } 208 }
209 } else { 209 } else {
210 /* if there is no written node page, write its inode page */ 210sync_nodes:
211 while (!sync_node_pages(sbi, ino, &wbc)) { 211 sync_node_pages(sbi, ino, &wbc);
212 if (fsync_mark_done(sbi, ino)) 212
213 goto out; 213 if (need_inode_block_update(sbi, ino)) {
214 mark_inode_dirty_sync(inode); 214 mark_inode_dirty_sync(inode);
215 ret = f2fs_write_inode(inode, NULL); 215 ret = f2fs_write_inode(inode, NULL);
216 if (ret) 216 if (ret)
217 goto out; 217 goto out;
218 goto sync_nodes;
218 } 219 }
220
219 ret = wait_on_node_pages_writeback(sbi, ino); 221 ret = wait_on_node_pages_writeback(sbi, ino);
220 if (ret) 222 if (ret)
221 goto out; 223 goto out;
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index d19d6b18cd4e..7a2d9c980c96 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -123,44 +123,48 @@ static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e)
123 kmem_cache_free(nat_entry_slab, e); 123 kmem_cache_free(nat_entry_slab, e);
124} 124}
125 125
126int is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid) 126bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
127{ 127{
128 struct f2fs_nm_info *nm_i = NM_I(sbi); 128 struct f2fs_nm_info *nm_i = NM_I(sbi);
129 struct nat_entry *e; 129 struct nat_entry *e;
130 int is_cp = 1; 130 bool is_cp = true;
131 131
132 read_lock(&nm_i->nat_tree_lock); 132 read_lock(&nm_i->nat_tree_lock);
133 e = __lookup_nat_cache(nm_i, nid); 133 e = __lookup_nat_cache(nm_i, nid);
134 if (e && !get_nat_flag(e, IS_CHECKPOINTED)) 134 if (e && !get_nat_flag(e, IS_CHECKPOINTED))
135 is_cp = 0; 135 is_cp = false;
136 read_unlock(&nm_i->nat_tree_lock); 136 read_unlock(&nm_i->nat_tree_lock);
137 return is_cp; 137 return is_cp;
138} 138}
139 139
140bool fsync_mark_done(struct f2fs_sb_info *sbi, nid_t nid) 140bool has_fsynced_inode(struct f2fs_sb_info *sbi, nid_t ino)
141{ 141{
142 struct f2fs_nm_info *nm_i = NM_I(sbi); 142 struct f2fs_nm_info *nm_i = NM_I(sbi);
143 struct nat_entry *e; 143 struct nat_entry *e;
144 bool fsync_done = false; 144 bool fsynced = false;
145 145
146 read_lock(&nm_i->nat_tree_lock); 146 read_lock(&nm_i->nat_tree_lock);
147 e = __lookup_nat_cache(nm_i, nid); 147 e = __lookup_nat_cache(nm_i, ino);
148 if (e) 148 if (e && get_nat_flag(e, HAS_FSYNCED_INODE))
149 fsync_done = get_nat_flag(e, HAS_FSYNC_MARK); 149 fsynced = true;
150 read_unlock(&nm_i->nat_tree_lock); 150 read_unlock(&nm_i->nat_tree_lock);
151 return fsync_done; 151 return fsynced;
152} 152}
153 153
154void fsync_mark_clear(struct f2fs_sb_info *sbi, nid_t nid) 154bool need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
155{ 155{
156 struct f2fs_nm_info *nm_i = NM_I(sbi); 156 struct f2fs_nm_info *nm_i = NM_I(sbi);
157 struct nat_entry *e; 157 struct nat_entry *e;
158 bool need_update = true;
158 159
159 write_lock(&nm_i->nat_tree_lock); 160 read_lock(&nm_i->nat_tree_lock);
160 e = __lookup_nat_cache(nm_i, nid); 161 e = __lookup_nat_cache(nm_i, ino);
161 if (e) 162 if (e && get_nat_flag(e, HAS_LAST_FSYNC) &&
162 set_nat_flag(e, HAS_FSYNC_MARK, false); 163 (get_nat_flag(e, IS_CHECKPOINTED) ||
163 write_unlock(&nm_i->nat_tree_lock); 164 get_nat_flag(e, HAS_FSYNCED_INODE)))
165 need_update = false;
166 read_unlock(&nm_i->nat_tree_lock);
167 return need_update;
164} 168}
165 169
166static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid) 170static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
@@ -176,7 +180,7 @@ static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
176 } 180 }
177 memset(new, 0, sizeof(struct nat_entry)); 181 memset(new, 0, sizeof(struct nat_entry));
178 nat_set_nid(new, nid); 182 nat_set_nid(new, nid);
179 set_nat_flag(new, IS_CHECKPOINTED, true); 183 nat_reset_flag(new);
180 list_add_tail(&new->list, &nm_i->nat_entries); 184 list_add_tail(&new->list, &nm_i->nat_entries);
181 nm_i->nat_cnt++; 185 nm_i->nat_cnt++;
182 return new; 186 return new;
@@ -244,12 +248,17 @@ retry:
244 248
245 /* change address */ 249 /* change address */
246 nat_set_blkaddr(e, new_blkaddr); 250 nat_set_blkaddr(e, new_blkaddr);
251 if (new_blkaddr == NEW_ADDR || new_blkaddr == NULL_ADDR)
252 set_nat_flag(e, IS_CHECKPOINTED, false);
247 __set_nat_cache_dirty(nm_i, e); 253 __set_nat_cache_dirty(nm_i, e);
248 254
249 /* update fsync_mark if its inode nat entry is still alive */ 255 /* update fsync_mark if its inode nat entry is still alive */
250 e = __lookup_nat_cache(nm_i, ni->ino); 256 e = __lookup_nat_cache(nm_i, ni->ino);
251 if (e) 257 if (e) {
252 set_nat_flag(e, HAS_FSYNC_MARK, fsync_done); 258 if (fsync_done && ni->nid == ni->ino)
259 set_nat_flag(e, HAS_FSYNCED_INODE, true);
260 set_nat_flag(e, HAS_LAST_FSYNC, fsync_done);
261 }
253 write_unlock(&nm_i->nat_tree_lock); 262 write_unlock(&nm_i->nat_tree_lock);
254} 263}
255 264
@@ -1121,10 +1130,14 @@ continue_unlock:
1121 1130
1122 /* called by fsync() */ 1131 /* called by fsync() */
1123 if (ino && IS_DNODE(page)) { 1132 if (ino && IS_DNODE(page)) {
1124 int mark = !is_checkpointed_node(sbi, ino);
1125 set_fsync_mark(page, 1); 1133 set_fsync_mark(page, 1);
1126 if (IS_INODE(page)) 1134 if (IS_INODE(page)) {
1127 set_dentry_mark(page, mark); 1135 if (!is_checkpointed_node(sbi, ino) &&
1136 !has_fsynced_inode(sbi, ino))
1137 set_dentry_mark(page, 1);
1138 else
1139 set_dentry_mark(page, 0);
1140 }
1128 nwritten++; 1141 nwritten++;
1129 } else { 1142 } else {
1130 set_fsync_mark(page, 0); 1143 set_fsync_mark(page, 0);
@@ -1912,6 +1925,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
1912 write_unlock(&nm_i->nat_tree_lock); 1925 write_unlock(&nm_i->nat_tree_lock);
1913 } else { 1926 } else {
1914 write_lock(&nm_i->nat_tree_lock); 1927 write_lock(&nm_i->nat_tree_lock);
1928 nat_reset_flag(ne);
1915 __clear_nat_cache_dirty(nm_i, ne); 1929 __clear_nat_cache_dirty(nm_i, ne);
1916 write_unlock(&nm_i->nat_tree_lock); 1930 write_unlock(&nm_i->nat_tree_lock);
1917 } 1931 }
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
index 3043778d805b..b8ba63c43b99 100644
--- a/fs/f2fs/node.h
+++ b/fs/f2fs/node.h
@@ -41,7 +41,8 @@ struct node_info {
41 41
42enum { 42enum {
43 IS_CHECKPOINTED, /* is it checkpointed before? */ 43 IS_CHECKPOINTED, /* is it checkpointed before? */
44 HAS_FSYNC_MARK, /* has the latest node fsync mark? */ 44 HAS_FSYNCED_INODE, /* is the inode fsynced before? */
45 HAS_LAST_FSYNC, /* has the latest node fsync mark? */
45}; 46};
46 47
47struct nat_entry { 48struct nat_entry {
@@ -60,15 +61,9 @@ struct nat_entry {
60#define nat_set_version(nat, v) (nat->ni.version = v) 61#define nat_set_version(nat, v) (nat->ni.version = v)
61 62
62#define __set_nat_cache_dirty(nm_i, ne) \ 63#define __set_nat_cache_dirty(nm_i, ne) \
63 do { \ 64 list_move_tail(&ne->list, &nm_i->dirty_nat_entries);
64 set_nat_flag(ne, IS_CHECKPOINTED, false); \
65 list_move_tail(&ne->list, &nm_i->dirty_nat_entries); \
66 } while (0)
67#define __clear_nat_cache_dirty(nm_i, ne) \ 65#define __clear_nat_cache_dirty(nm_i, ne) \
68 do { \ 66 list_move_tail(&ne->list, &nm_i->nat_entries);
69 set_nat_flag(ne, IS_CHECKPOINTED, true); \
70 list_move_tail(&ne->list, &nm_i->nat_entries); \
71 } while (0)
72#define inc_node_version(version) (++version) 67#define inc_node_version(version) (++version)
73 68
74static inline void set_nat_flag(struct nat_entry *ne, 69static inline void set_nat_flag(struct nat_entry *ne,
@@ -87,6 +82,14 @@ static inline bool get_nat_flag(struct nat_entry *ne, unsigned int type)
87 return ne->flag & mask; 82 return ne->flag & mask;
88} 83}
89 84
85static inline void nat_reset_flag(struct nat_entry *ne)
86{
87 /* these states can be set only after checkpoint was done */
88 set_nat_flag(ne, IS_CHECKPOINTED, true);
89 set_nat_flag(ne, HAS_FSYNCED_INODE, false);
90 set_nat_flag(ne, HAS_LAST_FSYNC, true);
91}
92
90static inline void node_info_from_raw_nat(struct node_info *ni, 93static inline void node_info_from_raw_nat(struct node_info *ni,
91 struct f2fs_nat_entry *raw_ne) 94 struct f2fs_nat_entry *raw_ne)
92{ 95{