.TH "API" 3 "Sun Feb 12 2017" "Version 1.0.0" "libcrush" \" -*- nroff -*- .ad l .nh .SH NAME API .SH SYNOPSIS .br .PP .SS "Data Structures" .in +1c .ti -1c .RI "struct \fBcrush_bucket\fP" .br .ti -1c .RI "struct \fBcrush_bucket_uniform\fP" .br .ti -1c .RI "struct \fBcrush_bucket_list\fP" .br .ti -1c .RI "struct \fBcrush_bucket_straw2\fP" .br .ti -1c .RI "struct \fBcrush_map\fP" .br .in -1c .SS "Macros" .in +1c .ti -1c .RI "#define \fBCRUSH_ITEM_NONE\fP 0x7fffffff" .br .in -1c .SS "Enumerations" .in +1c .ti -1c .RI "enum \fBcrush_opcodes\fP { \fBCRUSH_RULE_NOOP\fP = 0, \fBCRUSH_RULE_TAKE\fP = 1, \fBCRUSH_RULE_CHOOSE_FIRSTN\fP = 2, \fBCRUSH_RULE_CHOOSE_INDEP\fP = 3, \fBCRUSH_RULE_EMIT\fP = 4, \fBCRUSH_RULE_CHOOSELEAF_FIRSTN\fP = 6, \fBCRUSH_RULE_CHOOSELEAF_INDEP\fP = 7, \fBCRUSH_RULE_SET_CHOOSE_TRIES\fP = 8, \fBCRUSH_RULE_SET_CHOOSELEAF_TRIES\fP = 9, \fBCRUSH_RULE_SET_CHOOSE_LOCAL_TRIES\fP = 10, \fBCRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES\fP = 11, \fBCRUSH_RULE_SET_CHOOSELEAF_VARY_R\fP = 12, \fBCRUSH_RULE_SET_CHOOSELEAF_STABLE\fP = 13 }" .br .ti -1c .RI "enum \fBcrush_algorithm\fP { \fBCRUSH_BUCKET_UNIFORM\fP = 1, \fBCRUSH_BUCKET_LIST\fP = 2, \fBCRUSH_BUCKET_STRAW2\fP = 5 }" .br .in -1c .SS "Functions" .in +1c .ti -1c .RI "struct \fBcrush_map\fP * \fBcrush_create\fP ()" .br .ti -1c .RI "void \fBcrush_finalize\fP (struct \fBcrush_map\fP *map)" .br .ti -1c .RI "struct \fBcrush_rule\fP * \fBcrush_make_rule\fP (int len, int ruleset, int type, int minsize, int maxsize)" .br .ti -1c .RI "void \fBcrush_rule_set_step\fP (struct \fBcrush_rule\fP *rule, int pos, int op, int arg1, int arg2)" .br .ti -1c .RI "int \fBcrush_add_rule\fP (struct \fBcrush_map\fP *map, struct \fBcrush_rule\fP *rule, int ruleno)" .br .ti -1c .RI "int \fBcrush_add_bucket\fP (struct \fBcrush_map\fP *map, int bucketno, struct \fBcrush_bucket\fP *bucket, int *idout)" .br .ti -1c .RI "struct \fBcrush_bucket\fP * \fBcrush_make_bucket\fP (struct \fBcrush_map\fP *map, int alg, int hash, int type, int size, int *items, int *weights)" .br .ti -1c .RI "int \fBcrush_bucket_add_item\fP (struct \fBcrush_map\fP *map, struct \fBcrush_bucket\fP *bucket, int item, int weight)" .br .ti -1c .RI "int \fBcrush_bucket_adjust_item_weight\fP (struct \fBcrush_map\fP *map, struct \fBcrush_bucket\fP *bucket, int item, int weight)" .br .ti -1c .RI "int \fBcrush_reweight_bucket\fP (struct \fBcrush_map\fP *crush, struct \fBcrush_bucket\fP *bucket)" .br .ti -1c .RI "int \fBcrush_remove_bucket\fP (struct \fBcrush_map\fP *map, struct \fBcrush_bucket\fP *bucket)" .br .ti -1c .RI "int \fBcrush_bucket_remove_item\fP (struct \fBcrush_map\fP *map, struct \fBcrush_bucket\fP *bucket, int item)" .br .ti -1c .RI "void \fBcrush_destroy\fP (struct \fBcrush_map\fP *map)" .br .ti -1c .RI "int \fBcrush_do_rule\fP (const struct \fBcrush_map\fP *map, int ruleno, int x, int *result, int result_max, const __u32 *weights, int weight_max, void *cwin)" .br .in -1c .SH "Detailed Description" .PP .SH "Macro Definition Documentation" .PP .SS "#define CRUSH_ITEM_NONE 0x7fffffff" The equivalent of NULL for an item, i\&.e\&. the absence of an item\&. .SH "Enumeration Type Documentation" .PP .SS "enum \fBcrush_algorithm\fP" Items within a bucket are chosen with \fBcrush_do_rule()\fP using one of three algorithms representing a tradeoff between performance and reorganization efficiency\&. If you are unsure of which bucket type to use, we recommend using \fBCRUSH_BUCKET_STRAW2\fP\&. .PP The table summarizes how the speed of each option measures up against mapping stability when items are added or removed\&. .PP .nf Bucket Alg Speed Additions Removals ------------------------------------------------ uniform O(1) poor poor list O(n) optimal poor straw2 O(n) optimal optimal .fi .PP .PP \fBEnumerator\fP .in +1c .TP \fB\fICRUSH_BUCKET_UNIFORM \fP\fP Devices are rarely added individually in a large system\&. Instead, new storage is typically deployed in blocks of identical devices, often as an additional shelf in a server rack or perhaps an entire cabinet\&. Devices reaching their end of life are often similarly decommissioned as a set (individual failures aside), making it natural to treat them as a unit\&. CRUSH uniform buckets are used to represent an identical set of devices in such circumstances\&. The key advantage in doing so is performance related: CRUSH can map replicas into uniform buckets in constant time\&. In cases where the uniformity restrictions are not appropriate, other bucket types can be used\&. If the size of a uniform bucket changes, there is a complete reshuffling of data between devices, much like conventional hash-based distribution strategies\&. .TP \fB\fICRUSH_BUCKET_LIST \fP\fP List buckets structure their contents as a linked list, and can contain items with arbitrary weights\&. To place a replica, CRUSH begins at the head of the list with the most recently added item and compares its weight to the sum of all remaining items’ weights\&. Depending on the value of hash( x , r , item), either the current item is chosen with the appropriate probability, or the process continues recursively down the list\&. This is a natural and intuitive choice for an expanding cluster: either an object is relocated to the newest device with some appropriate probability, or it remains on the older devices as before\&. The result is optimal data migration when items are added to the bucket\&. Items removed from the middle or tail of the list, however, can result in a significant amount of unnecessary movement, making list buckets most suitable for circumstances in which they never (or very rarely) shrink\&. .TP \fB\fICRUSH_BUCKET_STRAW2 \fP\fP List and tree buckets are structured such that a limited number of hash values need to be calculated and compared to weights in order to select a bucket item\&. In doing so, they divide and conquer in a way that either gives certain items precedence (e\&. g\&., those at the beginning of a list) or obviates the need to consider entire subtrees of items at all\&. That im- proves the performance of the replica placement process, but can also introduce suboptimal reorganization behavior when the contents of a bucket change due an addition, removal, or re-weighting of an item\&. .PP The straw2 bucket type allows all items to fairly “compete” against each other for replica placement through a process analogous to a draw of straws\&. To place a replica, a straw of random length is drawn for each item in the bucket\&. The item with the longest straw wins\&. The length of each straw is initially a value in a fixed range\&. Each straw length is scaled by a factor based on the item’s weight so that heavily weighted items are more likely to win the draw\&. Although this process is almost twice as slow (on average) than a list bucket and even slower than a tree bucket (which scales logarithmically), straw2 buckets result in optimal data movement between nested items when modified\&. .SS "enum \fBcrush_opcodes\fP" .PP \fBEnumerator\fP .in +1c .TP \fB\fICRUSH_RULE_NOOP \fP\fP do nothing .TP \fB\fICRUSH_RULE_TAKE \fP\fP .TP \fB\fICRUSH_RULE_CHOOSE_FIRSTN \fP\fP .TP \fB\fICRUSH_RULE_CHOOSE_INDEP \fP\fP .TP \fB\fICRUSH_RULE_EMIT \fP\fP .TP \fB\fICRUSH_RULE_CHOOSELEAF_FIRSTN \fP\fP .TP \fB\fICRUSH_RULE_CHOOSELEAF_INDEP \fP\fP .TP \fB\fICRUSH_RULE_SET_CHOOSE_TRIES \fP\fP .TP \fB\fICRUSH_RULE_SET_CHOOSELEAF_TRIES \fP\fP .TP \fB\fICRUSH_RULE_SET_CHOOSE_LOCAL_TRIES \fP\fP .TP \fB\fICRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES \fP\fP .TP \fB\fICRUSH_RULE_SET_CHOOSELEAF_VARY_R \fP\fP .TP \fB\fICRUSH_RULE_SET_CHOOSELEAF_STABLE \fP\fP .SH "Function Documentation" .PP .SS "int crush_add_bucket (struct \fBcrush_map\fP * map, int bucketno, struct \fBcrush_bucket\fP * bucket, int * idout)" Add \fBbucket\fP into the crush \fBmap\fP and assign it the \fBbucketno\fP unique identifier\&. If \fBbucketno\fP is -1, the function will assign the lowest available identifier\&. The bucket identifier must be a negative integer\&. The bucket identifier is returned via \fBidout\fP\&. .PP .IP "\(bu" 2 return -ENOMEM if \fBrealloc(3)\fP fails to expand the array of buckets in the \fBmap\fP .IP "\(bu" 2 return -EEXIST if the \fBbucketno\fP identifier is already assigned to another bucket\&. .PP .PP \fBParameters:\fP .RS 4 \fImap\fP the \fBcrush_map\fP .br \fIbucketno\fP the bucket unique identifer or -1 .br \fIbucket\fP the bucket to add to the \fBmap\fP .br \fIidout\fP a pointer to the bucket identifier .RE .PP \fBReturns:\fP .RS 4 0 on success, < 0 on error .RE .PP .SS "int crush_add_rule (struct \fBcrush_map\fP * map, struct \fBcrush_rule\fP * rule, int ruleno)" Add the \fBrule\fP into the crush \fBmap\fP and assign it the \fBruleno\fP unique identifier\&. If \fBruleno\fP is -1, the function will assign the lowest available identifier\&. The \fBruleno\fP value must be a positive integer lower than \fBCRUSH_MAX_RULES\fP\&. .PP .IP "\(bu" 2 return -ENOSPC if the rule identifier is >= \fBCRUSH_MAX_RULES\fP .IP "\(bu" 2 return -ENOMEM if \fBrealloc(3)\fP fails to expand the array of rules in the \fBmap\fP .PP .PP \fBParameters:\fP .RS 4 \fImap\fP the \fBcrush_map\fP .br \fIrule\fP the rule to add to the \fBmap\fP .br \fIruleno\fP a positive integer < \fBCRUSH_MAX_RULES\fP or -1 .RE .PP \fBReturns:\fP .RS 4 the rule unique identifier on success, < 0 on error .RE .PP .SS "int crush_bucket_add_item (struct \fBcrush_map\fP * map, struct \fBcrush_bucket\fP * bucket, int item, int weight)" Add \fBitem\fP to \fBbucket\fP with \fBweight\fP\&. The weight of the new item is added to the weight of the bucket so that it reflects the total weight of all items\&. .PP If \fBbucket->alg\fP is \fBCRUSH_BUCKET_UNIFORM\fP, the value of \fBweight\fP must be equal to __(struct crush_bucket_uniform *)bucket->item_weight__\&. .PP .IP "\(bu" 2 return -ENOMEN if the \fBbucket\fP cannot be resized with \fBrealloc(3)\fP\&. .IP "\(bu" 2 return -ERANGE if adding \fBweight\fP to the weight of the bucket overflows\&. .IP "\(bu" 2 return -1 if the value of \fBbucket->alg\fP is unknown\&. .PP .PP \fBReturns:\fP .RS 4 0 on success, < 0 on error .RE .PP .SS "int crush_bucket_adjust_item_weight (struct \fBcrush_map\fP * map, struct \fBcrush_bucket\fP * bucket, int item, int weight)" If \fBbucket->alg\fP is \fBCRUSH_BUCKET_UNIFORM\fP, __(struct crush_bucket_uniform *)bucket->item_weight__ is set to \fBweight\fP and the weight of the bucket is set to be the number of items in the bucket times the weight\&. The return value is the difference between the new bucket weight and the former bucket weight\&. The \fBitem\fP argument is ignored\&. .PP If \fBbucket->alg\fP is different from \fBCRUSH_BUCKET_UNIFORM\fP, set the \fBweight\fP of \fBitem\fP in \fBbucket\fP\&. The former weight of the item is subtracted from the weight of of the bucket and the new weight is added\&. The return value is the difference between the new item weight and the former item weight\&. .PP \fBReturns:\fP .RS 4 the difference between the new weight and the former weight .RE .PP .SS "int crush_bucket_remove_item (struct \fBcrush_map\fP * map, struct \fBcrush_bucket\fP * bucket, int item)" Remove \fBitem\fP from \fBbucket\fP and subtract the item weight from the bucket weight\&. If the weight of the item is greater than the weight of the bucket, silentely set the bucket weight to zero\&. .PP .IP "\(bu" 2 return -ENOMEN if the \fBbucket\fP cannot be sized down with \fBrealloc(3)\fP\&. .IP "\(bu" 2 return -1 if the value of \fBbucket->alg\fP is unknown\&. .PP .PP \fBParameters:\fP .RS 4 \fImap\fP \fBunused\fP .br \fIbucket\fP the bucket from which \fBitem\fP is removed .br \fIitem\fP the item to remove from \fBbucket\fP .RE .PP \fBReturns:\fP .RS 4 0 on success, < 0 on error .RE .PP .SS "struct \fBcrush_map\fP* crush_create ()" Allocate a \fBcrush_map\fP with \fBmalloc(3)\fP and initialize it\&. The caller is responsible for deallocating the \fBcrush_map\fP with \fBcrush_destroy()\fP\&. .PP The content of the allocated \fBcrush_map\fP is undefined and it is the responsibility of the caller to set meaningful values\&. .PP The recommended values are: .PP .nf struct crush_map *m = crush_create(); m->choose_local_tries = 0; m->choose_local_fallback_tries = 0; m->choose_total_tries = 50; m->chooseleaf_descend_once = 1; m->chooseleaf_vary_r = 1; m->chooseleaf_stable = 1; m->allowed_bucket_algs = (1 << CRUSH_BUCKET_UNIFORM) | (1 << CRUSH_BUCKET_LIST) | (1 << CRUSH_BUCKET_STRAW2); .fi .PP .PP \fBReturns:\fP .RS 4 a pointer to the newly created \fBcrush_map\fP or NULL .RE .PP .SS "void crush_destroy (struct \fBcrush_map\fP * map)" Deallocate the \fBmap\fP, previously allocated with crush_create\&. .PP \fBParameters:\fP .RS 4 \fImap\fP the crush map .RE .PP .SS "int crush_do_rule (const struct \fBcrush_map\fP * map, int ruleno, int x, int * result, int result_max, const __u32 * weights, int weight_max, void * cwin)" Map \fBx\fP to \fBresult_max\fP items and store them in the \fBresult\fP array\&. The mapping is done by following each step of the rule \fBruleno\fP\&. See \fBcrush_make_rule()\fP, \fBcrush_rule_set_step()\fP and \fBcrush_add_rule()\fP for more information on how the rules are created, populated and added to the crush \fBmap\fP\&. .PP The return value is the the number of items in the \fBresult\fP array\&. If the caller asked for \fBresult_max\fP items and the return value is X where X < \fBresult_max\fP, the content of __result[0,X[__ is defined but the content of __result[X,result_max[__ is undefined\&. For example: .PP .nf crush_do_rule(map, ruleno=1, x=1, result, result_max=3,...) == 1 result[0] is set result[1] is undefined result[2] is undefined .fi .PP .PP An entry in the \fBresult\fP array is either an item in the crush \fBmap\fP or \fBCRUSH_ITEM_NONE\fP if no item was found\&. For example: .PP .nf crush_do_rule(map, ruleno=1, x=1, result, result_max=4,...) == 2 result[0] is CRUSH_ITEM_NONE result[1] is item number 5 result[2] is undefined result[3] is undefined .fi .PP .PP The \fBweight\fP array contains the probabilities that a leaf is ignored even if it is selected\&. It is a 16\&.16 fixed point number in the range [0x00000,0x10000]\&. The lower the value, the more often the leaf is ignored\&. For instance: .PP .IP "\(bu" 2 weight[leaf] == 0x00000 == 0\&.0 always ignore .IP "\(bu" 2 weight[leaf] == 0x10000 == 1\&.0 never ignore .IP "\(bu" 2 weight[leaf] == 0x08000 == 0\&.5 ignore 50% of the time .IP "\(bu" 2 weight[leaf] == 0x04000 == 0\&.25 ignore 75% of the time .IP "\(bu" 2 etc\&. .PP .PP During mapping, each leaf is checked against the \fBweight\fP array, using the leaf as an index\&. If there is no entry in \fBweight\fP for the leaf, it is ignored\&. If there is an entry, the leaf will be ignored some of the time, depending on the probability\&. .PP The \fBcwin\fP argument must be set as follows: .PP .nf char __cwin__[crush_work_size(__map__, __result_max__)]; crush_init_workspace(__map__, __cwin__); .fi .PP .PP \fBParameters:\fP .RS 4 \fImap\fP the \fBcrush_map\fP .br \fIruleno\fP a positive integer < \fBCRUSH_MAX_RULES\fP .br \fIx\fP the value to map to \fBresult_max\fP items .br \fIresult\fP an array of items of size \fBresult_max\fP .br \fIresult_max\fP the size of the \fBresult\fP array .br \fIweights\fP an array of weights of size \fBweight_max\fP .br \fIweight_max\fP the size of the \fBweights\fP array .br \fIcwin\fP must be the value of crush_work_size(\fBmap\fP, \fBresult_max\fP) .RE .PP \fBReturns:\fP .RS 4 0 on error or the size of \fBresult\fP on success .RE .PP .SS "void crush_finalize (struct \fBcrush_map\fP * map)" Analyze the content of \fBmap\fP and set the internal values required before it can be used to map values with \fBcrush_do_rule()\fP\&. The caller must make sure it is run before \fBcrush_do_rule()\fP and after any function that modifies the \fBmap\fP (\fBcrush_add_bucket()\fP, etc\&.)\&. .PP \fBParameters:\fP .RS 4 \fImap\fP the \fBcrush_map\fP .RE .PP .SS "struct \fBcrush_bucket\fP* crush_make_bucket (struct \fBcrush_map\fP * map, int alg, int hash, int type, int size, int * items, int * weights)" Allocate a \fBcrush_bucket\fP with \fBmalloc(3)\fP and initialize it\&. The content of the bucket is filled with \fBsize\fP items from \fBitems\fP\&. The item selection is set to use \fBalg\fP which is one of \fBCRUSH_BUCKET_UNIFORM\fP , \fBCRUSH_BUCKET_LIST\fP or \fBCRUSH_BUCKET_STRAW2\fP\&. The initial \fBitems\fP are assigned a weight from the \fBweights\fP array, depending on the value of \fBalg\fP\&. If \fBalg\fP is \fBCRUSH_BUCKET_UNIFORM\fP, all items are set to have a weight equal to \fBweights[0]\fP, otherwise the weight of \fBitems[x]\fP is set to be the value of \fBweights[x]\fP\&. .PP \fBParameters:\fP .RS 4 \fImap\fP \fBunused\fP .br \fIalg\fP algorithm for item selection .br \fIhash\fP always set to CRUSH_HASH_RJENKINS1 .br \fItype\fP user defined bucket type .br \fIsize\fP of the \fBitems\fP array .br \fIitems\fP array of \fBsize\fP items .br \fIweights\fP the weight of each item in \fBitems\fP, depending on \fBalg\fP .RE .PP .SS "struct \fBcrush_rule\fP* crush_make_rule (int len, int ruleset, int type, int minsize, int maxsize)" Allocate an empty \fBcrush_rule\fP structure large enough to store \fBlen\fP steps\&. Steps can be added to a rule via \fBcrush_rule_set_step()\fP\&. The \fBruleset\fP is a user defined integer, not used by \fBlibcrush\fP and stored in the allocated rule at \fBrule->ruleset\fP\&. .PP The rule is designed to allow \fBcrush_do_rule()\fP to get at least \fBminsize\fP items and at most \fBmaxsize\fP items\&. .PP The \fBtype\fP is defined by the caller and will be used by \fBcrush_find_rule()\fP when looking for a rule and by \fBCRUSH_RULE_CHOOSE*\fP steps when looking for items\&. .PP If \fBmalloc(3)\fP fails, return NULL\&. .PP \fBParameters:\fP .RS 4 \fIlen\fP number of steps in the rule .br \fIruleset\fP user defined value .br \fItype\fP user defined value .br \fIminsize\fP minimum number of items the rule can map .br \fImaxsize\fP maximum number of items the rule can map .RE .PP \fBReturns:\fP .RS 4 a pointer to the newly created rule or NULL .RE .PP .SS "int crush_remove_bucket (struct \fBcrush_map\fP * map, struct \fBcrush_bucket\fP * bucket)" Remove \fBbucket\fP from \fBmap\fP and deallocate it via \fBcrush_destroy_bucket()\fP\&. \fBassert(3)\fP that \fBbucket\fP is in \fBmap\fP\&. The caller is responsible for making sure the bucket is not the child of any other bucket in the \fBmap\fP\&. .PP \fBParameters:\fP .RS 4 \fImap\fP a \fBcrush_map\fP containing \fBbucket\fP .br \fIbucket\fP the bucket to remove from \fBmap\fP .RE .PP \fBReturns:\fP .RS 4 0 .RE .PP .SS "int crush_reweight_bucket (struct \fBcrush_map\fP * crush, struct \fBcrush_bucket\fP * bucket)" Recursively update the weight of \fBbucket\fP and its children, deep first\&. The \fBbucket\fP weight is set to the sum of the weight of the items it contains\&. .PP .IP "\(bu" 2 return -ERANGE if the sum of the weight of the items in \fBbucket\fP overflows\&. .IP "\(bu" 2 return -1 if the value of \fBbucket->alg\fP is unknown\&. .PP .PP \fBParameters:\fP .RS 4 \fIcrush\fP a \fBcrush_map\fP containing \fBbucket\fP .br \fIbucket\fP the root of the tree to reweight .RE .PP \fBReturns:\fP .RS 4 0 on success, < 0 on error .RE .PP .SS "void crush_rule_set_step (struct \fBcrush_rule\fP * rule, int pos, int op, int arg1, int arg2)" Set the \fBpos\fP step of the \fBrule\fP to an operand and up to two arguments\&. The value of the operand \fBop\fP determines if the arguments are used and how: .PP .IP "\(bu" 2 \fBCRUSH_RULE_NOOP\fP do nothing\&. .IP "\(bu" 2 \fBCRUSH_RULE_TAKE\fP select the \fBarg1\fP item .IP "\(bu" 2 \fBCRUSH_RULE_CHOOSE_FIRSTN\fP and \fBCRUSH_RULE_CHOOSE_INDEP\fP recursively explore each bucket currently selected, looking for \fBarg1\fP items of type \fBarg2\fP and select them\&. .IP "\(bu" 2 \fBCRUSH_RULE_CHOOSELEAF_FIRSTN\fP and \fBCRUSH_RULE_CHOOSELEAF_INDEP\fP recursively explore each bucket currently selected, looking for \fBarg1\fP leaves within all the buckets of type \fBarg2\fP and select them\&. .IP "\(bu" 2 \fBCRUSH_RULE_EMIT\fP append the selection to the results and clear the selection .PP .PP In all \fBCHOOSE\fP steps, if \fBarg1\fP is zero, the number of items to select is determined by the \fBmax_result\fP argument of \fBcrush_do_rule()\fP, i\&.e\&. \fBarg1\fP is \fBmax_result\fP minus the number of items already in the result\&. .PP \fBParameters:\fP .RS 4 \fIrule\fP the rule in which the step is inserted .br \fIpos\fP the zero based step index .br \fIop\fP one of \fBCRUSH_RULE_NOOP\fP, \fBCRUSH_RULE_TAKE\fP, \fBCRUSH_RULE_CHOOSE_FIRSTN\fP, \fBCRUSH_RULE_CHOOSE_INDEP\fP, \fBCRUSH_RULE_CHOOSELEAF_FIRSTN\fP, \fBCRUSH_RULE_CHOOSELEAF_INDEP\fP or \fBCRUSH_RULE_EMIT\fP .br \fIarg1\fP first argument for \fBop\fP .br \fIarg2\fP second argument for \fBop\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for libcrush from the source code\&.