From 085fcd5494a90a2fac01327ad3cb182abc50b0de Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Mon, 10 Dec 2018 11:56:15 -0500 Subject: [PATCH] maple_tree: Stop deallocating partial successes. Start tracking the number of nodes requested separately from the number of nodes allocated and only allocate the number of nodes needed on requests - including the failure path. Signed-off-by: Liam R. Howlett --- lib/maple_tree.c | 63 ++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/lib/maple_tree.c b/lib/maple_tree.c index e10847d60dc5..8a9c1c20fc8b 100644 --- a/lib/maple_tree.c +++ b/lib/maple_tree.c @@ -65,16 +65,26 @@ static inline void *ma_mk_node(const struct maple_node *node) static inline void ma_set_alloc_cnt(struct maple_state *ms, int count) { - ms->alloc = (struct maple_node *)((unsigned long)ms->alloc & ~3); + ms->alloc = (struct maple_node *)((unsigned long)ms->alloc & ~0x03); ms->alloc = (struct maple_node *)((unsigned long)ms->alloc | count); } static inline int ma_get_alloc_cnt(const struct maple_state *ms) { return (int)((unsigned long)ms->alloc & 3); } +static inline void ma_set_alloc_req(struct maple_state *ms, int count) +{ + ms->alloc = (struct maple_node *)((unsigned long)ms->alloc & ~0x0C); + ms->alloc = (struct maple_node *)((unsigned long)ms->alloc | + (count << 2)); +} +static inline int ma_get_alloc_req(const struct maple_state *ms) +{ + return (int)(((unsigned long)ms->alloc & 0x0C) >> 2); +} static inline struct maple_node *ma_get_alloc(const struct maple_state *ms) { - return (struct maple_node *)((unsigned long)ms->alloc & ~3); + return (struct maple_node *)((unsigned long)ms->alloc & ~0x0F); } static inline struct maple_node *ma_next_alloc(struct maple_state *ms) { @@ -119,38 +129,45 @@ static inline bool _maple_is_node_4(struct maple_state *ms) return false; } -static void maple_new_node(struct maple_state *ms, int count, gfp_t gfp) +static void maple_new_node(struct maple_state *ms, gfp_t gfp) { struct maple_node *mn, *smn; - int i = 0; + int req = ma_get_alloc_req(ms); + int allocated = ma_get_alloc_cnt(ms); + int slot; - if (count == 0) + if (!req) return; mn = ma_get_alloc(ms); - if (!mn) + if (!mn) { mn = kzalloc(sizeof(*mn), gfp); - if (!mn) - goto list_failed; + if (!mn) + goto list_failed; + req--; + allocated++; + } - for (i = 0; i < count - 1; i++) { + slot = allocated - 1; + while (req > 0) { + req--; smn = kzalloc(sizeof(*mn), gfp); if (!smn) - goto kzalloc_failed; + goto slot_failed; smn->parent = NULL; - mn->slot[i] = smn; + mn->slot[slot++] = smn; + allocated++; } + +slot_failed: ms->alloc = mn; - ma_set_alloc_cnt(ms, count); - return; + ma_set_alloc_cnt(ms, allocated); + ma_set_alloc_req(ms, req); -kzalloc_failed: - while (--i >= 0) - kfree(mn->slot[i]); - kfree(mn); list_failed: - ma_set_alloc_cnt(ms, count); - mas_set_err(ms, -ENOMEM); + if (req > 0) + mas_set_err(ms, -ENOMEM); + return; } bool mas_nomem(struct maple_state *ms, gfp_t gfp) @@ -169,10 +186,10 @@ bool mas_nomem(struct maple_state *ms, gfp_t gfp) if (gfpflags_allow_blocking(gfp)) { mtree_unlock(ms->tree); - maple_new_node(ms, ma_get_alloc_cnt(ms), gfp); + maple_new_node(ms, gfp); mtree_lock(ms->tree); } else { - maple_new_node(ms, ma_get_alloc_cnt(ms), gfp); + maple_new_node(ms, gfp); } if (!ma_get_alloc(ms)) return false; @@ -324,8 +341,8 @@ static struct maple_node *maple_state_node(struct maple_state *ms, int count) BUG_ON(count > 3); if (allocated < count) { - int diff = count - allocated; - maple_new_node(ms, diff, GFP_NOWAIT | __GFP_NOWARN); + ma_set_alloc_req(ms, count - allocated); + maple_new_node(ms, GFP_NOWAIT | __GFP_NOWARN); } return ms->alloc; } -- 2.50.1