diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-08-12 16:04:53 +0900 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-08-12 16:04:53 +0900 |
commit | 479bd73ac425ff117efeea051077b4277baab52e (patch) | |
tree | a078a20d6d657f4b77140392be5a6316c96110a3 /fs/f2fs | |
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>
Diffstat (limited to 'fs/f2fs')
-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, SetPageUptodate(page); set_page_dirty(page); + if (ofs == XATTR_NODE_OFFSET) + F2FS_I(dn->inode)->i_xattr_nid = dn->nid; + dn->node_page = page; if (ipage) 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, if (!fi->i_xattr_nid) { /* Allocate new attribute block */ struct dnode_of_data dn; + nid_t new_nid; - if (!alloc_nid(sbi, &fi->i_xattr_nid)) { + if (!alloc_nid(sbi, &new_nid)) { error = -ENOSPC; goto exit; } - set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid); + set_new_dnode(&dn, inode, NULL, NULL, new_nid); mark_inode_dirty(inode); page = new_node_page(&dn, XATTR_NODE_OFFSET, ipage); if (IS_ERR(page)) { - alloc_nid_failed(sbi, fi->i_xattr_nid); - fi->i_xattr_nid = 0; + alloc_nid_failed(sbi, new_nid); error = PTR_ERR(page); goto exit; } - alloc_nid_done(sbi, fi->i_xattr_nid); + alloc_nid_done(sbi, new_nid); base_addr = page_address(page); header = XATTR_HDR(base_addr); header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); |