mirror of https://gitee.com/openkylin/linux.git
af_iucv: release reference to HS device
For HiperSockets transport skbs sent are bound to one of the available HiperSockets devices. Add missing release of reference to a HiperSockets device before freeing an skb. Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
42bd48e014
commit
816abbadf9
|
@ -130,6 +130,17 @@ static inline void low_nmcpy(unsigned char *dst, char *src)
|
||||||
memcpy(&dst[8], src, 8);
|
memcpy(&dst[8], src, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void iucv_skb_queue_purge(struct sk_buff_head *list)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
while ((skb = skb_dequeue(list)) != NULL) {
|
||||||
|
if (skb->dev)
|
||||||
|
dev_put(skb->dev);
|
||||||
|
kfree_skb(skb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int afiucv_pm_prepare(struct device *dev)
|
static int afiucv_pm_prepare(struct device *dev)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_PM_DEBUG
|
#ifdef CONFIG_PM_DEBUG
|
||||||
|
@ -164,7 +175,7 @@ static int afiucv_pm_freeze(struct device *dev)
|
||||||
read_lock(&iucv_sk_list.lock);
|
read_lock(&iucv_sk_list.lock);
|
||||||
sk_for_each(sk, node, &iucv_sk_list.head) {
|
sk_for_each(sk, node, &iucv_sk_list.head) {
|
||||||
iucv = iucv_sk(sk);
|
iucv = iucv_sk(sk);
|
||||||
skb_queue_purge(&iucv->send_skb_q);
|
iucv_skb_queue_purge(&iucv->send_skb_q);
|
||||||
skb_queue_purge(&iucv->backlog_skb_q);
|
skb_queue_purge(&iucv->backlog_skb_q);
|
||||||
switch (sk->sk_state) {
|
switch (sk->sk_state) {
|
||||||
case IUCV_SEVERED:
|
case IUCV_SEVERED:
|
||||||
|
@ -366,9 +377,7 @@ 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));
|
||||||
|
|
||||||
rcu_read_lock();
|
skb->dev = dev_get_by_index(net, sock->sk_bound_dev_if);
|
||||||
skb->dev = dev_get_by_index_rcu(net, sock->sk_bound_dev_if);
|
|
||||||
rcu_read_unlock();
|
|
||||||
if (!skb->dev)
|
if (!skb->dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (!(skb->dev->flags & IFF_UP))
|
if (!(skb->dev->flags & IFF_UP))
|
||||||
|
@ -388,6 +397,7 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
|
||||||
err = dev_queue_xmit(skb);
|
err = dev_queue_xmit(skb);
|
||||||
if (err) {
|
if (err) {
|
||||||
skb_unlink(nskb, &iucv->send_skb_q);
|
skb_unlink(nskb, &iucv->send_skb_q);
|
||||||
|
dev_put(nskb->dev);
|
||||||
kfree_skb(nskb);
|
kfree_skb(nskb);
|
||||||
} else {
|
} else {
|
||||||
atomic_sub(confirm_recv, &iucv->msg_recv);
|
atomic_sub(confirm_recv, &iucv->msg_recv);
|
||||||
|
@ -481,16 +491,14 @@ static void iucv_sock_close(struct sock *sk)
|
||||||
blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
|
blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
|
||||||
skb = sock_alloc_send_skb(sk, blen, 1, &err);
|
skb = sock_alloc_send_skb(sk, blen, 1, &err);
|
||||||
if (skb) {
|
if (skb) {
|
||||||
skb_reserve(skb,
|
skb_reserve(skb, blen);
|
||||||
sizeof(struct af_iucv_trans_hdr) +
|
|
||||||
ETH_HLEN);
|
|
||||||
err = afiucv_hs_send(NULL, sk, skb,
|
err = afiucv_hs_send(NULL, sk, skb,
|
||||||
AF_IUCV_FLAG_FIN);
|
AF_IUCV_FLAG_FIN);
|
||||||
}
|
}
|
||||||
sk->sk_state = IUCV_DISCONN;
|
sk->sk_state = IUCV_DISCONN;
|
||||||
sk->sk_state_change(sk);
|
sk->sk_state_change(sk);
|
||||||
}
|
}
|
||||||
case IUCV_DISCONN:
|
case IUCV_DISCONN: /* fall through */
|
||||||
sk->sk_state = IUCV_CLOSING;
|
sk->sk_state = IUCV_CLOSING;
|
||||||
sk->sk_state_change(sk);
|
sk->sk_state_change(sk);
|
||||||
|
|
||||||
|
@ -520,7 +528,7 @@ static void iucv_sock_close(struct sock *sk)
|
||||||
sk->sk_err = ECONNRESET;
|
sk->sk_err = ECONNRESET;
|
||||||
sk->sk_state_change(sk);
|
sk->sk_state_change(sk);
|
||||||
|
|
||||||
skb_queue_purge(&iucv->send_skb_q);
|
iucv_skb_queue_purge(&iucv->send_skb_q);
|
||||||
skb_queue_purge(&iucv->backlog_skb_q);
|
skb_queue_purge(&iucv->backlog_skb_q);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -739,7 +747,7 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
|
||||||
if (!memcmp(dev->perm_addr, uid, 8)) {
|
if (!memcmp(dev->perm_addr, uid, 8)) {
|
||||||
memcpy(iucv->src_name, sa->siucv_name, 8);
|
memcpy(iucv->src_name, sa->siucv_name, 8);
|
||||||
memcpy(iucv->src_user_id, sa->siucv_user_id, 8);
|
memcpy(iucv->src_user_id, sa->siucv_user_id, 8);
|
||||||
sock->sk->sk_bound_dev_if = dev->ifindex;
|
sk->sk_bound_dev_if = dev->ifindex;
|
||||||
sk->sk_state = IUCV_BOUND;
|
sk->sk_state = IUCV_BOUND;
|
||||||
iucv->transport = AF_IUCV_TRANS_HIPER;
|
iucv->transport = AF_IUCV_TRANS_HIPER;
|
||||||
if (!iucv->msglimit)
|
if (!iucv->msglimit)
|
||||||
|
@ -1225,6 +1233,8 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
if (skb->dev)
|
||||||
|
dev_put(skb->dev);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
out:
|
out:
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
|
@ -1441,9 +1451,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
ETH_HLEN;
|
ETH_HLEN;
|
||||||
sskb = sock_alloc_send_skb(sk, blen, 1, &err);
|
sskb = sock_alloc_send_skb(sk, blen, 1, &err);
|
||||||
if (sskb) {
|
if (sskb) {
|
||||||
skb_reserve(sskb,
|
skb_reserve(sskb, blen);
|
||||||
sizeof(struct af_iucv_trans_hdr)
|
|
||||||
+ ETH_HLEN);
|
|
||||||
err = afiucv_hs_send(NULL, sk, sskb,
|
err = afiucv_hs_send(NULL, sk, sskb,
|
||||||
AF_IUCV_FLAG_WIN);
|
AF_IUCV_FLAG_WIN);
|
||||||
}
|
}
|
||||||
|
@ -2261,6 +2269,7 @@ static void afiucv_hs_callback_txnotify(struct sk_buff *skb,
|
||||||
case TX_NOTIFY_OK:
|
case TX_NOTIFY_OK:
|
||||||
__skb_unlink(this, list);
|
__skb_unlink(this, list);
|
||||||
iucv_sock_wake_msglim(sk);
|
iucv_sock_wake_msglim(sk);
|
||||||
|
dev_put(this->dev);
|
||||||
kfree_skb(this);
|
kfree_skb(this);
|
||||||
break;
|
break;
|
||||||
case TX_NOTIFY_PENDING:
|
case TX_NOTIFY_PENDING:
|
||||||
|
@ -2271,6 +2280,7 @@ static void afiucv_hs_callback_txnotify(struct sk_buff *skb,
|
||||||
atomic_dec(&iucv->pendings);
|
atomic_dec(&iucv->pendings);
|
||||||
if (atomic_read(&iucv->pendings) <= 0)
|
if (atomic_read(&iucv->pendings) <= 0)
|
||||||
iucv_sock_wake_msglim(sk);
|
iucv_sock_wake_msglim(sk);
|
||||||
|
dev_put(this->dev);
|
||||||
kfree_skb(this);
|
kfree_skb(this);
|
||||||
break;
|
break;
|
||||||
case TX_NOTIFY_UNREACHABLE:
|
case TX_NOTIFY_UNREACHABLE:
|
||||||
|
@ -2279,6 +2289,7 @@ static void afiucv_hs_callback_txnotify(struct sk_buff *skb,
|
||||||
case TX_NOTIFY_GENERALERROR:
|
case TX_NOTIFY_GENERALERROR:
|
||||||
case TX_NOTIFY_DELAYED_GENERALERROR:
|
case TX_NOTIFY_DELAYED_GENERALERROR:
|
||||||
__skb_unlink(this, list);
|
__skb_unlink(this, list);
|
||||||
|
dev_put(this->dev);
|
||||||
kfree_skb(this);
|
kfree_skb(this);
|
||||||
if (!list_empty(&iucv->accept_q))
|
if (!list_empty(&iucv->accept_q))
|
||||||
sk->sk_state = IUCV_SEVERED;
|
sk->sk_state = IUCV_SEVERED;
|
||||||
|
|
Loading…
Reference in New Issue