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; }