[NET]: make netlink user -> kernel interface synchronious
authorDenis V. Lunev <den@openvz.org>
Thu, 11 Oct 2007 04:15:29 +0000 (21:15 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 11 Oct 2007 04:15:29 +0000 (21:15 -0700)
This patch make processing netlink user -> kernel messages synchronious.
This change was inspired by the talk with Alexey Kuznetsov about current
netlink messages processing. He says that he was badly wrong when introduced
asynchronious user -> kernel communication.

The call netlink_unicast is the only path to send message to the kernel
netlink socket. But, unfortunately, it is also used to send data to the
user.

Before this change the user message has been attached to the socket queue
and sk->sk_data_ready was called. The process has been blocked until all
pending messages were processed. The bad thing is that this processing
may occur in the arbitrary process context.

This patch changes nlk->data_ready callback to get 1 skb and force packet
processing right in the netlink_unicast.

Kernel -> user path in netlink_unicast remains untouched.

EINTR processing for in netlink_run_queue was changed. It forces rtnl_lock
drop, but the process remains in the cycle until the message will be fully
processed. So, there is no need to use this kludges now.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Signed-off-by: David S. Miller <davem@davemloft.net>
18 files changed:
drivers/connector/connector.c
drivers/scsi/scsi_netlink.c
drivers/scsi/scsi_transport_iscsi.c
fs/ecryptfs/netlink.c
include/linux/connector.h
include/linux/netlink.h
include/net/netlink.h
kernel/audit.c
net/core/rtnetlink.c
net/decnet/netfilter/dn_rtmsg.c
net/ipv4/fib_frontend.c
net/ipv4/inet_diag.c
net/ipv4/netfilter/ip_queue.c
net/ipv6/netfilter/ip6_queue.c
net/netfilter/nfnetlink.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/xfrm/xfrm_user.c

index 569070997cc1fac4d6847b404371ff8cb93cda27..0e328d387af4cbecdb326238b12d904dfe4988b1 100644 (file)
@@ -234,18 +234,6 @@ out:
        kfree_skb(__skb);
 }
 
-/*
- * Netlink socket input callback - dequeues the skbs and calls the
- * main netlink receiving function.
- */
-static void cn_input(struct sock *sk, int len)
-{
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
-               cn_rx_skb(skb);
-}
-
 /*
  * Notification routing.
  *
@@ -442,7 +430,7 @@ static int __devinit cn_init(void)
        struct cn_dev *dev = &cdev;
        int err;
 
-       dev->input = cn_input;
+       dev->input = cn_rx_skb;
        dev->id.idx = cn_idx;
        dev->id.val = cn_val;
 
index 163acf6ad2d3b40dfcbf229b5a2a7849ebca2c8c..40579edca101a465f997266343a5862ccebcb2c0 100644 (file)
@@ -64,7 +64,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
 
                if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
                        err = -EBADMSG;
-                       goto next_msg;
+                       return;
                }
 
                hdr = NLMSG_DATA(nlh);
@@ -98,27 +98,6 @@ next_msg:
 }
 
 
-/**
- * scsi_nl_rcv_msg -
- *    Receive handler for a socket. Extracts a received message buffer from
- *    the socket, and starts message processing.
- *
- * @sk:                socket
- * @len:       unused
- *
- **/
-static void
-scsi_nl_rcv(struct sock *sk, int len)
-{
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
-               scsi_nl_rcv_msg(skb);
-               kfree_skb(skb);
-       }
-}
-
-
 /**
  * scsi_nl_rcv_event -
  *    Event handler for a netlink socket.
@@ -168,7 +147,7 @@ scsi_netlink_init(void)
        }
 
        scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT,
-                               SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL,
+                               SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL,
                                THIS_MODULE);
        if (!scsi_nl_sock) {
                printk(KERN_ERR "%s: register of recieve handler failed\n",
index 4916f01230dc548067ab1a67bde17eccab9617f3..5428d15f23c617d5bfc579baea6391664c1c47c4 100644 (file)
@@ -1097,61 +1097,49 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 }
 
 /*
- * Get message from skb (based on rtnetlink_rcv_skb).  Each message is
- * processed by iscsi_if_recv_msg.  Malformed skbs with wrong lengths or
- * invalid creds are discarded silently.
+ * Get message from skb.  Each message is processed by iscsi_if_recv_msg.
+ * Malformed skbs with wrong lengths or invalid creds are not processed.
  */
 static void
-iscsi_if_rx(struct sock *sk, int len)
+iscsi_if_rx(struct sk_buff *skb)
 {
-       struct sk_buff *skb;
-
        mutex_lock(&rx_queue_mutex);
-       while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-               if (NETLINK_CREDS(skb)->uid) {
-                       skb_pull(skb, skb->len);
-                       goto free_skb;
+       while (skb->len >= NLMSG_SPACE(0)) {
+               int err;
+               uint32_t rlen;
+               struct nlmsghdr *nlh;
+               struct iscsi_uevent *ev;
+
+               nlh = nlmsg_hdr(skb);
+               if (nlh->nlmsg_len < sizeof(*nlh) ||
+                   skb->len < nlh->nlmsg_len) {
+                       break;
                }
 
-               while (skb->len >= NLMSG_SPACE(0)) {
-                       int err;
-                       uint32_t rlen;
-                       struct nlmsghdr *nlh;
-                       struct iscsi_uevent *ev;
+               ev = NLMSG_DATA(nlh);
+               rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (rlen > skb->len)
+                       rlen = skb->len;
 
-                       nlh = nlmsg_hdr(skb);
-                       if (nlh->nlmsg_len < sizeof(*nlh) ||
-                           skb->len < nlh->nlmsg_len) {
-                               break;
-                       }
-
-                       ev = NLMSG_DATA(nlh);
-                       rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-                       if (rlen > skb->len)
-                               rlen = skb->len;
-
-                       err = iscsi_if_recv_msg(skb, nlh);
-                       if (err) {
-                               ev->type = ISCSI_KEVENT_IF_ERROR;
-                               ev->iferror = err;
-                       }
-                       do {
-                               /*
-                                * special case for GET_STATS:
-                                * on success - sending reply and stats from
-                                * inside of if_recv_msg(),
-                                * on error - fall through.
-                                */
-                               if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-                                       break;
-                               err = iscsi_if_send_reply(
-                                       NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
-                                       nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-                       } while (err < 0 && err != -ECONNREFUSED);
-                       skb_pull(skb, rlen);
+               err = iscsi_if_recv_msg(skb, nlh);
+               if (err) {
+                       ev->type = ISCSI_KEVENT_IF_ERROR;
+                       ev->iferror = err;
                }
-free_skb:
-               kfree_skb(skb);
+               do {
+                       /*
+                        * special case for GET_STATS:
+                        * on success - sending reply and stats from
+                        * inside of if_recv_msg(),
+                        * on error - fall through.
+                        */
+                       if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
+                               break;
+                       err = iscsi_if_send_reply(
+                               NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+                               nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
+               } while (err < 0 && err != -ECONNREFUSED);
+               skb_pull(skb, rlen);
        }
        mutex_unlock(&rx_queue_mutex);
 }
index 056519cd92bcf5e1583ebf1deaa6f5bc2e8ee045..9aa345121e09cf2bf2f600259f95a03557f85de3 100644 (file)
@@ -165,22 +165,10 @@ static int ecryptfs_process_nl_quit(struct sk_buff *skb)
  * it to its desired netlink context element and wake up the process
  * that is waiting for a response.
  */
-static void ecryptfs_receive_nl_message(struct sock *sk, int len)
+static void ecryptfs_receive_nl_message(struct sk_buff *skb)
 {
-       struct sk_buff *skb;
        struct nlmsghdr *nlh;
-       int rc = 0;     /* skb_recv_datagram requires this */
 
-receive:
-       skb = skb_recv_datagram(sk, 0, 0, &rc);
-       if (rc == -EINTR)
-               goto receive;
-       else if (rc < 0) {
-               ecryptfs_printk(KERN_ERR, "Error occurred while "
-                               "receiving eCryptfs netlink message; "
-                               "rc = [%d]\n", rc);
-               return;
-       }
        nlh = nlmsg_hdr(skb);
        if (!NLMSG_OK(nlh, skb->len)) {
                ecryptfs_printk(KERN_ERR, "Received corrupt netlink "
index 10eb56b2940ad8c8b7f6775de247d552a99cc6fe..b62f823e90cf631537a23ec7e5f17f87c6ce64e9 100644 (file)
@@ -153,7 +153,7 @@ struct cn_dev {
 
        u32 seq, groups;
        struct sock *nls;
-       void (*input) (struct sock * sk, int len);
+       void (*input) (struct sk_buff *skb);
 
        struct cn_queue_dev *cbdev;
 };
index 7b552b6c2c19b5277efb4e47e7877653c6cc2a98..7c1f3b1d2ee5a3e3b6c6cda0794a4847e6e044ae 100644 (file)
@@ -175,7 +175,7 @@ struct netlink_skb_parms
 
 extern struct sock *netlink_kernel_create(struct net *net,
                                          int unit,unsigned int groups,
-                                         void (*input)(struct sock *sk, int len),
+                                         void (*input)(struct sk_buff *skb),
                                          struct mutex *cb_mutex,
                                          struct module *module);
 extern int netlink_change_ngroups(struct sock *sk, unsigned int groups);
index 1afd3e837d2328f15950b79608d59291550f3b88..9298218c07f9afa7fda027fcbb07a8b4684b673f 100644 (file)
@@ -220,9 +220,9 @@ struct nl_info {
        u32                     pid;
 };
 
-extern unsigned int    netlink_run_queue(struct sock *sk, unsigned int qlen,
-                                         int (*cb)(struct sk_buff *,
-                                                   struct nlmsghdr *));
+extern int             netlink_rcv_skb(struct sk_buff *skb,
+                                       int (*cb)(struct sk_buff *,
+                                                 struct nlmsghdr *));
 extern int             nlmsg_notify(struct sock *sk, struct sk_buff *skb,
                                     u32 pid, unsigned int group, int report,
                                     gfp_t flags);
index f3c390f6c0b402e18ccd9992e6a4d1ccef2de290..2924251a6547bebb25d952dc64ea5590848b1bce 100644 (file)
@@ -847,18 +847,10 @@ static void audit_receive_skb(struct sk_buff *skb)
 }
 
 /* Receive messages from netlink socket. */
-static void audit_receive(struct sock *sk, int length)
+static void audit_receive(struct sk_buff  *skb)
 {
-       struct sk_buff  *skb;
-       unsigned int qlen;
-
        mutex_lock(&audit_cmd_mutex);
-
-       for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
-               skb = skb_dequeue(&sk->sk_receive_queue);
-               audit_receive_skb(skb);
-               kfree_skb(skb);
-       }
+       audit_receive_skb(skb);
        mutex_unlock(&audit_cmd_mutex);
 }
 
index 471d2d9f8eae8c9722e27f4326d0f716703154d0..1072d16696c3b651993ef7130bd09a475c072b81 100644 (file)
@@ -1312,15 +1312,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        return doit(skb, nlh, (void *)&rta_buf[0]);
 }
 
-static void rtnetlink_rcv(struct sock *sk, int len)
+static void rtnetlink_rcv(struct sk_buff *skb)
 {
-       unsigned int qlen = 0;
-
-       do {
-               rtnl_lock();
-               qlen = netlink_run_queue(sk, qlen, &rtnetlink_rcv_msg);
-               rtnl_unlock();
-       } while (qlen);
+       rtnl_lock();
+       netlink_rcv_skb(skb, &rtnetlink_rcv_msg);
+       rtnl_unlock();
 }
 
 static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)
index ebb38feb4df3b8e0e49ab5c856fe0c4615e0c084..f7fba7721e639812e89f1c75d00b4ebaca9a1581 100644 (file)
@@ -115,17 +115,6 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
        RCV_SKB_FAIL(-EINVAL);
 }
 
-static void dnrmg_receive_user_sk(struct sock *sk, int len)
-{
-       struct sk_buff *skb;
-       unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
-
-       for (; qlen && (skb = skb_dequeue(&sk->sk_receive_queue)); qlen--) {
-               dnrmg_receive_user_skb(skb);
-               kfree_skb(skb);
-       }
-}
-
 static struct nf_hook_ops dnrmg_ops = {
        .hook           = dnrmg_hook,
        .pf             = PF_DECnet,
@@ -139,7 +128,8 @@ static int __init dn_rtmsg_init(void)
 
        dnrmg = netlink_kernel_create(&init_net,
                                      NETLINK_DNRTMSG, DNRNG_NLGRP_MAX,
-                                     dnrmg_receive_user_sk, NULL, THIS_MODULE);
+                                     dnrmg_receive_user_skb,
+                                     NULL, THIS_MODULE);
        if (dnrmg == NULL) {
                printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
                return -ENOMEM;
index f823ca34cb12fd691e7e2ccbdf13fa59cf5bf478..a5cba2349605e75528216ff9936ceeb2db32a14d 100644 (file)
@@ -62,6 +62,9 @@ static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
 #define FIB_TABLE_HASHSZ 256
 static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
 
+static struct sock *fibnl = NULL;
+
+
 struct fib_table *fib_new_table(u32 id)
 {
        struct fib_table *tb;
@@ -811,13 +814,13 @@ static void nl_fib_input(struct sock *sk, int len)
        pid = NETLINK_CB(skb).pid;       /* pid of sending process */
        NETLINK_CB(skb).pid = 0;         /* from kernel */
        NETLINK_CB(skb).dst_group = 0;  /* unicast */
-       netlink_unicast(sk, skb, pid, MSG_DONTWAIT);
+       netlink_unicast(fibnl, skb, pid, MSG_DONTWAIT);
 }
 
 static void nl_fib_lookup_init(void)
 {
-       netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0, nl_fib_input,
-                               NULL, THIS_MODULE);
+       fibnl = netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0,
+                                     nl_fib_input, NULL, THIS_MODULE);
 }
 
 static void fib_disable_ip(struct net_device *dev, int force)
index b04a6ee5a9a118c313bbc450922597cc857f20b6..7eb83ebed2ec5754af310cb17db9a8108bcb0578 100644 (file)
@@ -839,15 +839,11 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
 static DEFINE_MUTEX(inet_diag_mutex);
 
-static void inet_diag_rcv(struct sock *sk, int len)
+static void inet_diag_rcv(struct sk_buff *skb)
 {
-       unsigned int qlen = 0;
-
-       do {
-               mutex_lock(&inet_diag_mutex);
-               qlen = netlink_run_queue(sk, qlen, &inet_diag_rcv_msg);
-               mutex_unlock(&inet_diag_mutex);
-       } while (qlen);
+       mutex_lock(&inet_diag_mutex);
+       netlink_rcv_skb(skb, &inet_diag_rcv_msg);
+       mutex_unlock(&inet_diag_mutex);
 }
 
 static DEFINE_SPINLOCK(inet_diag_register_lock);
index aaa3f5c567611ab77168d0104ea0b61fd6671cba..23cbfc7c80fd982f7b1f57a51d7cc2125342432a 100644 (file)
@@ -475,7 +475,7 @@ ipq_dev_drop(int ifindex)
 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 
 static inline void
-ipq_rcv_skb(struct sk_buff *skb)
+__ipq_rcv_skb(struct sk_buff *skb)
 {
        int status, type, pid, flags, nlmsglen, skblen;
        struct nlmsghdr *nlh;
@@ -533,19 +533,10 @@ ipq_rcv_skb(struct sk_buff *skb)
 }
 
 static void
-ipq_rcv_sk(struct sock *sk, int len)
+ipq_rcv_skb(struct sk_buff *skb)
 {
-       struct sk_buff *skb;
-       unsigned int qlen;
-
        mutex_lock(&ipqnl_mutex);
-
-       for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
-               skb = skb_dequeue(&sk->sk_receive_queue);
-               ipq_rcv_skb(skb);
-               kfree_skb(skb);
-       }
-
+       __ipq_rcv_skb(skb);
        mutex_unlock(&ipqnl_mutex);
 }
 
@@ -670,7 +661,7 @@ static int __init ip_queue_init(void)
 
        netlink_register_notifier(&ipq_nl_notifier);
        ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0,
-                                     ipq_rcv_sk, NULL, THIS_MODULE);
+                                     ipq_rcv_skb, NULL, THIS_MODULE);
        if (ipqnl == NULL) {
                printk(KERN_ERR "ip_queue: failed to create netlink socket\n");
                goto cleanup_netlink_notifier;
index c75f467a8f51175c4f536109b3742e85994f20a3..0473145ac534fd98dc60997418a94b1c68e37d91 100644 (file)
@@ -464,7 +464,7 @@ ipq_dev_drop(int ifindex)
 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 
 static inline void
-ipq_rcv_skb(struct sk_buff *skb)
+__ipq_rcv_skb(struct sk_buff *skb)
 {
        int status, type, pid, flags, nlmsglen, skblen;
        struct nlmsghdr *nlh;
@@ -522,19 +522,10 @@ ipq_rcv_skb(struct sk_buff *skb)
 }
 
 static void
-ipq_rcv_sk(struct sock *sk, int len)
+ipq_rcv_skb(struct sk_buff *skb)
 {
-       struct sk_buff *skb;
-       unsigned int qlen;
-
        mutex_lock(&ipqnl_mutex);
-
-       for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
-               skb = skb_dequeue(&sk->sk_receive_queue);
-               ipq_rcv_skb(skb);
-               kfree_skb(skb);
-       }
-
+       __ipq_rcv_skb(skb);
        mutex_unlock(&ipqnl_mutex);
 }
 
@@ -658,8 +649,8 @@ static int __init ip6_queue_init(void)
        struct proc_dir_entry *proc;
 
        netlink_register_notifier(&ipq_nl_notifier);
-       ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0, ipq_rcv_sk,
-                                       NULL, THIS_MODULE);
+       ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0,
+                                     ipq_rcv_skb, NULL, THIS_MODULE);
        if (ipqnl == NULL) {
                printk(KERN_ERR "ip6_queue: failed to create netlink socket\n");
                goto cleanup_netlink_notifier;
index 99775af19ff4071ff71407dadb72ea618dc45918..2128542995f79279fb026bcc4688eef46b434305 100644 (file)
@@ -169,15 +169,11 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        }
 }
 
-static void nfnetlink_rcv(struct sock *sk, int len)
+static void nfnetlink_rcv(struct sk_buff *skb)
 {
-       unsigned int qlen = 0;
-
-       do {
-               nfnl_lock();
-               qlen = netlink_run_queue(sk, qlen, nfnetlink_rcv_msg);
-               nfnl_unlock();
-       } while (qlen);
+       nfnl_lock();
+       netlink_rcv_skb(skb, &nfnetlink_rcv_msg);
+       nfnl_unlock();
 }
 
 static void __exit nfnetlink_exit(void)
index 4ce7dcbcb6ef94c2c87d934322abb8ab1587ca8c..c776bcd9f8257b8008b968aec37c93d389d6854f 100644 (file)
@@ -80,7 +80,7 @@ struct netlink_sock {
        struct netlink_callback *cb;
        struct mutex            *cb_mutex;
        struct mutex            cb_def_mutex;
-       void                    (*data_ready)(struct sock *sk, int bytes);
+       void                    (*netlink_rcv)(struct sk_buff *skb);
        struct module           *module;
 };
 
@@ -127,7 +127,6 @@ static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
 
 static int netlink_dump(struct sock *sk);
 static void netlink_destroy_callback(struct netlink_callback *cb);
-static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb);
 
 static DEFINE_RWLOCK(nl_table_lock);
 static atomic_t nl_table_users = ATOMIC_INIT(0);
@@ -709,21 +708,17 @@ static void netlink_overrun(struct sock *sk)
 
 static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid)
 {
-       int protocol = ssk->sk_protocol;
-       struct net *net;
        struct sock *sock;
        struct netlink_sock *nlk;
 
-       net = ssk->sk_net;
-       sock = netlink_lookup(net, protocol, pid);
+       sock = netlink_lookup(ssk->sk_net, ssk->sk_protocol, pid);
        if (!sock)
                return ERR_PTR(-ECONNREFUSED);
 
        /* Don't bother queuing skb if kernel socket has no input function */
        nlk = nlk_sk(sock);
-       if ((netlink_is_kernel(sock) && !nlk->data_ready) ||
-           (sock->sk_state == NETLINK_CONNECTED &&
-            nlk->dst_pid != nlk_sk(ssk)->pid)) {
+       if (sock->sk_state == NETLINK_CONNECTED &&
+           nlk->dst_pid != nlk_sk(ssk)->pid) {
                sock_put(sock);
                return ERR_PTR(-ECONNREFUSED);
        }
@@ -837,7 +832,34 @@ static inline struct sk_buff *netlink_trim(struct sk_buff *skb,
        return skb;
 }
 
-int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock)
+static inline void netlink_rcv_wake(struct sock *sk)
+{
+       struct netlink_sock *nlk = nlk_sk(sk);
+
+       if (skb_queue_empty(&sk->sk_receive_queue))
+               clear_bit(0, &nlk->state);
+       if (!test_bit(0, &nlk->state))
+               wake_up_interruptible(&nlk->wait);
+}
+
+static inline int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb)
+{
+       int ret;
+       struct netlink_sock *nlk = nlk_sk(sk);
+
+       ret = -ECONNREFUSED;
+       if (nlk->netlink_rcv != NULL) {
+               ret = skb->len;
+               skb_set_owner_r(skb, sk);
+               nlk->netlink_rcv(skb);
+       }
+       kfree_skb(skb);
+       sock_put(sk);
+       return ret;
+}
+
+int netlink_unicast(struct sock *ssk, struct sk_buff *skb,
+                   u32 pid, int nonblock)
 {
        struct sock *sk;
        int err;
@@ -852,6 +874,9 @@ retry:
                kfree_skb(skb);
                return PTR_ERR(sk);
        }
+       if (netlink_is_kernel(sk))
+               return netlink_unicast_kernel(sk, skb);
+
        err = netlink_attachskb(sk, skb, nonblock, timeo, ssk);
        if (err == 1)
                goto retry;
@@ -1151,16 +1176,6 @@ static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
        put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info);
 }
 
-static inline void netlink_rcv_wake(struct sock *sk)
-{
-       struct netlink_sock *nlk = nlk_sk(sk);
-
-       if (skb_queue_empty(&sk->sk_receive_queue))
-               clear_bit(0, &nlk->state);
-       if (!test_bit(0, &nlk->state))
-               wake_up_interruptible(&nlk->wait);
-}
-
 static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
                           struct msghdr *msg, size_t len)
 {
@@ -1308,11 +1323,7 @@ out:
 
 static void netlink_data_ready(struct sock *sk, int len)
 {
-       struct netlink_sock *nlk = nlk_sk(sk);
-
-       if (nlk->data_ready)
-               nlk->data_ready(sk, len);
-       netlink_rcv_wake(sk);
+       BUG();
 }
 
 /*
@@ -1323,7 +1334,7 @@ static void netlink_data_ready(struct sock *sk, int len)
 
 struct sock *
 netlink_kernel_create(struct net *net, int unit, unsigned int groups,
-                     void (*input)(struct sock *sk, int len),
+                     void (*input)(struct sk_buff *skb),
                      struct mutex *cb_mutex, struct module *module)
 {
        struct socket *sock;
@@ -1352,7 +1363,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
        sk = sock->sk;
        sk->sk_data_ready = netlink_data_ready;
        if (input)
-               nlk_sk(sk)->data_ready = input;
+               nlk_sk(sk)->netlink_rcv = input;
 
        if (netlink_insert(sk, net, 0))
                goto out_sock_release;
@@ -1552,12 +1563,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
 
        netlink_dump(sk);
        sock_put(sk);
-
-       /* We successfully started a dump, by returning -EINTR we
-        * signal the queue mangement to interrupt processing of
-        * any netlink messages so userspace gets a chance to read
-        * the results. */
-       return -EINTR;
+       return 0;
 }
 
 void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
@@ -1594,13 +1600,15 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
        netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
 }
 
-static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
+int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
                                                     struct nlmsghdr *))
 {
        struct nlmsghdr *nlh;
        int err;
 
        while (skb->len >= nlmsg_total_size(0)) {
+               int msglen;
+
                nlh = nlmsg_hdr(skb);
                err = 0;
 
@@ -1616,85 +1624,19 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
                        goto skip;
 
                err = cb(skb, nlh);
-               if (err == -EINTR) {
-                       /* Not an error, but we interrupt processing */
-                       netlink_queue_skip(nlh, skb);
-                       return err;
-               }
 skip:
                if (nlh->nlmsg_flags & NLM_F_ACK || err)
                        netlink_ack(skb, nlh, err);
 
-               netlink_queue_skip(nlh, skb);
+               msglen = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (msglen > skb->len)
+                       msglen = skb->len;
+               skb_pull(skb, msglen);
        }
 
        return 0;
 }
 
-/**
- * nelink_run_queue - Process netlink receive queue.
- * @sk: Netlink socket containing the queue
- * @qlen: Initial queue length
- * @cb: Callback function invoked for each netlink message found
- *
- * Processes as much as there was in the queue upon entry and invokes
- * a callback function for each netlink message found. The callback
- * function may refuse a message by returning a negative error code
- * but setting the error pointer to 0 in which case this function
- * returns with a qlen != 0.
- *
- * qlen must be initialized to 0 before the initial entry, afterwards
- * the function may be called repeatedly until the returned qlen is 0.
- *
- * The callback function may return -EINTR to signal that processing
- * of netlink messages shall be interrupted. In this case the message
- * currently being processed will NOT be requeued onto the receive
- * queue.
- */
-unsigned int netlink_run_queue(struct sock *sk, unsigned int qlen,
-                              int (*cb)(struct sk_buff *, struct nlmsghdr *))
-{
-       struct sk_buff *skb;
-
-       if (!qlen || qlen > skb_queue_len(&sk->sk_receive_queue))
-               qlen = skb_queue_len(&sk->sk_receive_queue);
-
-       for (; qlen; qlen--) {
-               skb = skb_dequeue(&sk->sk_receive_queue);
-               if (netlink_rcv_skb(skb, cb)) {
-                       if (skb->len)
-                               skb_queue_head(&sk->sk_receive_queue, skb);
-                       else {
-                               kfree_skb(skb);
-                               qlen--;
-                       }
-                       break;
-               }
-
-               kfree_skb(skb);
-       }
-
-       return qlen;
-}
-
-/**
- * netlink_queue_skip - Skip netlink message while processing queue.
- * @nlh: Netlink message to be skipped
- * @skb: Socket buffer containing the netlink messages.
- *
- * Pulls the given netlink message off the socket buffer so the next
- * call to netlink_queue_run() will not reconsider the message.
- */
-static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb)
-{
-       int msglen = NLMSG_ALIGN(nlh->nlmsg_len);
-
-       if (msglen > skb->len)
-               msglen = skb->len;
-
-       skb_pull(skb, msglen);
-}
-
 /**
  * nlmsg_notify - send a notification netlink message
  * @sk: netlink socket to use
@@ -1998,7 +1940,7 @@ panic:
 core_initcall(netlink_proto_init);
 
 EXPORT_SYMBOL(netlink_ack);
-EXPORT_SYMBOL(netlink_run_queue);
+EXPORT_SYMBOL(netlink_rcv_skb);
 EXPORT_SYMBOL(netlink_broadcast);
 EXPORT_SYMBOL(netlink_dump_start);
 EXPORT_SYMBOL(netlink_kernel_create);
index 3f1104dc128bbe5b33eb1c44dfa96d167abcb3e6..150579a21469d664563dfcee8bdef5d3f0e355e1 100644 (file)
@@ -470,15 +470,11 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        return ops->doit(skb, &info);
 }
 
-static void genl_rcv(struct sock *sk, int len)
+static void genl_rcv(struct sk_buff *skb)
 {
-       unsigned int qlen = 0;
-
-       do {
-               genl_lock();
-               qlen = netlink_run_queue(sk, qlen, genl_rcv_msg);
-               genl_unlock();
-       } while (qlen && genl_sock && genl_sock->sk_receive_queue.qlen);
+       genl_lock();
+       netlink_rcv_skb(skb, &genl_rcv_msg);
+       genl_unlock();
 }
 
 /**************************************************************************
index 5238f6a8dfad9face8a889132fe3ba4aa27e19ed..d41588d101d01db756f5db3a1cd40d6e783883a9 100644 (file)
@@ -1895,16 +1895,11 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        return link->doit(skb, nlh, attrs);
 }
 
-static void xfrm_netlink_rcv(struct sock *sk, int len)
+static void xfrm_netlink_rcv(struct sk_buff *skb)
 {
-       unsigned int qlen = 0;
-
-       do {
-               mutex_lock(&xfrm_cfg_mutex);
-               qlen = netlink_run_queue(sk, qlen, &xfrm_user_rcv_msg);
-               mutex_unlock(&xfrm_cfg_mutex);
-
-       } while (qlen);
+       mutex_lock(&xfrm_cfg_mutex);
+       netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
+       mutex_unlock(&xfrm_cfg_mutex);
 }
 
 static inline size_t xfrm_expire_msgsize(void)