int crush_adjust_tree_bucket_item_weight(struct crush_bucket_tree *bucket, int item, int weight) { int diff; int node; unsigned i, j; unsigned depth = calc_depth(bucket->h.size); for (i = 0; i < bucket->h.size; i++) { if (bucket->h.items[i] == item) break; } if (i == bucket->h.size) return 0; node = crush_calc_tree_node(i); diff = weight - bucket->node_weights[node]; bucket->node_weights[node] = weight; bucket->h.weight += diff; for (j=1; j<depth; j++) { node = parent(node); bucket->node_weights[node] += diff; } return diff; }
int crush_add_tree_bucket_item(struct crush_bucket_tree *bucket, int item, int weight) { int newsize = bucket->h.size + 1; int depth = calc_depth(newsize);; int node; int j; void *_realloc = NULL; bucket->num_nodes = 1 << depth; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } if ((_realloc = realloc(bucket->node_weights, sizeof(__u32)*bucket->num_nodes)) == NULL) { return -ENOMEM; } else { bucket->node_weights = _realloc; } node = crush_calc_tree_node(newsize-1); bucket->node_weights[node] = weight; /* if the depth increase, we need to initialize the new root node's weight before add bucket item */ int root = bucket->num_nodes/2; if (depth >= 2 && (node - 1) == root) { /* if the new item is the first node in right sub tree, so * the root node initial weight is left sub tree's weight */ bucket->node_weights[root] = bucket->node_weights[root/2]; } for (j=1; j<depth; j++) { node = parent(node); if (crush_addition_is_unsafe(bucket->node_weights[node], weight)) return -ERANGE; bucket->node_weights[node] += weight; dprintk(" node %d weight %d\n", node, bucket->node_weights[node]); } if (crush_addition_is_unsafe(bucket->h.weight, weight)) return -ERANGE; bucket->h.items[newsize-1] = item; bucket->h.weight += weight; bucket->h.size++; return 0; }
/** * crush_get_bucket_item_weight - Get weight of an item in given bucket * @param b bucket pointer * @param p item index in bucket */ int crush_get_bucket_item_weight(const struct crush_bucket *b, int p) { if ((__u32)p >= b->size) return 0; switch (b->alg) { case CRUSH_BUCKET_UNIFORM: return ((struct crush_bucket_uniform *)b)->item_weight; case CRUSH_BUCKET_LIST: return ((struct crush_bucket_list *)b)->item_weights[p]; case CRUSH_BUCKET_TREE: return ((struct crush_bucket_tree *)b)->node_weights[crush_calc_tree_node(p)]; case CRUSH_BUCKET_STRAW: return ((struct crush_bucket_straw *)b)->item_weights[p]; } return 0; }
static int crush_reweight_tree_bucket(struct crush_map *crush, struct crush_bucket_tree *bucket) { unsigned i; bucket->h.weight = 0; for (i = 0; i < bucket->h.size; i++) { int node = crush_calc_tree_node(i); int id = bucket->h.items[i]; if (id < 0) { struct crush_bucket *c = crush->buckets[-1-id]; crush_reweight_bucket(crush, c); bucket->node_weights[node] = c->weight; } if (crush_addition_is_unsafe(bucket->h.weight, bucket->node_weights[node])) return -ERANGE; bucket->h.weight += bucket->node_weights[node]; } return 0; }
int crush_remove_tree_bucket_item(struct crush_bucket_tree *bucket, int item) { unsigned i; unsigned newsize; for (i = 0; i < bucket->h.size; i++) { int node; int weight; int j; int depth = calc_depth(bucket->h.size); if (bucket->h.items[i] != item) continue; node = crush_calc_tree_node(i); weight = bucket->node_weights[node]; bucket->node_weights[node] = 0; for (j = 1; j < depth; j++) { node = parent(node); bucket->node_weights[node] -= weight; dprintk(" node %d weight %d\n", node, bucket->node_weights[node]); } bucket->h.weight -= weight; break; } if (i == bucket->h.size) return -ENOENT; newsize = bucket->h.size; while (newsize > 0) { int node = crush_calc_tree_node(newsize - 1); if (bucket->node_weights[node]) break; --newsize; } if (newsize != bucket->h.size) { int olddepth, newdepth; void *_realloc = NULL; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->h.perm, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.perm = _realloc; } olddepth = calc_depth(bucket->h.size); newdepth = calc_depth(newsize); if (olddepth != newdepth) { bucket->num_nodes = 1 << newdepth; if ((_realloc = realloc(bucket->node_weights, sizeof(__u32)*bucket->num_nodes)) == NULL) { return -ENOMEM; } else { bucket->node_weights = _realloc; } } bucket->h.size = newsize; } return 0; }
struct crush_bucket_tree* crush_make_tree_bucket(int hash, int type, int size, int *items, /* in leaf order */ int *weights) { struct crush_bucket_tree *bucket; int depth; int node; int i, j; bucket = malloc(sizeof(*bucket)); if (!bucket) return NULL; memset(bucket, 0, sizeof(*bucket)); bucket->h.alg = CRUSH_BUCKET_TREE; bucket->h.hash = hash; bucket->h.type = type; bucket->h.size = size; if (size == 0) { bucket->h.items = NULL; bucket->h.perm = NULL; bucket->h.weight = 0; bucket->node_weights = NULL; bucket->num_nodes = 0; /* printf("size 0 depth 0 nodes 0\n"); */ return bucket; } bucket->h.items = malloc(sizeof(__s32)*size); if (!bucket->h.items) goto err; bucket->h.perm = malloc(sizeof(__u32)*size); if (!bucket->h.perm) goto err; /* calc tree depth */ depth = calc_depth(size); bucket->num_nodes = 1 << depth; dprintk("size %d depth %d nodes %d\n", size, depth, bucket->num_nodes); bucket->node_weights = malloc(sizeof(__u32)*bucket->num_nodes); if (!bucket->node_weights) goto err; memset(bucket->h.items, 0, sizeof(__s32)*bucket->h.size); memset(bucket->node_weights, 0, sizeof(__u32)*bucket->num_nodes); for (i=0; i<size; i++) { bucket->h.items[i] = items[i]; node = crush_calc_tree_node(i); dprintk("item %d node %d weight %d\n", i, node, weights[i]); bucket->node_weights[node] = weights[i]; if (crush_addition_is_unsafe(bucket->h.weight, weights[i])) goto err; bucket->h.weight += weights[i]; for (j=1; j<depth; j++) { node = parent(node); if (crush_addition_is_unsafe(bucket->node_weights[node], weights[i])) goto err; bucket->node_weights[node] += weights[i]; dprintk(" node %d weight %d\n", node, bucket->node_weights[node]); } } BUG_ON(bucket->node_weights[bucket->num_nodes/2] != bucket->h.weight); return bucket; err: free(bucket->node_weights); free(bucket->h.perm); free(bucket->h.items); free(bucket); return NULL; }