18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Ceph - scalable distributed file system 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2015 Intel Corporation All Rights Reserved 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This is free software; you can redistribute it and/or 78c2ecf20Sopenharmony_ci * modify it under the terms of the GNU Lesser General Public 88c2ecf20Sopenharmony_ci * License version 2.1, as published by the Free Software 98c2ecf20Sopenharmony_ci * Foundation. See file COPYING. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#ifdef __KERNEL__ 148c2ecf20Sopenharmony_ci# include <linux/string.h> 158c2ecf20Sopenharmony_ci# include <linux/slab.h> 168c2ecf20Sopenharmony_ci# include <linux/bug.h> 178c2ecf20Sopenharmony_ci# include <linux/kernel.h> 188c2ecf20Sopenharmony_ci# include <linux/crush/crush.h> 198c2ecf20Sopenharmony_ci# include <linux/crush/hash.h> 208c2ecf20Sopenharmony_ci# include <linux/crush/mapper.h> 218c2ecf20Sopenharmony_ci#else 228c2ecf20Sopenharmony_ci# include "crush_compat.h" 238c2ecf20Sopenharmony_ci# include "crush.h" 248c2ecf20Sopenharmony_ci# include "hash.h" 258c2ecf20Sopenharmony_ci# include "mapper.h" 268c2ecf20Sopenharmony_ci#endif 278c2ecf20Sopenharmony_ci#include "crush_ln_table.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define dprintk(args...) /* printf(args) */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * Implement the core CRUSH mapping algorithm. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/** 368c2ecf20Sopenharmony_ci * crush_find_rule - find a crush_rule id for a given ruleset, type, and size. 378c2ecf20Sopenharmony_ci * @map: the crush_map 388c2ecf20Sopenharmony_ci * @ruleset: the storage ruleset id (user defined) 398c2ecf20Sopenharmony_ci * @type: storage ruleset type (user defined) 408c2ecf20Sopenharmony_ci * @size: output set size 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ciint crush_find_rule(const struct crush_map *map, int ruleset, int type, int size) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci __u32 i; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci for (i = 0; i < map->max_rules; i++) { 478c2ecf20Sopenharmony_ci if (map->rules[i] && 488c2ecf20Sopenharmony_ci map->rules[i]->mask.ruleset == ruleset && 498c2ecf20Sopenharmony_ci map->rules[i]->mask.type == type && 508c2ecf20Sopenharmony_ci map->rules[i]->mask.min_size <= size && 518c2ecf20Sopenharmony_ci map->rules[i]->mask.max_size >= size) 528c2ecf20Sopenharmony_ci return i; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci return -1; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * bucket choose methods 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * For each bucket algorithm, we have a "choose" method that, given a 618c2ecf20Sopenharmony_ci * crush input @x and replica position (usually, position in output set) @r, 628c2ecf20Sopenharmony_ci * will produce an item in the bucket. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* 668c2ecf20Sopenharmony_ci * Choose based on a random permutation of the bucket. 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * We used to use some prime number arithmetic to do this, but it 698c2ecf20Sopenharmony_ci * wasn't very random, and had some other bad behaviors. Instead, we 708c2ecf20Sopenharmony_ci * calculate an actual random permutation of the bucket members. 718c2ecf20Sopenharmony_ci * Since this is expensive, we optimize for the r=0 case, which 728c2ecf20Sopenharmony_ci * captures the vast majority of calls. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_cistatic int bucket_perm_choose(const struct crush_bucket *bucket, 758c2ecf20Sopenharmony_ci struct crush_work_bucket *work, 768c2ecf20Sopenharmony_ci int x, int r) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci unsigned int pr = r % bucket->size; 798c2ecf20Sopenharmony_ci unsigned int i, s; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* start a new permutation if @x has changed */ 828c2ecf20Sopenharmony_ci if (work->perm_x != (__u32)x || work->perm_n == 0) { 838c2ecf20Sopenharmony_ci dprintk("bucket %d new x=%d\n", bucket->id, x); 848c2ecf20Sopenharmony_ci work->perm_x = x; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* optimize common r=0 case */ 878c2ecf20Sopenharmony_ci if (pr == 0) { 888c2ecf20Sopenharmony_ci s = crush_hash32_3(bucket->hash, x, bucket->id, 0) % 898c2ecf20Sopenharmony_ci bucket->size; 908c2ecf20Sopenharmony_ci work->perm[0] = s; 918c2ecf20Sopenharmony_ci work->perm_n = 0xffff; /* magic value, see below */ 928c2ecf20Sopenharmony_ci goto out; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci for (i = 0; i < bucket->size; i++) 968c2ecf20Sopenharmony_ci work->perm[i] = i; 978c2ecf20Sopenharmony_ci work->perm_n = 0; 988c2ecf20Sopenharmony_ci } else if (work->perm_n == 0xffff) { 998c2ecf20Sopenharmony_ci /* clean up after the r=0 case above */ 1008c2ecf20Sopenharmony_ci for (i = 1; i < bucket->size; i++) 1018c2ecf20Sopenharmony_ci work->perm[i] = i; 1028c2ecf20Sopenharmony_ci work->perm[work->perm[0]] = 0; 1038c2ecf20Sopenharmony_ci work->perm_n = 1; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* calculate permutation up to pr */ 1078c2ecf20Sopenharmony_ci for (i = 0; i < work->perm_n; i++) 1088c2ecf20Sopenharmony_ci dprintk(" perm_choose have %d: %d\n", i, work->perm[i]); 1098c2ecf20Sopenharmony_ci while (work->perm_n <= pr) { 1108c2ecf20Sopenharmony_ci unsigned int p = work->perm_n; 1118c2ecf20Sopenharmony_ci /* no point in swapping the final entry */ 1128c2ecf20Sopenharmony_ci if (p < bucket->size - 1) { 1138c2ecf20Sopenharmony_ci i = crush_hash32_3(bucket->hash, x, bucket->id, p) % 1148c2ecf20Sopenharmony_ci (bucket->size - p); 1158c2ecf20Sopenharmony_ci if (i) { 1168c2ecf20Sopenharmony_ci unsigned int t = work->perm[p + i]; 1178c2ecf20Sopenharmony_ci work->perm[p + i] = work->perm[p]; 1188c2ecf20Sopenharmony_ci work->perm[p] = t; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci dprintk(" perm_choose swap %d with %d\n", p, p+i); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci work->perm_n++; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci for (i = 0; i < bucket->size; i++) 1258c2ecf20Sopenharmony_ci dprintk(" perm_choose %d: %d\n", i, work->perm[i]); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci s = work->perm[pr]; 1288c2ecf20Sopenharmony_ciout: 1298c2ecf20Sopenharmony_ci dprintk(" perm_choose %d sz=%d x=%d r=%d (%d) s=%d\n", bucket->id, 1308c2ecf20Sopenharmony_ci bucket->size, x, r, pr, s); 1318c2ecf20Sopenharmony_ci return bucket->items[s]; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* uniform */ 1358c2ecf20Sopenharmony_cistatic int bucket_uniform_choose(const struct crush_bucket_uniform *bucket, 1368c2ecf20Sopenharmony_ci struct crush_work_bucket *work, int x, int r) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci return bucket_perm_choose(&bucket->h, work, x, r); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* list */ 1428c2ecf20Sopenharmony_cistatic int bucket_list_choose(const struct crush_bucket_list *bucket, 1438c2ecf20Sopenharmony_ci int x, int r) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci int i; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci for (i = bucket->h.size-1; i >= 0; i--) { 1488c2ecf20Sopenharmony_ci __u64 w = crush_hash32_4(bucket->h.hash, x, bucket->h.items[i], 1498c2ecf20Sopenharmony_ci r, bucket->h.id); 1508c2ecf20Sopenharmony_ci w &= 0xffff; 1518c2ecf20Sopenharmony_ci dprintk("list_choose i=%d x=%d r=%d item %d weight %x " 1528c2ecf20Sopenharmony_ci "sw %x rand %llx", 1538c2ecf20Sopenharmony_ci i, x, r, bucket->h.items[i], bucket->item_weights[i], 1548c2ecf20Sopenharmony_ci bucket->sum_weights[i], w); 1558c2ecf20Sopenharmony_ci w *= bucket->sum_weights[i]; 1568c2ecf20Sopenharmony_ci w = w >> 16; 1578c2ecf20Sopenharmony_ci /*dprintk(" scaled %llx\n", w);*/ 1588c2ecf20Sopenharmony_ci if (w < bucket->item_weights[i]) { 1598c2ecf20Sopenharmony_ci return bucket->h.items[i]; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci dprintk("bad list sums for bucket %d\n", bucket->h.id); 1648c2ecf20Sopenharmony_ci return bucket->h.items[0]; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* (binary) tree */ 1698c2ecf20Sopenharmony_cistatic int height(int n) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci int h = 0; 1728c2ecf20Sopenharmony_ci while ((n & 1) == 0) { 1738c2ecf20Sopenharmony_ci h++; 1748c2ecf20Sopenharmony_ci n = n >> 1; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci return h; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int left(int x) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci int h = height(x); 1828c2ecf20Sopenharmony_ci return x - (1 << (h-1)); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int right(int x) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci int h = height(x); 1888c2ecf20Sopenharmony_ci return x + (1 << (h-1)); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int terminal(int x) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci return x & 1; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int bucket_tree_choose(const struct crush_bucket_tree *bucket, 1978c2ecf20Sopenharmony_ci int x, int r) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int n; 2008c2ecf20Sopenharmony_ci __u32 w; 2018c2ecf20Sopenharmony_ci __u64 t; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* start at root */ 2048c2ecf20Sopenharmony_ci n = bucket->num_nodes >> 1; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci while (!terminal(n)) { 2078c2ecf20Sopenharmony_ci int l; 2088c2ecf20Sopenharmony_ci /* pick point in [0, w) */ 2098c2ecf20Sopenharmony_ci w = bucket->node_weights[n]; 2108c2ecf20Sopenharmony_ci t = (__u64)crush_hash32_4(bucket->h.hash, x, n, r, 2118c2ecf20Sopenharmony_ci bucket->h.id) * (__u64)w; 2128c2ecf20Sopenharmony_ci t = t >> 32; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* descend to the left or right? */ 2158c2ecf20Sopenharmony_ci l = left(n); 2168c2ecf20Sopenharmony_ci if (t < bucket->node_weights[l]) 2178c2ecf20Sopenharmony_ci n = l; 2188c2ecf20Sopenharmony_ci else 2198c2ecf20Sopenharmony_ci n = right(n); 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return bucket->h.items[n >> 1]; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/* straw */ 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic int bucket_straw_choose(const struct crush_bucket_straw *bucket, 2298c2ecf20Sopenharmony_ci int x, int r) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci __u32 i; 2328c2ecf20Sopenharmony_ci int high = 0; 2338c2ecf20Sopenharmony_ci __u64 high_draw = 0; 2348c2ecf20Sopenharmony_ci __u64 draw; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci for (i = 0; i < bucket->h.size; i++) { 2378c2ecf20Sopenharmony_ci draw = crush_hash32_3(bucket->h.hash, x, bucket->h.items[i], r); 2388c2ecf20Sopenharmony_ci draw &= 0xffff; 2398c2ecf20Sopenharmony_ci draw *= bucket->straws[i]; 2408c2ecf20Sopenharmony_ci if (i == 0 || draw > high_draw) { 2418c2ecf20Sopenharmony_ci high = i; 2428c2ecf20Sopenharmony_ci high_draw = draw; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci return bucket->h.items[high]; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* compute 2^44*log2(input+1) */ 2498c2ecf20Sopenharmony_cistatic __u64 crush_ln(unsigned int xin) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci unsigned int x = xin; 2528c2ecf20Sopenharmony_ci int iexpon, index1, index2; 2538c2ecf20Sopenharmony_ci __u64 RH, LH, LL, xl64, result; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci x++; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* normalize input */ 2588c2ecf20Sopenharmony_ci iexpon = 15; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* 2618c2ecf20Sopenharmony_ci * figure out number of bits we need to shift and 2628c2ecf20Sopenharmony_ci * do it in one step instead of iteratively 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci if (!(x & 0x18000)) { 2658c2ecf20Sopenharmony_ci int bits = __builtin_clz(x & 0x1FFFF) - 16; 2668c2ecf20Sopenharmony_ci x <<= bits; 2678c2ecf20Sopenharmony_ci iexpon = 15 - bits; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci index1 = (x >> 8) << 1; 2718c2ecf20Sopenharmony_ci /* RH ~ 2^56/index1 */ 2728c2ecf20Sopenharmony_ci RH = __RH_LH_tbl[index1 - 256]; 2738c2ecf20Sopenharmony_ci /* LH ~ 2^48 * log2(index1/256) */ 2748c2ecf20Sopenharmony_ci LH = __RH_LH_tbl[index1 + 1 - 256]; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* RH*x ~ 2^48 * (2^15 + xf), xf<2^8 */ 2778c2ecf20Sopenharmony_ci xl64 = (__s64)x * RH; 2788c2ecf20Sopenharmony_ci xl64 >>= 48; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci result = iexpon; 2818c2ecf20Sopenharmony_ci result <<= (12 + 32); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci index2 = xl64 & 0xff; 2848c2ecf20Sopenharmony_ci /* LL ~ 2^48*log2(1.0+index2/2^15) */ 2858c2ecf20Sopenharmony_ci LL = __LL_tbl[index2]; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci LH = LH + LL; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci LH >>= (48 - 12 - 32); 2908c2ecf20Sopenharmony_ci result += LH; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return result; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/* 2978c2ecf20Sopenharmony_ci * straw2 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * for reference, see: 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * https://en.wikipedia.org/wiki/Exponential_distribution#Distribution_of_the_minimum_of_exponential_random_variables 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic __u32 *get_choose_arg_weights(const struct crush_bucket_straw2 *bucket, 3068c2ecf20Sopenharmony_ci const struct crush_choose_arg *arg, 3078c2ecf20Sopenharmony_ci int position) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci if (!arg || !arg->weight_set) 3108c2ecf20Sopenharmony_ci return bucket->item_weights; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (position >= arg->weight_set_size) 3138c2ecf20Sopenharmony_ci position = arg->weight_set_size - 1; 3148c2ecf20Sopenharmony_ci return arg->weight_set[position].weights; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic __s32 *get_choose_arg_ids(const struct crush_bucket_straw2 *bucket, 3188c2ecf20Sopenharmony_ci const struct crush_choose_arg *arg) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci if (!arg || !arg->ids) 3218c2ecf20Sopenharmony_ci return bucket->h.items; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return arg->ids; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int bucket_straw2_choose(const struct crush_bucket_straw2 *bucket, 3278c2ecf20Sopenharmony_ci int x, int r, 3288c2ecf20Sopenharmony_ci const struct crush_choose_arg *arg, 3298c2ecf20Sopenharmony_ci int position) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci unsigned int i, high = 0; 3328c2ecf20Sopenharmony_ci unsigned int u; 3338c2ecf20Sopenharmony_ci __s64 ln, draw, high_draw = 0; 3348c2ecf20Sopenharmony_ci __u32 *weights = get_choose_arg_weights(bucket, arg, position); 3358c2ecf20Sopenharmony_ci __s32 *ids = get_choose_arg_ids(bucket, arg); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci for (i = 0; i < bucket->h.size; i++) { 3388c2ecf20Sopenharmony_ci dprintk("weight 0x%x item %d\n", weights[i], ids[i]); 3398c2ecf20Sopenharmony_ci if (weights[i]) { 3408c2ecf20Sopenharmony_ci u = crush_hash32_3(bucket->h.hash, x, ids[i], r); 3418c2ecf20Sopenharmony_ci u &= 0xffff; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * for some reason slightly less than 0x10000 produces 3458c2ecf20Sopenharmony_ci * a slightly more accurate distribution... probably a 3468c2ecf20Sopenharmony_ci * rounding effect. 3478c2ecf20Sopenharmony_ci * 3488c2ecf20Sopenharmony_ci * the natural log lookup table maps [0,0xffff] 3498c2ecf20Sopenharmony_ci * (corresponding to real numbers [1/0x10000, 1] to 3508c2ecf20Sopenharmony_ci * [0, 0xffffffffffff] (corresponding to real numbers 3518c2ecf20Sopenharmony_ci * [-11.090355,0]). 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci ln = crush_ln(u) - 0x1000000000000ll; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* 3568c2ecf20Sopenharmony_ci * divide by 16.16 fixed-point weight. note 3578c2ecf20Sopenharmony_ci * that the ln value is negative, so a larger 3588c2ecf20Sopenharmony_ci * weight means a larger (less negative) value 3598c2ecf20Sopenharmony_ci * for draw. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci draw = div64_s64(ln, weights[i]); 3628c2ecf20Sopenharmony_ci } else { 3638c2ecf20Sopenharmony_ci draw = S64_MIN; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (i == 0 || draw > high_draw) { 3678c2ecf20Sopenharmony_ci high = i; 3688c2ecf20Sopenharmony_ci high_draw = draw; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return bucket->h.items[high]; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int crush_bucket_choose(const struct crush_bucket *in, 3778c2ecf20Sopenharmony_ci struct crush_work_bucket *work, 3788c2ecf20Sopenharmony_ci int x, int r, 3798c2ecf20Sopenharmony_ci const struct crush_choose_arg *arg, 3808c2ecf20Sopenharmony_ci int position) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci dprintk(" crush_bucket_choose %d x=%d r=%d\n", in->id, x, r); 3838c2ecf20Sopenharmony_ci BUG_ON(in->size == 0); 3848c2ecf20Sopenharmony_ci switch (in->alg) { 3858c2ecf20Sopenharmony_ci case CRUSH_BUCKET_UNIFORM: 3868c2ecf20Sopenharmony_ci return bucket_uniform_choose( 3878c2ecf20Sopenharmony_ci (const struct crush_bucket_uniform *)in, 3888c2ecf20Sopenharmony_ci work, x, r); 3898c2ecf20Sopenharmony_ci case CRUSH_BUCKET_LIST: 3908c2ecf20Sopenharmony_ci return bucket_list_choose((const struct crush_bucket_list *)in, 3918c2ecf20Sopenharmony_ci x, r); 3928c2ecf20Sopenharmony_ci case CRUSH_BUCKET_TREE: 3938c2ecf20Sopenharmony_ci return bucket_tree_choose((const struct crush_bucket_tree *)in, 3948c2ecf20Sopenharmony_ci x, r); 3958c2ecf20Sopenharmony_ci case CRUSH_BUCKET_STRAW: 3968c2ecf20Sopenharmony_ci return bucket_straw_choose( 3978c2ecf20Sopenharmony_ci (const struct crush_bucket_straw *)in, 3988c2ecf20Sopenharmony_ci x, r); 3998c2ecf20Sopenharmony_ci case CRUSH_BUCKET_STRAW2: 4008c2ecf20Sopenharmony_ci return bucket_straw2_choose( 4018c2ecf20Sopenharmony_ci (const struct crush_bucket_straw2 *)in, 4028c2ecf20Sopenharmony_ci x, r, arg, position); 4038c2ecf20Sopenharmony_ci default: 4048c2ecf20Sopenharmony_ci dprintk("unknown bucket %d alg %d\n", in->id, in->alg); 4058c2ecf20Sopenharmony_ci return in->items[0]; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* 4108c2ecf20Sopenharmony_ci * true if device is marked "out" (failed, fully offloaded) 4118c2ecf20Sopenharmony_ci * of the cluster 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_cistatic int is_out(const struct crush_map *map, 4148c2ecf20Sopenharmony_ci const __u32 *weight, int weight_max, 4158c2ecf20Sopenharmony_ci int item, int x) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci if (item >= weight_max) 4188c2ecf20Sopenharmony_ci return 1; 4198c2ecf20Sopenharmony_ci if (weight[item] >= 0x10000) 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci if (weight[item] == 0) 4228c2ecf20Sopenharmony_ci return 1; 4238c2ecf20Sopenharmony_ci if ((crush_hash32_2(CRUSH_HASH_RJENKINS1, x, item) & 0xffff) 4248c2ecf20Sopenharmony_ci < weight[item]) 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci return 1; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/** 4308c2ecf20Sopenharmony_ci * crush_choose_firstn - choose numrep distinct items of given type 4318c2ecf20Sopenharmony_ci * @map: the crush_map 4328c2ecf20Sopenharmony_ci * @bucket: the bucket we are choose an item from 4338c2ecf20Sopenharmony_ci * @x: crush input value 4348c2ecf20Sopenharmony_ci * @numrep: the number of items to choose 4358c2ecf20Sopenharmony_ci * @type: the type of item to choose 4368c2ecf20Sopenharmony_ci * @out: pointer to output vector 4378c2ecf20Sopenharmony_ci * @outpos: our position in that vector 4388c2ecf20Sopenharmony_ci * @out_size: size of the out vector 4398c2ecf20Sopenharmony_ci * @tries: number of attempts to make 4408c2ecf20Sopenharmony_ci * @recurse_tries: number of attempts to have recursive chooseleaf make 4418c2ecf20Sopenharmony_ci * @local_retries: localized retries 4428c2ecf20Sopenharmony_ci * @local_fallback_retries: localized fallback retries 4438c2ecf20Sopenharmony_ci * @recurse_to_leaf: true if we want one device under each item of given type (chooseleaf instead of choose) 4448c2ecf20Sopenharmony_ci * @stable: stable mode starts rep=0 in the recursive call for all replicas 4458c2ecf20Sopenharmony_ci * @vary_r: pass r to recursive calls 4468c2ecf20Sopenharmony_ci * @out2: second output vector for leaf items (if @recurse_to_leaf) 4478c2ecf20Sopenharmony_ci * @parent_r: r value passed from the parent 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_cistatic int crush_choose_firstn(const struct crush_map *map, 4508c2ecf20Sopenharmony_ci struct crush_work *work, 4518c2ecf20Sopenharmony_ci const struct crush_bucket *bucket, 4528c2ecf20Sopenharmony_ci const __u32 *weight, int weight_max, 4538c2ecf20Sopenharmony_ci int x, int numrep, int type, 4548c2ecf20Sopenharmony_ci int *out, int outpos, 4558c2ecf20Sopenharmony_ci int out_size, 4568c2ecf20Sopenharmony_ci unsigned int tries, 4578c2ecf20Sopenharmony_ci unsigned int recurse_tries, 4588c2ecf20Sopenharmony_ci unsigned int local_retries, 4598c2ecf20Sopenharmony_ci unsigned int local_fallback_retries, 4608c2ecf20Sopenharmony_ci int recurse_to_leaf, 4618c2ecf20Sopenharmony_ci unsigned int vary_r, 4628c2ecf20Sopenharmony_ci unsigned int stable, 4638c2ecf20Sopenharmony_ci int *out2, 4648c2ecf20Sopenharmony_ci int parent_r, 4658c2ecf20Sopenharmony_ci const struct crush_choose_arg *choose_args) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci int rep; 4688c2ecf20Sopenharmony_ci unsigned int ftotal, flocal; 4698c2ecf20Sopenharmony_ci int retry_descent, retry_bucket, skip_rep; 4708c2ecf20Sopenharmony_ci const struct crush_bucket *in = bucket; 4718c2ecf20Sopenharmony_ci int r; 4728c2ecf20Sopenharmony_ci int i; 4738c2ecf20Sopenharmony_ci int item = 0; 4748c2ecf20Sopenharmony_ci int itemtype; 4758c2ecf20Sopenharmony_ci int collide, reject; 4768c2ecf20Sopenharmony_ci int count = out_size; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci dprintk("CHOOSE%s bucket %d x %d outpos %d numrep %d tries %d recurse_tries %d local_retries %d local_fallback_retries %d parent_r %d stable %d\n", 4798c2ecf20Sopenharmony_ci recurse_to_leaf ? "_LEAF" : "", 4808c2ecf20Sopenharmony_ci bucket->id, x, outpos, numrep, 4818c2ecf20Sopenharmony_ci tries, recurse_tries, local_retries, local_fallback_retries, 4828c2ecf20Sopenharmony_ci parent_r, stable); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci for (rep = stable ? 0 : outpos; rep < numrep && count > 0 ; rep++) { 4858c2ecf20Sopenharmony_ci /* keep trying until we get a non-out, non-colliding item */ 4868c2ecf20Sopenharmony_ci ftotal = 0; 4878c2ecf20Sopenharmony_ci skip_rep = 0; 4888c2ecf20Sopenharmony_ci do { 4898c2ecf20Sopenharmony_ci retry_descent = 0; 4908c2ecf20Sopenharmony_ci in = bucket; /* initial bucket */ 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* choose through intervening buckets */ 4938c2ecf20Sopenharmony_ci flocal = 0; 4948c2ecf20Sopenharmony_ci do { 4958c2ecf20Sopenharmony_ci collide = 0; 4968c2ecf20Sopenharmony_ci retry_bucket = 0; 4978c2ecf20Sopenharmony_ci r = rep + parent_r; 4988c2ecf20Sopenharmony_ci /* r' = r + f_total */ 4998c2ecf20Sopenharmony_ci r += ftotal; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* bucket choose */ 5028c2ecf20Sopenharmony_ci if (in->size == 0) { 5038c2ecf20Sopenharmony_ci reject = 1; 5048c2ecf20Sopenharmony_ci goto reject; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci if (local_fallback_retries > 0 && 5078c2ecf20Sopenharmony_ci flocal >= (in->size>>1) && 5088c2ecf20Sopenharmony_ci flocal > local_fallback_retries) 5098c2ecf20Sopenharmony_ci item = bucket_perm_choose( 5108c2ecf20Sopenharmony_ci in, work->work[-1-in->id], 5118c2ecf20Sopenharmony_ci x, r); 5128c2ecf20Sopenharmony_ci else 5138c2ecf20Sopenharmony_ci item = crush_bucket_choose( 5148c2ecf20Sopenharmony_ci in, work->work[-1-in->id], 5158c2ecf20Sopenharmony_ci x, r, 5168c2ecf20Sopenharmony_ci (choose_args ? 5178c2ecf20Sopenharmony_ci &choose_args[-1-in->id] : NULL), 5188c2ecf20Sopenharmony_ci outpos); 5198c2ecf20Sopenharmony_ci if (item >= map->max_devices) { 5208c2ecf20Sopenharmony_ci dprintk(" bad item %d\n", item); 5218c2ecf20Sopenharmony_ci skip_rep = 1; 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* desired type? */ 5268c2ecf20Sopenharmony_ci if (item < 0) 5278c2ecf20Sopenharmony_ci itemtype = map->buckets[-1-item]->type; 5288c2ecf20Sopenharmony_ci else 5298c2ecf20Sopenharmony_ci itemtype = 0; 5308c2ecf20Sopenharmony_ci dprintk(" item %d type %d\n", item, itemtype); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* keep going? */ 5338c2ecf20Sopenharmony_ci if (itemtype != type) { 5348c2ecf20Sopenharmony_ci if (item >= 0 || 5358c2ecf20Sopenharmony_ci (-1-item) >= map->max_buckets) { 5368c2ecf20Sopenharmony_ci dprintk(" bad item type %d\n", type); 5378c2ecf20Sopenharmony_ci skip_rep = 1; 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci in = map->buckets[-1-item]; 5418c2ecf20Sopenharmony_ci retry_bucket = 1; 5428c2ecf20Sopenharmony_ci continue; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* collision? */ 5468c2ecf20Sopenharmony_ci for (i = 0; i < outpos; i++) { 5478c2ecf20Sopenharmony_ci if (out[i] == item) { 5488c2ecf20Sopenharmony_ci collide = 1; 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci reject = 0; 5548c2ecf20Sopenharmony_ci if (!collide && recurse_to_leaf) { 5558c2ecf20Sopenharmony_ci if (item < 0) { 5568c2ecf20Sopenharmony_ci int sub_r; 5578c2ecf20Sopenharmony_ci if (vary_r) 5588c2ecf20Sopenharmony_ci sub_r = r >> (vary_r-1); 5598c2ecf20Sopenharmony_ci else 5608c2ecf20Sopenharmony_ci sub_r = 0; 5618c2ecf20Sopenharmony_ci if (crush_choose_firstn( 5628c2ecf20Sopenharmony_ci map, 5638c2ecf20Sopenharmony_ci work, 5648c2ecf20Sopenharmony_ci map->buckets[-1-item], 5658c2ecf20Sopenharmony_ci weight, weight_max, 5668c2ecf20Sopenharmony_ci x, stable ? 1 : outpos+1, 0, 5678c2ecf20Sopenharmony_ci out2, outpos, count, 5688c2ecf20Sopenharmony_ci recurse_tries, 0, 5698c2ecf20Sopenharmony_ci local_retries, 5708c2ecf20Sopenharmony_ci local_fallback_retries, 5718c2ecf20Sopenharmony_ci 0, 5728c2ecf20Sopenharmony_ci vary_r, 5738c2ecf20Sopenharmony_ci stable, 5748c2ecf20Sopenharmony_ci NULL, 5758c2ecf20Sopenharmony_ci sub_r, 5768c2ecf20Sopenharmony_ci choose_args) <= outpos) 5778c2ecf20Sopenharmony_ci /* didn't get leaf */ 5788c2ecf20Sopenharmony_ci reject = 1; 5798c2ecf20Sopenharmony_ci } else { 5808c2ecf20Sopenharmony_ci /* we already have a leaf! */ 5818c2ecf20Sopenharmony_ci out2[outpos] = item; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (!reject && !collide) { 5868c2ecf20Sopenharmony_ci /* out? */ 5878c2ecf20Sopenharmony_ci if (itemtype == 0) 5888c2ecf20Sopenharmony_ci reject = is_out(map, weight, 5898c2ecf20Sopenharmony_ci weight_max, 5908c2ecf20Sopenharmony_ci item, x); 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cireject: 5948c2ecf20Sopenharmony_ci if (reject || collide) { 5958c2ecf20Sopenharmony_ci ftotal++; 5968c2ecf20Sopenharmony_ci flocal++; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (collide && flocal <= local_retries) 5998c2ecf20Sopenharmony_ci /* retry locally a few times */ 6008c2ecf20Sopenharmony_ci retry_bucket = 1; 6018c2ecf20Sopenharmony_ci else if (local_fallback_retries > 0 && 6028c2ecf20Sopenharmony_ci flocal <= in->size + local_fallback_retries) 6038c2ecf20Sopenharmony_ci /* exhaustive bucket search */ 6048c2ecf20Sopenharmony_ci retry_bucket = 1; 6058c2ecf20Sopenharmony_ci else if (ftotal < tries) 6068c2ecf20Sopenharmony_ci /* then retry descent */ 6078c2ecf20Sopenharmony_ci retry_descent = 1; 6088c2ecf20Sopenharmony_ci else 6098c2ecf20Sopenharmony_ci /* else give up */ 6108c2ecf20Sopenharmony_ci skip_rep = 1; 6118c2ecf20Sopenharmony_ci dprintk(" reject %d collide %d " 6128c2ecf20Sopenharmony_ci "ftotal %u flocal %u\n", 6138c2ecf20Sopenharmony_ci reject, collide, ftotal, 6148c2ecf20Sopenharmony_ci flocal); 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci } while (retry_bucket); 6178c2ecf20Sopenharmony_ci } while (retry_descent); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (skip_rep) { 6208c2ecf20Sopenharmony_ci dprintk("skip rep\n"); 6218c2ecf20Sopenharmony_ci continue; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci dprintk("CHOOSE got %d\n", item); 6258c2ecf20Sopenharmony_ci out[outpos] = item; 6268c2ecf20Sopenharmony_ci outpos++; 6278c2ecf20Sopenharmony_ci count--; 6288c2ecf20Sopenharmony_ci#ifndef __KERNEL__ 6298c2ecf20Sopenharmony_ci if (map->choose_tries && ftotal <= map->choose_total_tries) 6308c2ecf20Sopenharmony_ci map->choose_tries[ftotal]++; 6318c2ecf20Sopenharmony_ci#endif 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci dprintk("CHOOSE returns %d\n", outpos); 6358c2ecf20Sopenharmony_ci return outpos; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci/** 6408c2ecf20Sopenharmony_ci * crush_choose_indep: alternative breadth-first positionally stable mapping 6418c2ecf20Sopenharmony_ci * 6428c2ecf20Sopenharmony_ci */ 6438c2ecf20Sopenharmony_cistatic void crush_choose_indep(const struct crush_map *map, 6448c2ecf20Sopenharmony_ci struct crush_work *work, 6458c2ecf20Sopenharmony_ci const struct crush_bucket *bucket, 6468c2ecf20Sopenharmony_ci const __u32 *weight, int weight_max, 6478c2ecf20Sopenharmony_ci int x, int left, int numrep, int type, 6488c2ecf20Sopenharmony_ci int *out, int outpos, 6498c2ecf20Sopenharmony_ci unsigned int tries, 6508c2ecf20Sopenharmony_ci unsigned int recurse_tries, 6518c2ecf20Sopenharmony_ci int recurse_to_leaf, 6528c2ecf20Sopenharmony_ci int *out2, 6538c2ecf20Sopenharmony_ci int parent_r, 6548c2ecf20Sopenharmony_ci const struct crush_choose_arg *choose_args) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci const struct crush_bucket *in = bucket; 6578c2ecf20Sopenharmony_ci int endpos = outpos + left; 6588c2ecf20Sopenharmony_ci int rep; 6598c2ecf20Sopenharmony_ci unsigned int ftotal; 6608c2ecf20Sopenharmony_ci int r; 6618c2ecf20Sopenharmony_ci int i; 6628c2ecf20Sopenharmony_ci int item = 0; 6638c2ecf20Sopenharmony_ci int itemtype; 6648c2ecf20Sopenharmony_ci int collide; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci dprintk("CHOOSE%s INDEP bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "", 6678c2ecf20Sopenharmony_ci bucket->id, x, outpos, numrep); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* initially my result is undefined */ 6708c2ecf20Sopenharmony_ci for (rep = outpos; rep < endpos; rep++) { 6718c2ecf20Sopenharmony_ci out[rep] = CRUSH_ITEM_UNDEF; 6728c2ecf20Sopenharmony_ci if (out2) 6738c2ecf20Sopenharmony_ci out2[rep] = CRUSH_ITEM_UNDEF; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci for (ftotal = 0; left > 0 && ftotal < tries; ftotal++) { 6778c2ecf20Sopenharmony_ci#ifdef DEBUG_INDEP 6788c2ecf20Sopenharmony_ci if (out2 && ftotal) { 6798c2ecf20Sopenharmony_ci dprintk("%u %d a: ", ftotal, left); 6808c2ecf20Sopenharmony_ci for (rep = outpos; rep < endpos; rep++) { 6818c2ecf20Sopenharmony_ci dprintk(" %d", out[rep]); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci dprintk("\n"); 6848c2ecf20Sopenharmony_ci dprintk("%u %d b: ", ftotal, left); 6858c2ecf20Sopenharmony_ci for (rep = outpos; rep < endpos; rep++) { 6868c2ecf20Sopenharmony_ci dprintk(" %d", out2[rep]); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci dprintk("\n"); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci#endif 6918c2ecf20Sopenharmony_ci for (rep = outpos; rep < endpos; rep++) { 6928c2ecf20Sopenharmony_ci if (out[rep] != CRUSH_ITEM_UNDEF) 6938c2ecf20Sopenharmony_ci continue; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci in = bucket; /* initial bucket */ 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* choose through intervening buckets */ 6988c2ecf20Sopenharmony_ci for (;;) { 6998c2ecf20Sopenharmony_ci /* note: we base the choice on the position 7008c2ecf20Sopenharmony_ci * even in the nested call. that means that 7018c2ecf20Sopenharmony_ci * if the first layer chooses the same bucket 7028c2ecf20Sopenharmony_ci * in a different position, we will tend to 7038c2ecf20Sopenharmony_ci * choose a different item in that bucket. 7048c2ecf20Sopenharmony_ci * this will involve more devices in data 7058c2ecf20Sopenharmony_ci * movement and tend to distribute the load. 7068c2ecf20Sopenharmony_ci */ 7078c2ecf20Sopenharmony_ci r = rep + parent_r; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* be careful */ 7108c2ecf20Sopenharmony_ci if (in->alg == CRUSH_BUCKET_UNIFORM && 7118c2ecf20Sopenharmony_ci in->size % numrep == 0) 7128c2ecf20Sopenharmony_ci /* r'=r+(n+1)*f_total */ 7138c2ecf20Sopenharmony_ci r += (numrep+1) * ftotal; 7148c2ecf20Sopenharmony_ci else 7158c2ecf20Sopenharmony_ci /* r' = r + n*f_total */ 7168c2ecf20Sopenharmony_ci r += numrep * ftotal; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* bucket choose */ 7198c2ecf20Sopenharmony_ci if (in->size == 0) { 7208c2ecf20Sopenharmony_ci dprintk(" empty bucket\n"); 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci item = crush_bucket_choose( 7258c2ecf20Sopenharmony_ci in, work->work[-1-in->id], 7268c2ecf20Sopenharmony_ci x, r, 7278c2ecf20Sopenharmony_ci (choose_args ? 7288c2ecf20Sopenharmony_ci &choose_args[-1-in->id] : NULL), 7298c2ecf20Sopenharmony_ci outpos); 7308c2ecf20Sopenharmony_ci if (item >= map->max_devices) { 7318c2ecf20Sopenharmony_ci dprintk(" bad item %d\n", item); 7328c2ecf20Sopenharmony_ci out[rep] = CRUSH_ITEM_NONE; 7338c2ecf20Sopenharmony_ci if (out2) 7348c2ecf20Sopenharmony_ci out2[rep] = CRUSH_ITEM_NONE; 7358c2ecf20Sopenharmony_ci left--; 7368c2ecf20Sopenharmony_ci break; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* desired type? */ 7408c2ecf20Sopenharmony_ci if (item < 0) 7418c2ecf20Sopenharmony_ci itemtype = map->buckets[-1-item]->type; 7428c2ecf20Sopenharmony_ci else 7438c2ecf20Sopenharmony_ci itemtype = 0; 7448c2ecf20Sopenharmony_ci dprintk(" item %d type %d\n", item, itemtype); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* keep going? */ 7478c2ecf20Sopenharmony_ci if (itemtype != type) { 7488c2ecf20Sopenharmony_ci if (item >= 0 || 7498c2ecf20Sopenharmony_ci (-1-item) >= map->max_buckets) { 7508c2ecf20Sopenharmony_ci dprintk(" bad item type %d\n", type); 7518c2ecf20Sopenharmony_ci out[rep] = CRUSH_ITEM_NONE; 7528c2ecf20Sopenharmony_ci if (out2) 7538c2ecf20Sopenharmony_ci out2[rep] = 7548c2ecf20Sopenharmony_ci CRUSH_ITEM_NONE; 7558c2ecf20Sopenharmony_ci left--; 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci in = map->buckets[-1-item]; 7598c2ecf20Sopenharmony_ci continue; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* collision? */ 7638c2ecf20Sopenharmony_ci collide = 0; 7648c2ecf20Sopenharmony_ci for (i = outpos; i < endpos; i++) { 7658c2ecf20Sopenharmony_ci if (out[i] == item) { 7668c2ecf20Sopenharmony_ci collide = 1; 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci if (collide) 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (recurse_to_leaf) { 7748c2ecf20Sopenharmony_ci if (item < 0) { 7758c2ecf20Sopenharmony_ci crush_choose_indep( 7768c2ecf20Sopenharmony_ci map, 7778c2ecf20Sopenharmony_ci work, 7788c2ecf20Sopenharmony_ci map->buckets[-1-item], 7798c2ecf20Sopenharmony_ci weight, weight_max, 7808c2ecf20Sopenharmony_ci x, 1, numrep, 0, 7818c2ecf20Sopenharmony_ci out2, rep, 7828c2ecf20Sopenharmony_ci recurse_tries, 0, 7838c2ecf20Sopenharmony_ci 0, NULL, r, 7848c2ecf20Sopenharmony_ci choose_args); 7858c2ecf20Sopenharmony_ci if (out2[rep] == CRUSH_ITEM_NONE) { 7868c2ecf20Sopenharmony_ci /* placed nothing; no leaf */ 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci } else { 7908c2ecf20Sopenharmony_ci /* we already have a leaf! */ 7918c2ecf20Sopenharmony_ci out2[rep] = item; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* out? */ 7968c2ecf20Sopenharmony_ci if (itemtype == 0 && 7978c2ecf20Sopenharmony_ci is_out(map, weight, weight_max, item, x)) 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* yay! */ 8018c2ecf20Sopenharmony_ci out[rep] = item; 8028c2ecf20Sopenharmony_ci left--; 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci for (rep = outpos; rep < endpos; rep++) { 8088c2ecf20Sopenharmony_ci if (out[rep] == CRUSH_ITEM_UNDEF) { 8098c2ecf20Sopenharmony_ci out[rep] = CRUSH_ITEM_NONE; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci if (out2 && out2[rep] == CRUSH_ITEM_UNDEF) { 8128c2ecf20Sopenharmony_ci out2[rep] = CRUSH_ITEM_NONE; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci#ifndef __KERNEL__ 8168c2ecf20Sopenharmony_ci if (map->choose_tries && ftotal <= map->choose_total_tries) 8178c2ecf20Sopenharmony_ci map->choose_tries[ftotal]++; 8188c2ecf20Sopenharmony_ci#endif 8198c2ecf20Sopenharmony_ci#ifdef DEBUG_INDEP 8208c2ecf20Sopenharmony_ci if (out2) { 8218c2ecf20Sopenharmony_ci dprintk("%u %d a: ", ftotal, left); 8228c2ecf20Sopenharmony_ci for (rep = outpos; rep < endpos; rep++) { 8238c2ecf20Sopenharmony_ci dprintk(" %d", out[rep]); 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci dprintk("\n"); 8268c2ecf20Sopenharmony_ci dprintk("%u %d b: ", ftotal, left); 8278c2ecf20Sopenharmony_ci for (rep = outpos; rep < endpos; rep++) { 8288c2ecf20Sopenharmony_ci dprintk(" %d", out2[rep]); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci dprintk("\n"); 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci#endif 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci/* 8378c2ecf20Sopenharmony_ci * This takes a chunk of memory and sets it up to be a shiny new 8388c2ecf20Sopenharmony_ci * working area for a CRUSH placement computation. It must be called 8398c2ecf20Sopenharmony_ci * on any newly allocated memory before passing it in to 8408c2ecf20Sopenharmony_ci * crush_do_rule. It may be used repeatedly after that, so long as the 8418c2ecf20Sopenharmony_ci * map has not changed. If the map /has/ changed, you must make sure 8428c2ecf20Sopenharmony_ci * the working size is no smaller than what was allocated and re-run 8438c2ecf20Sopenharmony_ci * crush_init_workspace. 8448c2ecf20Sopenharmony_ci * 8458c2ecf20Sopenharmony_ci * If you do retain the working space between calls to crush, make it 8468c2ecf20Sopenharmony_ci * thread-local. 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_civoid crush_init_workspace(const struct crush_map *map, void *v) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci struct crush_work *w = v; 8518c2ecf20Sopenharmony_ci __s32 b; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* 8548c2ecf20Sopenharmony_ci * We work by moving through the available space and setting 8558c2ecf20Sopenharmony_ci * values and pointers as we go. 8568c2ecf20Sopenharmony_ci * 8578c2ecf20Sopenharmony_ci * It's a bit like Forth's use of the 'allot' word since we 8588c2ecf20Sopenharmony_ci * set the pointer first and then reserve the space for it to 8598c2ecf20Sopenharmony_ci * point to by incrementing the point. 8608c2ecf20Sopenharmony_ci */ 8618c2ecf20Sopenharmony_ci v += sizeof(struct crush_work); 8628c2ecf20Sopenharmony_ci w->work = v; 8638c2ecf20Sopenharmony_ci v += map->max_buckets * sizeof(struct crush_work_bucket *); 8648c2ecf20Sopenharmony_ci for (b = 0; b < map->max_buckets; ++b) { 8658c2ecf20Sopenharmony_ci if (!map->buckets[b]) 8668c2ecf20Sopenharmony_ci continue; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci w->work[b] = v; 8698c2ecf20Sopenharmony_ci switch (map->buckets[b]->alg) { 8708c2ecf20Sopenharmony_ci default: 8718c2ecf20Sopenharmony_ci v += sizeof(struct crush_work_bucket); 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci w->work[b]->perm_x = 0; 8758c2ecf20Sopenharmony_ci w->work[b]->perm_n = 0; 8768c2ecf20Sopenharmony_ci w->work[b]->perm = v; 8778c2ecf20Sopenharmony_ci v += map->buckets[b]->size * sizeof(__u32); 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci BUG_ON(v - (void *)w != map->working_size); 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci/** 8838c2ecf20Sopenharmony_ci * crush_do_rule - calculate a mapping with the given input and rule 8848c2ecf20Sopenharmony_ci * @map: the crush_map 8858c2ecf20Sopenharmony_ci * @ruleno: the rule id 8868c2ecf20Sopenharmony_ci * @x: hash input 8878c2ecf20Sopenharmony_ci * @result: pointer to result vector 8888c2ecf20Sopenharmony_ci * @result_max: maximum result size 8898c2ecf20Sopenharmony_ci * @weight: weight vector (for map leaves) 8908c2ecf20Sopenharmony_ci * @weight_max: size of weight vector 8918c2ecf20Sopenharmony_ci * @cwin: pointer to at least crush_work_size() bytes of memory 8928c2ecf20Sopenharmony_ci * @choose_args: weights and ids for each known bucket 8938c2ecf20Sopenharmony_ci */ 8948c2ecf20Sopenharmony_ciint crush_do_rule(const struct crush_map *map, 8958c2ecf20Sopenharmony_ci int ruleno, int x, int *result, int result_max, 8968c2ecf20Sopenharmony_ci const __u32 *weight, int weight_max, 8978c2ecf20Sopenharmony_ci void *cwin, const struct crush_choose_arg *choose_args) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci int result_len; 9008c2ecf20Sopenharmony_ci struct crush_work *cw = cwin; 9018c2ecf20Sopenharmony_ci int *a = cwin + map->working_size; 9028c2ecf20Sopenharmony_ci int *b = a + result_max; 9038c2ecf20Sopenharmony_ci int *c = b + result_max; 9048c2ecf20Sopenharmony_ci int *w = a; 9058c2ecf20Sopenharmony_ci int *o = b; 9068c2ecf20Sopenharmony_ci int recurse_to_leaf; 9078c2ecf20Sopenharmony_ci int wsize = 0; 9088c2ecf20Sopenharmony_ci int osize; 9098c2ecf20Sopenharmony_ci int *tmp; 9108c2ecf20Sopenharmony_ci const struct crush_rule *rule; 9118c2ecf20Sopenharmony_ci __u32 step; 9128c2ecf20Sopenharmony_ci int i, j; 9138c2ecf20Sopenharmony_ci int numrep; 9148c2ecf20Sopenharmony_ci int out_size; 9158c2ecf20Sopenharmony_ci /* 9168c2ecf20Sopenharmony_ci * the original choose_total_tries value was off by one (it 9178c2ecf20Sopenharmony_ci * counted "retries" and not "tries"). add one. 9188c2ecf20Sopenharmony_ci */ 9198c2ecf20Sopenharmony_ci int choose_tries = map->choose_total_tries + 1; 9208c2ecf20Sopenharmony_ci int choose_leaf_tries = 0; 9218c2ecf20Sopenharmony_ci /* 9228c2ecf20Sopenharmony_ci * the local tries values were counted as "retries", though, 9238c2ecf20Sopenharmony_ci * and need no adjustment 9248c2ecf20Sopenharmony_ci */ 9258c2ecf20Sopenharmony_ci int choose_local_retries = map->choose_local_tries; 9268c2ecf20Sopenharmony_ci int choose_local_fallback_retries = map->choose_local_fallback_tries; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci int vary_r = map->chooseleaf_vary_r; 9298c2ecf20Sopenharmony_ci int stable = map->chooseleaf_stable; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if ((__u32)ruleno >= map->max_rules) { 9328c2ecf20Sopenharmony_ci dprintk(" bad ruleno %d\n", ruleno); 9338c2ecf20Sopenharmony_ci return 0; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci rule = map->rules[ruleno]; 9378c2ecf20Sopenharmony_ci result_len = 0; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci for (step = 0; step < rule->len; step++) { 9408c2ecf20Sopenharmony_ci int firstn = 0; 9418c2ecf20Sopenharmony_ci const struct crush_rule_step *curstep = &rule->steps[step]; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci switch (curstep->op) { 9448c2ecf20Sopenharmony_ci case CRUSH_RULE_TAKE: 9458c2ecf20Sopenharmony_ci if ((curstep->arg1 >= 0 && 9468c2ecf20Sopenharmony_ci curstep->arg1 < map->max_devices) || 9478c2ecf20Sopenharmony_ci (-1-curstep->arg1 >= 0 && 9488c2ecf20Sopenharmony_ci -1-curstep->arg1 < map->max_buckets && 9498c2ecf20Sopenharmony_ci map->buckets[-1-curstep->arg1])) { 9508c2ecf20Sopenharmony_ci w[0] = curstep->arg1; 9518c2ecf20Sopenharmony_ci wsize = 1; 9528c2ecf20Sopenharmony_ci } else { 9538c2ecf20Sopenharmony_ci dprintk(" bad take value %d\n", curstep->arg1); 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci case CRUSH_RULE_SET_CHOOSE_TRIES: 9588c2ecf20Sopenharmony_ci if (curstep->arg1 > 0) 9598c2ecf20Sopenharmony_ci choose_tries = curstep->arg1; 9608c2ecf20Sopenharmony_ci break; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci case CRUSH_RULE_SET_CHOOSELEAF_TRIES: 9638c2ecf20Sopenharmony_ci if (curstep->arg1 > 0) 9648c2ecf20Sopenharmony_ci choose_leaf_tries = curstep->arg1; 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci case CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES: 9688c2ecf20Sopenharmony_ci if (curstep->arg1 >= 0) 9698c2ecf20Sopenharmony_ci choose_local_retries = curstep->arg1; 9708c2ecf20Sopenharmony_ci break; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci case CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES: 9738c2ecf20Sopenharmony_ci if (curstep->arg1 >= 0) 9748c2ecf20Sopenharmony_ci choose_local_fallback_retries = curstep->arg1; 9758c2ecf20Sopenharmony_ci break; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci case CRUSH_RULE_SET_CHOOSELEAF_VARY_R: 9788c2ecf20Sopenharmony_ci if (curstep->arg1 >= 0) 9798c2ecf20Sopenharmony_ci vary_r = curstep->arg1; 9808c2ecf20Sopenharmony_ci break; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci case CRUSH_RULE_SET_CHOOSELEAF_STABLE: 9838c2ecf20Sopenharmony_ci if (curstep->arg1 >= 0) 9848c2ecf20Sopenharmony_ci stable = curstep->arg1; 9858c2ecf20Sopenharmony_ci break; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci case CRUSH_RULE_CHOOSELEAF_FIRSTN: 9888c2ecf20Sopenharmony_ci case CRUSH_RULE_CHOOSE_FIRSTN: 9898c2ecf20Sopenharmony_ci firstn = 1; 9908c2ecf20Sopenharmony_ci fallthrough; 9918c2ecf20Sopenharmony_ci case CRUSH_RULE_CHOOSELEAF_INDEP: 9928c2ecf20Sopenharmony_ci case CRUSH_RULE_CHOOSE_INDEP: 9938c2ecf20Sopenharmony_ci if (wsize == 0) 9948c2ecf20Sopenharmony_ci break; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci recurse_to_leaf = 9978c2ecf20Sopenharmony_ci curstep->op == 9988c2ecf20Sopenharmony_ci CRUSH_RULE_CHOOSELEAF_FIRSTN || 9998c2ecf20Sopenharmony_ci curstep->op == 10008c2ecf20Sopenharmony_ci CRUSH_RULE_CHOOSELEAF_INDEP; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* reset output */ 10038c2ecf20Sopenharmony_ci osize = 0; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci for (i = 0; i < wsize; i++) { 10068c2ecf20Sopenharmony_ci int bno; 10078c2ecf20Sopenharmony_ci numrep = curstep->arg1; 10088c2ecf20Sopenharmony_ci if (numrep <= 0) { 10098c2ecf20Sopenharmony_ci numrep += result_max; 10108c2ecf20Sopenharmony_ci if (numrep <= 0) 10118c2ecf20Sopenharmony_ci continue; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci j = 0; 10148c2ecf20Sopenharmony_ci /* make sure bucket id is valid */ 10158c2ecf20Sopenharmony_ci bno = -1 - w[i]; 10168c2ecf20Sopenharmony_ci if (bno < 0 || bno >= map->max_buckets) { 10178c2ecf20Sopenharmony_ci /* w[i] is probably CRUSH_ITEM_NONE */ 10188c2ecf20Sopenharmony_ci dprintk(" bad w[i] %d\n", w[i]); 10198c2ecf20Sopenharmony_ci continue; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci if (firstn) { 10228c2ecf20Sopenharmony_ci int recurse_tries; 10238c2ecf20Sopenharmony_ci if (choose_leaf_tries) 10248c2ecf20Sopenharmony_ci recurse_tries = 10258c2ecf20Sopenharmony_ci choose_leaf_tries; 10268c2ecf20Sopenharmony_ci else if (map->chooseleaf_descend_once) 10278c2ecf20Sopenharmony_ci recurse_tries = 1; 10288c2ecf20Sopenharmony_ci else 10298c2ecf20Sopenharmony_ci recurse_tries = choose_tries; 10308c2ecf20Sopenharmony_ci osize += crush_choose_firstn( 10318c2ecf20Sopenharmony_ci map, 10328c2ecf20Sopenharmony_ci cw, 10338c2ecf20Sopenharmony_ci map->buckets[bno], 10348c2ecf20Sopenharmony_ci weight, weight_max, 10358c2ecf20Sopenharmony_ci x, numrep, 10368c2ecf20Sopenharmony_ci curstep->arg2, 10378c2ecf20Sopenharmony_ci o+osize, j, 10388c2ecf20Sopenharmony_ci result_max-osize, 10398c2ecf20Sopenharmony_ci choose_tries, 10408c2ecf20Sopenharmony_ci recurse_tries, 10418c2ecf20Sopenharmony_ci choose_local_retries, 10428c2ecf20Sopenharmony_ci choose_local_fallback_retries, 10438c2ecf20Sopenharmony_ci recurse_to_leaf, 10448c2ecf20Sopenharmony_ci vary_r, 10458c2ecf20Sopenharmony_ci stable, 10468c2ecf20Sopenharmony_ci c+osize, 10478c2ecf20Sopenharmony_ci 0, 10488c2ecf20Sopenharmony_ci choose_args); 10498c2ecf20Sopenharmony_ci } else { 10508c2ecf20Sopenharmony_ci out_size = ((numrep < (result_max-osize)) ? 10518c2ecf20Sopenharmony_ci numrep : (result_max-osize)); 10528c2ecf20Sopenharmony_ci crush_choose_indep( 10538c2ecf20Sopenharmony_ci map, 10548c2ecf20Sopenharmony_ci cw, 10558c2ecf20Sopenharmony_ci map->buckets[bno], 10568c2ecf20Sopenharmony_ci weight, weight_max, 10578c2ecf20Sopenharmony_ci x, out_size, numrep, 10588c2ecf20Sopenharmony_ci curstep->arg2, 10598c2ecf20Sopenharmony_ci o+osize, j, 10608c2ecf20Sopenharmony_ci choose_tries, 10618c2ecf20Sopenharmony_ci choose_leaf_tries ? 10628c2ecf20Sopenharmony_ci choose_leaf_tries : 1, 10638c2ecf20Sopenharmony_ci recurse_to_leaf, 10648c2ecf20Sopenharmony_ci c+osize, 10658c2ecf20Sopenharmony_ci 0, 10668c2ecf20Sopenharmony_ci choose_args); 10678c2ecf20Sopenharmony_ci osize += out_size; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (recurse_to_leaf) 10728c2ecf20Sopenharmony_ci /* copy final _leaf_ values to output set */ 10738c2ecf20Sopenharmony_ci memcpy(o, c, osize*sizeof(*o)); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* swap o and w arrays */ 10768c2ecf20Sopenharmony_ci tmp = o; 10778c2ecf20Sopenharmony_ci o = w; 10788c2ecf20Sopenharmony_ci w = tmp; 10798c2ecf20Sopenharmony_ci wsize = osize; 10808c2ecf20Sopenharmony_ci break; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci case CRUSH_RULE_EMIT: 10848c2ecf20Sopenharmony_ci for (i = 0; i < wsize && result_len < result_max; i++) { 10858c2ecf20Sopenharmony_ci result[result_len] = w[i]; 10868c2ecf20Sopenharmony_ci result_len++; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci wsize = 0; 10898c2ecf20Sopenharmony_ci break; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci default: 10928c2ecf20Sopenharmony_ci dprintk(" unknown op %d at step %d\n", 10938c2ecf20Sopenharmony_ci curstep->op, step); 10948c2ecf20Sopenharmony_ci break; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci return result_len; 10998c2ecf20Sopenharmony_ci} 1100