aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeniy Polyakov <johnpol@2ka.mipt.ru>2005-09-26 18:06:50 -0400
committerDavid S. Miller <davem@davemloft.net>2005-09-26 18:06:50 -0400
commitacd042bb2de50d4e6fb969281a00cc8b8b71e46d (patch)
treec696f1c0bdbc6eabcb9c13d395abb73f0d08e129
parentb9d717a7b413f227ebb2d61d9c118335f7292137 (diff)
[CONNECTOR]: async connector mode.
If input message rate from userspace is too high, do not drop them, but try to deliver using work queue allocation. Failing there is some kind of congestion control. It also removes warn_on on this condition, which scares people. Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/connector/cn_queue.c32
-rw-r--r--drivers/connector/connector.c74
-rw-r--r--include/linux/connector.h21
3 files changed, 72 insertions, 55 deletions
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index 966632182e2d..9f2f00d82917 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -31,16 +31,19 @@
31#include <linux/connector.h> 31#include <linux/connector.h>
32#include <linux/delay.h> 32#include <linux/delay.h>
33 33
34static void cn_queue_wrapper(void *data) 34void cn_queue_wrapper(void *data)
35{ 35{
36 struct cn_callback_entry *cbq = data; 36 struct cn_callback_data *d = data;
37 37
38 cbq->cb->callback(cbq->cb->priv); 38 d->callback(d->callback_priv);
39 cbq->destruct_data(cbq->ddata); 39
40 cbq->ddata = NULL; 40 d->destruct_data(d->ddata);
41 d->ddata = NULL;
42
43 kfree(d->free);
41} 44}
42 45
43static struct cn_callback_entry *cn_queue_alloc_callback_entry(struct cn_callback *cb) 46static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struct cb_id *id, void (*callback)(void *))
44{ 47{
45 struct cn_callback_entry *cbq; 48 struct cn_callback_entry *cbq;
46 49
@@ -50,8 +53,11 @@ static struct cn_callback_entry *cn_queue_alloc_callback_entry(struct cn_callbac
50 return NULL; 53 return NULL;
51 } 54 }
52 55
53 cbq->cb = cb; 56 snprintf(cbq->id.name, sizeof(cbq->id.name), "%s", name);
54 INIT_WORK(&cbq->work, &cn_queue_wrapper, cbq); 57 memcpy(&cbq->id.id, id, sizeof(struct cb_id));
58 cbq->data.callback = callback;
59
60 INIT_WORK(&cbq->work, &cn_queue_wrapper, &cbq->data);
55 return cbq; 61 return cbq;
56} 62}
57 63
@@ -68,12 +74,12 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
68 return ((i1->idx == i2->idx) && (i1->val == i2->val)); 74 return ((i1->idx == i2->idx) && (i1->val == i2->val));
69} 75}
70 76
71int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb) 77int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *))
72{ 78{
73 struct cn_callback_entry *cbq, *__cbq; 79 struct cn_callback_entry *cbq, *__cbq;
74 int found = 0; 80 int found = 0;
75 81
76 cbq = cn_queue_alloc_callback_entry(cb); 82 cbq = cn_queue_alloc_callback_entry(name, id, callback);
77 if (!cbq) 83 if (!cbq)
78 return -ENOMEM; 84 return -ENOMEM;
79 85
@@ -82,7 +88,7 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb)
82 88
83 spin_lock_bh(&dev->queue_lock); 89 spin_lock_bh(&dev->queue_lock);
84 list_for_each_entry(__cbq, &dev->queue_list, callback_entry) { 90 list_for_each_entry(__cbq, &dev->queue_list, callback_entry) {
85 if (cn_cb_equal(&__cbq->cb->id, &cb->id)) { 91 if (cn_cb_equal(&__cbq->id.id, id)) {
86 found = 1; 92 found = 1;
87 break; 93 break;
88 } 94 }
@@ -99,7 +105,7 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb)
99 105
100 cbq->nls = dev->nls; 106 cbq->nls = dev->nls;
101 cbq->seq = 0; 107 cbq->seq = 0;
102 cbq->group = cbq->cb->id.idx; 108 cbq->group = cbq->id.id.idx;
103 109
104 return 0; 110 return 0;
105} 111}
@@ -111,7 +117,7 @@ void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id)
111 117
112 spin_lock_bh(&dev->queue_lock); 118 spin_lock_bh(&dev->queue_lock);
113 list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) { 119 list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) {
114 if (cn_cb_equal(&cbq->cb->id, id)) { 120 if (cn_cb_equal(&cbq->id.id, id)) {
115 list_del(&cbq->callback_entry); 121 list_del(&cbq->callback_entry);
116 found = 1; 122 found = 1;
117 break; 123 break;
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index aaf6d468a8b9..bb0b3a8de14b 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -84,7 +84,7 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask)
84 spin_lock_bh(&dev->cbdev->queue_lock); 84 spin_lock_bh(&dev->cbdev->queue_lock);
85 list_for_each_entry(__cbq, &dev->cbdev->queue_list, 85 list_for_each_entry(__cbq, &dev->cbdev->queue_list,
86 callback_entry) { 86 callback_entry) {
87 if (cn_cb_equal(&__cbq->cb->id, &msg->id)) { 87 if (cn_cb_equal(&__cbq->id.id, &msg->id)) {
88 found = 1; 88 found = 1;
89 group = __cbq->group; 89 group = __cbq->group;
90 } 90 }
@@ -127,42 +127,56 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
127{ 127{
128 struct cn_callback_entry *__cbq; 128 struct cn_callback_entry *__cbq;
129 struct cn_dev *dev = &cdev; 129 struct cn_dev *dev = &cdev;
130 int found = 0; 130 int err = -ENODEV;
131 131
132 spin_lock_bh(&dev->cbdev->queue_lock); 132 spin_lock_bh(&dev->cbdev->queue_lock);
133 list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) { 133 list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) {
134 if (cn_cb_equal(&__cbq->cb->id, &msg->id)) { 134 if (cn_cb_equal(&__cbq->id.id, &msg->id)) {
135 /*
136 * Let's scream if there is some magic and the
137 * data will arrive asynchronously here.
138 * [i.e. netlink messages will be queued].
139 * After the first warning I will fix it
140 * quickly, but now I think it is
141 * impossible. --zbr (2004_04_27).
142 */
143 if (likely(!test_bit(0, &__cbq->work.pending) && 135 if (likely(!test_bit(0, &__cbq->work.pending) &&
144 __cbq->ddata == NULL)) { 136 __cbq->data.ddata == NULL)) {
145 __cbq->cb->priv = msg; 137 __cbq->data.callback_priv = msg;
146 138
147 __cbq->ddata = data; 139 __cbq->data.ddata = data;
148 __cbq->destruct_data = destruct_data; 140 __cbq->data.destruct_data = destruct_data;
149 141
150 if (queue_work(dev->cbdev->cn_queue, 142 if (queue_work(dev->cbdev->cn_queue,
151 &__cbq->work)) 143 &__cbq->work))
152 found = 1; 144 err = 0;
153 } else { 145 } else {
154 printk("%s: cbq->data=%p, " 146 struct work_struct *w;
155 "work->pending=%08lx.\n", 147 struct cn_callback_data *d;
156 __func__, __cbq->ddata, 148
157 __cbq->work.pending); 149 w = kzalloc(sizeof(*w) + sizeof(*d), GFP_ATOMIC);
158 WARN_ON(1); 150 if (w) {
151 d = (struct cn_callback_data *)(w+1);
152
153 d->callback_priv = msg;
154 d->callback = __cbq->data.callback;
155 d->ddata = data;
156 d->destruct_data = destruct_data;
157 d->free = w;
158
159 INIT_LIST_HEAD(&w->entry);
160 w->pending = 0;
161 w->func = &cn_queue_wrapper;
162 w->data = d;
163 init_timer(&w->timer);
164
165 if (queue_work(dev->cbdev->cn_queue, w))
166 err = 0;
167 else {
168 kfree(w);
169 err = -EINVAL;
170 }
171 } else
172 err = -ENOMEM;
159 } 173 }
160 break; 174 break;
161 } 175 }
162 } 176 }
163 spin_unlock_bh(&dev->cbdev->queue_lock); 177 spin_unlock_bh(&dev->cbdev->queue_lock);
164 178
165 return found ? 0 : -ENODEV; 179 return err;
166} 180}
167 181
168/* 182/*
@@ -291,22 +305,10 @@ int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *))
291{ 305{
292 int err; 306 int err;
293 struct cn_dev *dev = &cdev; 307 struct cn_dev *dev = &cdev;
294 struct cn_callback *cb;
295
296 cb = kzalloc(sizeof(*cb), GFP_KERNEL);
297 if (!cb)
298 return -ENOMEM;
299
300 scnprintf(cb->name, sizeof(cb->name), "%s", name);
301 308
302 memcpy(&cb->id, id, sizeof(cb->id)); 309 err = cn_queue_add_callback(dev->cbdev, name, id, callback);
303 cb->callback = callback; 310 if (err)
304
305 err = cn_queue_add_callback(dev->cbdev, cb);
306 if (err) {
307 kfree(cb);
308 return err; 311 return err;
309 }
310 312
311 cn_notify(id, 0); 313 cn_notify(id, 0);
312 314
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 96de26301f84..86d4b0a81713 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -104,12 +104,19 @@ struct cn_queue_dev {
104 struct sock *nls; 104 struct sock *nls;
105}; 105};
106 106
107struct cn_callback { 107struct cn_callback_id {
108 unsigned char name[CN_CBQ_NAMELEN]; 108 unsigned char name[CN_CBQ_NAMELEN];
109
110 struct cb_id id; 109 struct cb_id id;
110};
111
112struct cn_callback_data {
113 void (*destruct_data) (void *);
114 void *ddata;
115
116 void *callback_priv;
111 void (*callback) (void *); 117 void (*callback) (void *);
112 void *priv; 118
119 void *free;
113}; 120};
114 121
115struct cn_callback_entry { 122struct cn_callback_entry {
@@ -118,8 +125,8 @@ struct cn_callback_entry {
118 struct work_struct work; 125 struct work_struct work;
119 struct cn_queue_dev *pdev; 126 struct cn_queue_dev *pdev;
120 127
121 void (*destruct_data) (void *); 128 struct cn_callback_id id;
122 void *ddata; 129 struct cn_callback_data data;
123 130
124 int seq, group; 131 int seq, group;
125 struct sock *nls; 132 struct sock *nls;
@@ -144,7 +151,7 @@ int cn_add_callback(struct cb_id *, char *, void (*callback) (void *));
144void cn_del_callback(struct cb_id *); 151void cn_del_callback(struct cb_id *);
145int cn_netlink_send(struct cn_msg *, u32, int); 152int cn_netlink_send(struct cn_msg *, u32, int);
146 153
147int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb); 154int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *));
148void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id); 155void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id);
149 156
150struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *); 157struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *);
@@ -152,6 +159,8 @@ void cn_queue_free_dev(struct cn_queue_dev *dev);
152 159
153int cn_cb_equal(struct cb_id *, struct cb_id *); 160int cn_cb_equal(struct cb_id *, struct cb_id *);
154 161
162void cn_queue_wrapper(void *data);
163
155extern int cn_already_initialized; 164extern int cn_already_initialized;
156 165
157#endif /* __KERNEL__ */ 166#endif /* __KERNEL__ */