diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-12-27 03:04:17 -0500 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2014-01-06 02:42:21 -0500 |
commit | a8865372a8414298982e07f4ac8d6dc0ab1e0a3d (patch) | |
tree | d854711c56be4c135701610710c0fda95a297d13 /fs/f2fs | |
parent | 1e1bb4baf10be371f72150e2801d97a04d40b3b9 (diff) |
f2fs: handle errors correctly during f2fs_reserve_block
The get_dnode_of_data nullifies inode and node page when error is occurred.
There are two cases that passes inode page into get_dnode_of_data().
1. make_empty_dir()
-> get_new_data_page()
-> f2fs_reserve_block(ipage)
-> get_dnode_of_data()
2. f2fs_convert_inline_data()
-> __f2fs_convert_inline_data()
-> f2fs_reserve_block(ipage)
-> get_dnode_of_data()
This patch adds correct error handling codes when get_dnode_of_data() returns
an error.
At first, f2fs_reserve_block() calls f2fs_put_dnode() whenever reserve_new_block
returns an error.
So, the rule of f2fs_reserve_block() is to nullify inode page when there is any
error internally.
Finally, two callers of f2fs_reserve_block() should call f2fs_put_dnode()
appropriately if they got an error since successful f2fs_reserve_block().
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/data.c | 29 | ||||
-rw-r--r-- | fs/f2fs/dir.c | 7 | ||||
-rw-r--r-- | fs/f2fs/inline.c | 6 |
3 files changed, 26 insertions, 16 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index fc7a28c5ad23..63d190264a36 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c | |||
@@ -258,13 +258,16 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index) | |||
258 | bool need_put = dn->inode_page ? false : true; | 258 | bool need_put = dn->inode_page ? false : true; |
259 | int err; | 259 | int err; |
260 | 260 | ||
261 | /* if inode_page exists, index should be zero */ | ||
262 | f2fs_bug_on(!need_put && index); | ||
263 | |||
261 | err = get_dnode_of_data(dn, index, ALLOC_NODE); | 264 | err = get_dnode_of_data(dn, index, ALLOC_NODE); |
262 | if (err) | 265 | if (err) |
263 | return err; | 266 | return err; |
267 | |||
264 | if (dn->data_blkaddr == NULL_ADDR) | 268 | if (dn->data_blkaddr == NULL_ADDR) |
265 | err = reserve_new_block(dn); | 269 | err = reserve_new_block(dn); |
266 | 270 | if (err || need_put) | |
267 | if (need_put) | ||
268 | f2fs_put_dnode(dn); | 271 | f2fs_put_dnode(dn); |
269 | return err; | 272 | return err; |
270 | } | 273 | } |
@@ -510,10 +513,10 @@ repeat: | |||
510 | * | 513 | * |
511 | * Also, caller should grab and release a rwsem by calling f2fs_lock_op() and | 514 | * Also, caller should grab and release a rwsem by calling f2fs_lock_op() and |
512 | * f2fs_unlock_op(). | 515 | * f2fs_unlock_op(). |
513 | * Note that, npage is set only by make_empty_dir. | 516 | * Note that, ipage is set only by make_empty_dir. |
514 | */ | 517 | */ |
515 | struct page *get_new_data_page(struct inode *inode, | 518 | struct page *get_new_data_page(struct inode *inode, |
516 | struct page *npage, pgoff_t index, bool new_i_size) | 519 | struct page *ipage, pgoff_t index, bool new_i_size) |
517 | { | 520 | { |
518 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); | 521 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); |
519 | struct address_space *mapping = inode->i_mapping; | 522 | struct address_space *mapping = inode->i_mapping; |
@@ -521,14 +524,16 @@ struct page *get_new_data_page(struct inode *inode, | |||
521 | struct dnode_of_data dn; | 524 | struct dnode_of_data dn; |
522 | int err; | 525 | int err; |
523 | 526 | ||
524 | set_new_dnode(&dn, inode, npage, npage, 0); | 527 | set_new_dnode(&dn, inode, ipage, NULL, 0); |
525 | err = f2fs_reserve_block(&dn, index); | 528 | err = f2fs_reserve_block(&dn, index); |
526 | if (err) | 529 | if (err) |
527 | return ERR_PTR(err); | 530 | return ERR_PTR(err); |
528 | repeat: | 531 | repeat: |
529 | page = grab_cache_page(mapping, index); | 532 | page = grab_cache_page(mapping, index); |
530 | if (!page) | 533 | if (!page) { |
531 | return ERR_PTR(-ENOMEM); | 534 | err = -ENOMEM; |
535 | goto put_err; | ||
536 | } | ||
532 | 537 | ||
533 | if (PageUptodate(page)) | 538 | if (PageUptodate(page)) |
534 | return page; | 539 | return page; |
@@ -540,11 +545,13 @@ repeat: | |||
540 | err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr, | 545 | err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr, |
541 | READ_SYNC); | 546 | READ_SYNC); |
542 | if (err) | 547 | if (err) |
543 | return ERR_PTR(err); | 548 | goto put_err; |
549 | |||
544 | lock_page(page); | 550 | lock_page(page); |
545 | if (unlikely(!PageUptodate(page))) { | 551 | if (unlikely(!PageUptodate(page))) { |
546 | f2fs_put_page(page, 1); | 552 | f2fs_put_page(page, 1); |
547 | return ERR_PTR(-EIO); | 553 | err = -EIO; |
554 | goto put_err; | ||
548 | } | 555 | } |
549 | if (unlikely(page->mapping != mapping)) { | 556 | if (unlikely(page->mapping != mapping)) { |
550 | f2fs_put_page(page, 1); | 557 | f2fs_put_page(page, 1); |
@@ -560,6 +567,10 @@ repeat: | |||
560 | mark_inode_dirty_sync(inode); | 567 | mark_inode_dirty_sync(inode); |
561 | } | 568 | } |
562 | return page; | 569 | return page; |
570 | |||
571 | put_err: | ||
572 | f2fs_put_dnode(&dn); | ||
573 | return ERR_PTR(err); | ||
563 | } | 574 | } |
564 | 575 | ||
565 | static int __allocate_data_block(struct dnode_of_data *dn) | 576 | static int __allocate_data_block(struct dnode_of_data *dn) |
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 6da77e5c753b..f815ca0c5819 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c | |||
@@ -342,11 +342,11 @@ static struct page *init_inode_metadata(struct inode *inode, | |||
342 | 342 | ||
343 | err = f2fs_init_acl(inode, dir, page); | 343 | err = f2fs_init_acl(inode, dir, page); |
344 | if (err) | 344 | if (err) |
345 | goto error; | 345 | goto put_error; |
346 | 346 | ||
347 | err = f2fs_init_security(inode, dir, name, page); | 347 | err = f2fs_init_security(inode, dir, name, page); |
348 | if (err) | 348 | if (err) |
349 | goto error; | 349 | goto put_error; |
350 | 350 | ||
351 | wait_on_page_writeback(page); | 351 | wait_on_page_writeback(page); |
352 | } else { | 352 | } else { |
@@ -370,8 +370,9 @@ static struct page *init_inode_metadata(struct inode *inode, | |||
370 | } | 370 | } |
371 | return page; | 371 | return page; |
372 | 372 | ||
373 | error: | 373 | put_error: |
374 | f2fs_put_page(page, 1); | 374 | f2fs_put_page(page, 1); |
375 | error: | ||
375 | remove_inode_page(inode); | 376 | remove_inode_page(inode); |
376 | return ERR_PTR(err); | 377 | return ERR_PTR(err); |
377 | } | 378 | } |
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 2a756e57aed9..688305afbc74 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c | |||
@@ -81,10 +81,9 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page) | |||
81 | * i_addr[0] is not used for inline data, | 81 | * i_addr[0] is not used for inline data, |
82 | * so reserving new block will not destroy inline data | 82 | * so reserving new block will not destroy inline data |
83 | */ | 83 | */ |
84 | set_new_dnode(&dn, inode, ipage, ipage, 0); | 84 | set_new_dnode(&dn, inode, ipage, NULL, 0); |
85 | err = f2fs_reserve_block(&dn, 0); | 85 | err = f2fs_reserve_block(&dn, 0); |
86 | if (err) { | 86 | if (err) { |
87 | f2fs_put_page(ipage, 1); | ||
88 | f2fs_unlock_op(sbi); | 87 | f2fs_unlock_op(sbi); |
89 | return err; | 88 | return err; |
90 | } | 89 | } |
@@ -111,9 +110,8 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page) | |||
111 | stat_dec_inline_inode(inode); | 110 | stat_dec_inline_inode(inode); |
112 | 111 | ||
113 | sync_inode_page(&dn); | 112 | sync_inode_page(&dn); |
114 | f2fs_put_page(ipage, 1); | 113 | f2fs_put_dnode(&dn); |
115 | f2fs_unlock_op(sbi); | 114 | f2fs_unlock_op(sbi); |
116 | |||
117 | return err; | 115 | return err; |
118 | } | 116 | } |
119 | 117 | ||