[PATCH] cond_resched_lock() fix
[linux-2.6] / net / rxrpc / krxiod.c
1 /* krxiod.c: Rx I/O daemon
2  *
3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #include <linux/sched.h>
13 #include <linux/completion.h>
14 #include <linux/spinlock.h>
15 #include <linux/init.h>
16 #include <rxrpc/krxiod.h>
17 #include <rxrpc/transport.h>
18 #include <rxrpc/peer.h>
19 #include <rxrpc/call.h>
20 #include "internal.h"
21
22 static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxiod_sleepq);
23 static DECLARE_COMPLETION(rxrpc_krxiod_dead);
24
25 static atomic_t rxrpc_krxiod_qcount = ATOMIC_INIT(0);
26
27 static LIST_HEAD(rxrpc_krxiod_transportq);
28 static DEFINE_SPINLOCK(rxrpc_krxiod_transportq_lock);
29
30 static LIST_HEAD(rxrpc_krxiod_callq);
31 static DEFINE_SPINLOCK(rxrpc_krxiod_callq_lock);
32
33 static volatile int rxrpc_krxiod_die;
34
35 /*****************************************************************************/
36 /*
37  * Rx I/O daemon
38  */
39 static int rxrpc_krxiod(void *arg)
40 {
41         DECLARE_WAITQUEUE(krxiod,current);
42
43         printk("Started krxiod %d\n",current->pid);
44
45         daemonize("krxiod");
46
47         /* loop around waiting for work to do */
48         do {
49                 /* wait for work or to be told to exit */
50                 _debug("### Begin Wait");
51                 if (!atomic_read(&rxrpc_krxiod_qcount)) {
52                         set_current_state(TASK_INTERRUPTIBLE);
53
54                         add_wait_queue(&rxrpc_krxiod_sleepq, &krxiod);
55
56                         for (;;) {
57                                 set_current_state(TASK_INTERRUPTIBLE);
58                                 if (atomic_read(&rxrpc_krxiod_qcount) ||
59                                     rxrpc_krxiod_die ||
60                                     signal_pending(current))
61                                         break;
62
63                                 schedule();
64                         }
65
66                         remove_wait_queue(&rxrpc_krxiod_sleepq, &krxiod);
67                         set_current_state(TASK_RUNNING);
68                 }
69                 _debug("### End Wait");
70
71                 /* do work if been given some to do */
72                 _debug("### Begin Work");
73
74                 /* see if there's a transport in need of attention */
75                 if (!list_empty(&rxrpc_krxiod_transportq)) {
76                         struct rxrpc_transport *trans = NULL;
77
78                         spin_lock_irq(&rxrpc_krxiod_transportq_lock);
79
80                         if (!list_empty(&rxrpc_krxiod_transportq)) {
81                                 trans = list_entry(
82                                         rxrpc_krxiod_transportq.next,
83                                         struct rxrpc_transport,
84                                         krxiodq_link);
85
86                                 list_del_init(&trans->krxiodq_link);
87                                 atomic_dec(&rxrpc_krxiod_qcount);
88
89                                 /* make sure it hasn't gone away and doesn't go
90                                  * away */
91                                 if (atomic_read(&trans->usage)>0)
92                                         rxrpc_get_transport(trans);
93                                 else
94                                         trans = NULL;
95                         }
96
97                         spin_unlock_irq(&rxrpc_krxiod_transportq_lock);
98
99                         if (trans) {
100                                 rxrpc_trans_receive_packet(trans);
101                                 rxrpc_put_transport(trans);
102                         }
103                 }
104
105                 /* see if there's a call in need of attention */
106                 if (!list_empty(&rxrpc_krxiod_callq)) {
107                         struct rxrpc_call *call = NULL;
108
109                         spin_lock_irq(&rxrpc_krxiod_callq_lock);
110
111                         if (!list_empty(&rxrpc_krxiod_callq)) {
112                                 call = list_entry(rxrpc_krxiod_callq.next,
113                                                   struct rxrpc_call,
114                                                   rcv_krxiodq_lk);
115                                 list_del_init(&call->rcv_krxiodq_lk);
116                                 atomic_dec(&rxrpc_krxiod_qcount);
117
118                                 /* make sure it hasn't gone away and doesn't go
119                                  * away */
120                                 if (atomic_read(&call->usage) > 0) {
121                                         _debug("@@@ KRXIOD"
122                                                " Begin Attend Call %p", call);
123                                         rxrpc_get_call(call);
124                                 }
125                                 else {
126                                         call = NULL;
127                                 }
128                         }
129
130                         spin_unlock_irq(&rxrpc_krxiod_callq_lock);
131
132                         if (call) {
133                                 rxrpc_call_do_stuff(call);
134                                 rxrpc_put_call(call);
135                                 _debug("@@@ KRXIOD End Attend Call %p", call);
136                         }
137                 }
138
139                 _debug("### End Work");
140
141                 try_to_freeze(PF_FREEZE);
142
143                 /* discard pending signals */
144                 rxrpc_discard_my_signals();
145
146         } while (!rxrpc_krxiod_die);
147
148         /* and that's all */
149         complete_and_exit(&rxrpc_krxiod_dead, 0);
150
151 } /* end rxrpc_krxiod() */
152
153 /*****************************************************************************/
154 /*
155  * start up a krxiod daemon
156  */
157 int __init rxrpc_krxiod_init(void)
158 {
159         return kernel_thread(rxrpc_krxiod, NULL, 0);
160
161 } /* end rxrpc_krxiod_init() */
162
163 /*****************************************************************************/
164 /*
165  * kill the krxiod daemon and wait for it to complete
166  */
167 void rxrpc_krxiod_kill(void)
168 {
169         rxrpc_krxiod_die = 1;
170         wake_up_all(&rxrpc_krxiod_sleepq);
171         wait_for_completion(&rxrpc_krxiod_dead);
172
173 } /* end rxrpc_krxiod_kill() */
174
175 /*****************************************************************************/
176 /*
177  * queue a transport for attention by krxiod
178  */
179 void rxrpc_krxiod_queue_transport(struct rxrpc_transport *trans)
180 {
181         unsigned long flags;
182
183         _enter("");
184
185         if (list_empty(&trans->krxiodq_link)) {
186                 spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags);
187
188                 if (list_empty(&trans->krxiodq_link)) {
189                         if (atomic_read(&trans->usage) > 0) {
190                                 list_add_tail(&trans->krxiodq_link,
191                                               &rxrpc_krxiod_transportq);
192                                 atomic_inc(&rxrpc_krxiod_qcount);
193                         }
194                 }
195
196                 spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags);
197                 wake_up_all(&rxrpc_krxiod_sleepq);
198         }
199
200         _leave("");
201
202 } /* end rxrpc_krxiod_queue_transport() */
203
204 /*****************************************************************************/
205 /*
206  * dequeue a transport from krxiod's attention queue
207  */
208 void rxrpc_krxiod_dequeue_transport(struct rxrpc_transport *trans)
209 {
210         unsigned long flags;
211
212         _enter("");
213
214         spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags);
215         if (!list_empty(&trans->krxiodq_link)) {
216                 list_del_init(&trans->krxiodq_link);
217                 atomic_dec(&rxrpc_krxiod_qcount);
218         }
219         spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags);
220
221         _leave("");
222
223 } /* end rxrpc_krxiod_dequeue_transport() */
224
225 /*****************************************************************************/
226 /*
227  * queue a call for attention by krxiod
228  */
229 void rxrpc_krxiod_queue_call(struct rxrpc_call *call)
230 {
231         unsigned long flags;
232
233         if (list_empty(&call->rcv_krxiodq_lk)) {
234                 spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags);
235                 if (atomic_read(&call->usage) > 0) {
236                         list_add_tail(&call->rcv_krxiodq_lk,
237                                       &rxrpc_krxiod_callq);
238                         atomic_inc(&rxrpc_krxiod_qcount);
239                 }
240                 spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags);
241         }
242         wake_up_all(&rxrpc_krxiod_sleepq);
243
244 } /* end rxrpc_krxiod_queue_call() */
245
246 /*****************************************************************************/
247 /*
248  * dequeue a call from krxiod's attention queue
249  */
250 void rxrpc_krxiod_dequeue_call(struct rxrpc_call *call)
251 {
252         unsigned long flags;
253
254         spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags);
255         if (!list_empty(&call->rcv_krxiodq_lk)) {
256                 list_del_init(&call->rcv_krxiodq_lk);
257                 atomic_dec(&rxrpc_krxiod_qcount);
258         }
259         spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags);
260
261 } /* end rxrpc_krxiod_dequeue_call() */