diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-12-25 22:49:48 -0500 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2014-01-06 02:42:20 -0500 |
commit | 1e1bb4baf10be371f72150e2801d97a04d40b3b9 (patch) | |
tree | 708ae4f4d93b05f063aa1c50538c53cdcbae5350 /fs/f2fs | |
parent | 0dbdc2ae9bba0a358816cc4a22e41a6ef16db8a2 (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.h | 2 | ||||
-rw-r--r-- | fs/f2fs/file.c | 2 | ||||
-rw-r--r-- | fs/f2fs/inline.c | 48 | ||||
-rw-r--r-- | fs/f2fs/recovery.c | 8 |
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 | */ |
1016 | int f2fs_sync_file(struct file *, loff_t, loff_t, int); | 1016 | int f2fs_sync_file(struct file *, loff_t, loff_t, int); |
1017 | void truncate_data_blocks(struct dnode_of_data *); | 1017 | void truncate_data_blocks(struct dnode_of_data *); |
1018 | int truncate_blocks(struct inode *, u64); | ||
1018 | void f2fs_truncate(struct inode *); | 1019 | void f2fs_truncate(struct inode *); |
1019 | int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *); | 1020 | int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *); |
1020 | int f2fs_setattr(struct dentry *, struct iattr *); | 1021 | int f2fs_setattr(struct dentry *, struct iattr *); |
@@ -1322,4 +1323,5 @@ bool f2fs_may_inline(struct inode *); | |||
1322 | int f2fs_read_inline_data(struct inode *, struct page *); | 1323 | int f2fs_read_inline_data(struct inode *, struct page *); |
1323 | int f2fs_convert_inline_data(struct inode *, pgoff_t); | 1324 | int f2fs_convert_inline_data(struct inode *, pgoff_t); |
1324 | int f2fs_write_inline_data(struct inode *, struct page *, unsigned int); | 1325 | int f2fs_write_inline_data(struct inode *, struct page *, unsigned int); |
1326 | int 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 | ||
254 | static int truncate_blocks(struct inode *inode, u64 from) | 254 | int 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 | |||
173 | int 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) { | ||
193 | process_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, | |||
361 | err: | 365 | err: |
362 | f2fs_put_dnode(&dn); | 366 | f2fs_put_dnode(&dn); |
363 | f2fs_unlock_op(sbi); | 367 | f2fs_unlock_op(sbi); |
364 | 368 | out: | |
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); |