Commit 99838e60 authored by David S. Miller's avatar David S. Miller

Merge branch 'af_iucv-fixes'

Julian Wiedmann says:

====================
net/af_iucv: fixes 2019-06-18

I spent a few cycles on transmit problems for af_iucv over regular
netdevices - please apply the following fixes to -net.

The first patch allows for skb allocations outside of GFP_DMA, while the
second patch respects that drivers might use skb_cow_head() and/or want
additional dev->needed_headroom.
Patch 3 is for a separate issue, where we didn't setup some of the
netdevice-specific infrastructure when running as a z/VM guest.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 48620e34 06996c1d
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -347,14 +348,14 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, ...@@ -347,14 +348,14 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
if (imsg) if (imsg)
memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message)); memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message));
skb_push(skb, ETH_HLEN);
memset(skb->data, 0, ETH_HLEN);
skb->dev = iucv->hs_dev; skb->dev = iucv->hs_dev;
if (!skb->dev) { if (!skb->dev) {
err = -ENODEV; err = -ENODEV;
goto err_free; goto err_free;
} }
dev_hard_header(skb, skb->dev, ETH_P_AF_IUCV, NULL, NULL, skb->len);
if (!(skb->dev->flags & IFF_UP) || !netif_carrier_ok(skb->dev)) { if (!(skb->dev->flags & IFF_UP) || !netif_carrier_ok(skb->dev)) {
err = -ENETDOWN; err = -ENETDOWN;
goto err_free; goto err_free;
...@@ -367,6 +368,8 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, ...@@ -367,6 +368,8 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
skb_trim(skb, skb->dev->mtu); skb_trim(skb, skb->dev->mtu);
} }
skb->protocol = cpu_to_be16(ETH_P_AF_IUCV); skb->protocol = cpu_to_be16(ETH_P_AF_IUCV);
__skb_header_release(skb);
nskb = skb_clone(skb, GFP_ATOMIC); nskb = skb_clone(skb, GFP_ATOMIC);
if (!nskb) { if (!nskb) {
err = -ENOMEM; err = -ENOMEM;
...@@ -466,12 +469,14 @@ static void iucv_sever_path(struct sock *sk, int with_user_data) ...@@ -466,12 +469,14 @@ static void iucv_sever_path(struct sock *sk, int with_user_data)
/* Send controlling flags through an IUCV socket for HIPER transport */ /* Send controlling flags through an IUCV socket for HIPER transport */
static int iucv_send_ctrl(struct sock *sk, u8 flags) static int iucv_send_ctrl(struct sock *sk, u8 flags)
{ {
struct iucv_sock *iucv = iucv_sk(sk);
int err = 0; int err = 0;
int blen; int blen;
struct sk_buff *skb; struct sk_buff *skb;
u8 shutdown = 0; u8 shutdown = 0;
blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN; blen = sizeof(struct af_iucv_trans_hdr) +
LL_RESERVED_SPACE(iucv->hs_dev);
if (sk->sk_shutdown & SEND_SHUTDOWN) { if (sk->sk_shutdown & SEND_SHUTDOWN) {
/* controlling flags should be sent anyway */ /* controlling flags should be sent anyway */
shutdown = sk->sk_shutdown; shutdown = sk->sk_shutdown;
...@@ -588,7 +593,6 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio, ...@@ -588,7 +593,6 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio,
sk->sk_destruct = iucv_sock_destruct; sk->sk_destruct = iucv_sock_destruct;
sk->sk_sndtimeo = IUCV_CONN_TIMEOUT; sk->sk_sndtimeo = IUCV_CONN_TIMEOUT;
sk->sk_allocation = GFP_DMA;
sock_reset_flag(sk, SOCK_ZAPPED); sock_reset_flag(sk, SOCK_ZAPPED);
...@@ -782,6 +786,7 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, ...@@ -782,6 +786,7 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
memcpy(iucv->src_user_id, iucv_userid, 8); memcpy(iucv->src_user_id, iucv_userid, 8);
sk->sk_state = IUCV_BOUND; sk->sk_state = IUCV_BOUND;
iucv->transport = AF_IUCV_TRANS_IUCV; iucv->transport = AF_IUCV_TRANS_IUCV;
sk->sk_allocation |= GFP_DMA;
if (!iucv->msglimit) if (!iucv->msglimit)
iucv->msglimit = IUCV_QUEUELEN_DEFAULT; iucv->msglimit = IUCV_QUEUELEN_DEFAULT;
goto done_unlock; goto done_unlock;
...@@ -806,6 +811,8 @@ static int iucv_sock_autobind(struct sock *sk) ...@@ -806,6 +811,8 @@ static int iucv_sock_autobind(struct sock *sk)
return -EPROTO; return -EPROTO;
memcpy(iucv->src_user_id, iucv_userid, 8); memcpy(iucv->src_user_id, iucv_userid, 8);
iucv->transport = AF_IUCV_TRANS_IUCV;
sk->sk_allocation |= GFP_DMA;
write_lock_bh(&iucv_sk_list.lock); write_lock_bh(&iucv_sk_list.lock);
__iucv_auto_name(iucv); __iucv_auto_name(iucv);
...@@ -1131,7 +1138,8 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg, ...@@ -1131,7 +1138,8 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg,
* segmented records using the MSG_EOR flag), but * segmented records using the MSG_EOR flag), but
* for SOCK_STREAM we might want to improve it in future */ * for SOCK_STREAM we might want to improve it in future */
if (iucv->transport == AF_IUCV_TRANS_HIPER) { if (iucv->transport == AF_IUCV_TRANS_HIPER) {
headroom = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN; headroom = sizeof(struct af_iucv_trans_hdr) +
LL_RESERVED_SPACE(iucv->hs_dev);
linear = len; linear = len;
} else { } else {
if (len < PAGE_SIZE) { if (len < PAGE_SIZE) {
...@@ -1781,6 +1789,8 @@ static int iucv_callback_connreq(struct iucv_path *path, ...@@ -1781,6 +1789,8 @@ static int iucv_callback_connreq(struct iucv_path *path,
niucv = iucv_sk(nsk); niucv = iucv_sk(nsk);
iucv_sock_init(nsk, sk); iucv_sock_init(nsk, sk);
niucv->transport = AF_IUCV_TRANS_IUCV;
nsk->sk_allocation |= GFP_DMA;
/* Set the new iucv_sock */ /* Set the new iucv_sock */
memcpy(niucv->dst_name, ipuser + 8, 8); memcpy(niucv->dst_name, ipuser + 8, 8);
...@@ -2430,6 +2440,13 @@ static int afiucv_iucv_init(void) ...@@ -2430,6 +2440,13 @@ static int afiucv_iucv_init(void)
return err; return err;
} }
static void afiucv_iucv_exit(void)
{
device_unregister(af_iucv_dev);
driver_unregister(&af_iucv_driver);
pr_iucv->iucv_unregister(&af_iucv_handler, 0);
}
static int __init afiucv_init(void) static int __init afiucv_init(void)
{ {
int err; int err;
...@@ -2463,11 +2480,18 @@ static int __init afiucv_init(void) ...@@ -2463,11 +2480,18 @@ static int __init afiucv_init(void)
err = afiucv_iucv_init(); err = afiucv_iucv_init();
if (err) if (err)
goto out_sock; goto out_sock;
} else }
register_netdevice_notifier(&afiucv_netdev_notifier);
err = register_netdevice_notifier(&afiucv_netdev_notifier);
if (err)
goto out_notifier;
dev_add_pack(&iucv_packet_type); dev_add_pack(&iucv_packet_type);
return 0; return 0;
out_notifier:
if (pr_iucv)
afiucv_iucv_exit();
out_sock: out_sock:
sock_unregister(PF_IUCV); sock_unregister(PF_IUCV);
out_proto: out_proto:
...@@ -2481,12 +2505,11 @@ static int __init afiucv_init(void) ...@@ -2481,12 +2505,11 @@ static int __init afiucv_init(void)
static void __exit afiucv_exit(void) static void __exit afiucv_exit(void)
{ {
if (pr_iucv) { if (pr_iucv) {
device_unregister(af_iucv_dev); afiucv_iucv_exit();
driver_unregister(&af_iucv_driver);
pr_iucv->iucv_unregister(&af_iucv_handler, 0);
symbol_put(iucv_if); symbol_put(iucv_if);
} else }
unregister_netdevice_notifier(&afiucv_netdev_notifier);
unregister_netdevice_notifier(&afiucv_netdev_notifier);
dev_remove_pack(&iucv_packet_type); dev_remove_pack(&iucv_packet_type);
sock_unregister(PF_IUCV); sock_unregister(PF_IUCV);
proto_unregister(&iucv_proto); proto_unregister(&iucv_proto);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment