1) change svc->num_dests to fixed size when allocate memory.
2) return -ENOMEM if memory allocation is faild(non-failing methods)
Signed-off-by: Inju Song <inju.song@xxxxxxxxxxxxx>
---
net/netfilter/ipvs/ip_vs_mh.c | 101 +++++++++++++++++++++++++++---------------
1 file changed, 65 insertions(+), 36 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_mh.c b/net/netfilter/ipvs/ip_vs_mh.c
index 534a9f5..b3fa8c4 100644
--- a/net/netfilter/ipvs/ip_vs_mh.c
+++ b/net/netfilter/ipvs/ip_vs_mh.c
@@ -19,11 +19,17 @@ struct ip_vs_mh_lookup {
};
/* for IPVS MH entry hash table */
-#define IP_VS_MH_LOOKUP_SIZE 65537 /* Must be prime number */
+#ifndef CONFIG_IP_VS_MH_TAB_BITS
+#define CONFIG_IP_VS_MH_TAB_BITS 8
+#endif
+#define IP_VS_MH_TAB_BITS CONFIG_IP_VS_MH_TAB_BITS
+#define IP_VS_MH_TAB_SIZE BIT(IP_VS_MH_TAB_BITS)
+#define IP_VS_MH_LOOKUP_SIZE 65537 /* Must be prime number */
struct ip_vs_mh_state {
struct rcu_head rcu_head;
struct ip_vs_mh_lookup lookup[IP_VS_MH_LOOKUP_SIZE];
+ unsigned int **permutation;
hsiphash_key_t hash1, hash2;
};
@@ -61,25 +67,21 @@ static inline bool is_unavailable(struct ip_vs_dest *dest)
return hsiphash(&v, sizeof(v), key);
}
-static inline unsigned int **
-ip_vs_mh_permutate(struct ip_vs_mh_state *s, struct ip_vs_service *svc)
+static inline int ip_vs_mh_permutate(struct ip_vs_mh_state *s,
+ struct ip_vs_service *svc)
{
int i, j;
- unsigned int **permutation;
struct list_head *p;
struct ip_vs_dest *dest;
unsigned int offset, skip;
- int dcnt;
- dcnt = svc->num_dests;
- permutation = kcalloc(dcnt, sizeof(unsigned int *), GFP_KERNEL);
- permutation[0] = kcalloc(dcnt * IP_VS_MH_LOOKUP_SIZE,
- sizeof(unsigned int), GFP_KERNEL);
- for (i = 1; i < dcnt; i++)
- permutation[i] = permutation[i - 1] + IP_VS_MH_LOOKUP_SIZE;
+ /* extending permutation table to 2d arrays */
+ for (i = 1; i < svc->num_dests; i++)
+ s->permutation[i] = s->permutation[i - 1] +
+ IP_VS_MH_LOOKUP_SIZE;
- p = &svc->destinations;
i = 0;
+ p = &svc->destinations;
while ((p = p->next) != &svc->destinations) {
dest = list_entry(p, struct ip_vs_dest, n_list);
offset = ip_vs_mh_hashkey(svc->af, &dest->addr, dest->port,
@@ -89,44 +91,53 @@ static inline bool is_unavailable(struct ip_vs_dest *dest)
(IP_VS_MH_LOOKUP_SIZE - 1) + 1;
for (j = 0; j < IP_VS_MH_LOOKUP_SIZE; j++) {
- permutation[i][j] = (offset + (j * skip)) %
+ s->permutation[i][j] = (offset + (j * skip)) %
IP_VS_MH_LOOKUP_SIZE;
}
i++;
}
- return permutation;
+ return 0;
}
static inline int
-ip_vs_mh_populate(struct ip_vs_mh_state *s, struct ip_vs_service *svc,
- unsigned int **permutation)
+ip_vs_mh_populate(struct ip_vs_mh_state *s, struct ip_vs_service *svc)
{
- int i;
+ int i, ret;
unsigned int *next;
+ unsigned int **pmt;
struct ip_vs_mh_lookup *entry, *l;
struct list_head *p;
struct ip_vs_dest *dest;
- int dcnt;
unsigned int n, c;
- dcnt = svc->num_dests;
- next = kcalloc(dcnt, sizeof(unsigned int), GFP_KERNEL);
+ ret = 0;
+ next = kcalloc(IP_VS_MH_TAB_SIZE, sizeof(unsigned int),
+ GFP_KERNEL);
+ if (!next)
+ return -ENOMEM;
+
entry = kcalloc(IP_VS_MH_LOOKUP_SIZE, sizeof(*entry),
GFP_KERNEL);
+ if (!entry) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
for (i = 0; i < IP_VS_MH_LOOKUP_SIZE; i++)
RCU_INIT_POINTER(entry[i].dest, NULL);
n = 0;
+ pmt = s->permutation;
while (n < IP_VS_MH_LOOKUP_SIZE) {
p = &svc->destinations;
- for (i = 0; i < dcnt; i++) {
+ for (i = 0; i < svc->num_dests; i++) {
p = p->next;
- c = permutation[i][next[i]];
+ c = pmt[i][next[i]];
while (entry[c].dest) {
next[i] = next[i] + 1;
- c = permutation[i][next[i]];
+ c = pmt[i][next[i]];
}
dest = list_entry(p, struct ip_vs_dest, n_list);
@@ -152,10 +163,11 @@ static inline bool is_unavailable(struct ip_vs_dest *dest)
RCU_INIT_POINTER(entry[i].dest, NULL);
l++;
}
- kfree(next);
- kfree(entry);
- return 0;
+ kfree(entry);
+err_alloc:
+ kfree(next);
+ return ret;
}
/* Get ip_vs_dest associated with supplied parameters. */
@@ -236,24 +248,41 @@ static void ip_vs_mh_flush(struct ip_vs_mh_state *s)
static int
ip_vs_mh_reassign(struct ip_vs_mh_state *s, struct ip_vs_service *svc)
{
- int dcnt;
- unsigned int **permutation;
+ int ret;
/* flush all the hash entry before assigning mh entry */
ip_vs_mh_flush(s);
- /* if destination number is zero, skip mh assign */
- dcnt = svc->num_dests;
- if (dcnt <= 0)
- return 0;
+ /* ip_vs_mh_reassign is responsible for assigning
+ * and releasing s->permutation table
+ */
+ s->permutation = kcalloc(IP_VS_MH_TAB_SIZE, sizeof(unsigned int *),
+ GFP_KERNEL);
+ if (!s->permutation)
+ return -ENOMEM;
- permutation = ip_vs_mh_permutate(s, svc);
- ip_vs_mh_populate(s, svc, permutation);
+ s->permutation[0] = kcalloc(IP_VS_MH_TAB_SIZE * IP_VS_MH_LOOKUP_SIZE,
+ sizeof(unsigned int), GFP_KERNEL);
+ if (!s->permutation[0]) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
- kfree(permutation[0]);
- kfree(permutation);
+ ret = ip_vs_mh_permutate(s, svc);
+ if (ret < 0)
+ goto err_out;
+
+ ret = ip_vs_mh_populate(s, svc);
+ if (ret < 0)
+ goto err_out;
return 0;
+
+err_out:
+ kfree(s->permutation[0]);
+err_alloc:
+ kfree(s->permutation);
+ return ret;
}
static int ip_vs_mh_init_svc(struct ip_vs_service *svc)
--
1.8.3.1
--
Inju Song
NAVER Corporation
--
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
|