예제 #1
0
static int create(struct ip_set *set, const void *data, size_t size)
{
	struct ip_set_req_ipporthash_create *req =
	    (struct ip_set_req_ipporthash_create *) data;
	struct ip_set_ipporthash *map;
	uint16_t i;

	if (size != sizeof(struct ip_set_req_ipporthash_create)) {
		ip_set_printk("data length wrong (want %zu, have %zu)",
			       sizeof(struct ip_set_req_ipporthash_create),
			       size);
		return -EINVAL;
	}

	if (req->hashsize < 1) {
		ip_set_printk("hashsize too small");
		return -ENOEXEC;
	}

	if (req->probes < 1) {
		ip_set_printk("probes too small");
		return -ENOEXEC;
	}

	map = kmalloc(sizeof(struct ip_set_ipporthash) 
		      + req->probes * sizeof(uint32_t), GFP_KERNEL);
	if (!map) {
		DP("out of memory for %d bytes",
		   sizeof(struct ip_set_ipporthash)
		   + req->probes * sizeof(uint32_t));
		return -ENOMEM;
	}
	for (i = 0; i < req->probes; i++)
		get_random_bytes(((uint32_t *) map->initval)+i, 4);
	map->elements = 0;
	map->hashsize = req->hashsize;
	map->probes = req->probes;
	map->resize = req->resize;
	map->first_ip = req->from;
	map->last_ip = req->to;
	map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
	if (!map->members) {
		DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
		kfree(map);
		return -ENOMEM;
	}

	set->data = map;
	return 0;
}
static int retry(struct ip_set *set)
{
	struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
	ip_set_ip_t *elem;
	void *members;
	u_int32_t i, hashsize = map->hashsize;
	int res;
	struct ip_set_ipporthash *tmp;
	
	if (map->resize == 0)
		return -ERANGE;

    again:
    	res = 0;
    	
	/* Calculate new hash size */
	hashsize += (hashsize * map->resize)/100;
	if (hashsize == map->hashsize)
		hashsize++;
	
	ip_set_printk("rehashing of set %s triggered: "
		      "hashsize grows from %u to %u",
		      set->name, map->hashsize, hashsize);

	tmp = kmalloc(sizeof(struct ip_set_ipporthash) 
		      + map->probes * sizeof(uint32_t), GFP_ATOMIC);
	if (!tmp) {
		DP("out of memory for %d bytes",
		   sizeof(struct ip_set_ipporthash)
		   + map->probes * sizeof(uint32_t));
		return -ENOMEM;
	}
	tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
	if (!tmp->members) {
		DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
		kfree(tmp);
		return -ENOMEM;
	}
	tmp->hashsize = hashsize;
	tmp->probes = map->probes;
	tmp->resize = map->resize;
	tmp->first_ip = map->first_ip;
	tmp->last_ip = map->last_ip;
	memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
	
	write_lock_bh(&set->lock);
	map = (struct ip_set_ipporthash *) set->data; /* Play safe */
	for (i = 0; i < map->hashsize && res == 0; i++) {
		elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);	
		if (*elem)
			res = __add_haship(tmp, *elem);
	}
	if (res) {
		/* Failure, try again */
		write_unlock_bh(&set->lock);
		harray_free(tmp->members);
		kfree(tmp);
		goto again;
	}
	
	/* Success at resizing! */
	members = map->members;

	map->hashsize = tmp->hashsize;
	map->members = tmp->members;
	write_unlock_bh(&set->lock);

	harray_free(members);
	kfree(tmp);

	return 0;
}