1119 lines · 26.2 KB · C
RawDownload
 #include <linux/ceph/ceph_debug.h> #include <linux/module.h>#include <linux/slab.h>#include <asm/div64.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> char *ceph_osdmap_state_str(char *str, int len, int state){	int flag = 0; 	if (!len)		goto done; 	*str = '\0';	if (state) {		if (state & CEPH_OSD_EXISTS) {			snprintf(str, len, "exists");			flag = 1;		}		if (state & CEPH_OSD_UP) {			snprintf(str, len, "%s%s%s", str, (flag ? ", " : ""),				 "up");			flag = 1;		}	} else {		snprintf(str, len, "doesn't exist");	}done:	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(le32_to_cpu(pi->v.pg_num)-1)) - 1;	pi->pgp_num_mask =		(1 << calc_bits_of(le32_to_cpu(pi->v.pgp_num)-1)) - 1;	pi->lpg_num_mask =		(1 << calc_bits_of(le32_to_cpu(pi->v.lpg_num)-1)) - 1;	pi->lpgp_num_mask =		(1 << calc_bits_of(le32_to_cpu(pi->v.lpgp_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_need(p, end, (1+b->h.size) * sizeof(u32), bad);	b->item_weight = ceph_decode_32(p);	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_32_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 struct crush_map *crush_decode(void *pbyval, void *end){	struct crush_map *c;	int err = -EINVAL;	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(sizeof(*c), GFP_NOFS);	if (c == NULL)		return ERR_PTR(-ENOMEM); 	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 = kcalloc(c->max_buckets, sizeof(*c->buckets), GFP_NOFS);	if (c->buckets == NULL)		goto badmem;	c->rules = kcalloc(c->max_rules, sizeof(*c->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;		case CRUSH_BUCKET_TREE:			size = sizeof(struct crush_bucket_tree);			break;		case CRUSH_BUCKET_STRAW:			size = sizeof(struct crush_bucket_straw);			break;		default:			err = -EINVAL;			goto bad;		}		BUG_ON(size == 0);		b = c->buckets[i] = kzalloc(size, GFP_NOFS);		if (b == NULL)			goto badmem; 		ceph_decode_need(p, end, 4*sizeof(u32), bad);		b->id = ceph_decode_32(p);		b->type = ceph_decode_16(p);		b->alg = ceph_decode_8(p);		b->hash = ceph_decode_8(p);		b->weight = ceph_decode_32(p);		b->size = ceph_decode_32(p); 		dout("crush_decode bucket size %d off %x %p to %p\n",		     b->size, (int)(*p-start), *p, end); 		b->items = kcalloc(b->size, sizeof(__s32), GFP_NOFS);		if (b->items == NULL)			goto badmem;		b->perm = kcalloc(b->size, sizeof(u32), GFP_NOFS);		if (b->perm == NULL)			goto badmem;		b->perm_n = 0; 		ceph_decode_need(p, end, b->size*sizeof(u32), bad);		for (j = 0; j < b->size; j++)			b->items[j] = ceph_decode_32(p); 		switch (b->alg) {		case CRUSH_BUCKET_UNIFORM:			err = crush_decode_uniform_bucket(p, end,				  (struct crush_bucket_uniform *)b);			if (err < 0)				goto bad;			break;		case CRUSH_BUCKET_LIST:			err = crush_decode_list_bucket(p, end,			       (struct crush_bucket_list *)b);			if (err < 0)				goto bad;			break;		case CRUSH_BUCKET_TREE:			err = crush_decode_tree_bucket(p, end,				(struct crush_bucket_tree *)b);			if (err < 0)				goto bad;			break;		case CRUSH_BUCKET_STRAW:			err = crush_decode_straw_bucket(p, end,				(struct crush_bucket_straw *)b);			if (err < 0)				goto bad;			break;		}	} 	/* rules */	dout("rule vec is %p\n", c->rules);	for (i = 0; i < c->max_rules; i++) {		u32 yes;		struct crush_rule *r; 		ceph_decode_32_safe(p, end, yes, bad);		if (!yes) {			dout("crush_decode NO rule %d off %x %p to %p\n",			     i, (int)(*p-start), *p, end);			c->rules[i] = NULL;			continue;		} 		dout("crush_decode rule %d off %x %p to %p\n",		     i, (int)(*p-start), *p, end); 		/* len */		ceph_decode_32_safe(p, end, yes, bad);#if BITS_PER_LONG == 32		err = -EINVAL;		if (yes > (ULONG_MAX - sizeof(*r))			  / sizeof(struct crush_rule_step))			goto bad;#endif		r = c->rules[i] = kmalloc(sizeof(*r) +					  yes*sizeof(struct crush_rule_step),					  GFP_NOFS);		if (r == NULL)			goto badmem;		dout(" rule %d is at %p\n", i, r);		r->len = yes;		ceph_decode_copy_safe(p, end, &r->mask, 4, bad); /* 4 u8's */		ceph_decode_need(p, end, r->len*3*sizeof(u32), bad);		for (j = 0; j < r->len; j++) {			r->steps[j].op = ceph_decode_32(p);			r->steps[j].arg1 = ceph_decode_32(p);			r->steps[j].arg2 = ceph_decode_32(p);		}	} 	/* ignore trailing name maps. */ 	dout("crush_decode success\n");	return c; badmem:	err = -ENOMEM;bad:	dout("crush_decode fail %d\n", err);	crush_destroy(c);	return ERR_PTR(err);} /* * rbtree of pg_mapping for handling pg_temp (explicit mapping of pgid * to a set of osds) */static int pgid_cmp(struct ceph_pg l, struct ceph_pg r){	u64 a = *(u64 *)&l;	u64 b = *(u64 *)&r; 	if (a < b)		return -1;	if (a > b)		return 1;	return 0;} static int __insert_pg_mapping(struct ceph_pg_mapping *new,			       struct rb_root *root){	struct rb_node **p = &root->rb_node;	struct rb_node *parent = NULL;	struct ceph_pg_mapping *pg = NULL;	int c; 	dout("__insert_pg_mapping %llx %p\n", *(u64 *)&new->pgid, new);	while (*p) {		parent = *p;		pg = rb_entry(parent, struct ceph_pg_mapping, node);		c = pgid_cmp(new->pgid, pg->pgid);		if (c < 0)			p = &(*p)->rb_left;		else if (c > 0)			p = &(*p)->rb_right;		else			return -EEXIST;	} 	rb_link_node(&new->node, parent, p);	rb_insert_color(&new->node, root);	return 0;} static struct ceph_pg_mapping *__lookup_pg_mapping(struct rb_root *root,						   struct ceph_pg pgid){	struct rb_node *n = root->rb_node;	struct ceph_pg_mapping *pg;	int c; 	while (n) {		pg = rb_entry(n, struct ceph_pg_mapping, node);		c = pgid_cmp(pgid, pg->pgid);		if (c < 0) {			n = n->rb_left;		} else if (c > 0) {			n = n->rb_right;		} else {			dout("__lookup_pg_mapping %llx got %p\n",			     *(u64 *)&pgid, pg);			return pg;		}	}	return NULL;} static int __remove_pg_mapping(struct rb_root *root, struct ceph_pg pgid){	struct ceph_pg_mapping *pg = __lookup_pg_mapping(root, pgid); 	if (pg) {		dout("__remove_pg_mapping %llx %p\n", *(u64 *)&pgid, pg);		rb_erase(&pg->node, root);		kfree(pg);		return 0;	}	dout("__remove_pg_mapping %llx dne\n", *(u64 *)&pgid);	return -ENOENT;} /* * rbtree of pg pool info */static int __insert_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *new){	struct rb_node **p = &root->rb_node;	struct rb_node *parent = NULL;	struct ceph_pg_pool_info *pi = NULL; 	while (*p) {		parent = *p;		pi = rb_entry(parent, struct ceph_pg_pool_info, node);		if (new->id < pi->id)			p = &(*p)->rb_left;		else if (new->id > pi->id)			p = &(*p)->rb_right;		else			return -EEXIST;	} 	rb_link_node(&new->node, parent, p);	rb_insert_color(&new->node, root);	return 0;} static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, int id){	struct ceph_pg_pool_info *pi;	struct rb_node *n = root->rb_node; 	while (n) {		pi = rb_entry(n, struct ceph_pg_pool_info, node);		if (id < pi->id)			n = n->rb_left;		else if (id > pi->id)			n = n->rb_right;		else			return pi;	}	return NULL;} int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name){	struct rb_node *rbp; 	for (rbp = rb_first(&map->pg_pools); rbp; rbp = rb_next(rbp)) {		struct ceph_pg_pool_info *pi =			rb_entry(rbp, struct ceph_pg_pool_info, node);		if (pi->name && strcmp(pi->name, name) == 0)			return pi->id;	}	return -ENOENT;}EXPORT_SYMBOL(ceph_pg_poolid_by_name); static void __remove_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *pi){	rb_erase(&pi->node, root);	kfree(pi->name);	kfree(pi);} static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi){	unsigned int n, m; 	ceph_decode_copy(p, &pi->v, sizeof(pi->v));	calc_pg_masks(pi); 	/* num_snaps * snap_info_t */	n = le32_to_cpu(pi->v.num_snaps);	while (n--) {		ceph_decode_need(p, end, sizeof(u64) + 1 + sizeof(u64) +				 sizeof(struct ceph_timespec), bad);		*p += sizeof(u64) +       /* key */			1 + sizeof(u64) + /* u8, snapid */			sizeof(struct ceph_timespec);		m = ceph_decode_32(p);    /* snap name */		*p += m;	} 	*p += le32_to_cpu(pi->v.num_removed_snap_intervals) * sizeof(u64) * 2;	return 0; bad:	return -EINVAL;} static int __decode_pool_names(void **p, void *end, struct ceph_osdmap *map){	struct ceph_pg_pool_info *pi;	u32 num, len, pool; 	ceph_decode_32_safe(p, end, num, bad);	dout(" %d pool names\n", num);	while (num--) {		ceph_decode_32_safe(p, end, pool, bad);		ceph_decode_32_safe(p, end, len, bad);		dout("  pool %d len %d\n", pool, len);		pi = __lookup_pg_pool(&map->pg_pools, pool);		if (pi) {			kfree(pi->name);			pi->name = kmalloc(len + 1, GFP_NOFS);			if (pi->name) {				memcpy(pi->name, *p, len);				pi->name[len] = '\0';				dout("  name is %s\n", pi->name);			}		}

Lines 1–500 of 1119.