diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-08-12 03:04:53 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-08-12 03:04:53 -0400 |
commit | 479bd73ac425ff117efeea051077b4277baab52e (patch) | |
tree | a078a20d6d657f4b77140392be5a6316c96110a3 | |
parent | 9c02740c0174932162531a28ba8593e82884a9d7 (diff) |
f2fs: should cover i_xattr_nid with its xattr node page lock
Previously, f2fs_setxattr assigns i_xattr_nid in the inode page inconsistently.
The scenario is:
= Thread 1 = = Thread 2 = = fi->i_xattr_nid = = on-disk nid =
f2fs_setxattr 0 0
new_node_page X 0
sync_inode_page X X
checkpoint X X -.
grab_cache_page X X |
--> allocate a new xattr node block or -ENOSPC <----------------'
At this moment, the checkpoint stores inconsistent data where the inode has
i_xattr_nid but actual xattr node block is not allocated yet.
So, we should assign the real i_xattr_nid only after its xattr node block is
allocated.
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
-rw-r--r-- | fs/f2fs/node.c | 3 | ||||
-rw-r--r-- | fs/f2fs/xattr.c | 10 |
2 files changed, 8 insertions, 5 deletions
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 858a333f6ab9..1c21344fba30 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c | |||
@@ -851,6 +851,9 @@ struct page *new_node_page(struct dnode_of_data *dn, | |||
851 | SetPageUptodate(page); | 851 | SetPageUptodate(page); |
852 | set_page_dirty(page); | 852 | set_page_dirty(page); |
853 | 853 | ||
854 | if (ofs == XATTR_NODE_OFFSET) | ||
855 | F2FS_I(dn->inode)->i_xattr_nid = dn->nid; | ||
856 | |||
854 | dn->node_page = page; | 857 | dn->node_page = page; |
855 | if (ipage) | 858 | if (ipage) |
856 | update_inode(dn->inode, ipage); | 859 | update_inode(dn->inode, ipage); |
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index fb16f71e4c23..3bc307c22b70 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c | |||
@@ -378,23 +378,23 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name, | |||
378 | if (!fi->i_xattr_nid) { | 378 | if (!fi->i_xattr_nid) { |
379 | /* Allocate new attribute block */ | 379 | /* Allocate new attribute block */ |
380 | struct dnode_of_data dn; | 380 | struct dnode_of_data dn; |
381 | nid_t new_nid; | ||
381 | 382 | ||
382 | if (!alloc_nid(sbi, &fi->i_xattr_nid)) { | 383 | if (!alloc_nid(sbi, &new_nid)) { |
383 | error = -ENOSPC; | 384 | error = -ENOSPC; |
384 | goto exit; | 385 | goto exit; |
385 | } | 386 | } |
386 | set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid); | 387 | set_new_dnode(&dn, inode, NULL, NULL, new_nid); |
387 | mark_inode_dirty(inode); | 388 | mark_inode_dirty(inode); |
388 | 389 | ||
389 | page = new_node_page(&dn, XATTR_NODE_OFFSET, ipage); | 390 | page = new_node_page(&dn, XATTR_NODE_OFFSET, ipage); |
390 | if (IS_ERR(page)) { | 391 | if (IS_ERR(page)) { |
391 | alloc_nid_failed(sbi, fi->i_xattr_nid); | 392 | alloc_nid_failed(sbi, new_nid); |
392 | fi->i_xattr_nid = 0; | ||
393 | error = PTR_ERR(page); | 393 | error = PTR_ERR(page); |
394 | goto exit; | 394 | goto exit; |
395 | } | 395 | } |
396 | 396 | ||
397 | alloc_nid_done(sbi, fi->i_xattr_nid); | 397 | alloc_nid_done(sbi, new_nid); |
398 | base_addr = page_address(page); | 398 | base_addr = page_address(page); |
399 | header = XATTR_HDR(base_addr); | 399 | header = XATTR_HDR(base_addr); |
400 | header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); | 400 | header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); |