Hi!
From: Eric Dumazet edumazet@google.com
commit 764f4eb6846f5475f1244767d24d25dd86528a4a upstream.
Whenever llc_ui_bind() and/or llc_ui_autobind() took a reference on a netdevice but subsequently fail, they must properly release their reference or risk the infamous message from unregister_netdevice() at device dismantle.
unregister_netdevice: waiting for eth0 to become free. Usage count = 3
Can someone check this? AFAICT this is buggy.
static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) { struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); struct llc_sap *sap; int rc = -EINVAL;
if (!sock_flag(sk, SOCK_ZAPPED)) goto out;
There are 'goto out's from both before dev_get() and after it, dev_put() will be called with NULL pointer. dev_put() can't handle NULL at least in the old kernels... this is simply confused.
Mainline has dev_put_track() there, but I see same confusion.
Best regards, Pavel
--- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -311,6 +311,10 @@ static int llc_ui_autobind(struct socket sock_reset_flag(sk, SOCK_ZAPPED); rc = 0; out:
- if (rc) {
dev_put(llc->dev);
llc->dev = NULL;
- } return rc;
} @@ -409,6 +413,10 @@ static int llc_ui_bind(struct socket *so out_put: llc_sap_put(sap); out:
- if (rc) {
dev_put(llc->dev);
llc->dev = NULL;
- } release_sock(sk); return rc;
}