[NETNS][FRAGS]: Duplicate sysctl tables for new namespaces.

Each namespace has to have own tables to tune their
different parameters, so duplicate the tables and
register them.

All the tables in sub-namespaces are temporarily made
read-only.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 4f01334..c51e1a1 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -661,17 +661,53 @@
 
 static int ip4_frags_ctl_register(struct net *net)
 {
+	struct ctl_table *table;
 	struct ctl_table_header *hdr;
 
-	hdr = register_net_sysctl_table(net, net_ipv4_ctl_path,
-			ip4_frags_ctl_table);
-	return hdr == NULL ? -ENOMEM : 0;
+	table = ip4_frags_ctl_table;
+	if (net != &init_net) {
+		table = kmemdup(table, sizeof(ip4_frags_ctl_table), GFP_KERNEL);
+		if (table == NULL)
+			goto err_alloc;
+
+		table[0].mode &= ~0222;
+		table[1].mode &= ~0222;
+		table[2].mode &= ~0222;
+		table[3].mode &= ~0222;
+		table[4].mode &= ~0222;
+	}
+
+	hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table);
+	if (hdr == NULL)
+		goto err_reg;
+
+	net->ipv4.frags_hdr = hdr;
+	return 0;
+
+err_reg:
+	if (net != &init_net)
+		kfree(table);
+err_alloc:
+	return -ENOMEM;
+}
+
+static void ip4_frags_ctl_unregister(struct net *net)
+{
+	struct ctl_table *table;
+
+	table = net->ipv4.frags_hdr->ctl_table_arg;
+	unregister_net_sysctl_table(net->ipv4.frags_hdr);
+	kfree(table);
 }
 #else
 static inline int ip4_frags_ctl_register(struct net *net)
 {
 	return 0;
 }
+
+static inline void ip4_frags_ctl_unregister(struct net *net)
+{
+}
 #endif
 
 static int ipv4_frags_init_net(struct net *net)