aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2013-12-25 22:49:48 -0500
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2014-01-06 02:42:20 -0500
commit1e1bb4baf10be371f72150e2801d97a04d40b3b9 (patch)
tree708ae4f4d93b05f063aa1c50538c53cdcbae5350 /fs/f2fs
parent0dbdc2ae9bba0a358816cc4a22e41a6ef16db8a2 (diff)
f2fs: add inline_data recovery routine
This patch adds a inline_data recovery routine with the following policy. [prev.] [next] of inline_data flag o o -> recover inline_data o x -> remove inline_data, and then recover data blocks x o -> remove inline_data, and then recover inline_data x x -> recover data blocks Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r--fs/f2fs/f2fs.h2
-rw-r--r--fs/f2fs/file.c2
-rw-r--r--fs/f2fs/inline.c48
-rw-r--r--fs/f2fs/recovery.c8
4 files changed, 57 insertions, 3 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 0b6badadbfd8..07a7ae0d4413 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1015,6 +1015,7 @@ static inline int f2fs_readonly(struct super_block *sb)
1015 */ 1015 */
1016int f2fs_sync_file(struct file *, loff_t, loff_t, int); 1016int f2fs_sync_file(struct file *, loff_t, loff_t, int);
1017void truncate_data_blocks(struct dnode_of_data *); 1017void truncate_data_blocks(struct dnode_of_data *);
1018int truncate_blocks(struct inode *, u64);
1018void f2fs_truncate(struct inode *); 1019void f2fs_truncate(struct inode *);
1019int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *); 1020int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
1020int f2fs_setattr(struct dentry *, struct iattr *); 1021int f2fs_setattr(struct dentry *, struct iattr *);
@@ -1322,4 +1323,5 @@ bool f2fs_may_inline(struct inode *);
1322int f2fs_read_inline_data(struct inode *, struct page *); 1323int f2fs_read_inline_data(struct inode *, struct page *);
1323int f2fs_convert_inline_data(struct inode *, pgoff_t); 1324int f2fs_convert_inline_data(struct inode *, pgoff_t);
1324int f2fs_write_inline_data(struct inode *, struct page *, unsigned int); 1325int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
1326int recover_inline_data(struct inode *, struct page *);
1325#endif 1327#endif
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 68dd7bfce1a1..c77ad4d8b564 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -251,7 +251,7 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
251 f2fs_put_page(page, 1); 251 f2fs_put_page(page, 1);
252} 252}
253 253
254static int truncate_blocks(struct inode *inode, u64 from) 254int truncate_blocks(struct inode *inode, u64 from)
255{ 255{
256 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 256 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
257 unsigned int blocksize = inode->i_sb->s_blocksize; 257 unsigned int blocksize = inode->i_sb->s_blocksize;
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 3c9261cd215f..2a756e57aed9 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -169,3 +169,51 @@ int f2fs_write_inline_data(struct inode *inode,
169 169
170 return 0; 170 return 0;
171} 171}
172
173int recover_inline_data(struct inode *inode, struct page *npage)
174{
175 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
176 struct f2fs_inode *ri = NULL;
177 void *src_addr, *dst_addr;
178 struct page *ipage;
179
180 /*
181 * The inline_data recovery policy is as follows.
182 * [prev.] [next] of inline_data flag
183 * o o -> recover inline_data
184 * o x -> remove inline_data, and then recover data blocks
185 * x o -> remove inline_data, and then recover inline_data
186 * x x -> recover data blocks
187 */
188 if (IS_INODE(npage))
189 ri = F2FS_INODE(npage);
190
191 if (f2fs_has_inline_data(inode) &&
192 ri && ri->i_inline & F2FS_INLINE_DATA) {
193process_inline:
194 ipage = get_node_page(sbi, inode->i_ino);
195 f2fs_bug_on(IS_ERR(ipage));
196
197 src_addr = inline_data_addr(npage);
198 dst_addr = inline_data_addr(ipage);
199 memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
200 update_inode(inode, ipage);
201 f2fs_put_page(ipage, 1);
202 return -1;
203 }
204
205 if (f2fs_has_inline_data(inode)) {
206 ipage = get_node_page(sbi, inode->i_ino);
207 f2fs_bug_on(IS_ERR(ipage));
208 zero_user_segment(ipage, INLINE_DATA_OFFSET,
209 INLINE_DATA_OFFSET + MAX_INLINE_DATA);
210 clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
211 update_inode(inode, ipage);
212 f2fs_put_page(ipage, 1);
213 } else if (ri && ri->i_inline & F2FS_INLINE_DATA) {
214 truncate_blocks(inode, 0);
215 set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
216 goto process_inline;
217 }
218 return 0;
219}
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 96e690b6f0fa..655791e518cf 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -298,6 +298,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
298 struct node_info ni; 298 struct node_info ni;
299 int err = 0, recovered = 0; 299 int err = 0, recovered = 0;
300 300
301 if (recover_inline_data(inode, page))
302 goto out;
303
301 start = start_bidx_of_node(ofs_of_node(page), fi); 304 start = start_bidx_of_node(ofs_of_node(page), fi);
302 if (IS_INODE(page)) 305 if (IS_INODE(page))
303 end = start + ADDRS_PER_INODE(fi); 306 end = start + ADDRS_PER_INODE(fi);
@@ -305,12 +308,13 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
305 end = start + ADDRS_PER_BLOCK; 308 end = start + ADDRS_PER_BLOCK;
306 309
307 f2fs_lock_op(sbi); 310 f2fs_lock_op(sbi);
311
308 set_new_dnode(&dn, inode, NULL, NULL, 0); 312 set_new_dnode(&dn, inode, NULL, NULL, 0);
309 313
310 err = get_dnode_of_data(&dn, start, ALLOC_NODE); 314 err = get_dnode_of_data(&dn, start, ALLOC_NODE);
311 if (err) { 315 if (err) {
312 f2fs_unlock_op(sbi); 316 f2fs_unlock_op(sbi);
313 return err; 317 goto out;
314 } 318 }
315 319
316 wait_on_page_writeback(dn.node_page); 320 wait_on_page_writeback(dn.node_page);
@@ -361,7 +365,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
361err: 365err:
362 f2fs_put_dnode(&dn); 366 f2fs_put_dnode(&dn);
363 f2fs_unlock_op(sbi); 367 f2fs_unlock_op(sbi);
364 368out:
365 f2fs_msg(sbi->sb, KERN_NOTICE, "recover_data: ino = %lx, " 369 f2fs_msg(sbi->sb, KERN_NOTICE, "recover_data: ino = %lx, "
366 "recovered_data = %d blocks, err = %d", 370 "recovered_data = %d blocks, err = %d",
367 inode->i_ino, recovered, err); 371 inode->i_ino, recovered, err);