]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/5.0.1/staging-erofs-fix-race-of-initializing-xattrs-of-a-inode-at-the-same-time.patch
5.0-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 5.0.1 / staging-erofs-fix-race-of-initializing-xattrs-of-a-inode-at-the-same-time.patch
1 From 62dc45979f3f8cb0ea67302a93bff686f0c46c5a Mon Sep 17 00:00:00 2001
2 From: Gao Xiang <gaoxiang25@huawei.com>
3 Date: Mon, 18 Feb 2019 15:19:04 +0800
4 Subject: staging: erofs: fix race of initializing xattrs of a inode at the same time
5
6 From: Gao Xiang <gaoxiang25@huawei.com>
7
8 commit 62dc45979f3f8cb0ea67302a93bff686f0c46c5a upstream.
9
10 In real scenario, there could be several threads accessing xattrs
11 of the same xattr-uninitialized inode, and init_inode_xattrs()
12 almost at the same time.
13
14 That's actually an unexpected behavior, this patch closes the race.
15
16 Fixes: b17500a0fdba ("staging: erofs: introduce xattr & acl support")
17 Cc: <stable@vger.kernel.org> # 4.19+
18 Reviewed-by: Chao Yu <yuchao0@huawei.com>
19 Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
20 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
21
22 ---
23 drivers/staging/erofs/internal.h | 11 +++++++---
24 drivers/staging/erofs/xattr.c | 41 +++++++++++++++++++++++++++------------
25 2 files changed, 37 insertions(+), 15 deletions(-)
26
27 --- a/drivers/staging/erofs/internal.h
28 +++ b/drivers/staging/erofs/internal.h
29 @@ -354,12 +354,17 @@ static inline erofs_off_t iloc(struct er
30 return blknr_to_addr(sbi->meta_blkaddr) + (nid << sbi->islotbits);
31 }
32
33 -#define inode_set_inited_xattr(inode) (EROFS_V(inode)->flags |= 1)
34 -#define inode_has_inited_xattr(inode) (EROFS_V(inode)->flags & 1)
35 +/* atomic flag definitions */
36 +#define EROFS_V_EA_INITED_BIT 0
37 +
38 +/* bitlock definitions (arranged in reverse order) */
39 +#define EROFS_V_BL_XATTR_BIT (BITS_PER_LONG - 1)
40
41 struct erofs_vnode {
42 erofs_nid_t nid;
43 - unsigned int flags;
44 +
45 + /* atomic flags (including bitlocks) */
46 + unsigned long flags;
47
48 unsigned char data_mapping_mode;
49 /* inline size in bytes */
50 --- a/drivers/staging/erofs/xattr.c
51 +++ b/drivers/staging/erofs/xattr.c
52 @@ -44,18 +44,25 @@ static inline void xattr_iter_end_final(
53
54 static int init_inode_xattrs(struct inode *inode)
55 {
56 + struct erofs_vnode *const vi = EROFS_V(inode);
57 struct xattr_iter it;
58 unsigned int i;
59 struct erofs_xattr_ibody_header *ih;
60 struct super_block *sb;
61 struct erofs_sb_info *sbi;
62 - struct erofs_vnode *vi;
63 bool atomic_map;
64 + int ret = 0;
65
66 - if (likely(inode_has_inited_xattr(inode)))
67 + /* the most case is that xattrs of this inode are initialized. */
68 + if (test_bit(EROFS_V_EA_INITED_BIT, &vi->flags))
69 return 0;
70
71 - vi = EROFS_V(inode);
72 + if (wait_on_bit_lock(&vi->flags, EROFS_V_BL_XATTR_BIT, TASK_KILLABLE))
73 + return -ERESTARTSYS;
74 +
75 + /* someone has initialized xattrs for us? */
76 + if (test_bit(EROFS_V_EA_INITED_BIT, &vi->flags))
77 + goto out_unlock;
78
79 /*
80 * bypass all xattr operations if ->xattr_isize is not greater than
81 @@ -68,13 +75,16 @@ static int init_inode_xattrs(struct inod
82 if (vi->xattr_isize == sizeof(struct erofs_xattr_ibody_header)) {
83 errln("xattr_isize %d of nid %llu is not supported yet",
84 vi->xattr_isize, vi->nid);
85 - return -ENOTSUPP;
86 + ret = -ENOTSUPP;
87 + goto out_unlock;
88 } else if (vi->xattr_isize < sizeof(struct erofs_xattr_ibody_header)) {
89 if (unlikely(vi->xattr_isize)) {
90 DBG_BUGON(1);
91 - return -EIO; /* xattr ondisk layout error */
92 + ret = -EIO;
93 + goto out_unlock; /* xattr ondisk layout error */
94 }
95 - return -ENOATTR;
96 + ret = -ENOATTR;
97 + goto out_unlock;
98 }
99
100 sb = inode->i_sb;
101 @@ -83,8 +93,10 @@ static int init_inode_xattrs(struct inod
102 it.ofs = erofs_blkoff(iloc(sbi, vi->nid) + vi->inode_isize);
103
104 it.page = erofs_get_inline_page(inode, it.blkaddr);
105 - if (IS_ERR(it.page))
106 - return PTR_ERR(it.page);
107 + if (IS_ERR(it.page)) {
108 + ret = PTR_ERR(it.page);
109 + goto out_unlock;
110 + }
111
112 /* read in shared xattr array (non-atomic, see kmalloc below) */
113 it.kaddr = kmap(it.page);
114 @@ -97,7 +109,8 @@ static int init_inode_xattrs(struct inod
115 sizeof(uint), GFP_KERNEL);
116 if (vi->xattr_shared_xattrs == NULL) {
117 xattr_iter_end(&it, atomic_map);
118 - return -ENOMEM;
119 + ret = -ENOMEM;
120 + goto out_unlock;
121 }
122
123 /* let's skip ibody header */
124 @@ -114,7 +127,8 @@ static int init_inode_xattrs(struct inod
125 if (IS_ERR(it.page)) {
126 kfree(vi->xattr_shared_xattrs);
127 vi->xattr_shared_xattrs = NULL;
128 - return PTR_ERR(it.page);
129 + ret = PTR_ERR(it.page);
130 + goto out_unlock;
131 }
132
133 it.kaddr = kmap_atomic(it.page);
134 @@ -127,8 +141,11 @@ static int init_inode_xattrs(struct inod
135 }
136 xattr_iter_end(&it, atomic_map);
137
138 - inode_set_inited_xattr(inode);
139 - return 0;
140 + set_bit(EROFS_V_EA_INITED_BIT, &vi->flags);
141 +
142 +out_unlock:
143 + clear_and_wake_up_bit(EROFS_V_BL_XATTR_BIT, &vi->flags);
144 + return ret;
145 }
146
147 /*