1 |
commit: 516de23c184688cd1071c1c815fbb2e9827612ad |
2 |
Author: Mike Pagano <mpagano <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sat Oct 3 16:07:16 2015 +0000 |
4 |
Commit: Mike Pagano <mpagano <AT> gentoo <DOT> org> |
5 |
CommitDate: Sat Oct 3 16:07:16 2015 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=516de23c |
7 |
|
8 |
Linux patch 4.1.10 |
9 |
|
10 |
0000_README | 4 + |
11 |
1009_linux-4.1.10.patch | 1353 +++++++++++++++++++++++++++++++++++++++++++++++ |
12 |
2 files changed, 1357 insertions(+) |
13 |
|
14 |
diff --git a/0000_README b/0000_README |
15 |
index 348e8f5..b9b941a 100644 |
16 |
--- a/0000_README |
17 |
+++ b/0000_README |
18 |
@@ -79,6 +79,10 @@ Patch: 1008_linux-4.1.9.patch |
19 |
From: http://www.kernel.org |
20 |
Desc: Linux 4.1.9 |
21 |
|
22 |
+Patch: 1009_linux-4.1.10.patch |
23 |
+From: http://www.kernel.org |
24 |
+Desc: Linux 4.1.10 |
25 |
+ |
26 |
Patch: 1500_XATTR_USER_PREFIX.patch |
27 |
From: https://bugs.gentoo.org/show_bug.cgi?id=470644 |
28 |
Desc: Support for namespace user.pax.* on tmpfs. |
29 |
|
30 |
diff --git a/1009_linux-4.1.10.patch b/1009_linux-4.1.10.patch |
31 |
new file mode 100644 |
32 |
index 0000000..8d80808 |
33 |
--- /dev/null |
34 |
+++ b/1009_linux-4.1.10.patch |
35 |
@@ -0,0 +1,1353 @@ |
36 |
+diff --git a/Documentation/devicetree/bindings/net/ethernet.txt b/Documentation/devicetree/bindings/net/ethernet.txt |
37 |
+index 41b3f3f864e8..5d88f37480b6 100644 |
38 |
+--- a/Documentation/devicetree/bindings/net/ethernet.txt |
39 |
++++ b/Documentation/devicetree/bindings/net/ethernet.txt |
40 |
+@@ -25,7 +25,11 @@ The following properties are common to the Ethernet controllers: |
41 |
+ flow control thresholds. |
42 |
+ - tx-fifo-depth: the size of the controller's transmit fifo in bytes. This |
43 |
+ is used for components that can have configurable fifo sizes. |
44 |
++- managed: string, specifies the PHY management type. Supported values are: |
45 |
++ "auto", "in-band-status". "auto" is the default, it usess MDIO for |
46 |
++ management if fixed-link is not specified. |
47 |
+ |
48 |
+ Child nodes of the Ethernet controller are typically the individual PHY devices |
49 |
+ connected via the MDIO bus (sometimes the MDIO bus controller is separate). |
50 |
+ They are described in the phy.txt file in this same directory. |
51 |
++For non-MDIO PHY management see fixed-link.txt. |
52 |
+diff --git a/Makefile b/Makefile |
53 |
+index e071176b2ce6..d02f16b510dc 100644 |
54 |
+--- a/Makefile |
55 |
++++ b/Makefile |
56 |
+@@ -1,6 +1,6 @@ |
57 |
+ VERSION = 4 |
58 |
+ PATCHLEVEL = 1 |
59 |
+-SUBLEVEL = 9 |
60 |
++SUBLEVEL = 10 |
61 |
+ EXTRAVERSION = |
62 |
+ NAME = Series 4800 |
63 |
+ |
64 |
+diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c |
65 |
+index f1ff39a3d1c1..54d946a9eee6 100644 |
66 |
+--- a/drivers/block/zram/zcomp.c |
67 |
++++ b/drivers/block/zram/zcomp.c |
68 |
+@@ -325,12 +325,14 @@ void zcomp_destroy(struct zcomp *comp) |
69 |
+ * allocate new zcomp and initialize it. return compressing |
70 |
+ * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL) |
71 |
+ * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in |
72 |
+- * case of allocation error. |
73 |
++ * case of allocation error, or any other error potentially |
74 |
++ * returned by functions zcomp_strm_{multi,single}_create. |
75 |
+ */ |
76 |
+ struct zcomp *zcomp_create(const char *compress, int max_strm) |
77 |
+ { |
78 |
+ struct zcomp *comp; |
79 |
+ struct zcomp_backend *backend; |
80 |
++ int error; |
81 |
+ |
82 |
+ backend = find_backend(compress); |
83 |
+ if (!backend) |
84 |
+@@ -342,12 +344,12 @@ struct zcomp *zcomp_create(const char *compress, int max_strm) |
85 |
+ |
86 |
+ comp->backend = backend; |
87 |
+ if (max_strm > 1) |
88 |
+- zcomp_strm_multi_create(comp, max_strm); |
89 |
++ error = zcomp_strm_multi_create(comp, max_strm); |
90 |
+ else |
91 |
+- zcomp_strm_single_create(comp); |
92 |
+- if (!comp->stream) { |
93 |
++ error = zcomp_strm_single_create(comp); |
94 |
++ if (error) { |
95 |
+ kfree(comp); |
96 |
+- return ERR_PTR(-ENOMEM); |
97 |
++ return ERR_PTR(error); |
98 |
+ } |
99 |
+ return comp; |
100 |
+ } |
101 |
+diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c |
102 |
+index cedb572bf25a..db9ebbc1a732 100644 |
103 |
+--- a/drivers/net/dsa/bcm_sf2.c |
104 |
++++ b/drivers/net/dsa/bcm_sf2.c |
105 |
+@@ -417,7 +417,7 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port) |
106 |
+ core_writel(priv, port, CORE_FAST_AGE_PORT); |
107 |
+ |
108 |
+ reg = core_readl(priv, CORE_FAST_AGE_CTRL); |
109 |
+- reg |= EN_AGE_PORT | FAST_AGE_STR_DONE; |
110 |
++ reg |= EN_AGE_PORT | EN_AGE_DYNAMIC | FAST_AGE_STR_DONE; |
111 |
+ core_writel(priv, reg, CORE_FAST_AGE_CTRL); |
112 |
+ |
113 |
+ do { |
114 |
+@@ -431,6 +431,8 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port) |
115 |
+ if (!timeout) |
116 |
+ return -ETIMEDOUT; |
117 |
+ |
118 |
++ core_writel(priv, 0, CORE_FAST_AGE_CTRL); |
119 |
++ |
120 |
+ return 0; |
121 |
+ } |
122 |
+ |
123 |
+@@ -506,7 +508,7 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port, |
124 |
+ u32 reg; |
125 |
+ |
126 |
+ reg = core_readl(priv, CORE_G_PCTL_PORT(port)); |
127 |
+- cur_hw_state = reg >> G_MISTP_STATE_SHIFT; |
128 |
++ cur_hw_state = reg & (G_MISTP_STATE_MASK << G_MISTP_STATE_SHIFT); |
129 |
+ |
130 |
+ switch (state) { |
131 |
+ case BR_STATE_DISABLED: |
132 |
+@@ -530,10 +532,12 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port, |
133 |
+ } |
134 |
+ |
135 |
+ /* Fast-age ARL entries if we are moving a port from Learning or |
136 |
+- * Forwarding state to Disabled, Blocking or Listening state |
137 |
++ * Forwarding (cur_hw_state) state to Disabled, Blocking or Listening |
138 |
++ * state (hw_state) |
139 |
+ */ |
140 |
+ if (cur_hw_state != hw_state) { |
141 |
+- if (cur_hw_state & 4 && !(hw_state & 4)) { |
142 |
++ if (cur_hw_state >= G_MISTP_LEARN_STATE && |
143 |
++ hw_state <= G_MISTP_LISTEN_STATE) { |
144 |
+ ret = bcm_sf2_sw_fast_age_port(ds, port); |
145 |
+ if (ret) { |
146 |
+ pr_err("%s: fast-ageing failed\n", __func__); |
147 |
+@@ -889,15 +893,11 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port, |
148 |
+ struct fixed_phy_status *status) |
149 |
+ { |
150 |
+ struct bcm_sf2_priv *priv = ds_to_priv(ds); |
151 |
+- u32 duplex, pause, speed; |
152 |
++ u32 duplex, pause; |
153 |
+ u32 reg; |
154 |
+ |
155 |
+ duplex = core_readl(priv, CORE_DUPSTS); |
156 |
+ pause = core_readl(priv, CORE_PAUSESTS); |
157 |
+- speed = core_readl(priv, CORE_SPDSTS); |
158 |
+- |
159 |
+- speed >>= (port * SPDSTS_SHIFT); |
160 |
+- speed &= SPDSTS_MASK; |
161 |
+ |
162 |
+ status->link = 0; |
163 |
+ |
164 |
+@@ -925,18 +925,6 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port, |
165 |
+ reg &= ~LINK_STS; |
166 |
+ core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port)); |
167 |
+ |
168 |
+- switch (speed) { |
169 |
+- case SPDSTS_10: |
170 |
+- status->speed = SPEED_10; |
171 |
+- break; |
172 |
+- case SPDSTS_100: |
173 |
+- status->speed = SPEED_100; |
174 |
+- break; |
175 |
+- case SPDSTS_1000: |
176 |
+- status->speed = SPEED_1000; |
177 |
+- break; |
178 |
+- } |
179 |
+- |
180 |
+ if ((pause & (1 << port)) && |
181 |
+ (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) { |
182 |
+ status->asym_pause = 1; |
183 |
+diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h |
184 |
+index 22e2ebf31333..789d7b7737da 100644 |
185 |
+--- a/drivers/net/dsa/bcm_sf2.h |
186 |
++++ b/drivers/net/dsa/bcm_sf2.h |
187 |
+@@ -112,8 +112,8 @@ static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off) \ |
188 |
+ spin_unlock(&priv->indir_lock); \ |
189 |
+ return (u64)indir << 32 | dir; \ |
190 |
+ } \ |
191 |
+-static inline void name##_writeq(struct bcm_sf2_priv *priv, u32 off, \ |
192 |
+- u64 val) \ |
193 |
++static inline void name##_writeq(struct bcm_sf2_priv *priv, u64 val, \ |
194 |
++ u32 off) \ |
195 |
+ { \ |
196 |
+ spin_lock(&priv->indir_lock); \ |
197 |
+ reg_writel(priv, upper_32_bits(val), REG_DIR_DATA_WRITE); \ |
198 |
+diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c |
199 |
+index da48e66377b5..8207877d6237 100644 |
200 |
+--- a/drivers/net/ethernet/altera/altera_tse_main.c |
201 |
++++ b/drivers/net/ethernet/altera/altera_tse_main.c |
202 |
+@@ -511,8 +511,7 @@ static int tse_poll(struct napi_struct *napi, int budget) |
203 |
+ |
204 |
+ if (rxcomplete < budget) { |
205 |
+ |
206 |
+- napi_gro_flush(napi, false); |
207 |
+- __napi_complete(napi); |
208 |
++ napi_complete(napi); |
209 |
+ |
210 |
+ netdev_dbg(priv->dev, |
211 |
+ "NAPI Complete, did %d packets with budget %d\n", |
212 |
+diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c |
213 |
+index 66d47e448e4d..570390b5cd42 100644 |
214 |
+--- a/drivers/net/ethernet/freescale/fec_main.c |
215 |
++++ b/drivers/net/ethernet/freescale/fec_main.c |
216 |
+@@ -1396,6 +1396,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) |
217 |
+ if ((status & BD_ENET_RX_LAST) == 0) |
218 |
+ netdev_err(ndev, "rcv is not +last\n"); |
219 |
+ |
220 |
++ writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT); |
221 |
+ |
222 |
+ /* Check for errors. */ |
223 |
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | |
224 |
+diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c |
225 |
+index 74d0389bf233..4d608f0117cd 100644 |
226 |
+--- a/drivers/net/ethernet/marvell/mvneta.c |
227 |
++++ b/drivers/net/ethernet/marvell/mvneta.c |
228 |
+@@ -3029,8 +3029,8 @@ static int mvneta_probe(struct platform_device *pdev) |
229 |
+ const char *dt_mac_addr; |
230 |
+ char hw_mac_addr[ETH_ALEN]; |
231 |
+ const char *mac_from; |
232 |
++ const char *managed; |
233 |
+ int phy_mode; |
234 |
+- int fixed_phy = 0; |
235 |
+ int err; |
236 |
+ |
237 |
+ /* Our multiqueue support is not complete, so for now, only |
238 |
+@@ -3064,7 +3064,6 @@ static int mvneta_probe(struct platform_device *pdev) |
239 |
+ dev_err(&pdev->dev, "cannot register fixed PHY\n"); |
240 |
+ goto err_free_irq; |
241 |
+ } |
242 |
+- fixed_phy = 1; |
243 |
+ |
244 |
+ /* In the case of a fixed PHY, the DT node associated |
245 |
+ * to the PHY is the Ethernet MAC DT node. |
246 |
+@@ -3088,8 +3087,10 @@ static int mvneta_probe(struct platform_device *pdev) |
247 |
+ pp = netdev_priv(dev); |
248 |
+ pp->phy_node = phy_node; |
249 |
+ pp->phy_interface = phy_mode; |
250 |
+- pp->use_inband_status = (phy_mode == PHY_INTERFACE_MODE_SGMII) && |
251 |
+- fixed_phy; |
252 |
++ |
253 |
++ err = of_property_read_string(dn, "managed", &managed); |
254 |
++ pp->use_inband_status = (err == 0 && |
255 |
++ strcmp(managed, "in-band-status") == 0); |
256 |
+ |
257 |
+ pp->clk = devm_clk_get(&pdev->dev, NULL); |
258 |
+ if (IS_ERR(pp->clk)) { |
259 |
+diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c |
260 |
+index eab4e080ebd2..80aac20104de 100644 |
261 |
+--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c |
262 |
++++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c |
263 |
+@@ -1256,8 +1256,6 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) |
264 |
+ rss_context->hash_fn = MLX4_RSS_HASH_TOP; |
265 |
+ memcpy(rss_context->rss_key, priv->rss_key, |
266 |
+ MLX4_EN_RSS_KEY_SIZE); |
267 |
+- netdev_rss_key_fill(rss_context->rss_key, |
268 |
+- MLX4_EN_RSS_KEY_SIZE); |
269 |
+ } else { |
270 |
+ en_err(priv, "Unknown RSS hash function requested\n"); |
271 |
+ err = -EINVAL; |
272 |
+diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c |
273 |
+index 8c350c5d54ad..58858c5589db 100644 |
274 |
+--- a/drivers/net/macvtap.c |
275 |
++++ b/drivers/net/macvtap.c |
276 |
+@@ -1054,10 +1054,10 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, |
277 |
+ return 0; |
278 |
+ |
279 |
+ case TUNSETSNDBUF: |
280 |
+- if (get_user(u, up)) |
281 |
++ if (get_user(s, sp)) |
282 |
+ return -EFAULT; |
283 |
+ |
284 |
+- q->sk.sk_sndbuf = u; |
285 |
++ q->sk.sk_sndbuf = s; |
286 |
+ return 0; |
287 |
+ |
288 |
+ case TUNGETVNETHDRSZ: |
289 |
+diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c |
290 |
+index 1960b46add65..479b93f9581c 100644 |
291 |
+--- a/drivers/net/phy/fixed_phy.c |
292 |
++++ b/drivers/net/phy/fixed_phy.c |
293 |
+@@ -52,6 +52,10 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) |
294 |
+ u16 lpagb = 0; |
295 |
+ u16 lpa = 0; |
296 |
+ |
297 |
++ if (!fp->status.link) |
298 |
++ goto done; |
299 |
++ bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; |
300 |
++ |
301 |
+ if (fp->status.duplex) { |
302 |
+ bmcr |= BMCR_FULLDPLX; |
303 |
+ |
304 |
+@@ -96,15 +100,13 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) |
305 |
+ } |
306 |
+ } |
307 |
+ |
308 |
+- if (fp->status.link) |
309 |
+- bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; |
310 |
+- |
311 |
+ if (fp->status.pause) |
312 |
+ lpa |= LPA_PAUSE_CAP; |
313 |
+ |
314 |
+ if (fp->status.asym_pause) |
315 |
+ lpa |= LPA_PAUSE_ASYM; |
316 |
+ |
317 |
++done: |
318 |
+ fp->regs[MII_PHYSID1] = 0; |
319 |
+ fp->regs[MII_PHYSID2] = 0; |
320 |
+ |
321 |
+diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c |
322 |
+index 3c86b107275a..e0498571ae26 100644 |
323 |
+--- a/drivers/net/usb/usbnet.c |
324 |
++++ b/drivers/net/usb/usbnet.c |
325 |
+@@ -778,7 +778,7 @@ int usbnet_stop (struct net_device *net) |
326 |
+ { |
327 |
+ struct usbnet *dev = netdev_priv(net); |
328 |
+ struct driver_info *info = dev->driver_info; |
329 |
+- int retval, pm; |
330 |
++ int retval, pm, mpn; |
331 |
+ |
332 |
+ clear_bit(EVENT_DEV_OPEN, &dev->flags); |
333 |
+ netif_stop_queue (net); |
334 |
+@@ -809,6 +809,8 @@ int usbnet_stop (struct net_device *net) |
335 |
+ |
336 |
+ usbnet_purge_paused_rxq(dev); |
337 |
+ |
338 |
++ mpn = !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags); |
339 |
++ |
340 |
+ /* deferred work (task, timer, softirq) must also stop. |
341 |
+ * can't flush_scheduled_work() until we drop rtnl (later), |
342 |
+ * else workers could deadlock; so make workers a NOP. |
343 |
+@@ -819,8 +821,7 @@ int usbnet_stop (struct net_device *net) |
344 |
+ if (!pm) |
345 |
+ usb_autopm_put_interface(dev->intf); |
346 |
+ |
347 |
+- if (info->manage_power && |
348 |
+- !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags)) |
349 |
++ if (info->manage_power && mpn) |
350 |
+ info->manage_power(dev, 0); |
351 |
+ else |
352 |
+ usb_autopm_put_interface(dev->intf); |
353 |
+diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c |
354 |
+index 21a0fbf1ed94..0085b8df83e2 100644 |
355 |
+--- a/drivers/net/vxlan.c |
356 |
++++ b/drivers/net/vxlan.c |
357 |
+@@ -2212,6 +2212,8 @@ static int vxlan_open(struct net_device *dev) |
358 |
+ |
359 |
+ if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip)) { |
360 |
+ ret = vxlan_igmp_join(vxlan); |
361 |
++ if (ret == -EADDRINUSE) |
362 |
++ ret = 0; |
363 |
+ if (ret) { |
364 |
+ vxlan_sock_release(vs); |
365 |
+ return ret; |
366 |
+diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c |
367 |
+index 0c064485d1c2..bec8ec2b31f6 100644 |
368 |
+--- a/drivers/of/of_mdio.c |
369 |
++++ b/drivers/of/of_mdio.c |
370 |
+@@ -263,7 +263,8 @@ EXPORT_SYMBOL(of_phy_attach); |
371 |
+ bool of_phy_is_fixed_link(struct device_node *np) |
372 |
+ { |
373 |
+ struct device_node *dn; |
374 |
+- int len; |
375 |
++ int len, err; |
376 |
++ const char *managed; |
377 |
+ |
378 |
+ /* New binding */ |
379 |
+ dn = of_get_child_by_name(np, "fixed-link"); |
380 |
+@@ -272,6 +273,10 @@ bool of_phy_is_fixed_link(struct device_node *np) |
381 |
+ return true; |
382 |
+ } |
383 |
+ |
384 |
++ err = of_property_read_string(np, "managed", &managed); |
385 |
++ if (err == 0 && strcmp(managed, "auto") != 0) |
386 |
++ return true; |
387 |
++ |
388 |
+ /* Old binding */ |
389 |
+ if (of_get_property(np, "fixed-link", &len) && |
390 |
+ len == (5 * sizeof(__be32))) |
391 |
+@@ -286,8 +291,18 @@ int of_phy_register_fixed_link(struct device_node *np) |
392 |
+ struct fixed_phy_status status = {}; |
393 |
+ struct device_node *fixed_link_node; |
394 |
+ const __be32 *fixed_link_prop; |
395 |
+- int len; |
396 |
++ int len, err; |
397 |
+ struct phy_device *phy; |
398 |
++ const char *managed; |
399 |
++ |
400 |
++ err = of_property_read_string(np, "managed", &managed); |
401 |
++ if (err == 0) { |
402 |
++ if (strcmp(managed, "in-band-status") == 0) { |
403 |
++ /* status is zeroed, namely its .link member */ |
404 |
++ phy = fixed_phy_register(PHY_POLL, &status, np); |
405 |
++ return IS_ERR(phy) ? PTR_ERR(phy) : 0; |
406 |
++ } |
407 |
++ } |
408 |
+ |
409 |
+ /* New binding */ |
410 |
+ fixed_link_node = of_get_child_by_name(np, "fixed-link"); |
411 |
+diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c |
412 |
+index 06697315a088..fb4dd7b3ee71 100644 |
413 |
+--- a/drivers/platform/x86/hp-wmi.c |
414 |
++++ b/drivers/platform/x86/hp-wmi.c |
415 |
+@@ -54,8 +54,9 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); |
416 |
+ #define HPWMI_HARDWARE_QUERY 0x4 |
417 |
+ #define HPWMI_WIRELESS_QUERY 0x5 |
418 |
+ #define HPWMI_BIOS_QUERY 0x9 |
419 |
++#define HPWMI_FEATURE_QUERY 0xb |
420 |
+ #define HPWMI_HOTKEY_QUERY 0xc |
421 |
+-#define HPWMI_FEATURE_QUERY 0xd |
422 |
++#define HPWMI_FEATURE2_QUERY 0xd |
423 |
+ #define HPWMI_WIRELESS2_QUERY 0x1b |
424 |
+ #define HPWMI_POSTCODEERROR_QUERY 0x2a |
425 |
+ |
426 |
+@@ -295,25 +296,33 @@ static int hp_wmi_tablet_state(void) |
427 |
+ return (state & 0x4) ? 1 : 0; |
428 |
+ } |
429 |
+ |
430 |
+-static int __init hp_wmi_bios_2009_later(void) |
431 |
++static int __init hp_wmi_bios_2008_later(void) |
432 |
+ { |
433 |
+ int state = 0; |
434 |
+ int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state, |
435 |
+ sizeof(state), sizeof(state)); |
436 |
+- if (ret) |
437 |
+- return ret; |
438 |
++ if (!ret) |
439 |
++ return 1; |
440 |
+ |
441 |
+- return (state & 0x10) ? 1 : 0; |
442 |
++ return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO; |
443 |
+ } |
444 |
+ |
445 |
+-static int hp_wmi_enable_hotkeys(void) |
446 |
++static int __init hp_wmi_bios_2009_later(void) |
447 |
+ { |
448 |
+- int ret; |
449 |
+- int query = 0x6e; |
450 |
++ int state = 0; |
451 |
++ int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, 0, &state, |
452 |
++ sizeof(state), sizeof(state)); |
453 |
++ if (!ret) |
454 |
++ return 1; |
455 |
+ |
456 |
+- ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query), |
457 |
+- 0); |
458 |
++ return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO; |
459 |
++} |
460 |
+ |
461 |
++static int __init hp_wmi_enable_hotkeys(void) |
462 |
++{ |
463 |
++ int value = 0x6e; |
464 |
++ int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &value, |
465 |
++ sizeof(value), 0); |
466 |
+ if (ret) |
467 |
+ return -EINVAL; |
468 |
+ return 0; |
469 |
+@@ -663,7 +672,7 @@ static int __init hp_wmi_input_setup(void) |
470 |
+ hp_wmi_tablet_state()); |
471 |
+ input_sync(hp_wmi_input_dev); |
472 |
+ |
473 |
+- if (hp_wmi_bios_2009_later() == 4) |
474 |
++ if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later()) |
475 |
+ hp_wmi_enable_hotkeys(); |
476 |
+ |
477 |
+ status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); |
478 |
+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c |
479 |
+index ff667e18b2d6..9ba383f5b0c4 100644 |
480 |
+--- a/net/bridge/br_multicast.c |
481 |
++++ b/net/bridge/br_multicast.c |
482 |
+@@ -980,7 +980,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br, |
483 |
+ |
484 |
+ ih = igmpv3_report_hdr(skb); |
485 |
+ num = ntohs(ih->ngrec); |
486 |
+- len = sizeof(*ih); |
487 |
++ len = skb_transport_offset(skb) + sizeof(*ih); |
488 |
+ |
489 |
+ for (i = 0; i < num; i++) { |
490 |
+ len += sizeof(*grec); |
491 |
+@@ -1035,7 +1035,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br, |
492 |
+ |
493 |
+ icmp6h = icmp6_hdr(skb); |
494 |
+ num = ntohs(icmp6h->icmp6_dataun.un_data16[1]); |
495 |
+- len = sizeof(*icmp6h); |
496 |
++ len = skb_transport_offset(skb) + sizeof(*icmp6h); |
497 |
+ |
498 |
+ for (i = 0; i < num; i++) { |
499 |
+ __be16 *nsrcs, _nsrcs; |
500 |
+diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c |
501 |
+index 9a12668f7d62..0ad144fb0c79 100644 |
502 |
+--- a/net/core/fib_rules.c |
503 |
++++ b/net/core/fib_rules.c |
504 |
+@@ -615,15 +615,17 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb, |
505 |
+ { |
506 |
+ int idx = 0; |
507 |
+ struct fib_rule *rule; |
508 |
++ int err = 0; |
509 |
+ |
510 |
+ rcu_read_lock(); |
511 |
+ list_for_each_entry_rcu(rule, &ops->rules_list, list) { |
512 |
+ if (idx < cb->args[1]) |
513 |
+ goto skip; |
514 |
+ |
515 |
+- if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid, |
516 |
+- cb->nlh->nlmsg_seq, RTM_NEWRULE, |
517 |
+- NLM_F_MULTI, ops) < 0) |
518 |
++ err = fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid, |
519 |
++ cb->nlh->nlmsg_seq, RTM_NEWRULE, |
520 |
++ NLM_F_MULTI, ops); |
521 |
++ if (err) |
522 |
+ break; |
523 |
+ skip: |
524 |
+ idx++; |
525 |
+@@ -632,7 +634,7 @@ skip: |
526 |
+ cb->args[1] = idx; |
527 |
+ rules_ops_put(ops); |
528 |
+ |
529 |
+- return skb->len; |
530 |
++ return err; |
531 |
+ } |
532 |
+ |
533 |
+ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb) |
534 |
+@@ -648,7 +650,9 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb) |
535 |
+ if (ops == NULL) |
536 |
+ return -EAFNOSUPPORT; |
537 |
+ |
538 |
+- return dump_rules(skb, cb, ops); |
539 |
++ dump_rules(skb, cb, ops); |
540 |
++ |
541 |
++ return skb->len; |
542 |
+ } |
543 |
+ |
544 |
+ rcu_read_lock(); |
545 |
+diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c |
546 |
+index 74dddf84adcd..556ecf96a385 100644 |
547 |
+--- a/net/core/sock_diag.c |
548 |
++++ b/net/core/sock_diag.c |
549 |
+@@ -86,6 +86,9 @@ int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk, |
550 |
+ goto out; |
551 |
+ |
552 |
+ fprog = filter->prog->orig_prog; |
553 |
++ if (!fprog) |
554 |
++ goto out; |
555 |
++ |
556 |
+ flen = bpf_classic_proglen(fprog); |
557 |
+ |
558 |
+ attr = nla_reserve(skb, attrtype, flen); |
559 |
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c |
560 |
+index a369e8a70b2c..986440b24978 100644 |
561 |
+--- a/net/ipv4/tcp_output.c |
562 |
++++ b/net/ipv4/tcp_output.c |
563 |
+@@ -2893,6 +2893,7 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority) |
564 |
+ skb_reserve(skb, MAX_TCP_HEADER); |
565 |
+ tcp_init_nondata_skb(skb, tcp_acceptable_seq(sk), |
566 |
+ TCPHDR_ACK | TCPHDR_RST); |
567 |
++ skb_mstamp_get(&skb->skb_mstamp); |
568 |
+ /* Send it off. */ |
569 |
+ if (tcp_transmit_skb(sk, skb, 0, priority)) |
570 |
+ NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED); |
571 |
+diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c |
572 |
+index 447a7fbd1bb6..f5e2ba1c18bf 100644 |
573 |
+--- a/net/ipv6/exthdrs_offload.c |
574 |
++++ b/net/ipv6/exthdrs_offload.c |
575 |
+@@ -36,6 +36,6 @@ out: |
576 |
+ return ret; |
577 |
+ |
578 |
+ out_rt: |
579 |
+- inet_del_offload(&rthdr_offload, IPPROTO_ROUTING); |
580 |
++ inet6_del_offload(&rthdr_offload, IPPROTO_ROUTING); |
581 |
+ goto out; |
582 |
+ } |
583 |
+diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c |
584 |
+index a38d3ac0f18f..69f4f689f06a 100644 |
585 |
+--- a/net/ipv6/ip6_gre.c |
586 |
++++ b/net/ipv6/ip6_gre.c |
587 |
+@@ -361,6 +361,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev) |
588 |
+ struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); |
589 |
+ |
590 |
+ ip6gre_tunnel_unlink(ign, t); |
591 |
++ ip6_tnl_dst_reset(t); |
592 |
+ dev_put(dev); |
593 |
+ } |
594 |
+ |
595 |
+diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c |
596 |
+index 74ceb73c1c9a..5f36266b1f5e 100644 |
597 |
+--- a/net/ipv6/ip6mr.c |
598 |
++++ b/net/ipv6/ip6mr.c |
599 |
+@@ -550,7 +550,7 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) |
600 |
+ |
601 |
+ if (it->cache == &mrt->mfc6_unres_queue) |
602 |
+ spin_unlock_bh(&mfc_unres_lock); |
603 |
+- else if (it->cache == mrt->mfc6_cache_array) |
604 |
++ else if (it->cache == &mrt->mfc6_cache_array[it->ct]) |
605 |
+ read_unlock(&mrt_lock); |
606 |
+ } |
607 |
+ |
608 |
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c |
609 |
+index c73ae5039e46..f371fefa7fdc 100644 |
610 |
+--- a/net/ipv6/route.c |
611 |
++++ b/net/ipv6/route.c |
612 |
+@@ -1515,7 +1515,7 @@ static int ip6_convert_metrics(struct mx6_config *mxc, |
613 |
+ return -EINVAL; |
614 |
+ } |
615 |
+ |
616 |
+-int ip6_route_add(struct fib6_config *cfg) |
617 |
++int ip6_route_info_create(struct fib6_config *cfg, struct rt6_info **rt_ret) |
618 |
+ { |
619 |
+ int err; |
620 |
+ struct net *net = cfg->fc_nlinfo.nl_net; |
621 |
+@@ -1523,7 +1523,6 @@ int ip6_route_add(struct fib6_config *cfg) |
622 |
+ struct net_device *dev = NULL; |
623 |
+ struct inet6_dev *idev = NULL; |
624 |
+ struct fib6_table *table; |
625 |
+- struct mx6_config mxc = { .mx = NULL, }; |
626 |
+ int addr_type; |
627 |
+ |
628 |
+ if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) |
629 |
+@@ -1719,6 +1718,32 @@ install_route: |
630 |
+ |
631 |
+ cfg->fc_nlinfo.nl_net = dev_net(dev); |
632 |
+ |
633 |
++ *rt_ret = rt; |
634 |
++ |
635 |
++ return 0; |
636 |
++out: |
637 |
++ if (dev) |
638 |
++ dev_put(dev); |
639 |
++ if (idev) |
640 |
++ in6_dev_put(idev); |
641 |
++ if (rt) |
642 |
++ dst_free(&rt->dst); |
643 |
++ |
644 |
++ *rt_ret = NULL; |
645 |
++ |
646 |
++ return err; |
647 |
++} |
648 |
++ |
649 |
++int ip6_route_add(struct fib6_config *cfg) |
650 |
++{ |
651 |
++ struct mx6_config mxc = { .mx = NULL, }; |
652 |
++ struct rt6_info *rt = NULL; |
653 |
++ int err; |
654 |
++ |
655 |
++ err = ip6_route_info_create(cfg, &rt); |
656 |
++ if (err) |
657 |
++ goto out; |
658 |
++ |
659 |
+ err = ip6_convert_metrics(&mxc, cfg); |
660 |
+ if (err) |
661 |
+ goto out; |
662 |
+@@ -1726,14 +1751,12 @@ install_route: |
663 |
+ err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc); |
664 |
+ |
665 |
+ kfree(mxc.mx); |
666 |
++ |
667 |
+ return err; |
668 |
+ out: |
669 |
+- if (dev) |
670 |
+- dev_put(dev); |
671 |
+- if (idev) |
672 |
+- in6_dev_put(idev); |
673 |
+ if (rt) |
674 |
+ dst_free(&rt->dst); |
675 |
++ |
676 |
+ return err; |
677 |
+ } |
678 |
+ |
679 |
+@@ -2496,19 +2519,78 @@ errout: |
680 |
+ return err; |
681 |
+ } |
682 |
+ |
683 |
+-static int ip6_route_multipath(struct fib6_config *cfg, int add) |
684 |
++struct rt6_nh { |
685 |
++ struct rt6_info *rt6_info; |
686 |
++ struct fib6_config r_cfg; |
687 |
++ struct mx6_config mxc; |
688 |
++ struct list_head next; |
689 |
++}; |
690 |
++ |
691 |
++static void ip6_print_replace_route_err(struct list_head *rt6_nh_list) |
692 |
++{ |
693 |
++ struct rt6_nh *nh; |
694 |
++ |
695 |
++ list_for_each_entry(nh, rt6_nh_list, next) { |
696 |
++ pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6 nexthop %pI6 ifi %d\n", |
697 |
++ &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway, |
698 |
++ nh->r_cfg.fc_ifindex); |
699 |
++ } |
700 |
++} |
701 |
++ |
702 |
++static int ip6_route_info_append(struct list_head *rt6_nh_list, |
703 |
++ struct rt6_info *rt, struct fib6_config *r_cfg) |
704 |
++{ |
705 |
++ struct rt6_nh *nh; |
706 |
++ struct rt6_info *rtnh; |
707 |
++ int err = -EEXIST; |
708 |
++ |
709 |
++ list_for_each_entry(nh, rt6_nh_list, next) { |
710 |
++ /* check if rt6_info already exists */ |
711 |
++ rtnh = nh->rt6_info; |
712 |
++ |
713 |
++ if (rtnh->dst.dev == rt->dst.dev && |
714 |
++ rtnh->rt6i_idev == rt->rt6i_idev && |
715 |
++ ipv6_addr_equal(&rtnh->rt6i_gateway, |
716 |
++ &rt->rt6i_gateway)) |
717 |
++ return err; |
718 |
++ } |
719 |
++ |
720 |
++ nh = kzalloc(sizeof(*nh), GFP_KERNEL); |
721 |
++ if (!nh) |
722 |
++ return -ENOMEM; |
723 |
++ nh->rt6_info = rt; |
724 |
++ err = ip6_convert_metrics(&nh->mxc, r_cfg); |
725 |
++ if (err) { |
726 |
++ kfree(nh); |
727 |
++ return err; |
728 |
++ } |
729 |
++ memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg)); |
730 |
++ list_add_tail(&nh->next, rt6_nh_list); |
731 |
++ |
732 |
++ return 0; |
733 |
++} |
734 |
++ |
735 |
++static int ip6_route_multipath_add(struct fib6_config *cfg) |
736 |
+ { |
737 |
+ struct fib6_config r_cfg; |
738 |
+ struct rtnexthop *rtnh; |
739 |
++ struct rt6_info *rt; |
740 |
++ struct rt6_nh *err_nh; |
741 |
++ struct rt6_nh *nh, *nh_safe; |
742 |
+ int remaining; |
743 |
+ int attrlen; |
744 |
+- int err = 0, last_err = 0; |
745 |
++ int err = 1; |
746 |
++ int nhn = 0; |
747 |
++ int replace = (cfg->fc_nlinfo.nlh && |
748 |
++ (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE)); |
749 |
++ LIST_HEAD(rt6_nh_list); |
750 |
+ |
751 |
+ remaining = cfg->fc_mp_len; |
752 |
+-beginning: |
753 |
+ rtnh = (struct rtnexthop *)cfg->fc_mp; |
754 |
+ |
755 |
+- /* Parse a Multipath Entry */ |
756 |
++ /* Parse a Multipath Entry and build a list (rt6_nh_list) of |
757 |
++ * rt6_info structs per nexthop |
758 |
++ */ |
759 |
+ while (rtnh_ok(rtnh, remaining)) { |
760 |
+ memcpy(&r_cfg, cfg, sizeof(*cfg)); |
761 |
+ if (rtnh->rtnh_ifindex) |
762 |
+@@ -2524,22 +2606,32 @@ beginning: |
763 |
+ r_cfg.fc_flags |= RTF_GATEWAY; |
764 |
+ } |
765 |
+ } |
766 |
+- err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg); |
767 |
++ |
768 |
++ err = ip6_route_info_create(&r_cfg, &rt); |
769 |
++ if (err) |
770 |
++ goto cleanup; |
771 |
++ |
772 |
++ err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg); |
773 |
+ if (err) { |
774 |
+- last_err = err; |
775 |
+- /* If we are trying to remove a route, do not stop the |
776 |
+- * loop when ip6_route_del() fails (because next hop is |
777 |
+- * already gone), we should try to remove all next hops. |
778 |
+- */ |
779 |
+- if (add) { |
780 |
+- /* If add fails, we should try to delete all |
781 |
+- * next hops that have been already added. |
782 |
+- */ |
783 |
+- add = 0; |
784 |
+- remaining = cfg->fc_mp_len - remaining; |
785 |
+- goto beginning; |
786 |
+- } |
787 |
++ dst_free(&rt->dst); |
788 |
++ goto cleanup; |
789 |
++ } |
790 |
++ |
791 |
++ rtnh = rtnh_next(rtnh, &remaining); |
792 |
++ } |
793 |
++ |
794 |
++ err_nh = NULL; |
795 |
++ list_for_each_entry(nh, &rt6_nh_list, next) { |
796 |
++ err = __ip6_ins_rt(nh->rt6_info, &cfg->fc_nlinfo, &nh->mxc); |
797 |
++ /* nh->rt6_info is used or freed at this point, reset to NULL*/ |
798 |
++ nh->rt6_info = NULL; |
799 |
++ if (err) { |
800 |
++ if (replace && nhn) |
801 |
++ ip6_print_replace_route_err(&rt6_nh_list); |
802 |
++ err_nh = nh; |
803 |
++ goto add_errout; |
804 |
+ } |
805 |
++ |
806 |
+ /* Because each route is added like a single route we remove |
807 |
+ * these flags after the first nexthop: if there is a collision, |
808 |
+ * we have already failed to add the first nexthop: |
809 |
+@@ -2549,6 +2641,63 @@ beginning: |
810 |
+ */ |
811 |
+ cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL | |
812 |
+ NLM_F_REPLACE); |
813 |
++ nhn++; |
814 |
++ } |
815 |
++ |
816 |
++ goto cleanup; |
817 |
++ |
818 |
++add_errout: |
819 |
++ /* Delete routes that were already added */ |
820 |
++ list_for_each_entry(nh, &rt6_nh_list, next) { |
821 |
++ if (err_nh == nh) |
822 |
++ break; |
823 |
++ ip6_route_del(&nh->r_cfg); |
824 |
++ } |
825 |
++ |
826 |
++cleanup: |
827 |
++ list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) { |
828 |
++ if (nh->rt6_info) |
829 |
++ dst_free(&nh->rt6_info->dst); |
830 |
++ if (nh->mxc.mx) |
831 |
++ kfree(nh->mxc.mx); |
832 |
++ list_del(&nh->next); |
833 |
++ kfree(nh); |
834 |
++ } |
835 |
++ |
836 |
++ return err; |
837 |
++} |
838 |
++ |
839 |
++static int ip6_route_multipath_del(struct fib6_config *cfg) |
840 |
++{ |
841 |
++ struct fib6_config r_cfg; |
842 |
++ struct rtnexthop *rtnh; |
843 |
++ int remaining; |
844 |
++ int attrlen; |
845 |
++ int err = 1, last_err = 0; |
846 |
++ |
847 |
++ remaining = cfg->fc_mp_len; |
848 |
++ rtnh = (struct rtnexthop *)cfg->fc_mp; |
849 |
++ |
850 |
++ /* Parse a Multipath Entry */ |
851 |
++ while (rtnh_ok(rtnh, remaining)) { |
852 |
++ memcpy(&r_cfg, cfg, sizeof(*cfg)); |
853 |
++ if (rtnh->rtnh_ifindex) |
854 |
++ r_cfg.fc_ifindex = rtnh->rtnh_ifindex; |
855 |
++ |
856 |
++ attrlen = rtnh_attrlen(rtnh); |
857 |
++ if (attrlen > 0) { |
858 |
++ struct nlattr *nla, *attrs = rtnh_attrs(rtnh); |
859 |
++ |
860 |
++ nla = nla_find(attrs, attrlen, RTA_GATEWAY); |
861 |
++ if (nla) { |
862 |
++ nla_memcpy(&r_cfg.fc_gateway, nla, 16); |
863 |
++ r_cfg.fc_flags |= RTF_GATEWAY; |
864 |
++ } |
865 |
++ } |
866 |
++ err = ip6_route_del(&r_cfg); |
867 |
++ if (err) |
868 |
++ last_err = err; |
869 |
++ |
870 |
+ rtnh = rtnh_next(rtnh, &remaining); |
871 |
+ } |
872 |
+ |
873 |
+@@ -2565,7 +2714,7 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) |
874 |
+ return err; |
875 |
+ |
876 |
+ if (cfg.fc_mp) |
877 |
+- return ip6_route_multipath(&cfg, 0); |
878 |
++ return ip6_route_multipath_del(&cfg); |
879 |
+ else |
880 |
+ return ip6_route_del(&cfg); |
881 |
+ } |
882 |
+@@ -2580,7 +2729,7 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) |
883 |
+ return err; |
884 |
+ |
885 |
+ if (cfg.fc_mp) |
886 |
+- return ip6_route_multipath(&cfg, 1); |
887 |
++ return ip6_route_multipath_add(&cfg); |
888 |
+ else |
889 |
+ return ip6_route_add(&cfg); |
890 |
+ } |
891 |
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c |
892 |
+index 4856d975492d..980121e75d2e 100644 |
893 |
+--- a/net/netlink/af_netlink.c |
894 |
++++ b/net/netlink/af_netlink.c |
895 |
+@@ -123,6 +123,24 @@ static inline u32 netlink_group_mask(u32 group) |
896 |
+ return group ? 1 << (group - 1) : 0; |
897 |
+ } |
898 |
+ |
899 |
++static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb, |
900 |
++ gfp_t gfp_mask) |
901 |
++{ |
902 |
++ unsigned int len = skb_end_offset(skb); |
903 |
++ struct sk_buff *new; |
904 |
++ |
905 |
++ new = alloc_skb(len, gfp_mask); |
906 |
++ if (new == NULL) |
907 |
++ return NULL; |
908 |
++ |
909 |
++ NETLINK_CB(new).portid = NETLINK_CB(skb).portid; |
910 |
++ NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group; |
911 |
++ NETLINK_CB(new).creds = NETLINK_CB(skb).creds; |
912 |
++ |
913 |
++ memcpy(skb_put(new, len), skb->data, len); |
914 |
++ return new; |
915 |
++} |
916 |
++ |
917 |
+ int netlink_add_tap(struct netlink_tap *nt) |
918 |
+ { |
919 |
+ if (unlikely(nt->dev->type != ARPHRD_NETLINK)) |
920 |
+@@ -204,7 +222,11 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb, |
921 |
+ int ret = -ENOMEM; |
922 |
+ |
923 |
+ dev_hold(dev); |
924 |
+- nskb = skb_clone(skb, GFP_ATOMIC); |
925 |
++ |
926 |
++ if (netlink_skb_is_mmaped(skb) || is_vmalloc_addr(skb->head)) |
927 |
++ nskb = netlink_to_full_skb(skb, GFP_ATOMIC); |
928 |
++ else |
929 |
++ nskb = skb_clone(skb, GFP_ATOMIC); |
930 |
+ if (nskb) { |
931 |
+ nskb->dev = dev; |
932 |
+ nskb->protocol = htons((u16) sk->sk_protocol); |
933 |
+@@ -276,11 +298,6 @@ static void netlink_rcv_wake(struct sock *sk) |
934 |
+ } |
935 |
+ |
936 |
+ #ifdef CONFIG_NETLINK_MMAP |
937 |
+-static bool netlink_skb_is_mmaped(const struct sk_buff *skb) |
938 |
+-{ |
939 |
+- return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED; |
940 |
+-} |
941 |
+- |
942 |
+ static bool netlink_rx_is_mmaped(struct sock *sk) |
943 |
+ { |
944 |
+ return nlk_sk(sk)->rx_ring.pg_vec != NULL; |
945 |
+@@ -832,7 +849,6 @@ static void netlink_ring_set_copied(struct sock *sk, struct sk_buff *skb) |
946 |
+ } |
947 |
+ |
948 |
+ #else /* CONFIG_NETLINK_MMAP */ |
949 |
+-#define netlink_skb_is_mmaped(skb) false |
950 |
+ #define netlink_rx_is_mmaped(sk) false |
951 |
+ #define netlink_tx_is_mmaped(sk) false |
952 |
+ #define netlink_mmap sock_no_mmap |
953 |
+@@ -1080,8 +1096,8 @@ static int netlink_insert(struct sock *sk, u32 portid) |
954 |
+ |
955 |
+ lock_sock(sk); |
956 |
+ |
957 |
+- err = -EBUSY; |
958 |
+- if (nlk_sk(sk)->portid) |
959 |
++ err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY; |
960 |
++ if (nlk_sk(sk)->bound) |
961 |
+ goto err; |
962 |
+ |
963 |
+ err = -ENOMEM; |
964 |
+@@ -1101,10 +1117,13 @@ static int netlink_insert(struct sock *sk, u32 portid) |
965 |
+ err = -EOVERFLOW; |
966 |
+ if (err == -EEXIST) |
967 |
+ err = -EADDRINUSE; |
968 |
+- nlk_sk(sk)->portid = 0; |
969 |
+ sock_put(sk); |
970 |
+ } |
971 |
+ |
972 |
++ /* We need to ensure that the socket is hashed and visible. */ |
973 |
++ smp_wmb(); |
974 |
++ nlk_sk(sk)->bound = portid; |
975 |
++ |
976 |
+ err: |
977 |
+ release_sock(sk); |
978 |
+ return err; |
979 |
+@@ -1484,6 +1503,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, |
980 |
+ struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
981 |
+ int err; |
982 |
+ long unsigned int groups = nladdr->nl_groups; |
983 |
++ bool bound; |
984 |
+ |
985 |
+ if (addr_len < sizeof(struct sockaddr_nl)) |
986 |
+ return -EINVAL; |
987 |
+@@ -1500,9 +1520,14 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, |
988 |
+ return err; |
989 |
+ } |
990 |
+ |
991 |
+- if (nlk->portid) |
992 |
++ bound = nlk->bound; |
993 |
++ if (bound) { |
994 |
++ /* Ensure nlk->portid is up-to-date. */ |
995 |
++ smp_rmb(); |
996 |
++ |
997 |
+ if (nladdr->nl_pid != nlk->portid) |
998 |
+ return -EINVAL; |
999 |
++ } |
1000 |
+ |
1001 |
+ if (nlk->netlink_bind && groups) { |
1002 |
+ int group; |
1003 |
+@@ -1518,7 +1543,10 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, |
1004 |
+ } |
1005 |
+ } |
1006 |
+ |
1007 |
+- if (!nlk->portid) { |
1008 |
++ /* No need for barriers here as we return to user-space without |
1009 |
++ * using any of the bound attributes. |
1010 |
++ */ |
1011 |
++ if (!bound) { |
1012 |
+ err = nladdr->nl_pid ? |
1013 |
+ netlink_insert(sk, nladdr->nl_pid) : |
1014 |
+ netlink_autobind(sock); |
1015 |
+@@ -1566,7 +1594,10 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, |
1016 |
+ !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) |
1017 |
+ return -EPERM; |
1018 |
+ |
1019 |
+- if (!nlk->portid) |
1020 |
++ /* No need for barriers here as we return to user-space without |
1021 |
++ * using any of the bound attributes. |
1022 |
++ */ |
1023 |
++ if (!nlk->bound) |
1024 |
+ err = netlink_autobind(sock); |
1025 |
+ |
1026 |
+ if (err == 0) { |
1027 |
+@@ -2323,10 +2354,13 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) |
1028 |
+ dst_group = nlk->dst_group; |
1029 |
+ } |
1030 |
+ |
1031 |
+- if (!nlk->portid) { |
1032 |
++ if (!nlk->bound) { |
1033 |
+ err = netlink_autobind(sock); |
1034 |
+ if (err) |
1035 |
+ goto out; |
1036 |
++ } else { |
1037 |
++ /* Ensure nlk is hashed and visible. */ |
1038 |
++ smp_rmb(); |
1039 |
+ } |
1040 |
+ |
1041 |
+ /* It's a really convoluted way for userland to ask for mmaped |
1042 |
+diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h |
1043 |
+index 89008405d6b4..14437d9b1965 100644 |
1044 |
+--- a/net/netlink/af_netlink.h |
1045 |
++++ b/net/netlink/af_netlink.h |
1046 |
+@@ -35,6 +35,7 @@ struct netlink_sock { |
1047 |
+ unsigned long state; |
1048 |
+ size_t max_recvmsg_len; |
1049 |
+ wait_queue_head_t wait; |
1050 |
++ bool bound; |
1051 |
+ bool cb_running; |
1052 |
+ struct netlink_callback cb; |
1053 |
+ struct mutex *cb_mutex; |
1054 |
+@@ -59,6 +60,15 @@ static inline struct netlink_sock *nlk_sk(struct sock *sk) |
1055 |
+ return container_of(sk, struct netlink_sock, sk); |
1056 |
+ } |
1057 |
+ |
1058 |
++static inline bool netlink_skb_is_mmaped(const struct sk_buff *skb) |
1059 |
++{ |
1060 |
++#ifdef CONFIG_NETLINK_MMAP |
1061 |
++ return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED; |
1062 |
++#else |
1063 |
++ return false; |
1064 |
++#endif /* CONFIG_NETLINK_MMAP */ |
1065 |
++} |
1066 |
++ |
1067 |
+ struct netlink_table { |
1068 |
+ struct rhashtable hash; |
1069 |
+ struct hlist_head mc_list; |
1070 |
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c |
1071 |
+index 096c6276e6b9..27e14962b504 100644 |
1072 |
+--- a/net/openvswitch/datapath.c |
1073 |
++++ b/net/openvswitch/datapath.c |
1074 |
+@@ -906,7 +906,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) |
1075 |
+ if (error) |
1076 |
+ goto err_kfree_flow; |
1077 |
+ |
1078 |
+- ovs_flow_mask_key(&new_flow->key, &key, &mask); |
1079 |
++ ovs_flow_mask_key(&new_flow->key, &key, true, &mask); |
1080 |
+ |
1081 |
+ /* Extract flow identifier. */ |
1082 |
+ error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID], |
1083 |
+@@ -1033,7 +1033,7 @@ static struct sw_flow_actions *get_flow_actions(const struct nlattr *a, |
1084 |
+ struct sw_flow_key masked_key; |
1085 |
+ int error; |
1086 |
+ |
1087 |
+- ovs_flow_mask_key(&masked_key, key, mask); |
1088 |
++ ovs_flow_mask_key(&masked_key, key, true, mask); |
1089 |
+ error = ovs_nla_copy_actions(a, &masked_key, &acts, log); |
1090 |
+ if (error) { |
1091 |
+ OVS_NLERR(log, |
1092 |
+diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c |
1093 |
+index 4613df8c8290..aa349514e4cb 100644 |
1094 |
+--- a/net/openvswitch/flow_table.c |
1095 |
++++ b/net/openvswitch/flow_table.c |
1096 |
+@@ -56,20 +56,21 @@ static u16 range_n_bytes(const struct sw_flow_key_range *range) |
1097 |
+ } |
1098 |
+ |
1099 |
+ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, |
1100 |
+- const struct sw_flow_mask *mask) |
1101 |
++ bool full, const struct sw_flow_mask *mask) |
1102 |
+ { |
1103 |
+- const long *m = (const long *)((const u8 *)&mask->key + |
1104 |
+- mask->range.start); |
1105 |
+- const long *s = (const long *)((const u8 *)src + |
1106 |
+- mask->range.start); |
1107 |
+- long *d = (long *)((u8 *)dst + mask->range.start); |
1108 |
++ int start = full ? 0 : mask->range.start; |
1109 |
++ int len = full ? sizeof *dst : range_n_bytes(&mask->range); |
1110 |
++ const long *m = (const long *)((const u8 *)&mask->key + start); |
1111 |
++ const long *s = (const long *)((const u8 *)src + start); |
1112 |
++ long *d = (long *)((u8 *)dst + start); |
1113 |
+ int i; |
1114 |
+ |
1115 |
+- /* The memory outside of the 'mask->range' are not set since |
1116 |
+- * further operations on 'dst' only uses contents within |
1117 |
+- * 'mask->range'. |
1118 |
++ /* If 'full' is true then all of 'dst' is fully initialized. Otherwise, |
1119 |
++ * if 'full' is false the memory outside of the 'mask->range' is left |
1120 |
++ * uninitialized. This can be used as an optimization when further |
1121 |
++ * operations on 'dst' only use contents within 'mask->range'. |
1122 |
+ */ |
1123 |
+- for (i = 0; i < range_n_bytes(&mask->range); i += sizeof(long)) |
1124 |
++ for (i = 0; i < len; i += sizeof(long)) |
1125 |
+ *d++ = *s++ & *m++; |
1126 |
+ } |
1127 |
+ |
1128 |
+@@ -473,7 +474,7 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti, |
1129 |
+ u32 hash; |
1130 |
+ struct sw_flow_key masked_key; |
1131 |
+ |
1132 |
+- ovs_flow_mask_key(&masked_key, unmasked, mask); |
1133 |
++ ovs_flow_mask_key(&masked_key, unmasked, false, mask); |
1134 |
+ hash = flow_hash(&masked_key, &mask->range); |
1135 |
+ head = find_bucket(ti, hash); |
1136 |
+ hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver]) { |
1137 |
+diff --git a/net/openvswitch/flow_table.h b/net/openvswitch/flow_table.h |
1138 |
+index 616eda10d955..2dd9900f533d 100644 |
1139 |
+--- a/net/openvswitch/flow_table.h |
1140 |
++++ b/net/openvswitch/flow_table.h |
1141 |
+@@ -86,5 +86,5 @@ struct sw_flow *ovs_flow_tbl_lookup_ufid(struct flow_table *, |
1142 |
+ bool ovs_flow_cmp(const struct sw_flow *, const struct sw_flow_match *); |
1143 |
+ |
1144 |
+ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, |
1145 |
+- const struct sw_flow_mask *mask); |
1146 |
++ bool full, const struct sw_flow_mask *mask); |
1147 |
+ #endif /* flow_table.h */ |
1148 |
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c |
1149 |
+index 715e01e5910a..f23a3b68bba6 100644 |
1150 |
+--- a/net/sched/cls_fw.c |
1151 |
++++ b/net/sched/cls_fw.c |
1152 |
+@@ -33,7 +33,6 @@ |
1153 |
+ |
1154 |
+ struct fw_head { |
1155 |
+ u32 mask; |
1156 |
+- bool mask_set; |
1157 |
+ struct fw_filter __rcu *ht[HTSIZE]; |
1158 |
+ struct rcu_head rcu; |
1159 |
+ }; |
1160 |
+@@ -84,7 +83,7 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
1161 |
+ } |
1162 |
+ } |
1163 |
+ } else { |
1164 |
+- /* old method */ |
1165 |
++ /* Old method: classify the packet using its skb mark. */ |
1166 |
+ if (id && (TC_H_MAJ(id) == 0 || |
1167 |
+ !(TC_H_MAJ(id ^ tp->q->handle)))) { |
1168 |
+ res->classid = id; |
1169 |
+@@ -114,14 +113,9 @@ static unsigned long fw_get(struct tcf_proto *tp, u32 handle) |
1170 |
+ |
1171 |
+ static int fw_init(struct tcf_proto *tp) |
1172 |
+ { |
1173 |
+- struct fw_head *head; |
1174 |
+- |
1175 |
+- head = kzalloc(sizeof(struct fw_head), GFP_KERNEL); |
1176 |
+- if (head == NULL) |
1177 |
+- return -ENOBUFS; |
1178 |
+- |
1179 |
+- head->mask_set = false; |
1180 |
+- rcu_assign_pointer(tp->root, head); |
1181 |
++ /* We don't allocate fw_head here, because in the old method |
1182 |
++ * we don't need it at all. |
1183 |
++ */ |
1184 |
+ return 0; |
1185 |
+ } |
1186 |
+ |
1187 |
+@@ -252,7 +246,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, |
1188 |
+ int err; |
1189 |
+ |
1190 |
+ if (!opt) |
1191 |
+- return handle ? -EINVAL : 0; |
1192 |
++ return handle ? -EINVAL : 0; /* Succeed if it is old method. */ |
1193 |
+ |
1194 |
+ err = nla_parse_nested(tb, TCA_FW_MAX, opt, fw_policy); |
1195 |
+ if (err < 0) |
1196 |
+@@ -302,11 +296,17 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, |
1197 |
+ if (!handle) |
1198 |
+ return -EINVAL; |
1199 |
+ |
1200 |
+- if (!head->mask_set) { |
1201 |
+- head->mask = 0xFFFFFFFF; |
1202 |
++ if (!head) { |
1203 |
++ u32 mask = 0xFFFFFFFF; |
1204 |
+ if (tb[TCA_FW_MASK]) |
1205 |
+- head->mask = nla_get_u32(tb[TCA_FW_MASK]); |
1206 |
+- head->mask_set = true; |
1207 |
++ mask = nla_get_u32(tb[TCA_FW_MASK]); |
1208 |
++ |
1209 |
++ head = kzalloc(sizeof(*head), GFP_KERNEL); |
1210 |
++ if (!head) |
1211 |
++ return -ENOBUFS; |
1212 |
++ head->mask = mask; |
1213 |
++ |
1214 |
++ rcu_assign_pointer(tp->root, head); |
1215 |
+ } |
1216 |
+ |
1217 |
+ f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL); |
1218 |
+diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c |
1219 |
+index cab9e9b43967..4fbb67430ce4 100644 |
1220 |
+--- a/net/sched/cls_u32.c |
1221 |
++++ b/net/sched/cls_u32.c |
1222 |
+@@ -490,6 +490,19 @@ static bool u32_destroy(struct tcf_proto *tp, bool force) |
1223 |
+ return false; |
1224 |
+ } |
1225 |
+ } |
1226 |
++ |
1227 |
++ if (tp_c->refcnt > 1) |
1228 |
++ return false; |
1229 |
++ |
1230 |
++ if (tp_c->refcnt == 1) { |
1231 |
++ struct tc_u_hnode *ht; |
1232 |
++ |
1233 |
++ for (ht = rtnl_dereference(tp_c->hlist); |
1234 |
++ ht; |
1235 |
++ ht = rtnl_dereference(ht->next)) |
1236 |
++ if (!ht_empty(ht)) |
1237 |
++ return false; |
1238 |
++ } |
1239 |
+ } |
1240 |
+ |
1241 |
+ if (root_ht && --root_ht->refcnt == 0) |
1242 |
+diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c |
1243 |
+index 53b7acde9aa3..e13c3c3ea4ac 100644 |
1244 |
+--- a/net/sctp/protocol.c |
1245 |
++++ b/net/sctp/protocol.c |
1246 |
+@@ -1166,7 +1166,7 @@ static void sctp_v4_del_protocol(void) |
1247 |
+ unregister_inetaddr_notifier(&sctp_inetaddr_notifier); |
1248 |
+ } |
1249 |
+ |
1250 |
+-static int __net_init sctp_net_init(struct net *net) |
1251 |
++static int __net_init sctp_defaults_init(struct net *net) |
1252 |
+ { |
1253 |
+ int status; |
1254 |
+ |
1255 |
+@@ -1259,12 +1259,6 @@ static int __net_init sctp_net_init(struct net *net) |
1256 |
+ |
1257 |
+ sctp_dbg_objcnt_init(net); |
1258 |
+ |
1259 |
+- /* Initialize the control inode/socket for handling OOTB packets. */ |
1260 |
+- if ((status = sctp_ctl_sock_init(net))) { |
1261 |
+- pr_err("Failed to initialize the SCTP control sock\n"); |
1262 |
+- goto err_ctl_sock_init; |
1263 |
+- } |
1264 |
+- |
1265 |
+ /* Initialize the local address list. */ |
1266 |
+ INIT_LIST_HEAD(&net->sctp.local_addr_list); |
1267 |
+ spin_lock_init(&net->sctp.local_addr_lock); |
1268 |
+@@ -1280,9 +1274,6 @@ static int __net_init sctp_net_init(struct net *net) |
1269 |
+ |
1270 |
+ return 0; |
1271 |
+ |
1272 |
+-err_ctl_sock_init: |
1273 |
+- sctp_dbg_objcnt_exit(net); |
1274 |
+- sctp_proc_exit(net); |
1275 |
+ err_init_proc: |
1276 |
+ cleanup_sctp_mibs(net); |
1277 |
+ err_init_mibs: |
1278 |
+@@ -1291,15 +1282,12 @@ err_sysctl_register: |
1279 |
+ return status; |
1280 |
+ } |
1281 |
+ |
1282 |
+-static void __net_exit sctp_net_exit(struct net *net) |
1283 |
++static void __net_exit sctp_defaults_exit(struct net *net) |
1284 |
+ { |
1285 |
+ /* Free the local address list */ |
1286 |
+ sctp_free_addr_wq(net); |
1287 |
+ sctp_free_local_addr_list(net); |
1288 |
+ |
1289 |
+- /* Free the control endpoint. */ |
1290 |
+- inet_ctl_sock_destroy(net->sctp.ctl_sock); |
1291 |
+- |
1292 |
+ sctp_dbg_objcnt_exit(net); |
1293 |
+ |
1294 |
+ sctp_proc_exit(net); |
1295 |
+@@ -1307,9 +1295,32 @@ static void __net_exit sctp_net_exit(struct net *net) |
1296 |
+ sctp_sysctl_net_unregister(net); |
1297 |
+ } |
1298 |
+ |
1299 |
+-static struct pernet_operations sctp_net_ops = { |
1300 |
+- .init = sctp_net_init, |
1301 |
+- .exit = sctp_net_exit, |
1302 |
++static struct pernet_operations sctp_defaults_ops = { |
1303 |
++ .init = sctp_defaults_init, |
1304 |
++ .exit = sctp_defaults_exit, |
1305 |
++}; |
1306 |
++ |
1307 |
++static int __net_init sctp_ctrlsock_init(struct net *net) |
1308 |
++{ |
1309 |
++ int status; |
1310 |
++ |
1311 |
++ /* Initialize the control inode/socket for handling OOTB packets. */ |
1312 |
++ status = sctp_ctl_sock_init(net); |
1313 |
++ if (status) |
1314 |
++ pr_err("Failed to initialize the SCTP control sock\n"); |
1315 |
++ |
1316 |
++ return status; |
1317 |
++} |
1318 |
++ |
1319 |
++static void __net_init sctp_ctrlsock_exit(struct net *net) |
1320 |
++{ |
1321 |
++ /* Free the control endpoint. */ |
1322 |
++ inet_ctl_sock_destroy(net->sctp.ctl_sock); |
1323 |
++} |
1324 |
++ |
1325 |
++static struct pernet_operations sctp_ctrlsock_ops = { |
1326 |
++ .init = sctp_ctrlsock_init, |
1327 |
++ .exit = sctp_ctrlsock_exit, |
1328 |
+ }; |
1329 |
+ |
1330 |
+ /* Initialize the universe into something sensible. */ |
1331 |
+@@ -1442,8 +1453,11 @@ static __init int sctp_init(void) |
1332 |
+ sctp_v4_pf_init(); |
1333 |
+ sctp_v6_pf_init(); |
1334 |
+ |
1335 |
+- status = sctp_v4_protosw_init(); |
1336 |
++ status = register_pernet_subsys(&sctp_defaults_ops); |
1337 |
++ if (status) |
1338 |
++ goto err_register_defaults; |
1339 |
+ |
1340 |
++ status = sctp_v4_protosw_init(); |
1341 |
+ if (status) |
1342 |
+ goto err_protosw_init; |
1343 |
+ |
1344 |
+@@ -1451,9 +1465,9 @@ static __init int sctp_init(void) |
1345 |
+ if (status) |
1346 |
+ goto err_v6_protosw_init; |
1347 |
+ |
1348 |
+- status = register_pernet_subsys(&sctp_net_ops); |
1349 |
++ status = register_pernet_subsys(&sctp_ctrlsock_ops); |
1350 |
+ if (status) |
1351 |
+- goto err_register_pernet_subsys; |
1352 |
++ goto err_register_ctrlsock; |
1353 |
+ |
1354 |
+ status = sctp_v4_add_protocol(); |
1355 |
+ if (status) |
1356 |
+@@ -1469,12 +1483,14 @@ out: |
1357 |
+ err_v6_add_protocol: |
1358 |
+ sctp_v4_del_protocol(); |
1359 |
+ err_add_protocol: |
1360 |
+- unregister_pernet_subsys(&sctp_net_ops); |
1361 |
+-err_register_pernet_subsys: |
1362 |
++ unregister_pernet_subsys(&sctp_ctrlsock_ops); |
1363 |
++err_register_ctrlsock: |
1364 |
+ sctp_v6_protosw_exit(); |
1365 |
+ err_v6_protosw_init: |
1366 |
+ sctp_v4_protosw_exit(); |
1367 |
+ err_protosw_init: |
1368 |
++ unregister_pernet_subsys(&sctp_defaults_ops); |
1369 |
++err_register_defaults: |
1370 |
+ sctp_v4_pf_exit(); |
1371 |
+ sctp_v6_pf_exit(); |
1372 |
+ sctp_sysctl_unregister(); |
1373 |
+@@ -1507,12 +1523,14 @@ static __exit void sctp_exit(void) |
1374 |
+ sctp_v6_del_protocol(); |
1375 |
+ sctp_v4_del_protocol(); |
1376 |
+ |
1377 |
+- unregister_pernet_subsys(&sctp_net_ops); |
1378 |
++ unregister_pernet_subsys(&sctp_ctrlsock_ops); |
1379 |
+ |
1380 |
+ /* Free protosw registrations */ |
1381 |
+ sctp_v6_protosw_exit(); |
1382 |
+ sctp_v4_protosw_exit(); |
1383 |
+ |
1384 |
++ unregister_pernet_subsys(&sctp_defaults_ops); |
1385 |
++ |
1386 |
+ /* Unregister with socket layer. */ |
1387 |
+ sctp_v6_pf_exit(); |
1388 |
+ sctp_v4_pf_exit(); |