Skip to content

Commit 04f482f

Browse files
kaberdavem330
authored andcommitted
connector: convert to synchronous netlink message processing
Commits 01a16b2 (netlink: kill eff_cap from struct netlink_skb_parms) and c53fa1e (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 <[email protected]> Acked-by: Evgeniy Polyakov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e2666f8 commit 04f482f

File tree

3 files changed

+32
-89
lines changed

3 files changed

+32
-89
lines changed

drivers/connector/cn_queue.c

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,9 @@
3131
#include <linux/connector.h>
3232
#include <linux/delay.h>
3333

34-
void cn_queue_wrapper(struct work_struct *work)
35-
{
36-
struct cn_callback_entry *cbq =
37-
container_of(work, struct cn_callback_entry, work);
38-
struct cn_callback_data *d = &cbq->data;
39-
struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(d->skb));
40-
struct netlink_skb_parms *nsp = &NETLINK_CB(d->skb);
41-
42-
d->callback(msg, nsp);
43-
44-
kfree_skb(d->skb);
45-
d->skb = NULL;
46-
47-
kfree(d->free);
48-
}
49-
5034
static struct cn_callback_entry *
51-
cn_queue_alloc_callback_entry(const char *name, struct cb_id *id,
35+
cn_queue_alloc_callback_entry(struct cn_queue_dev *dev, const char *name,
36+
struct cb_id *id,
5237
void (*callback)(struct cn_msg *, struct netlink_skb_parms *))
5338
{
5439
struct cn_callback_entry *cbq;
@@ -59,17 +44,23 @@ cn_queue_alloc_callback_entry(const char *name, struct cb_id *id,
5944
return NULL;
6045
}
6146

47+
atomic_set(&cbq->refcnt, 1);
48+
49+
atomic_inc(&dev->refcnt);
50+
cbq->pdev = dev;
51+
6252
snprintf(cbq->id.name, sizeof(cbq->id.name), "%s", name);
6353
memcpy(&cbq->id.id, id, sizeof(struct cb_id));
64-
cbq->data.callback = callback;
65-
66-
INIT_WORK(&cbq->work, &cn_queue_wrapper);
54+
cbq->callback = callback;
6755
return cbq;
6856
}
6957

70-
static void cn_queue_free_callback(struct cn_callback_entry *cbq)
58+
void cn_queue_release_callback(struct cn_callback_entry *cbq)
7159
{
72-
flush_workqueue(cbq->pdev->cn_queue);
60+
if (!atomic_dec_and_test(&cbq->refcnt))
61+
return;
62+
63+
atomic_dec(&cbq->pdev->refcnt);
7364
kfree(cbq);
7465
}
7566

@@ -85,13 +76,10 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name,
8576
struct cn_callback_entry *cbq, *__cbq;
8677
int found = 0;
8778

88-
cbq = cn_queue_alloc_callback_entry(name, id, callback);
79+
cbq = cn_queue_alloc_callback_entry(dev, name, id, callback);
8980
if (!cbq)
9081
return -ENOMEM;
9182

92-
atomic_inc(&dev->refcnt);
93-
cbq->pdev = dev;
94-
9583
spin_lock_bh(&dev->queue_lock);
9684
list_for_each_entry(__cbq, &dev->queue_list, callback_entry) {
9785
if (cn_cb_equal(&__cbq->id.id, id)) {
@@ -104,8 +92,7 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name,
10492
spin_unlock_bh(&dev->queue_lock);
10593

10694
if (found) {
107-
cn_queue_free_callback(cbq);
108-
atomic_dec(&dev->refcnt);
95+
cn_queue_release_callback(cbq);
10996
return -EINVAL;
11097
}
11198

@@ -130,10 +117,8 @@ void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id)
130117
}
131118
spin_unlock_bh(&dev->queue_lock);
132119

133-
if (found) {
134-
cn_queue_free_callback(cbq);
135-
atomic_dec(&dev->refcnt);
136-
}
120+
if (found)
121+
cn_queue_release_callback(cbq);
137122
}
138123

139124
struct cn_queue_dev *cn_queue_alloc_dev(const char *name, struct sock *nls)
@@ -151,22 +136,13 @@ struct cn_queue_dev *cn_queue_alloc_dev(const char *name, struct sock *nls)
151136

152137
dev->nls = nls;
153138

154-
dev->cn_queue = alloc_ordered_workqueue(dev->name, 0);
155-
if (!dev->cn_queue) {
156-
kfree(dev);
157-
return NULL;
158-
}
159-
160139
return dev;
161140
}
162141

163142
void cn_queue_free_dev(struct cn_queue_dev *dev)
164143
{
165144
struct cn_callback_entry *cbq, *n;
166145

167-
flush_workqueue(dev->cn_queue);
168-
destroy_workqueue(dev->cn_queue);
169-
170146
spin_lock_bh(&dev->queue_lock);
171147
list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry)
172148
list_del(&cbq->callback_entry);

drivers/connector/connector.c

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -122,51 +122,28 @@ EXPORT_SYMBOL_GPL(cn_netlink_send);
122122
*/
123123
static int cn_call_callback(struct sk_buff *skb)
124124
{
125-
struct cn_callback_entry *__cbq, *__new_cbq;
125+
struct cn_callback_entry *i, *cbq = NULL;
126126
struct cn_dev *dev = &cdev;
127127
struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb));
128+
struct netlink_skb_parms *nsp = &NETLINK_CB(skb);
128129
int err = -ENODEV;
129130

130131
spin_lock_bh(&dev->cbdev->queue_lock);
131-
list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) {
132-
if (cn_cb_equal(&__cbq->id.id, &msg->id)) {
133-
if (likely(!work_pending(&__cbq->work) &&
134-
__cbq->data.skb == NULL)) {
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-
}
132+
list_for_each_entry(i, &dev->cbdev->queue_list, callback_entry) {
133+
if (cn_cb_equal(&i->id.id, &msg->id)) {
134+
atomic_inc(&i->refcnt);
135+
cbq = i;
165136
break;
166137
}
167138
}
168139
spin_unlock_bh(&dev->cbdev->queue_lock);
169140

141+
if (cbq != NULL) {
142+
cbq->callback(msg, nsp);
143+
kfree_skb(skb);
144+
cn_queue_release_callback(cbq);
145+
}
146+
170147
return err;
171148
}
172149

include/linux/connector.h

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ struct cn_queue_dev {
8888
atomic_t refcnt;
8989
unsigned char name[CN_CBQ_NAMELEN];
9090

91-
struct workqueue_struct *cn_queue;
92-
9391
struct list_head queue_list;
9492
spinlock_t queue_lock;
9593

@@ -101,20 +99,13 @@ struct cn_callback_id {
10199
struct cb_id id;
102100
};
103101

104-
struct cn_callback_data {
105-
struct sk_buff *skb;
106-
void (*callback) (struct cn_msg *, struct netlink_skb_parms *);
107-
108-
void *free;
109-
};
110-
111102
struct cn_callback_entry {
112103
struct list_head callback_entry;
113-
struct work_struct work;
104+
atomic_t refcnt;
114105
struct cn_queue_dev *pdev;
115106

116107
struct cn_callback_id id;
117-
struct cn_callback_data data;
108+
void (*callback) (struct cn_msg *, struct netlink_skb_parms *);
118109

119110
u32 seq, group;
120111
};
@@ -138,13 +129,12 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name,
138129
struct cb_id *id,
139130
void (*callback)(struct cn_msg *, struct netlink_skb_parms *));
140131
void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id);
132+
void cn_queue_release_callback(struct cn_callback_entry *);
141133

142134
struct cn_queue_dev *cn_queue_alloc_dev(const char *name, struct sock *);
143135
void cn_queue_free_dev(struct cn_queue_dev *dev);
144136

145137
int cn_cb_equal(struct cb_id *, struct cb_id *);
146138

147-
void cn_queue_wrapper(struct work_struct *work);
148-
149139
#endif /* __KERNEL__ */
150140
#endif /* __CONNECTOR_H */

0 commit comments

Comments
 (0)