*/
#define MAS_START ((struct maple_node *)1UL)
#define MAS_ROOT ((struct maple_node *)3UL)
+#define MA_ERROR(err) ((struct maple_node *)(((unsigned long)err << 2) | 2UL))
#define MAP_STATE(sname, stree, sindex, eindex)\
struct maple_state sname = { \
return mt->root == NULL;
}
+/* Advanced API */
+
+bool mas_nomem(struct maple_state *, gfp_t);
#endif
#include <linux/maple_tree.h>
#include <linux/rcupdate.h>
-#define MA_ERROR(err) ((struct maple_node *)(((unsigned long)err << 2) | 2UL))
-
static inline void mas_set_err(struct maple_state *mas, long err)
{
mas->node = MA_ERROR(err);
mas_set_err(ms, -ENOMEM);
}
-static bool __maple_nomem(struct maple_state *ms, gfp_t gfp)
+bool mas_nomem(struct maple_state *ms, gfp_t gfp)
__must_hold(ms->tree->lock)
{
- if (ms->node != MA_ERROR(-ENOMEM))
+ if (ms->node != MA_ERROR(-ENOMEM)) {
+ struct maple_node *node = ma_get_alloc(ms);
+ if (node) {
+ kfree(node->slot[1]);
+ kfree(node->slot[0]);
+ kfree(node);
+ }
+ ms->alloc = NULL;
return false;
+ }
if (gfpflags_allow_blocking(gfp)) {
mtree_unlock(ms->tree);
goto already_exists;
ret = _maple_insert(&ms, entry);
- if (__maple_nomem(&ms, gfp))
+ if (mas_nomem(&ms, gfp))
goto retry;
already_exists:
static noinline void check_nomem(struct maple_tree *mt)
{
+ MAP_STATE(ms, mt, 1, 1);
+
MT_BUG_ON(mt, !mtree_empty(mt));
/* Storing something at 1 requires memory allocation */
/* Storing something at 0 does not */
MT_BUG_ON(mt, mtree_insert_index(mt, 0, GFP_ATOMIC) != 0);
+ /*
+ * Simulate two threads racing; the first one fails to allocate
+ * memory to insert an entry at 1, then the second one succeeds
+ * in allocating memory to insert an entry at 2. The first one
+ * then needs to free the node it allocated. LeakSanitizer will
+ * notice this, as will the 'nr_allocated' debugging aid in the
+ * userspace test suite.
+ */
+ mtree_lock(mt);
+ _maple_setup_insert(&ms);
+ MT_BUG_ON(mt, ms.node != MA_ERROR(-ENOMEM));
+ _maple_insert(&ms, xa_mk_value(1));
+ mas_nomem(&ms, GFP_KERNEL);
+ MT_BUG_ON(mt, ms.node != MAS_START);
+ mtree_unlock(mt);
+ MT_BUG_ON(mt, mtree_insert_index(mt, 2, GFP_KERNEL) != 0);
+ mtree_lock(mt);
+ _maple_setup_insert(&ms);
+ _maple_insert(&ms, xa_mk_value(1));
+ mas_nomem(&ms, GFP_KERNEL);
+ mtree_unlock(mt);
+
mtree_destroy(mt);
}