Skip to content

Commit

Permalink
[NET]: make netlink user -> kernel interface synchronious
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Denis V. Lunev authored and David S. Miller committed Oct 11, 2007
1 parent aed8156 commit cd40b7d
Show file tree
Hide file tree
Showing 18 changed files with 130 additions and 299 deletions.
14 changes: 1 addition & 13 deletions drivers/connector/connector.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,18 +234,6 @@ static void cn_rx_skb(struct sk_buff *__skb)
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.
*
Expand Down Expand Up @@ -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;

Expand Down
25 changes: 2 additions & 23 deletions drivers/scsi/scsi_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -98,27 +98,6 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
}


/**
* 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.
Expand Down Expand Up @@ -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",
Expand Down
82 changes: 35 additions & 47 deletions drivers/scsi/scsi_transport_iscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
14 changes: 1 addition & 13 deletions fs/ecryptfs/netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down
2 changes: 1 addition & 1 deletion include/linux/connector.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
2 changes: 1 addition & 1 deletion include/linux/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions include/net/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 2 additions & 10 deletions kernel/audit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
12 changes: 4 additions & 8 deletions net/core/rtnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 2 additions & 12 deletions net/decnet/netfilter/dn_rtmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down
9 changes: 6 additions & 3 deletions net/ipv4/fib_frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 4 additions & 8 deletions net/ipv4/inet_diag.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
17 changes: 4 additions & 13 deletions net/ipv4/netfilter/ip_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit cd40b7d

Please sign in to comment.