aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/connector/connector.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2011-03-28 04:39:36 -0400
committerDavid S. Miller <davem@davemloft.net>2011-03-30 20:14:33 -0400
commit04f482faf50535229a5a5c8d629cf963899f857c (patch)
tree698d5c8e22e68f9a621c03972556e3a73c525465 /drivers/connector/connector.c
parente2666f84958adb3a034b98e99699b55705117e01 (diff)
connector: convert to synchronous netlink message processing
Commits 01a16b21 (netlink: kill eff_cap from struct netlink_skb_parms) and c53fa1ed (netlink: kill loginuid/sessionid/sid members from struct netlink_skb_parms) removed some members from struct netlink_skb_parms that depend on the current context, all netlink users are now required to do synchronous message processing. connector however queues received messages and processes them in a work queue, which is not valid anymore. This patch converts connector to do synchronous message processing by invoking the registered callback handler directly from the netlink receive function. In order to avoid invoking the callback with connector locks held, a reference count is added to struct cn_callback_entry, the reference is taken when finding a matching callback entry on the device's queue_list and released after the callback handler has been invoked. Signed-off-by: Patrick McHardy <kaber@trash.net> Acked-by: Evgeniy Polyakov <zbr@ioremap.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/connector/connector.c')
-rw-r--r--drivers/connector/connector.c47
1 files changed, 12 insertions, 35 deletions
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index f7554de3be5..d77005849af 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -122,51 +122,28 @@ EXPORT_SYMBOL_GPL(cn_netlink_send);
122 */ 122 */
123static int cn_call_callback(struct sk_buff *skb) 123static int cn_call_callback(struct sk_buff *skb)
124{ 124{
125 struct cn_callback_entry *__cbq, *__new_cbq; 125 struct cn_callback_entry *i, *cbq = NULL;
126 struct cn_dev *dev = &cdev; 126 struct cn_dev *dev = &cdev;
127 struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb)); 127 struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb));
128 struct netlink_skb_parms *nsp = &NETLINK_CB(skb);
128 int err = -ENODEV; 129 int err = -ENODEV;
129 130
130 spin_lock_bh(&dev->cbdev->queue_lock); 131 spin_lock_bh(&dev->cbdev->queue_lock);
131 list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) { 132 list_for_each_entry(i, &dev->cbdev->queue_list, callback_entry) {
132 if (cn_cb_equal(&__cbq->id.id, &msg->id)) { 133 if (cn_cb_equal(&i->id.id, &msg->id)) {
133 if (likely(!work_pending(&__cbq->work) && 134 atomic_inc(&i->refcnt);
134 __cbq->data.skb == NULL)) { 135 cbq = i;
135 __cbq->data.skb = skb;
136
137 if (queue_work(dev->cbdev->cn_queue,
138 &__cbq->work))
139 err = 0;
140 else
141 err = -EINVAL;
142 } else {
143 struct cn_callback_data *d;
144
145 err = -ENOMEM;
146 __new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC);
147 if (__new_cbq) {
148 d = &__new_cbq->data;
149 d->skb = skb;
150 d->callback = __cbq->data.callback;
151 d->free = __new_cbq;
152
153 INIT_WORK(&__new_cbq->work,
154 &cn_queue_wrapper);
155
156 if (queue_work(dev->cbdev->cn_queue,
157 &__new_cbq->work))
158 err = 0;
159 else {
160 kfree(__new_cbq);
161 err = -EINVAL;
162 }
163 }
164 }
165 break; 136 break;
166 } 137 }
167 } 138 }
168 spin_unlock_bh(&dev->cbdev->queue_lock); 139 spin_unlock_bh(&dev->cbdev->queue_lock);
169 140
141 if (cbq != NULL) {
142 cbq->callback(msg, nsp);
143 kfree_skb(skb);
144 cn_queue_release_callback(cbq);
145 }
146
170 return err; 147 return err;
171} 148}
172 149