3121 lines · 71.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0 #include <linux/ceph/ceph_debug.h> #include <linux/module.h>#include <linux/slab.h> #include <linux/ceph/libceph.h>#include <linux/ceph/osdmap.h>#include <linux/ceph/decode.h>#include <linux/crush/hash.h>#include <linux/crush/mapper.h> static __printf(2, 3)void osdmap_info(const struct ceph_osdmap *map, const char *fmt, ...){	struct va_format vaf;	va_list args; 	va_start(args, fmt);	vaf.fmt = fmt;	vaf.va = &args; 	printk(KERN_INFO "%s (%pU e%u): %pV", KBUILD_MODNAME, &map->fsid,	       map->epoch, &vaf); 	va_end(args);} char *ceph_osdmap_state_str(char *str, int len, u32 state){	if (!len)		return str; 	if ((state & CEPH_OSD_EXISTS) && (state & CEPH_OSD_UP))		snprintf(str, len, "exists, up");	else if (state & CEPH_OSD_EXISTS)		snprintf(str, len, "exists");	else if (state & CEPH_OSD_UP)		snprintf(str, len, "up");	else		snprintf(str, len, "doesn't exist"); 	return str;} /* maps */ static int calc_bits_of(unsigned int t){	int b = 0;	while (t) {		t = t >> 1;		b++;	}	return b;} /* * the foo_mask is the smallest value 2^n-1 that is >= foo. */static void calc_pg_masks(struct ceph_pg_pool_info *pi){	pi->pg_num_mask = (1 << calc_bits_of(pi->pg_num-1)) - 1;	pi->pgp_num_mask = (1 << calc_bits_of(pi->pgp_num-1)) - 1;} /* * decode crush map */static int crush_decode_uniform_bucket(void **p, void *end,				       struct crush_bucket_uniform *b){	dout("crush_decode_uniform_bucket %p to %p\n", *p, end);	ceph_decode_32_safe(p, end, b->item_weight, bad);	return 0;bad:	return -EINVAL;} static int crush_decode_list_bucket(void **p, void *end,				    struct crush_bucket_list *b){	int j;	dout("crush_decode_list_bucket %p to %p\n", *p, end);	b->item_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);	if (b->item_weights == NULL)		return -ENOMEM;	b->sum_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);	if (b->sum_weights == NULL)		return -ENOMEM;	ceph_decode_need(p, end, 2 * b->h.size * sizeof(u32), bad);	for (j = 0; j < b->h.size; j++) {		b->item_weights[j] = ceph_decode_32(p);		b->sum_weights[j] = ceph_decode_32(p);	}	return 0;bad:	return -EINVAL;} static int crush_decode_tree_bucket(void **p, void *end,				    struct crush_bucket_tree *b){	int j;	dout("crush_decode_tree_bucket %p to %p\n", *p, end);	ceph_decode_8_safe(p, end, b->num_nodes, bad);	b->node_weights = kcalloc(b->num_nodes, sizeof(u32), GFP_NOFS);	if (b->node_weights == NULL)		return -ENOMEM;	ceph_decode_need(p, end, b->num_nodes * sizeof(u32), bad);	for (j = 0; j < b->num_nodes; j++)		b->node_weights[j] = ceph_decode_32(p);	return 0;bad:	return -EINVAL;} static int crush_decode_straw_bucket(void **p, void *end,				     struct crush_bucket_straw *b){	int j;	dout("crush_decode_straw_bucket %p to %p\n", *p, end);	b->item_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);	if (b->item_weights == NULL)		return -ENOMEM;	b->straws = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);	if (b->straws == NULL)		return -ENOMEM;	ceph_decode_need(p, end, 2 * b->h.size * sizeof(u32), bad);	for (j = 0; j < b->h.size; j++) {		b->item_weights[j] = ceph_decode_32(p);		b->straws[j] = ceph_decode_32(p);	}	return 0;bad:	return -EINVAL;} static int crush_decode_straw2_bucket(void **p, void *end,				      struct crush_bucket_straw2 *b){	int j;	dout("crush_decode_straw2_bucket %p to %p\n", *p, end);	b->item_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);	if (b->item_weights == NULL)		return -ENOMEM;	ceph_decode_need(p, end, b->h.size * sizeof(u32), bad);	for (j = 0; j < b->h.size; j++)		b->item_weights[j] = ceph_decode_32(p);	return 0;bad:	return -EINVAL;} struct crush_name_node {	struct rb_node cn_node;	int cn_id;	char cn_name[];}; static struct crush_name_node *alloc_crush_name(size_t name_len){	struct crush_name_node *cn; 	cn = kmalloc(sizeof(*cn) + name_len + 1, GFP_NOIO);	if (!cn)		return NULL; 	RB_CLEAR_NODE(&cn->cn_node);	return cn;} static void free_crush_name(struct crush_name_node *cn){	WARN_ON(!RB_EMPTY_NODE(&cn->cn_node)); 	kfree(cn);} DEFINE_RB_FUNCS(crush_name, struct crush_name_node, cn_id, cn_node) static int decode_crush_names(void **p, void *end, struct rb_root *root){	u32 n; 	ceph_decode_32_safe(p, end, n, e_inval);	while (n--) {		struct crush_name_node *cn;		int id;		u32 name_len; 		ceph_decode_32_safe(p, end, id, e_inval);		ceph_decode_32_safe(p, end, name_len, e_inval);		ceph_decode_need(p, end, name_len, e_inval); 		cn = alloc_crush_name(name_len);		if (!cn)			return -ENOMEM; 		cn->cn_id = id;		memcpy(cn->cn_name, *p, name_len);		cn->cn_name[name_len] = '\0';		*p += name_len; 		if (!__insert_crush_name(root, cn)) {			free_crush_name(cn);			return -EEXIST;		}	} 	return 0; e_inval:	return -EINVAL;} void clear_crush_names(struct rb_root *root){	while (!RB_EMPTY_ROOT(root)) {		struct crush_name_node *cn =		    rb_entry(rb_first(root), struct crush_name_node, cn_node); 		erase_crush_name(root, cn);		free_crush_name(cn);	}} static struct crush_choose_arg_map *alloc_choose_arg_map(void){	struct crush_choose_arg_map *arg_map; 	arg_map = kzalloc_obj(*arg_map, GFP_NOIO);	if (!arg_map)		return NULL; 	RB_CLEAR_NODE(&arg_map->node);	return arg_map;} static void free_choose_arg_map(struct crush_choose_arg_map *arg_map){	int i, j; 	if (!arg_map)		return; 	WARN_ON(!RB_EMPTY_NODE(&arg_map->node)); 	if (arg_map->args) {		for (i = 0; i < arg_map->size; i++) {			struct crush_choose_arg *arg = &arg_map->args[i];			if (arg->weight_set) {				for (j = 0; j < arg->weight_set_size; j++)					kfree(arg->weight_set[j].weights);				kfree(arg->weight_set);			}			kfree(arg->ids);		}		kfree(arg_map->args);	}	kfree(arg_map);} DEFINE_RB_FUNCS(choose_arg_map, struct crush_choose_arg_map, choose_args_index,		node); void clear_choose_args(struct crush_map *c){	while (!RB_EMPTY_ROOT(&c->choose_args)) {		struct crush_choose_arg_map *arg_map =		    rb_entry(rb_first(&c->choose_args),			     struct crush_choose_arg_map, node); 		erase_choose_arg_map(&c->choose_args, arg_map);		free_choose_arg_map(arg_map);	}} static u32 *decode_array_32_alloc(void **p, void *end, u32 *plen){	u32 *a = NULL;	u32 len;	int ret; 	ceph_decode_32_safe(p, end, len, e_inval);	if (len) {		u32 i; 		a = kmalloc_array(len, sizeof(u32), GFP_NOIO);		if (!a) {			ret = -ENOMEM;			goto fail;		} 		ceph_decode_need(p, end, len * sizeof(u32), e_inval);		for (i = 0; i < len; i++)			a[i] = ceph_decode_32(p);	} 	*plen = len;	return a; e_inval:	ret = -EINVAL;fail:	kfree(a);	return ERR_PTR(ret);} /* * Assumes @arg is zero-initialized. */static int decode_choose_arg(void **p, void *end, struct crush_choose_arg *arg){	int ret; 	ceph_decode_32_safe(p, end, arg->weight_set_size, e_inval);	if (arg->weight_set_size) {		u32 i; 		arg->weight_set = kmalloc_objs(*arg->weight_set,					       arg->weight_set_size, GFP_NOIO);		if (!arg->weight_set)			return -ENOMEM; 		for (i = 0; i < arg->weight_set_size; i++) {			struct crush_weight_set *w = &arg->weight_set[i]; 			w->weights = decode_array_32_alloc(p, end, &w->size);			if (IS_ERR(w->weights)) {				ret = PTR_ERR(w->weights);				w->weights = NULL;				return ret;			}		}	} 	arg->ids = decode_array_32_alloc(p, end, &arg->ids_size);	if (IS_ERR(arg->ids)) {		ret = PTR_ERR(arg->ids);		arg->ids = NULL;		return ret;	} 	return 0; e_inval:	return -EINVAL;} static int decode_choose_args(void **p, void *end, struct crush_map *c){	struct crush_choose_arg_map *arg_map = NULL;	u32 num_choose_arg_maps, num_buckets;	int ret; 	ceph_decode_32_safe(p, end, num_choose_arg_maps, e_inval);	while (num_choose_arg_maps--) {		arg_map = alloc_choose_arg_map();		if (!arg_map) {			ret = -ENOMEM;			goto fail;		} 		ceph_decode_64_safe(p, end, arg_map->choose_args_index,				    e_inval);		arg_map->size = c->max_buckets;		arg_map->args = kzalloc_objs(*arg_map->args, arg_map->size,					     GFP_NOIO);		if (!arg_map->args) {			ret = -ENOMEM;			goto fail;		} 		ceph_decode_32_safe(p, end, num_buckets, e_inval);		while (num_buckets--) {			struct crush_choose_arg *arg;			u32 bucket_index; 			ceph_decode_32_safe(p, end, bucket_index, e_inval);			if (bucket_index >= arg_map->size)				goto e_inval; 			arg = &arg_map->args[bucket_index];			ret = decode_choose_arg(p, end, arg);			if (ret)				goto fail; 			if (arg->ids_size &&			    (!c->buckets[bucket_index] ||			     arg->ids_size != c->buckets[bucket_index]->size))				goto e_inval;		} 		if (!__insert_choose_arg_map(&c->choose_args, arg_map)) {			ret = -EEXIST;			goto fail;		}	} 	return 0; e_inval:	ret = -EINVAL;fail:	free_choose_arg_map(arg_map);	return ret;} static void crush_finalize(struct crush_map *c){	__s32 b; 	/* Space for the array of pointers to per-bucket workspace */	c->working_size = sizeof(struct crush_work) +	    c->max_buckets * sizeof(struct crush_work_bucket *); 	for (b = 0; b < c->max_buckets; b++) {		if (!c->buckets[b])			continue; 		switch (c->buckets[b]->alg) {		default:			/*			 * The base case, permutation variables and			 * the pointer to the permutation array.			 */			c->working_size += sizeof(struct crush_work_bucket);			break;		}		/* Every bucket has a permutation array. */		c->working_size += c->buckets[b]->size * sizeof(__u32);	}} static struct crush_map *crush_decode(void *pbyval, void *end){	struct crush_map *c;	int err;	int i, j;	void **p = &pbyval;	void *start = pbyval;	u32 magic; 	dout("crush_decode %p to %p len %d\n", *p, end, (int)(end - *p)); 	c = kzalloc_obj(*c, GFP_NOFS);	if (c == NULL)		return ERR_PTR(-ENOMEM); 	c->type_names = RB_ROOT;	c->names = RB_ROOT;	c->choose_args = RB_ROOT;         /* set tunables to default values */        c->choose_local_tries = 2;        c->choose_local_fallback_tries = 5;        c->choose_total_tries = 19;	c->chooseleaf_descend_once = 0; 	ceph_decode_need(p, end, 4*sizeof(u32), bad);	magic = ceph_decode_32(p);	if (magic != CRUSH_MAGIC) {		pr_err("crush_decode magic %x != current %x\n",		       (unsigned int)magic, (unsigned int)CRUSH_MAGIC);		goto bad;	}	c->max_buckets = ceph_decode_32(p);	c->max_rules = ceph_decode_32(p);	c->max_devices = ceph_decode_32(p); 	c->buckets = kzalloc_objs(*c->buckets, c->max_buckets, GFP_NOFS);	if (c->buckets == NULL)		goto badmem;	c->rules = kzalloc_objs(*c->rules, c->max_rules, GFP_NOFS);	if (c->rules == NULL)		goto badmem; 	/* buckets */	for (i = 0; i < c->max_buckets; i++) {		int size = 0;		u32 alg;		struct crush_bucket *b; 		ceph_decode_32_safe(p, end, alg, bad);		if (alg == 0) {			c->buckets[i] = NULL;			continue;		}		dout("crush_decode bucket %d off %x %p to %p\n",		     i, (int)(*p-start), *p, end); 		switch (alg) {		case CRUSH_BUCKET_UNIFORM:			size = sizeof(struct crush_bucket_uniform);			break;		case CRUSH_BUCKET_LIST:			size = sizeof(struct crush_bucket_list);			break;

Lines 1–500 of 3121.