mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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
					
				
					 1 changed files with 14 additions and 4 deletions
				
			
		| 
						 | 
					@ -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 a new issue