ukernel: Fix AFS_GUNLOCK panic in rx_ServerProc
[openafs.git] / src / rx / UKERNEL / rx_knet.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "rx/rx_kcommon.h"
15 #include "rx_atomic.h"
16 #include "rx_internal.h"
17
18 #define SECONDS_TO_SLEEP        0
19 #define NANO_SECONDS_TO_SLEEP   100000000       /* 100 milliseconds */
20 #define LOOPS_PER_WAITCHECK     10      /* once per second */
21
22 struct usr_socket {
23     int sock;
24     short port;
25 };
26
27 unsigned short usr_rx_port = 0;
28
29 struct usr_ifnet *usr_ifnet = NULL;
30 struct usr_in_ifaddr *usr_in_ifaddr = NULL;
31
32 void rxk_InitializeSocket(void);
33 extern int afs_osi_CheckTimedWaits(void);
34
35 void
36 afs_rxevent_daemon(void)
37 {
38     struct timespec tv;
39     struct clock temp;
40     int i = 0;
41
42     AFS_GUNLOCK();
43     while (1) {
44         tv.tv_sec = SECONDS_TO_SLEEP;
45         tv.tv_nsec = NANO_SECONDS_TO_SLEEP;
46         usr_thread_sleep(&tv);
47         /*
48          * Check for shutdown, don't try to stop the listener
49          */
50         if (afs_termState == AFSOP_STOP_RXEVENT
51             || afs_termState == AFSOP_STOP_RXK_LISTENER) {
52             AFS_GLOCK();
53             afs_termState = AFSOP_STOP_COMPLETE;
54             afs_osi_Wakeup(&afs_termState);
55             return;
56         }
57         rxevent_RaiseEvents(&temp);
58         if (++i >= LOOPS_PER_WAITCHECK) {
59             i = 0;
60             afs_osi_CheckTimedWaits();
61         }
62     }
63 }
64
65
66 /* Loop to listen on a socket. Return setting *newcallp if this
67  * thread should become a server thread.  */
68 void
69 rxi_ListenerProc(osi_socket usockp, int *tnop, struct rx_call **newcallp)
70 {
71     struct rx_packet *tp;
72     afs_uint32 host;
73     u_short port;
74     int rc;
75
76     /*
77      * Use the rxk_GetPacketProc and rxk_PacketArrivalProc routines
78      * to allocate rx_packet buffers and pass them to the RX layer
79      * for processing.
80      */
81     while (1) {
82         /* See if a check for additional packets was issued */
83         rx_CheckPackets();
84
85         tp = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
86         usr_assert(tp != NULL);
87         rc = rxi_ReadPacket(usockp, tp, &host, &port);
88         if (rc != 0) {
89             tp = rxi_ReceivePacket(tp, usockp, host, port, tnop, newcallp);
90             if (newcallp && *newcallp) {
91                 if (tp) {
92                     rxi_FreePacket(tp);
93                 }
94                 return;
95             }
96         }
97         if (tp) {
98             rxi_FreePacket(tp);
99         }
100         if (afs_termState == AFSOP_STOP_RXEVENT) {
101             afs_termState = AFSOP_STOP_RXK_LISTENER;
102             afs_osi_Wakeup(&afs_termState);
103         }
104     }
105 }
106
107 /* This is the listener process request loop. The listener process loop
108  * becomes a server thread when rxi_ListenerProc returns, and stays
109  * server thread until rxi_ServerProc returns. */
110 void
111 rxk_Listener(void)
112 {
113     int threadID;
114     osi_socket sock = (osi_socket) rx_socket;
115     struct rx_call *newcall;
116     struct usr_socket *usockp;
117
118     /*
119      * Initialize the rx_socket and start the receiver threads
120      */
121     rxk_InitializeSocket();
122
123     usockp = (struct usr_socket *)rx_socket;
124     assert(usockp != NULL);
125
126     AFS_GUNLOCK();
127     while (1) {
128         newcall = NULL;
129         threadID = -1;
130         rxi_ListenerProc(sock, &threadID, &newcall);
131         /* assert(threadID != -1); */
132         /* assert(newcall != NULL); */
133         sock = OSI_NULLSOCKET;
134         rxi_ServerProc(threadID, newcall, &sock);
135         if (sock == OSI_NULLSOCKET) {
136             break;
137         }
138     }
139     AFS_GLOCK();
140 }
141
142 /* This is the server process request loop. The server process loop
143  * becomes a listener thread when rxi_ServerProc returns, and stays
144  * listener thread until rxi_ListenerProc returns. */
145 void *
146 rx_ServerProc(void *unused)
147 {
148     osi_socket sock;
149     int threadID;
150     struct rx_call *newcall = NULL;
151
152     rxi_MorePackets(rx_maxReceiveWindow + 2);   /* alloc more packets */
153     rxi_dataQuota += rx_initSendWindow; /* Reserve some pkts for hard times */
154     /* threadID is used for making decisions in GetCall.  Get it by bumping
155      * number of threads handling incoming calls */
156     threadID = rxi_availProcs++;
157
158     while (1) {
159         sock = OSI_NULLSOCKET;
160         rxi_ServerProc(threadID, newcall, &sock);
161         if (sock == OSI_NULLSOCKET) {
162             break;
163         }
164         newcall = NULL;
165         threadID = -1;
166         rxi_ListenerProc(sock, &threadID, &newcall);
167         /* assert(threadID != -1); */
168         /* assert(newcall != NULL); */
169     }
170     return NULL;
171 }
172
173 /*
174  * At this point, RX wants a socket, but still has not initialized the
175  * rx_port variable or the pointers to the packet allocater and arrival
176  * routines. Allocate the socket buffer here, but don't open it until
177  * we start the receiver threads.
178  */
179 osi_socket *
180 rxk_NewSocketHost(afs_uint32 ahost, short aport)
181 {
182     struct usr_socket *usockp;
183
184     usockp = afs_osi_Alloc(sizeof(struct usr_socket));
185     usr_assert(usockp != NULL);
186
187     usockp->sock = -1;
188
189     return (osi_socket *)usockp;
190 }
191
192 osi_socket *
193 rxk_NewSocket(short aport)
194 {
195     return rxk_NewSocketHost(htonl(INADDR_ANY), aport);
196 }
197
198 /*
199  * This routine is called from rxk_Listener. By this time rx_port
200  * is set to 7001 and rx_socket points to the socket buffer
201  * we allocated in rxk_NewSocket. Now is the time to bind our
202  * socket and start the receiver threads.
203  */
204 void
205 rxk_InitializeSocket(void)
206 {
207     int rc, sock;
208 #ifdef AFS_USR_AIX_ENV
209     unsigned long len, optval, optval0, optlen;
210 #else /* AFS_USR_AIX_ENV */
211     socklen_t len, optlen;
212     int optval, optval0;
213 #endif /* AFS_USR_AIX_ENV */
214     struct usr_socket *usockp;
215     struct sockaddr_in lcladdr;
216
217     usr_assert(rx_socket != NULL);
218     usockp = (struct usr_socket *)rx_socket;
219
220     sock = socket(PF_INET, SOCK_DGRAM, 0);
221     usr_assert(sock >= 0);
222
223     memset((void *)&lcladdr, 0, sizeof(struct sockaddr_in));
224     lcladdr.sin_family = AF_INET;
225     lcladdr.sin_port = htons(usr_rx_port);
226     lcladdr.sin_addr.s_addr = INADDR_ANY;
227     rc = bind(sock, (struct sockaddr *)&lcladdr, sizeof(struct sockaddr_in));
228     usr_assert(rc >= 0);
229     len = sizeof(struct sockaddr_in);
230     rc = getsockname(sock, (struct sockaddr *)&lcladdr, &len);
231     usr_assert(rc >= 0);
232 #ifdef AFS_USR_LINUX_ENV
233     optval0 = 131070;
234 #else
235     optval0 = 131072;
236 #endif
237     optval = optval0;
238     rc = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&optval,
239                     sizeof(optval));
240     usr_assert(rc == 0);
241     optlen = sizeof(optval);
242     rc = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&optval, &optlen);
243     usr_assert(rc == 0);
244     /* usr_assert(optval == optval0); */
245 #ifdef AFS_USR_LINUX_ENV
246     optval0 = 131070;
247 #else
248     optval0 = 131072;
249 #endif
250     optval = optval0;
251     rc = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&optval,
252                     sizeof(optval));
253     usr_assert(rc == 0);
254     optlen = sizeof(optval);
255     rc = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&optval, &optlen);
256     usr_assert(rc == 0);
257     /* usr_assert(optval == optval0); */
258
259 #ifdef AFS_USR_AIX_ENV
260     optval = 1;
261     rc = setsockopt(sock, SOL_SOCKET, SO_CKSUMRECV, (void *)&optval,
262                     sizeof(optval));
263     usr_assert(rc == 0);
264 #endif /* AFS_USR_AIX_ENV */
265
266 #ifdef FD_CLOEXEC
267     fcntl(sock, F_SETFD, FD_CLOEXEC);
268 #endif
269
270     usockp->sock = sock;
271     usockp->port = lcladdr.sin_port;
272
273     /*
274      * Set the value of rx_port to reflect the address we actually
275      * are listening on, since the kernel is probably already using 7001.
276      */
277     rx_port = usockp->port;
278 }
279
280 int
281 rxk_FreeSocket(struct usr_socket *sockp)
282 {
283     return 0;
284 }
285
286 void
287 osi_StopListener(void)
288 {
289     rxk_FreeSocket((struct usr_socket *)rx_socket);
290 }
291
292 int
293 osi_NetSend(osi_socket sockp, struct sockaddr_in *addr, struct iovec *iov,
294             int nio, afs_int32 size, int stack)
295 {
296     int rc;
297     int i;
298     struct usr_socket *usockp = (struct usr_socket *)sockp;
299     struct msghdr msg;
300     struct iovec tmpiov[64];
301
302     /*
303      * The header is in the first iovec
304      */
305     usr_assert(nio > 0 && nio <= 64);
306     for (i = 0; i < nio; i++) {
307         tmpiov[i].iov_base = iov[i].iov_base;
308         tmpiov[i].iov_len = iov[i].iov_len;
309     }
310
311     memset(&msg, 0, sizeof(msg));
312     msg.msg_name = (void *)addr;
313     msg.msg_namelen = sizeof(struct sockaddr_in);
314     msg.msg_iov = &tmpiov[0];
315     msg.msg_iovlen = nio;
316
317     rc = sendmsg(usockp->sock, &msg, 0);
318     if (rc < 0) {
319         return errno;
320     }
321     usr_assert(rc == size);
322
323     return 0;
324 }
325
326 void
327 shutdown_rxkernel(void)
328 {
329     rxk_initDone = 0;
330     rxk_shutdownPorts();
331 }
332
333 void
334 rx_Finalize(void)
335 {
336     usr_assert(0);
337 }
338
339 /*
340  * Recvmsg.
341  *
342  */
343 int
344 rxi_Recvmsg(osi_socket socket, struct msghdr *msg_p, int flags)
345 {
346     struct usr_socket *usock = (struct usr_socket *)socket;
347     int ret;
348     do {
349         ret = recvmsg(usock->sock, msg_p, flags);
350     } while (ret == -1 && errno == EAGAIN);
351     return ret;
352 }