aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDenis V. Lunev <den@openvz.org>2007-10-11 00:15:29 -0400
committerDavid S. Miller <davem@davemloft.net>2007-10-11 00:15:29 -0400
commitcd40b7d3983c708aabe3d3008ec64ffce56d33b0 (patch)
tree0d6fe9cfd2f03fdeee126e317d4bfb145afc458d /drivers
parentaed815601f3f95281ab3a01f7e2cbe1bd54285a0 (diff)
[NET]: make netlink user -> kernel interface synchronious
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/connector/connector.c14
-rw-r--r--drivers/scsi/scsi_netlink.c25
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c82
3 files changed, 38 insertions, 83 deletions
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 569070997cc1..0e328d387af4 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -235,18 +235,6 @@ out:
235} 235}
236 236
237/* 237/*
238 * Netlink socket input callback - dequeues the skbs and calls the
239 * main netlink receiving function.
240 */
241static void cn_input(struct sock *sk, int len)
242{
243 struct sk_buff *skb;
244
245 while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
246 cn_rx_skb(skb);
247}
248
249/*
250 * Notification routing. 238 * Notification routing.
251 * 239 *
252 * Gets id and checks if there are notification request for it's idx 240 * Gets id and checks if there are notification request for it's idx
@@ -442,7 +430,7 @@ static int __devinit cn_init(void)
442 struct cn_dev *dev = &cdev; 430 struct cn_dev *dev = &cdev;
443 int err; 431 int err;
444 432
445 dev->input = cn_input; 433 dev->input = cn_rx_skb;
446 dev->id.idx = cn_idx; 434 dev->id.idx = cn_idx;
447 dev->id.val = cn_val; 435 dev->id.val = cn_val;
448 436
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 163acf6ad2d3..40579edca101 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -64,7 +64,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
64 64
65 if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { 65 if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
66 err = -EBADMSG; 66 err = -EBADMSG;
67 goto next_msg; 67 return;
68 } 68 }
69 69
70 hdr = NLMSG_DATA(nlh); 70 hdr = NLMSG_DATA(nlh);
@@ -99,27 +99,6 @@ next_msg:
99 99
100 100
101/** 101/**
102 * scsi_nl_rcv_msg -
103 * Receive handler for a socket. Extracts a received message buffer from
104 * the socket, and starts message processing.
105 *
106 * @sk: socket
107 * @len: unused
108 *
109 **/
110static void
111scsi_nl_rcv(struct sock *sk, int len)
112{
113 struct sk_buff *skb;
114
115 while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
116 scsi_nl_rcv_msg(skb);
117 kfree_skb(skb);
118 }
119}
120
121
122/**
123 * scsi_nl_rcv_event - 102 * scsi_nl_rcv_event -
124 * Event handler for a netlink socket. 103 * Event handler for a netlink socket.
125 * 104 *
@@ -168,7 +147,7 @@ scsi_netlink_init(void)
168 } 147 }
169 148
170 scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, 149 scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT,
171 SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL, 150 SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL,
172 THIS_MODULE); 151 THIS_MODULE);
173 if (!scsi_nl_sock) { 152 if (!scsi_nl_sock) {
174 printk(KERN_ERR "%s: register of recieve handler failed\n", 153 printk(KERN_ERR "%s: register of recieve handler failed\n",
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 4916f01230dc..5428d15f23c6 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1097,61 +1097,49 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1097} 1097}
1098 1098
1099/* 1099/*
1100 * Get message from skb (based on rtnetlink_rcv_skb). Each message is 1100 * Get message from skb. Each message is processed by iscsi_if_recv_msg.
1101 * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or 1101 * Malformed skbs with wrong lengths or invalid creds are not processed.
1102 * invalid creds are discarded silently.
1103 */ 1102 */
1104static void 1103static void
1105iscsi_if_rx(struct sock *sk, int len) 1104iscsi_if_rx(struct sk_buff *skb)
1106{ 1105{
1107 struct sk_buff *skb;
1108
1109 mutex_lock(&rx_queue_mutex); 1106 mutex_lock(&rx_queue_mutex);
1110 while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 1107 while (skb->len >= NLMSG_SPACE(0)) {
1111 if (NETLINK_CREDS(skb)->uid) { 1108 int err;
1112 skb_pull(skb, skb->len); 1109 uint32_t rlen;
1113 goto free_skb; 1110 struct nlmsghdr *nlh;
1111 struct iscsi_uevent *ev;
1112
1113 nlh = nlmsg_hdr(skb);
1114 if (nlh->nlmsg_len < sizeof(*nlh) ||
1115 skb->len < nlh->nlmsg_len) {
1116 break;
1114 } 1117 }
1115 1118
1116 while (skb->len >= NLMSG_SPACE(0)) { 1119 ev = NLMSG_DATA(nlh);
1117 int err; 1120 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1118 uint32_t rlen; 1121 if (rlen > skb->len)
1119 struct nlmsghdr *nlh; 1122 rlen = skb->len;
1120 struct iscsi_uevent *ev;
1121 1123
1122 nlh = nlmsg_hdr(skb); 1124 err = iscsi_if_recv_msg(skb, nlh);
1123 if (nlh->nlmsg_len < sizeof(*nlh) || 1125 if (err) {
1124 skb->len < nlh->nlmsg_len) { 1126 ev->type = ISCSI_KEVENT_IF_ERROR;
1125 break; 1127 ev->iferror = err;
1126 }
1127
1128 ev = NLMSG_DATA(nlh);
1129 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1130 if (rlen > skb->len)
1131 rlen = skb->len;
1132
1133 err = iscsi_if_recv_msg(skb, nlh);
1134 if (err) {
1135 ev->type = ISCSI_KEVENT_IF_ERROR;
1136 ev->iferror = err;
1137 }
1138 do {
1139 /*
1140 * special case for GET_STATS:
1141 * on success - sending reply and stats from
1142 * inside of if_recv_msg(),
1143 * on error - fall through.
1144 */
1145 if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
1146 break;
1147 err = iscsi_if_send_reply(
1148 NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
1149 nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
1150 } while (err < 0 && err != -ECONNREFUSED);
1151 skb_pull(skb, rlen);
1152 } 1128 }
1153free_skb: 1129 do {
1154 kfree_skb(skb); 1130 /*
1131 * special case for GET_STATS:
1132 * on success - sending reply and stats from
1133 * inside of if_recv_msg(),
1134 * on error - fall through.
1135 */
1136 if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
1137 break;
1138 err = iscsi_if_send_reply(
1139 NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
1140 nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
1141 } while (err < 0 && err != -ECONNREFUSED);
1142 skb_pull(skb, rlen);
1155 } 1143 }
1156 mutex_unlock(&rx_queue_mutex); 1144 mutex_unlock(&rx_queue_mutex);
1157} 1145}