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; }
static int crush_reweight_uniform_bucket(struct crush_map *crush, struct crush_bucket_uniform *bucket) { unsigned i; unsigned sum = 0, n = 0, leaves = 0; for (i = 0; i < bucket->h.size; i++) { int id = bucket->h.items[i]; if (id < 0) { struct crush_bucket *c = crush->buckets[-1-id]; crush_reweight_bucket(crush, c); if (crush_addition_is_unsafe(sum, c->weight)) return -ERANGE; sum += c->weight; n++; } else { leaves++; } } if (n > leaves) bucket->item_weight = sum / n; // more bucket children than leaves, average! bucket->h.weight = bucket->item_weight * bucket->h.size; return 0; }
int crush_add_uniform_bucket_item(struct crush_bucket_uniform *bucket, int item, int weight) { int newsize = bucket->h.size + 1; 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; } bucket->h.items[newsize-1] = item; if (crush_addition_is_unsafe(bucket->h.weight, weight)) return -ERANGE; bucket->h.weight += weight; bucket->h.size++; return 0; }
int crush_add_straw_bucket_item(struct crush_map *map, struct crush_bucket_straw *bucket, int item, int weight) { int newsize = bucket->h.size + 1; void *_realloc = NULL; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->item_weights, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->item_weights = _realloc; } if ((_realloc = realloc(bucket->straws, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->straws = _realloc; } bucket->h.items[newsize-1] = item; bucket->item_weights[newsize-1] = weight; if (crush_addition_is_unsafe(bucket->h.weight, weight)) return -ERANGE; bucket->h.weight += weight; bucket->h.size++; return crush_calc_straw(map, bucket); }
int crush_add_uniform_bucket_item(struct crush_bucket_uniform *bucket, int item, int weight) { int newsize = bucket->h.size + 1; void *_realloc = NULL; /* In such situation 'CRUSH_BUCKET_UNIFORM', the weight provided for the item should be the same as bucket->item_weight defined with 'crush_make_bucket'. This assumption is enforced by the return value which is always 0. */ if (bucket->item_weight != weight) { return -EINVAL; } if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } bucket->h.items[newsize-1] = item; if (crush_addition_is_unsafe(bucket->h.weight, weight)) return -ERANGE; bucket->h.weight += weight; bucket->h.size++; return 0; }
struct crush_bucket_list* crush_make_list_bucket(int hash, int type, int size, int *items, int *weights) { int i; int w; struct crush_bucket_list *bucket; bucket = malloc(sizeof(*bucket)); if (!bucket) return NULL; memset(bucket, 0, sizeof(*bucket)); bucket->h.alg = CRUSH_BUCKET_LIST; bucket->h.hash = hash; bucket->h.type = type; bucket->h.size = size; 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; bucket->item_weights = malloc(sizeof(__u32)*size); if (!bucket->item_weights) goto err; bucket->sum_weights = malloc(sizeof(__u32)*size); if (!bucket->sum_weights) goto err; w = 0; for (i=0; i<size; i++) { bucket->h.items[i] = items[i]; bucket->item_weights[i] = weights[i]; if (crush_addition_is_unsafe(w, weights[i])) goto err; w += weights[i]; bucket->sum_weights[i] = w; /*dprintk("pos %d item %d weight %d sum %d\n", i, items[i], weights[i], bucket->sum_weights[i]);*/ } bucket->h.weight = w; return bucket; err: free(bucket->sum_weights); free(bucket->item_weights); free(bucket->h.perm); free(bucket->h.items); free(bucket); return NULL; }
static int crush_reweight_straw_bucket(struct crush_map *crush, struct crush_bucket_straw *bucket) { unsigned i; bucket->h.weight = 0; for (i = 0; i < bucket->h.size; i++) { int id = bucket->h.items[i]; if (id < 0) { struct crush_bucket *c = crush->buckets[-1-id]; crush_reweight_bucket(crush, c); bucket->item_weights[i] = c->weight; } if (crush_addition_is_unsafe(bucket->h.weight, bucket->item_weights[i])) return -ERANGE; bucket->h.weight += bucket->item_weights[i]; } return 0; }
int crush_add_list_bucket_item(struct crush_bucket_list *bucket, int item, int weight) { int newsize = bucket->h.size + 1; void *_realloc = NULL; if ((_realloc = realloc(bucket->h.items, sizeof(__s32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->h.items = _realloc; } if ((_realloc = realloc(bucket->item_weights, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->item_weights = _realloc; } if ((_realloc = realloc(bucket->sum_weights, sizeof(__u32)*newsize)) == NULL) { return -ENOMEM; } else { bucket->sum_weights = _realloc; } bucket->h.items[newsize-1] = item; bucket->item_weights[newsize-1] = weight; if (newsize > 1) { if (crush_addition_is_unsafe(bucket->sum_weights[newsize-2], weight)) return -ERANGE; bucket->sum_weights[newsize-1] = bucket->sum_weights[newsize-2] + weight; } else { bucket->sum_weights[newsize-1] = weight; } bucket->h.weight += weight; bucket->h.size++; 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; }
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; }