forked from Minki/linux
netlink: handle errors from netlink_dump()
netlink_dump() may failed, but nobody handle its error. It generates output data, when a previous portion has been returned to user space. This mechanism works when all data isn't go in skb. If we enter in netlink_recvmsg() and skb is absent in the recv queue, the netlink_dump() will not been executed. So if netlink_dump() is failed one time, the new data never appear and the reader will sleep forever. netlink_dump() is called from two places: 1. from netlink_sendmsg->...->netlink_dump_start(). In this place we can report error directly and it will be returned by sendmsg(). 2. from netlink_recvmsg There we can't report error directly, because we have a portion of valid output data and call netlink_dump() for prepare the next portion. If netlink_dump() is failed, the socket will be mark as error and the next recvmsg will be failed. Signed-off-by: Andrey Vagin <avagin@openvz.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
dad3d44dcb
commit
b44d211e16
@ -1407,7 +1407,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
|
|||||||
int noblock = flags&MSG_DONTWAIT;
|
int noblock = flags&MSG_DONTWAIT;
|
||||||
size_t copied;
|
size_t copied;
|
||||||
struct sk_buff *skb, *data_skb;
|
struct sk_buff *skb, *data_skb;
|
||||||
int err;
|
int err, ret;
|
||||||
|
|
||||||
if (flags&MSG_OOB)
|
if (flags&MSG_OOB)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
@ -1470,8 +1470,13 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
|
|||||||
|
|
||||||
skb_free_datagram(sk, skb);
|
skb_free_datagram(sk, skb);
|
||||||
|
|
||||||
if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
|
if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) {
|
||||||
netlink_dump(sk);
|
ret = netlink_dump(sk);
|
||||||
|
if (ret) {
|
||||||
|
sk->sk_err = ret;
|
||||||
|
sk->sk_error_report(sk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scm_recv(sock, msg, siocb->scm, flags);
|
scm_recv(sock, msg, siocb->scm, flags);
|
||||||
out:
|
out:
|
||||||
@ -1736,6 +1741,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
|||||||
struct netlink_callback *cb;
|
struct netlink_callback *cb;
|
||||||
struct sock *sk;
|
struct sock *sk;
|
||||||
struct netlink_sock *nlk;
|
struct netlink_sock *nlk;
|
||||||
|
int ret;
|
||||||
|
|
||||||
cb = kzalloc(sizeof(*cb), GFP_KERNEL);
|
cb = kzalloc(sizeof(*cb), GFP_KERNEL);
|
||||||
if (cb == NULL)
|
if (cb == NULL)
|
||||||
@ -1764,9 +1770,13 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
|||||||
nlk->cb = cb;
|
nlk->cb = cb;
|
||||||
mutex_unlock(nlk->cb_mutex);
|
mutex_unlock(nlk->cb_mutex);
|
||||||
|
|
||||||
netlink_dump(sk);
|
ret = netlink_dump(sk);
|
||||||
|
|
||||||
sock_put(sk);
|
sock_put(sk);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* We successfully started a dump, by returning -EINTR we
|
/* We successfully started a dump, by returning -EINTR we
|
||||||
* signal not to send ACK even if it was requested.
|
* signal not to send ACK even if it was requested.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user