From 8c87e9502142d5b4a282b94f929ae776a49be1dc Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 21 Nov 2014 17:47:56 -0800 Subject: [PATCH] crush/builder: prevent bucket weight underflow on item removal It is possible to set a bucket weight that is not the sum of the item weights if you manually modify/build the CRUSH map. Protect against any underflow on the bucket weight when removing items. Signed-off-by: Sage Weil --- src/crush/builder.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/crush/builder.c b/src/crush/builder.c index 41b90aabf4452..1609eb4d71236 100644 --- a/src/crush/builder.c +++ b/src/crush/builder.c @@ -745,7 +745,10 @@ int crush_remove_uniform_bucket_item(struct crush_bucket_uniform *bucket, int it for (j = i; j < bucket->h.size; j++) bucket->h.items[j] = bucket->h.items[j+1]; newsize = --bucket->h.size; - bucket->h.weight -= bucket->item_weight; + if (bucket->item_weight < bucket->h.weight) + bucket->h.weight -= bucket->item_weight; + else + bucket->h.weight = 0; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; @@ -778,7 +781,10 @@ int crush_remove_list_bucket_item(struct crush_bucket_list *bucket, int item) bucket->item_weights[j] = bucket->item_weights[j+1]; bucket->sum_weights[j] = bucket->sum_weights[j+1] - weight; } - bucket->h.weight -= weight; + if (weight < bucket->h.weight) + bucket->h.weight -= weight; + else + bucket->h.weight = 0; newsize = --bucket->h.size; void *_realloc = NULL; @@ -829,7 +835,10 @@ int crush_remove_tree_bucket_item(struct crush_bucket_tree *bucket, int item) bucket->node_weights[node] -= weight; printf(" node %d weight %d\n", node, bucket->node_weights[node]); } - bucket->h.weight -= weight; + if (weight < bucket->h.weight) + bucket->h.weight -= weight; + else + bucket->h.weight = 0; break; } if (i == bucket->h.size) @@ -884,7 +893,10 @@ int crush_remove_straw_bucket_item(struct crush_bucket_straw *bucket, int item) for (i = 0; i < bucket->h.size; i++) { if (bucket->h.items[i] == item) { bucket->h.size--; - bucket->h.weight -= bucket->item_weights[i]; + if (bucket->item_weights[i] < bucket->h.weight) + bucket->h.weight -= bucket->item_weights[i]; + else + bucket->h.weight = 0; for (j = i; j < bucket->h.size; j++) { bucket->h.items[j] = bucket->h.items[j+1]; bucket->item_weights[j] = bucket->item_weights[j+1]; -- 2.39.5