diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-08 11:46:49 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-08 11:46:49 -0500 |
commit | 410ef736a77b584e1c54a3784ee56ca63114ce11 (patch) | |
tree | 53eb74b71298aee02b9acf8d33a2b82a392948c8 | |
parent | 4d8b3262af02c4245ac396b7f2bc71eb328931e2 (diff) | |
parent | b7e9728f3d7fc5c5c8508d99f1675212af5cfd49 (diff) |
Merge tag 'xarray-5.4' of git://git.infradead.org/users/willy/linux-dax
Pull XArray fixes from Matthew Wilcox:
"These all fix various bugs, some of which people have tripped over and
some of which have been caught by automatic tools"
* tag 'xarray-5.4' of git://git.infradead.org/users/willy/linux-dax:
idr: Fix idr_alloc_u32 on 32-bit systems
idr: Fix integer overflow in idr_for_each_entry
radix tree: Remove radix_tree_iter_find
idr: Fix idr_get_next_ul race with idr_remove
XArray: Fix xas_next() with a single entry at 0
-rw-r--r-- | include/linux/idr.h | 2 | ||||
-rw-r--r-- | include/linux/radix-tree.h | 18 | ||||
-rw-r--r-- | lib/idr.c | 31 | ||||
-rw-r--r-- | lib/radix-tree.c | 2 | ||||
-rw-r--r-- | lib/test_xarray.c | 24 | ||||
-rw-r--r-- | lib/xarray.c | 4 |
6 files changed, 41 insertions, 40 deletions
diff --git a/include/linux/idr.h b/include/linux/idr.h index 4ec8986e5dfb..ac6e946b6767 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h | |||
@@ -185,7 +185,7 @@ static inline void idr_preload_end(void) | |||
185 | * is convenient for a "not found" value. | 185 | * is convenient for a "not found" value. |
186 | */ | 186 | */ |
187 | #define idr_for_each_entry(idr, entry, id) \ | 187 | #define idr_for_each_entry(idr, entry, id) \ |
188 | for (id = 0; ((entry) = idr_get_next(idr, &(id))) != NULL; ++id) | 188 | for (id = 0; ((entry) = idr_get_next(idr, &(id))) != NULL; id += 1U) |
189 | 189 | ||
190 | /** | 190 | /** |
191 | * idr_for_each_entry_ul() - Iterate over an IDR's elements of a given type. | 191 | * idr_for_each_entry_ul() - Iterate over an IDR's elements of a given type. |
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index b5116013f27e..63e62372443a 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h | |||
@@ -316,24 +316,6 @@ radix_tree_iter_lookup(const struct radix_tree_root *root, | |||
316 | } | 316 | } |
317 | 317 | ||
318 | /** | 318 | /** |
319 | * radix_tree_iter_find - find a present entry | ||
320 | * @root: radix tree root | ||
321 | * @iter: iterator state | ||
322 | * @index: start location | ||
323 | * | ||
324 | * This function returns the slot containing the entry with the lowest index | ||
325 | * which is at least @index. If @index is larger than any present entry, this | ||
326 | * function returns NULL. The @iter is updated to describe the entry found. | ||
327 | */ | ||
328 | static inline void __rcu ** | ||
329 | radix_tree_iter_find(const struct radix_tree_root *root, | ||
330 | struct radix_tree_iter *iter, unsigned long index) | ||
331 | { | ||
332 | radix_tree_iter_init(iter, index); | ||
333 | return radix_tree_next_chunk(root, iter, 0); | ||
334 | } | ||
335 | |||
336 | /** | ||
337 | * radix_tree_iter_retry - retry this chunk of the iteration | 319 | * radix_tree_iter_retry - retry this chunk of the iteration |
338 | * @iter: iterator state | 320 | * @iter: iterator state |
339 | * | 321 | * |
@@ -215,7 +215,7 @@ int idr_for_each(const struct idr *idr, | |||
215 | EXPORT_SYMBOL(idr_for_each); | 215 | EXPORT_SYMBOL(idr_for_each); |
216 | 216 | ||
217 | /** | 217 | /** |
218 | * idr_get_next() - Find next populated entry. | 218 | * idr_get_next_ul() - Find next populated entry. |
219 | * @idr: IDR handle. | 219 | * @idr: IDR handle. |
220 | * @nextid: Pointer to an ID. | 220 | * @nextid: Pointer to an ID. |
221 | * | 221 | * |
@@ -224,7 +224,7 @@ EXPORT_SYMBOL(idr_for_each); | |||
224 | * to the ID of the found value. To use in a loop, the value pointed to by | 224 | * to the ID of the found value. To use in a loop, the value pointed to by |
225 | * nextid must be incremented by the user. | 225 | * nextid must be incremented by the user. |
226 | */ | 226 | */ |
227 | void *idr_get_next(struct idr *idr, int *nextid) | 227 | void *idr_get_next_ul(struct idr *idr, unsigned long *nextid) |
228 | { | 228 | { |
229 | struct radix_tree_iter iter; | 229 | struct radix_tree_iter iter; |
230 | void __rcu **slot; | 230 | void __rcu **slot; |
@@ -245,18 +245,14 @@ void *idr_get_next(struct idr *idr, int *nextid) | |||
245 | } | 245 | } |
246 | if (!slot) | 246 | if (!slot) |
247 | return NULL; | 247 | return NULL; |
248 | id = iter.index + base; | ||
249 | |||
250 | if (WARN_ON_ONCE(id > INT_MAX)) | ||
251 | return NULL; | ||
252 | 248 | ||
253 | *nextid = id; | 249 | *nextid = iter.index + base; |
254 | return entry; | 250 | return entry; |
255 | } | 251 | } |
256 | EXPORT_SYMBOL(idr_get_next); | 252 | EXPORT_SYMBOL(idr_get_next_ul); |
257 | 253 | ||
258 | /** | 254 | /** |
259 | * idr_get_next_ul() - Find next populated entry. | 255 | * idr_get_next() - Find next populated entry. |
260 | * @idr: IDR handle. | 256 | * @idr: IDR handle. |
261 | * @nextid: Pointer to an ID. | 257 | * @nextid: Pointer to an ID. |
262 | * | 258 | * |
@@ -265,22 +261,17 @@ EXPORT_SYMBOL(idr_get_next); | |||
265 | * to the ID of the found value. To use in a loop, the value pointed to by | 261 | * to the ID of the found value. To use in a loop, the value pointed to by |
266 | * nextid must be incremented by the user. | 262 | * nextid must be incremented by the user. |
267 | */ | 263 | */ |
268 | void *idr_get_next_ul(struct idr *idr, unsigned long *nextid) | 264 | void *idr_get_next(struct idr *idr, int *nextid) |
269 | { | 265 | { |
270 | struct radix_tree_iter iter; | ||
271 | void __rcu **slot; | ||
272 | unsigned long base = idr->idr_base; | ||
273 | unsigned long id = *nextid; | 266 | unsigned long id = *nextid; |
267 | void *entry = idr_get_next_ul(idr, &id); | ||
274 | 268 | ||
275 | id = (id < base) ? 0 : id - base; | 269 | if (WARN_ON_ONCE(id > INT_MAX)) |
276 | slot = radix_tree_iter_find(&idr->idr_rt, &iter, id); | ||
277 | if (!slot) | ||
278 | return NULL; | 270 | return NULL; |
279 | 271 | *nextid = id; | |
280 | *nextid = iter.index + base; | 272 | return entry; |
281 | return rcu_dereference_raw(*slot); | ||
282 | } | 273 | } |
283 | EXPORT_SYMBOL(idr_get_next_ul); | 274 | EXPORT_SYMBOL(idr_get_next); |
284 | 275 | ||
285 | /** | 276 | /** |
286 | * idr_replace() - replace pointer for given ID. | 277 | * idr_replace() - replace pointer for given ID. |
diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 18c1dfbb1765..c8fa1d274530 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c | |||
@@ -1529,7 +1529,7 @@ void __rcu **idr_get_free(struct radix_tree_root *root, | |||
1529 | offset = radix_tree_find_next_bit(node, IDR_FREE, | 1529 | offset = radix_tree_find_next_bit(node, IDR_FREE, |
1530 | offset + 1); | 1530 | offset + 1); |
1531 | start = next_index(start, node, offset); | 1531 | start = next_index(start, node, offset); |
1532 | if (start > max) | 1532 | if (start > max || start == 0) |
1533 | return ERR_PTR(-ENOSPC); | 1533 | return ERR_PTR(-ENOSPC); |
1534 | while (offset == RADIX_TREE_MAP_SIZE) { | 1534 | while (offset == RADIX_TREE_MAP_SIZE) { |
1535 | offset = node->offset + 1; | 1535 | offset = node->offset + 1; |
diff --git a/lib/test_xarray.c b/lib/test_xarray.c index 9d631a7b6a70..7df4f7f395bf 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c | |||
@@ -1110,6 +1110,28 @@ static noinline void check_find_entry(struct xarray *xa) | |||
1110 | XA_BUG_ON(xa, !xa_empty(xa)); | 1110 | XA_BUG_ON(xa, !xa_empty(xa)); |
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | static noinline void check_move_tiny(struct xarray *xa) | ||
1114 | { | ||
1115 | XA_STATE(xas, xa, 0); | ||
1116 | |||
1117 | XA_BUG_ON(xa, !xa_empty(xa)); | ||
1118 | rcu_read_lock(); | ||
1119 | XA_BUG_ON(xa, xas_next(&xas) != NULL); | ||
1120 | XA_BUG_ON(xa, xas_next(&xas) != NULL); | ||
1121 | rcu_read_unlock(); | ||
1122 | xa_store_index(xa, 0, GFP_KERNEL); | ||
1123 | rcu_read_lock(); | ||
1124 | xas_set(&xas, 0); | ||
1125 | XA_BUG_ON(xa, xas_next(&xas) != xa_mk_index(0)); | ||
1126 | XA_BUG_ON(xa, xas_next(&xas) != NULL); | ||
1127 | xas_set(&xas, 0); | ||
1128 | XA_BUG_ON(xa, xas_prev(&xas) != xa_mk_index(0)); | ||
1129 | XA_BUG_ON(xa, xas_prev(&xas) != NULL); | ||
1130 | rcu_read_unlock(); | ||
1131 | xa_erase_index(xa, 0); | ||
1132 | XA_BUG_ON(xa, !xa_empty(xa)); | ||
1133 | } | ||
1134 | |||
1113 | static noinline void check_move_small(struct xarray *xa, unsigned long idx) | 1135 | static noinline void check_move_small(struct xarray *xa, unsigned long idx) |
1114 | { | 1136 | { |
1115 | XA_STATE(xas, xa, 0); | 1137 | XA_STATE(xas, xa, 0); |
@@ -1217,6 +1239,8 @@ static noinline void check_move(struct xarray *xa) | |||
1217 | 1239 | ||
1218 | xa_destroy(xa); | 1240 | xa_destroy(xa); |
1219 | 1241 | ||
1242 | check_move_tiny(xa); | ||
1243 | |||
1220 | for (i = 0; i < 16; i++) | 1244 | for (i = 0; i < 16; i++) |
1221 | check_move_small(xa, 1UL << i); | 1245 | check_move_small(xa, 1UL << i); |
1222 | 1246 | ||
diff --git a/lib/xarray.c b/lib/xarray.c index 446b956c9188..1237c213f52b 100644 --- a/lib/xarray.c +++ b/lib/xarray.c | |||
@@ -994,6 +994,8 @@ void *__xas_prev(struct xa_state *xas) | |||
994 | 994 | ||
995 | if (!xas_frozen(xas->xa_node)) | 995 | if (!xas_frozen(xas->xa_node)) |
996 | xas->xa_index--; | 996 | xas->xa_index--; |
997 | if (!xas->xa_node) | ||
998 | return set_bounds(xas); | ||
997 | if (xas_not_node(xas->xa_node)) | 999 | if (xas_not_node(xas->xa_node)) |
998 | return xas_load(xas); | 1000 | return xas_load(xas); |
999 | 1001 | ||
@@ -1031,6 +1033,8 @@ void *__xas_next(struct xa_state *xas) | |||
1031 | 1033 | ||
1032 | if (!xas_frozen(xas->xa_node)) | 1034 | if (!xas_frozen(xas->xa_node)) |
1033 | xas->xa_index++; | 1035 | xas->xa_index++; |
1036 | if (!xas->xa_node) | ||
1037 | return set_bounds(xas); | ||
1034 | if (xas_not_node(xas->xa_node)) | 1038 | if (xas_not_node(xas->xa_node)) |
1035 | return xas_load(xas); | 1039 | return xas_load(xas); |
1036 | 1040 | ||