diff -NurpP linux-3.7-vs2.3.5.1/include/linux/vs_inet.h linux-3.7-vs2.3.5.1.1/include/linux/vs_inet.h --- linux-3.7-vs2.3.5.1/include/linux/vs_inet.h 2012-12-11 15:56:32.000000000 +0000 +++ linux-3.7-vs2.3.5.1.1/include/linux/vs_inet.h 2012-12-13 12:52:33.000000000 +0000 @@ -81,12 +81,15 @@ int v4_addr_in_nx_info(struct nx_info *n (nxi->v4_bcast.s_addr == addr)) goto out; ret = 5; + /* check for v4 addresses */ + spin_lock(&nxi->addr_lock); for (nxa = &nxi->v4; nxa; nxa = nxa->next) if (v4_addr_match(nxa, addr, tmask)) goto out; ret = 0; out: + spin_unlock(&nxi->addr_lock); vxdprintk(VXD_CBIT(net, 0), "v4_addr_in_nx_info(%p[#%u]," NIPQUAD_FMT ",%04x) = %d", nxi, nxi ? nxi->nx_id : 0, NIPQUAD(addr), tmask, ret); @@ -104,11 +107,16 @@ static inline int v4_nx_addr_in_nx_info(struct nx_info *nxi, struct nx_addr_v4 *nxa, uint16_t mask) { struct nx_addr_v4 *ptr; + int ret = 1; + spin_lock(&nxi->addr_lock); for (ptr = &nxi->v4; ptr; ptr = ptr->next) if (v4_nx_addr_match(ptr, nxa, mask)) - return 1; - return 0; + goto out; + ret = 0; +out: + spin_unlock(&nxi->addr_lock); + return ret; } #include diff -NurpP linux-3.7-vs2.3.5.1/include/linux/vs_inet6.h linux-3.7-vs2.3.5.1.1/include/linux/vs_inet6.h --- linux-3.7-vs2.3.5.1/include/linux/vs_inet6.h 2012-12-11 15:56:32.000000000 +0000 +++ linux-3.7-vs2.3.5.1.1/include/linux/vs_inet6.h 2012-12-13 12:52:39.000000000 +0000 @@ -45,11 +45,14 @@ int v6_addr_in_nx_info(struct nx_info *n if (!nxi) goto out; + + spin_lock(&nxi->addr_lock); for (nxa = &nxi->v6; nxa; nxa = nxa->next) if (v6_addr_match(nxa, addr, mask)) goto out; ret = 0; out: + spin_unlock(&nxi->addr_lock); vxdprintk(VXD_CBIT(net, 0), "v6_addr_in_nx_info(%p[#%u],%pI6,%04x) = %d", nxi, nxi ? nxi->nx_id : 0, addr, mask, ret); @@ -67,11 +70,16 @@ static inline int v6_nx_addr_in_nx_info(struct nx_info *nxi, struct nx_addr_v6 *nxa, uint16_t mask) { struct nx_addr_v6 *ptr; + int ret = 1; + spin_lock(&nxi->addr_lock); for (ptr = &nxi->v6; ptr; ptr = ptr->next) if (v6_nx_addr_match(ptr, nxa, mask)) - return 1; - return 0; + goto out; + ret = 0; +out: + spin_unlock(&nxi->addr_lock); + return ret; } diff -NurpP linux-3.7-vs2.3.5.1/include/linux/vserver/network.h linux-3.7-vs2.3.5.1.1/include/linux/vserver/network.h --- linux-3.7-vs2.3.5.1/include/linux/vserver/network.h 2012-12-11 15:56:32.000000000 +0000 +++ linux-3.7-vs2.3.5.1.1/include/linux/vserver/network.h 2012-12-13 13:40:52.000000000 +0000 @@ -109,6 +109,7 @@ struct nx_info { uint64_t nx_flags; /* network flag word */ uint64_t nx_ncaps; /* network capabilities */ + spinlock_t addr_lock; /* protect address changes */ struct in_addr v4_lback; /* Loopback address */ struct in_addr v4_bcast; /* Broadcast address */ struct nx_addr_v4 v4; /* First/Single ipv4 address */ diff -NurpP linux-3.7-vs2.3.5.1/kernel/vserver/network.c linux-3.7-vs2.3.5.1.1/kernel/vserver/network.c --- linux-3.7-vs2.3.5.1/kernel/vserver/network.c 2012-12-11 15:56:33.000000000 +0000 +++ linux-3.7-vs2.3.5.1.1/kernel/vserver/network.c 2012-12-13 13:48:35.000000000 +0000 @@ -131,6 +131,7 @@ static struct nx_info *__alloc_nx_info(n INIT_HLIST_NODE(&new->nx_hlist); atomic_set(&new->nx_usecnt, 0); atomic_set(&new->nx_tasks, 0); + spin_lock_init(&new->addr_lock); new->nx_state = 0; new->nx_flags = NXF_INIT_SET; @@ -593,26 +597,31 @@ int do_add_v4_addr(struct nx_info *nxi, uint16_t type, uint16_t flags) { struct nx_addr_v4 *nxa = &nxi->v4; + struct nx_addr_v4 *new = __alloc_nx_addr_v4(); + + if (IS_ERR(new)) + return PTR_ERR(new); + spin_lock(&nxi->addr_lock); if (NX_IPV4(nxi)) { /* locate last entry */ for (; nxa->next; nxa = nxa->next); - nxa->next = __alloc_nx_addr_v4(); - nxa = nxa->next; - - if (IS_ERR(nxa)) - return PTR_ERR(nxa); - } + nxa->next = new; + nxa = new; + new = NULL; - if (nxi->v4.next) /* remove single ip for ip list */ nxi->nx_flags &= ~NXF_SINGLE_IP; + } nxa->ip[0].s_addr = ip; nxa->ip[1].s_addr = ip2; nxa->mask.s_addr = mask; nxa->type = type; nxa->flags = flags; + spin_unlock(&nxi->addr_lock); + if (new) + __dealloc_nx_addr_v4(new); return 0; } @@ -620,20 +629,25 @@ int do_remove_v4_addr(struct nx_info *nx uint16_t type, uint16_t flags) { struct nx_addr_v4 *nxa = &nxi->v4; + struct nx_addr_v4 *old = NULL; + int ret = 0; + spin_lock(&nxi->addr_lock); switch (type) { /* case NXA_TYPE_ADDR: break; */ case NXA_TYPE_ANY: - __dealloc_nx_addr_v4_all(xchg(&nxa->next, NULL)); + old = xchg(&nxa->next, NULL); memset(nxa, 0, sizeof(*nxa)); break; default: - return -EINVAL; + ret = -EINVAL; } - return 0; + spin_unlock(&nxi->addr_lock); + __dealloc_nx_addr_v4_all(old); + return ret; } @@ -687,10 +701,7 @@ int vc_net_remove(struct nx_info *nxi, v switch (vc_data.type) { case NXA_TYPE_ANY: - __dealloc_nx_addr_v4_all(xchg(&nxi->v4.next, NULL)); - memset(&nxi->v4, 0, sizeof(nxi->v4)); - break; - + return do_remove_v4_addr(nxi, 0, 0, 0, vc_data.type, 0); default: return -EINVAL; } @@ -782,15 +793,18 @@ int do_add_v6_addr(struct nx_info *nxi, uint32_t prefix, uint16_t type, uint16_t flags) { struct nx_addr_v6 *nxa = &nxi->v6; + struct nx_addr_v6 *new = __alloc_nx_addr_v6(); + if (IS_ERR(new)) + return PTR_ERR(new); + + spin_lock(&nxi->addr_lock); if (NX_IPV6(nxi)) { /* locate last entry */ for (; nxa->next; nxa = nxa->next); - nxa->next = __alloc_nx_addr_v6(); - nxa = nxa->next; - - if (IS_ERR(nxa)) - return PTR_ERR(nxa); + nxa->next = new; + nxa = new; + new = NULL; } nxa->ip = *ip; @@ -798,6 +812,9 @@ int do_add_v6_addr(struct nx_info *nxi, nxa->prefix = prefix; nxa->type = type; nxa->flags = flags; + spin_unlock(&nxi->addr_lock); + if (new) + __dealloc_nx_addr_v6(new); return 0; }