wr_mas->offset_end = mas->offset = offset;
}
-static inline void rebalance_sib(struct ma_state *mas, struct ma_state *sib)
+static inline void rebalance_sib(struct ma_state *parent, struct ma_state *sib)
{
- unsigned char end;
-
- *sib = *mas;
- mas_ascend(sib);
- end = mas_data_end(sib);
+ *sib = *parent;
/* Prioritize move right to pull data left */
- if (sib->offset < end)
+ if (sib->offset < sib->end)
sib->offset++;
else
sib->offset--;
return false;
}
-static void push_data_sib(struct maple_copy *cp, struct ma_state *mas,
- struct ma_state *sib)
+static inline void push_data_sib(struct maple_copy *cp, struct ma_state *mas,
+ struct ma_state *sib, struct ma_state *parent)
{
+
if (mte_is_root(mas->node))
goto no_push;
- *sib = *mas;
- mas_ascend(sib);
+ *sib = *parent;
if (sib->offset) {
sib->offset--;
mas_descend(sib);
if (data_fits(sib, mas, cp)) /* Push left */
return;
- mas_ascend(sib);
- sib->offset++;
+ *sib = *parent;
}
- sib->end = mas_data_end(sib);
if (sib->offset >= sib->end)
goto no_push;
*
*/
static inline void rebalance_data(struct maple_copy *cp,
- struct ma_wr_state *wr_mas, struct ma_state *sib)
+ struct ma_wr_state *wr_mas, struct ma_state *sib,
+ struct ma_state *parent)
{
cp_data_calc(cp, wr_mas, wr_mas);
sib->end = 0;
if (cp->data >= mt_slots[wr_mas->type]) {
- push_data_sib(cp, wr_mas->mas, sib);
+ push_data_sib(cp, wr_mas->mas, sib, parent);
if (sib->end)
goto use_sib;
- }
-
- if (((wr_mas->mas->min != 0) || (wr_mas->mas->max != ULONG_MAX)) &&
- (cp->data <= mt_min_slots[wr_mas->type])) {
- rebalance_sib(wr_mas->mas, sib);
- goto use_sib;
+ } else if (cp->data <= mt_min_slots[wr_mas->type]) {
+ if ((wr_mas->mas->min != 0) ||
+ (wr_mas->mas->max != ULONG_MAX)) {
+ rebalance_sib(parent, sib);
+ goto use_sib;
+ }
}
return;
* needed, false otherwise.
*/
static inline bool rebalance_ascend(struct maple_copy *cp,
- struct ma_wr_state *wr_mas, struct ma_state *sib)
+ struct ma_wr_state *wr_mas, struct ma_state *sib,
+ struct ma_state *parent)
{
struct ma_state *mas;
unsigned long min;
return false;
cp->height++;
- mas_ascend(mas);
+ parent->alloc = mas->alloc;
+ *mas = *parent;
wr_mas_setup(wr_mas, mas);
wr_mas->offset_end = mas->offset;
if (r == sib)
* Return: true if another split operation on the next level is needed, false
* otherwise
*/
-static bool split_ascend(struct maple_copy *cp,
- struct ma_wr_state *wr_mas, struct ma_state *sib)
+static inline bool split_ascend(struct maple_copy *cp,
+ struct ma_wr_state *wr_mas, struct ma_state *sib,
+ struct ma_state *parent)
{
struct ma_state *mas;
unsigned long min, max;
return false;
cp->height++;
- mas_ascend(mas);
+ BUG_ON(mas->node == parent->node);
+ parent->alloc = mas->alloc;
+ *mas = *parent;
wr_mas_setup(wr_mas, mas);
wr_mas->offset_end = mas->offset;
if (sib->end) {
* indicate it will not be used.
*
*/
-static void split_data(struct maple_copy *cp,
- struct ma_wr_state *wr_mas, struct ma_state *sib)
+static inline void split_data(struct maple_copy *cp,
+ struct ma_wr_state *wr_mas, struct ma_state *sib,
+ struct ma_state *parent)
{
cp_data_calc(cp, wr_mas, wr_mas);
if (cp->data <= mt_slots[wr_mas->type]) {
return;
}
- push_data_sib(cp, wr_mas->mas, sib);
+ push_data_sib(cp, wr_mas->mas, sib, parent);
if (sib->end)
cp->data += sib->end + 1;
}
struct ma_state *mas;
struct maple_copy cp;
struct ma_state sib;
+ struct ma_state parent;
mas = wr_mas->mas;
+ parent = *mas;
trace_ma_op(__func__, mas);
cp_leaf_init(&cp, mas, wr_mas, wr_mas);
do {
- split_data(&cp, wr_mas, &sib);
+ if (!mte_is_root(parent.node)) {
+ mas_ascend(&parent);
+ parent.end = mas_data_end(&parent);
+ }
+ split_data(&cp, wr_mas, &sib, &parent);
multi_src_setup(&cp, wr_mas, wr_mas, &sib);
dst_setup(&cp, mas, wr_mas->type);
cp_data_write(&cp, mas);
- } while (split_ascend(&cp, wr_mas, &sib));
+ } while (split_ascend(&cp, wr_mas, &sib, &parent));
mas_wmb_replace(mas, &cp);
}
struct ma_state *mas;
struct maple_copy cp;
struct ma_state sib;
+ struct ma_state parent;
/*
* Rebalancing occurs if a node is insufficient. Data is rebalanced
mas = wr_mas->mas;
trace_ma_op(__func__, mas);
+ parent = *mas;
cp_leaf_init(&cp, mas, wr_mas, wr_mas);
do {
- rebalance_data(&cp, wr_mas, &sib);
+ if (!mte_is_root(parent.node)) {
+ mas_ascend(&parent);
+ parent.end = mas_data_end(&parent);
+ }
+ rebalance_data(&cp, wr_mas, &sib, &parent);
multi_src_setup(&cp, wr_mas, wr_mas, &sib);
dst_setup(&cp, mas, wr_mas->type);
cp_data_write(&cp, mas);
- } while (rebalance_ascend(&cp, wr_mas, &sib));
+ } while (rebalance_ascend(&cp, wr_mas, &sib, &parent));
mas_wmb_replace(mas, &cp);
}