sr.c is called by main() to handle messages sent by the file system process fs.
The object which primarily handles the messages is the array sr_fd_table.
The minor number of the device is an index in to the array sr_fd_table.
1 /* this file contains the interface of the network software with the file
2 * system.
3 *
4 * Copyright 1995 Philip Homburg
5 *
6 * The valid messages and their parameters are:
7 *
8 * Requests:
9 *
10 * m_type NDEV_MINOR NDEV_PROC NDEV_REF NDEV_MODE
11 * -------------------------------------------------------------
12 * | DEV_OPEN |minor dev | proc nr | fd | mode |
13 * |-------------+-----------+-----------+-----------+----------+
14 * | DEV_CLOSE |minor dev | proc nr | fd | |
15 * |-------------+-----------+-----------+-----------+----------+
16 *
17 * m_type NDEV_MINOR NDEV_PROC NDEV_REF NDEV_COUNT NDEV_BUFFER
18 * ---------------------------------------------------------------------------
19 * | DEV_READ |minor dev | proc nr | fd | count | buf ptr |
20 * |-------------+-----------+-----------+-----------+-----------+-----------|
21 * | DEV_WRITE |minor dev | proc nr | fd | count | buf ptr |
22 * |-------------+-----------+-----------+-----------+-----------+-----------|
23 *
24 * m_type NDEV_MINOR NDEV_PROC NDEV_REF NDEV_IOCTL NDEV_BUFFER
25 * ---------------------------------------------------------------------------
26 * | DEV_IOCTL3 |minor dev | proc nr | fd | command | buf ptr |
27 * |-------------+-----------+-----------+-----------+-----------+-----------|
28 *
29 * m_type NDEV_MINOR NDEV_PROC NDEV_REF NDEV_OPERATION
30 * -------------------------------------------------------------------|
31 * | DEV_CANCEL |minor dev | proc nr | fd | which operation|
32 * |-------------+-----------+-----------+-----------+----------------|
33 *
34 * Replies:
35 *
36 * m_type REP_PROC_NR REP_STATUS REP_REF REP_OPERATION
37 * ----------------------------------------------------------------------|
38 * | DEVICE_REPLY | proc nr | status | fd | which operation |
39 * |--------------+-------------+------------+---------+-----------------|
40 */
41 #include "inet.h"
42 #include <minix/callnr.h>
43 #include "mq.h"
44 #include "proto.h"
45 #include "generic/type.h"
46 #include "generic/assert.h"
47 #include "generic/buf.h"
48 #include "generic/sr.h"
49 THIS_FILE
All minor device numbers must be >= 0 and < FD_NR.
50 #define FD_NR 128
51 typedef struct sr_fd
52 {
srf_flags: flags which describe state of sr_fd.
53 int srf_flags;
srf_fd: is an index to the corresponding port table for the protocol or layer
(eg tcp, udp, ip, psip, etc.)
54 int srf_fd;
srf_port: is an index in to the corresponding fd table for the protocol or layer
(eg tcp, udp, ip, psip, etc.)
55 int srf_port;
srf_open: is a pointer to the open function of the corresponding port table for
the protocol or layer (eg tcp, udp, ip, psip, etc.)
56 sr_open_t srf_open;
srf_close: is a pointer to the close function of the corresponding port table for
the protocol or layer (eg tcp, udp, ip, psip, etc.)
57 sr_close_t srf_close;
srf_write: is a pointer to the write function of the corresponding port table for
the protocol or layer (eg tcp, udp, ip, psip, etc.)
58 sr_write_t srf_write;
srf_read: is a pointer to the read function of the corresponding port table for
the protocol or layer (eg tcp, udp, ip, psip, etc.)
59 sr_read_t srf_read;
srf_ioctl: is a pointer to the ioctl function of the corresponding port table for
the protocol or layer (eg tcp, udp, ip, psip, etc.)
60 sr_ioctl_t srf_ioctl;
srf_cancel: is a pointer to the cancel function of the corresponding port table for
the protocol or layer (eg tcp, udp, ip, psip, etc.)
61 sr_cancel_t srf_cancel;
srf_ioctl_q: is a pointer to the head of the linked list of ioctl messages which are
waiting to be completed (and hence the process is suspended)
srf_ioctl_q_tail: is a pointer to the end of the linked list of ioctl messages which
are waiting to be completed (and hence the process is suspended)
The linked list is a circular linked list.
62 mq_t *srf_ioctl_q, *srf_ioctl_q_tail;
srf_read_q: is a pointer to the head of the linked list of read messages which are
waiting to be completed (and hence the process is suspended)
srf_read_q_tail: is a pointer to the end of the linked list of read messages which are
waiting to be completed (and hence the process is suspended)
The linked list is a circular linked list.
63 mq_t *srf_read_q, *srf_read_q_tail;
srf_write_q: is a pointer to the head of the linked list of write messages which are
waiting to be completed (and hence the process is suspended)
srf_write_q_tail: is a pointer to the end of the linked list of write messages which are
waiting to be completed (and hence the process is suspended)
The linked list is a circular linked list.
64 mq_t *srf_write_q, *srf_write_q_tail;
65 } sr_fd_t;
SFF_FLAGS is used for the srf_flags field.
66 #define SFF_FLAGS 0x0F
SFF_FREE - means it is free.
67 # define SFF_FREE 0x00
SFF_MINOR - means it is a minor device number.
68 # define SFF_MINOR 0x01
SFF_INUSE - means the array element is being used.
69 # define SFF_INUSE 0x02
SFF_BUSY - means the array element is busy.
70 # define SFF_BUSY 0x3C
SFF_IOCTL_IP - means the array element being used for a ioctl system call.
71 # define SFF_IOCTL_IP 0x04
SFF_IOCTL_IP - means the array element being used for a read system call.
72 # define SFF_READ_IP 0x08
SFF_IOCTL_IP - means the array element being used for a write system call.
73 # define SFF_WRITE_IP 0x10
74 # define SFF_PENDING_REQ 0x30
SFF_IOCTL_IP - means the array element being used for a suspended system call.
75 # define SFF_SUSPENDED 0x1C0
SFF_IOCTL_IP - means the array element being used for a ioctl system call which is suspended.
76 # define SFF_IOCTL_SUSP 0x40
SFF_IOCTL_IP - means the array element being used for a read system call which is suspended.
77 # define SFF_READ_SUSP 0x80
SFF_IOCTL_IP - means the array element being used for a write system call which is suspended.
78 # define SFF_WRITE_SUSP 0x100
79 FORWARD _PROTOTYPE ( int sr_open, (message *m) );
80 FORWARD _PROTOTYPE ( void sr_close, (message *m) );
81 FORWARD _PROTOTYPE ( int sr_rwio, (mq_t *m) );
82 FORWARD _PROTOTYPE ( int sr_cancel, (message *m) );
83 FORWARD _PROTOTYPE ( void sr_reply, (mq_t *m, int reply, int can_enqueue) );
84 FORWARD _PROTOTYPE ( sr_fd_t *sr_getchannel, (int minor));
85 FORWARD _PROTOTYPE ( acc_t *sr_get_userdata, (int fd, vir_bytes offset,
86 vir_bytes count, int for_ioctl) );
87 FORWARD _PROTOTYPE ( int sr_put_userdata, (int fd, vir_bytes offset,
88 acc_t *data, int for_ioctl) );
89 FORWARD _PROTOTYPE ( int sr_repl_queue, (int proc, int ref, int operation) );
90 FORWARD _PROTOTYPE ( int walk_queue, (sr_fd_t *sr_fd, mq_t *q_head,
91 mq_t **q_tail_ptr, int type, int proc_nr, int ref) );
92 FORWARD _PROTOTYPE ( void process_req_q, (mq_t *mq, mq_t *tail,
93 mq_t **tail_ptr) );
94 FORWARD _PROTOTYPE ( int cp_u2b, (int proc, char *src, acc_t **var_acc_ptr,
95 int size) );
96 FORWARD _PROTOTYPE ( int cp_b2u, (acc_t *acc_ptr, int proc, char *dest) );
Each element of the array corresponds to a minor device number.
Each individual element is called a channel.
Each channel hold the data and functions used by the user process to access inet.
97 PRIVATE sr_fd_t sr_fd_table[FD_NR];
The repl_queue is used to handle deadlocks [Expand here]
98 PRIVATE mq_t *repl_queue, *repl_queue_tail;
99 PRIVATE cpvec_t cpvec[CPVEC_NR];
sr_init is called to initialize sr_fd_table. The channels in sr_fd_table is marked
as free by setting srf_flags = SFF_FREE.
100 PUBLIC void sr_init()
101 {
102 #if ZERO
103 int i;
104 for (i=0; i<FD_NR; i++)
105 sr_fd_table[i].srf_flags= SFF_FREE;
106 repl_queue= NULL;
107 #endif
108 }
sr_rec handles the different types of messages passed to inet by fs.
109 PUBLIC void sr_rec(m)
110 mq_t *m;
111 {
112 int result;
113 int send_reply, free_mess;
114 if (repl_queue)
115 {
116 if (m->mq_mess.m_type == NW_CANCEL)
117 {
118 result= sr_repl_queue(m->mq_mess.PROC_NR, 0, 0);
119 if (result)
120 {
121 mq_free(m);
122 return; /* canceled request in queue */
123 }
124 }
125 else
126 sr_repl_queue(ANY, 0, 0);
127 }
128 switch (m->mq_mess.m_type)
129 {
sr_open is called when a message from the open system call is received. m is a pointer
to a message entry. mq_mess is the message. main passes a pointer to the message to sr_open.
130 case DEV_OPEN:
131 result= sr_open(&m->mq_mess);
132 send_reply= 1;
133 free_mess= 1;
134 break;
sr_close is called when a message from the close system call is received. m is a pointer
to a message entry. mq_mess is the message. main passes a pointer to the message to sr_close.
135 case DEV_CLOSE:
136 sr_close(&m->mq_mess);
137 result= OK;
138 send_reply= 1;
139 free_mess= 1;
140 break;
sr_rwio is called when a message from the read/write/ioctl system call is received. m is a pointer
to a message entry. mq_mess is the message. main passes a pointer to the message to sr_rwio.
141 case DEV_READ:
142 case DEV_WRITE:
143 case DEV_IOCTL:
144 result= sr_rwio(m);
145 assert(result == OK || result == SUSPEND);
146 send_reply= (result == SUSPEND);
147 free_mess= 0;
148 break;
sr_cancel is called to cancel a suspended system call. A system call is canecelled
when an interrrupt occurs while inet is processing a system call. m is a pointer
to a message entry. mq_mess is the message. main passes a pointer to the message to sr_cancel.
A system call is cancelled when an interrupt occurs on the user process making the system call
while inet is processing the system call.
149 case CANCEL:
150 result= sr_cancel(&m->mq_mess);
151 assert(result == OK || result == EINTR);
152 send_reply= (result == EINTR);
153 free_mess= 1;
154 m->mq_mess.m_type= 0;
155 break;
156 default:
157 ip_panic(("unknown message, from %d, type %d",
158 m->mq_mess.m_source, m->mq_mess.m_type));
159 }
160 if (send_reply)
161 {
162 sr_reply(m, result, FALSE);
163 }
164 if (free_mess)
165 mq_free(m);
166 }
The minor number of the device is an index in to the array sr_fd_table. An internet
protocol (eg tcp, udp, ip) is started in inet by calling the corresponding initialization
routine (eg tcp_init(), udp_init(), ip_init()). All of the initialization routines are
started in inet.c in nw_init(). The corresponding initialization routine calls
sr_add_minor in sr.c which passes the minor device number as a parameter in the the
parameter minor. Minor is an index in to the array sr_fd_table. It gets the element of
the array with the index equal to minor and sets the various properties of the element
with the index. It then sets the flag of the element so that the element is marked as a
element corresponding to a minor device (by setting the flag SFF_MINOR ) and as being
used (by setting the flag SFF_INUSE ).
167 PUBLIC int sr_add_minor(minor, port, openf, closef, readf, writef,
168 ioctlf, cancelf)
169 int minor;
170 int port;
171 sr_open_t openf;
172 sr_close_t closef;
173 sr_read_t readf;
174 sr_write_t writef;
175 sr_ioctl_t ioctlf;
176 sr_cancel_t cancelf;
177 {
178 sr_fd_t *sr_fd;
179 assert (minor>=0 && minor<FD_NR);
180 sr_fd= &sr_fd_table[minor];
181 if (sr_fd->srf_flags & SFF_INUSE)
182 return EGENERIC;
183 sr_fd->srf_flags= SFF_INUSE | SFF_MINOR;
184 sr_fd->srf_port= port;
185 sr_fd->srf_open= openf;
186 sr_fd->srf_close= closef;
187 sr_fd->srf_write= writef;
188 sr_fd->srf_read= readf;
189 sr_fd->srf_ioctl= ioctlf;
190 sr_fd->srf_cancel= cancelf;
191 return OK;
192 }
sr_open returns an index to the first unused entry in the sr_fd_table array. The sr_fd_table
array is an array of sr_fd structures. The file descriptor returned to the user process
corresponds to an entry in the sr_fd_table array. The entry in the sr_fd_table array is marked
as used (by setting the flag SFF_INUSE ).
The index of the element in the sr_fd_table array is ultimately returned to the user process
by the fs process as follows. When the user process does an open system call to inet, fs calls
net_open in fs/device.c. When the index of the element in the sr_fd_table array is returned to
fs, fs (in the function net_open) replaces the minor device number with the index of the element
in the sr_fd_table array.
193 PRIVATE int sr_open(m)
194 message *m;
195 {
196 sr_fd_t *sr_fd;
197 int minor= m->DEVICE;
198 int i, fd;
All minor device numbers must be >= 0 and < FD_NR.
199 if (minor<0 || minor>FD_NR)
200 {
201 DBLOCK(1, printf("replying EINVAL\n"));
202 return EINVAL;
203 }
The sr_fd_table entry is declared as corresponding to a minor device by setting SFF_MINOR.
204 if (!(sr_fd_table[minor].srf_flags & SFF_MINOR))
205 {
206 DBLOCK(1, printf("replying ENXIO\n"));
207 return ENXIO;
208 }
Searches for a channel in sr_fd_table which is not being used.
209 for (i=0; i<FD_NR && (sr_fd_table[i].srf_flags & SFF_INUSE); i++);
210 if (i>=FD_NR)
211 {
212 DBLOCK(1, printf("replying ENFILE\n"));
213 return ENFILE;
214 }
i = index for channel.
sr_fd = channel
215 sr_fd= &sr_fd_table[i];
Copy channel of minor device to the unused channel.
216 *sr_fd= sr_fd_table[minor];
Mark unused channel as being used.
217 sr_fd->srf_flags= SFF_INUSE;
Each minor device has its own functions for open/read/write/ioctl.
We call the open function specific to the minor device in the following.
fd is the index to the fd array for the minor device.
218 fd= (*sr_fd->srf_open)(sr_fd->srf_port, i, sr_get_userdata,
219 sr_put_userdata, 0);
220 if (fd<0)
221 {
222 sr_fd->srf_flags= SFF_FREE;
223 DBLOCK(1, printf("replying %d\n", fd));
224 return fd;
225 }
Set srf_fd equal to fd.
226 sr_fd->srf_fd= fd;
227 return i;
228 }
sr_close closes a file descriptor. The user process passes the index of the element in
the sr_fd_table array which it wants to release and mark as unused.
The index of the element in the sr_fd_table array is m->DEVICE which is also the minor device number.
229 PRIVATE void sr_close(m)
230 message *m;
231 {
232 sr_fd_t *sr_fd;
sr_getchannel returns the channel ie the element in the sr_fd_table.
233 sr_fd= sr_getchannel(m->DEVICE);
234 assert (sr_fd);
235 if (sr_fd->srf_flags & SFF_BUSY)
236 ip_panic(("close on busy channel"));
If it's busy, it should not be closed.
237 assert (!(sr_fd->srf_flags & SFF_MINOR));
238 (*sr_fd->srf_close)(sr_fd->srf_fd);
Mark channel as free.
239 sr_fd->srf_flags= SFF_FREE;
240 }
sr_rwio(m) is called for read, writes, and ioctls.
241 PRIVATE int sr_rwio(m)
242 mq_t *m;
243 {
244 sr_fd_t *sr_fd;
245 mq_t **q_head_ptr, **q_tail_ptr;
246 int ip_flag, susp_flag;
247 int r;
248 ioreq_t request;
249 size_t size;
sr_getchannel retrieves the element in the sr_fd_table (ie channel) with the index
m->mq_mess.DEVICE. m->mq_mess.DEVICE should have been set in the open system call.
250 sr_fd= sr_getchannel(m->mq_mess.DEVICE);
251 assert (sr_fd);
Set q_head_ptr to point to head of linked list of message entries suspended on the system call.
Set q_tail_ptr to point to tail of linked list of message entries suspended on the system call.
Set ip_flag to the flag which marks the channel as busy processing the specific system call.
Set susp_flag to the flag which marks the channel as being suspended on the specific system call.
252 switch(m->mq_mess.m_type)
253 {
254 case DEV_READ:
255 q_head_ptr= &sr_fd->srf_read_q;
256 q_tail_ptr= &sr_fd->srf_read_q_tail;
257 ip_flag= SFF_READ_IP;
258 susp_flag= SFF_READ_SUSP;
259 break;
260 case DEV_WRITE:
261 q_head_ptr= &sr_fd->srf_write_q;
262 q_tail_ptr= &sr_fd->srf_write_q_tail;
263 ip_flag= SFF_WRITE_IP;
264 susp_flag= SFF_WRITE_SUSP;
265 break;
266 case DEV_IOCTL:
267 q_head_ptr= &sr_fd->srf_ioctl_q;
268 q_tail_ptr= &sr_fd->srf_ioctl_q_tail;
269 ip_flag= SFF_IOCTL_IP;
270 susp_flag= SFF_IOCTL_SUSP;
271 break;
272 default:
273 ip_panic(("illegal case entry"));
274 }
sr_fd->srf_flags & ip_flag means the channel is busy processing the specific system call and
is suspended on it and hence can't be used for another such call. The suspension flag should
also be set if the channel is suspended on the specific system call.
If the channel is suspended on the specific system call, then the message is added to the
message queue for the system call and the user process is suspended.
275 if (sr_fd->srf_flags & ip_flag)
276 {
277 assert(sr_fd->srf_flags & susp_flag);
278 assert(*q_head_ptr);
279 (*q_tail_ptr)->mq_next= m;
280 *q_tail_ptr= m;
281 return SUSPEND;
282 }
Message queue should be empty if there are no suspended calls for the specific system call.
283 assert(!*q_head_ptr);
Put message in message queue. Mark the channel as busy processing the specific system call.
284 *q_tail_ptr= *q_head_ptr= m;
285 sr_fd->srf_flags |= ip_flag;
Call the minor device specific system call function with appropriate parameters.
286 switch(m->mq_mess.m_type)
287 {
288 case DEV_READ:
289 r= (*sr_fd->srf_read)(sr_fd->srf_fd,
290 m->mq_mess.COUNT);
291 break;
292 case DEV_WRITE:
293 r= (*sr_fd->srf_write)(sr_fd->srf_fd,
294 m->mq_mess.COUNT);
295 break;
296 case DEV_IOCTL:
297 request= m->mq_mess.REQUEST;
298 #ifdef _IOCPARM_MASK
299 size= (request >> 16) & _IOCPARM_MASK;
300 if (size>MAX_IOCTL_S)
301 {
302 DBLOCK(1, printf("replying EINVAL\n"));
303 r= sr_put_userdata(sr_fd-sr_fd_table, EINVAL,
304 NULL, 1);
305 assert(r == OK);
306 return OK;
307 }
308 #endif
309 r= (*sr_fd->srf_ioctl)(sr_fd->srf_fd, request);
310 break;
311 default:
312 ip_panic(("illegal case entry"));
313 }
314 assert(r == OK || r == SUSPEND ||
315 (printf("r= %d\n", r), 0));
316 if (r == SUSPEND)
317 sr_fd->srf_flags |= susp_flag;
318 return r;
319 }
Cancels the message on the channel.
walk_queue does most of the work.
320 PRIVATE int sr_cancel(m)
321 message *m;
322 {
323 sr_fd_t *sr_fd;
324 int i, result;
325 mq_t *q_ptr, *q_ptr_prv;
326 int proc_nr, ref, operation;
327 result=EINTR;
328 proc_nr= m->PROC_NR;
329 ref= 0;
330 operation= 0;
331 sr_fd= sr_getchannel(m->DEVICE);
332 assert (sr_fd);
333 {
334 result= walk_queue(sr_fd, sr_fd->srf_ioctl_q,
335 &sr_fd->srf_ioctl_q_tail, SR_CANCEL_IOCTL,
336 proc_nr, ref);
337 if (result != EAGAIN)
338 return result;
339 }
340 {
341 result= walk_queue(sr_fd, sr_fd->srf_read_q,
342 &sr_fd->srf_read_q_tail, SR_CANCEL_READ,
343 proc_nr, ref);
344 if (result != EAGAIN)
345 return result;
346 }
347 {
348 result= walk_queue(sr_fd, sr_fd->srf_write_q,
349 &sr_fd->srf_write_q_tail, SR_CANCEL_WRITE,
350 proc_nr, ref);
351 if (result != EAGAIN)
352 return result;
353 }
354 ip_panic((
355 "request not found: from %d, type %d, MINOR= %d, PROC= %d, REF= %d OPERATION= %d",
356 m->m_source, m->m_type, m->DEVICE,
357 m->PROC_NR, 0, 0));
358 }
walk_queue removes all messages for the process with process number proc_nr on the channel sr_fd.
The message queue for the channel sr_fd should have the head q_head and tail q_tail_ptr.
359 PRIVATE int walk_queue(sr_fd, q_head, q_tail_ptr, type, proc_nr, ref)
360 sr_fd_t *sr_fd;
361 mq_t *q_head, **q_tail_ptr;
362 int type;
363 int proc_nr;
364 int ref;
365 {
366 mq_t *q_ptr_prv, *q_ptr;
367 int result;
Loop through message queue.
368 for(q_ptr_prv= NULL, q_ptr= q_head; q_ptr;
369 q_ptr_prv= q_ptr, q_ptr= q_ptr->mq_next)
370 {
Check process number of the source of the message.
371 if (q_ptr->mq_mess.PROC_NR != proc_nr)
372 continue;
If message is head of queue (and hence being serviced) and message is to be cancelled
call the minor device function to cancel the message.
373 if (!q_ptr_prv)
374 {
375 result= (*sr_fd->srf_cancel)(sr_fd->srf_fd, type);
376 assert(result == OK);
377 return OK;
378 }
Remove message from queue and free it by calling mq_free().
379 q_ptr_prv->mq_next= q_ptr->mq_next;
380 mq_free(q_ptr);
381 if (!q_ptr_prv->mq_next)
382 *q_tail_ptr= q_ptr_prv;
383 return EINTR;
384 }
385 return EAGAIN;
386 }
sr_getchannel() returns the sr_fd structure for the variable minor.
minor is an index in to the sr_fd_table array.
387 PRIVATE sr_fd_t *sr_getchannel(minor)
388 int minor;
389 {
390 sr_fd_t *loc_fd;
391 compare(minor, >=, 0);
392 compare(minor, <, FD_NR);
393 loc_fd= &sr_fd_table[minor];
394 assert (!(loc_fd->srf_flags & SFF_MINOR) &&
395 (loc_fd->srf_flags & SFF_INUSE));
396 return loc_fd;
397 }
sr_reply() replies to the process which called the inet process. Typically the process
being replied to is the file system process fs. All replies are done through sr_reply().
398 PRIVATE void sr_reply (mq, status, can_enqueue)
399 mq_t *mq;
400 int status;
401 int can_enqueue;
402 {
403 int result, proc, ref,operation;
404 message reply, *mp;
405 proc= mq->mq_mess.PROC_NR;
406 ref= 0;
407 operation= mq->mq_mess.m_type;
408 if (can_enqueue)
409 mp= &mq->mq_mess;
410 else
411 mp= &reply;
412 mp->m_type= REVIVE;
413 mp->REP_PROC_NR= proc;
414 mp->REP_STATUS= status;
415 result= send(mq->mq_mess.m_source, mp);
416 if (result == ELOCKED && can_enqueue)
417 {
418 if (repl_queue)
419 repl_queue_tail->mq_next= mq;
420 else
421 repl_queue= mq;
422 repl_queue_tail= mq;
423 return;
424 }
425 if (result != OK)
426 ip_panic(("unable to send"));
427 if (can_enqueue)
428 mq_free(mq);
429 }
sr_get_userdata() does 1 of 2 things.
If count > 0 then sr_get_userdata() copies data from an array in another process space
(typically an array in user process space) to an array in the inet space. sr_get_userdata()
is typically used by a minor device specific function to get the data passed to inet
in a system call to inet eg the data in the buf array in write(fd, buf, size).
sr_get_userdata() is used by the minor device specific functions called in a write
system call. If count = 0,
sr_get_userdata() wakes up the process which was suspended on the system call to inet.
The integer result returned to the user process (in the case count = 0) is the offset.
For an ioctl call (ie for_ioctl = 1), you can return an integer result to the user process
either by calling sr_put_userdata(x, y, 0, 1) or sr_get_userdata(x, y, 0, 1).
430 PRIVATE acc_t *sr_get_userdata (fd, offset, count, for_ioctl)
431 int fd;
432 vir_bytes offset;
433 vir_bytes count;
434 int for_ioctl;
435 {
436 sr_fd_t *loc_fd;
437 mq_t **head_ptr, **tail_ptr, *m, *tail, *mq;
438 int ip_flag, susp_flag;
439 int result;
440 int suspended;
441 char *src;
442 acc_t *acc;
443 loc_fd= &sr_fd_table[fd];
Point head_ptr and tail_ptr to the message queue for the system call.
If for_ioctl = 1, then they point to the ioctl message queue.
Otherwise they point to the write message queue.
444 if (for_ioctl)
445 {
446 head_ptr= &loc_fd->srf_ioctl_q;
447 tail_ptr= &loc_fd->srf_ioctl_q_tail;
448 ip_flag= SFF_IOCTL_IP;
449 susp_flag= SFF_IOCTL_SUSP;
450 }
451 else
452 {
453 head_ptr= &loc_fd->srf_write_q;
454 tail_ptr= &loc_fd->srf_write_q_tail;
455 ip_flag= SFF_WRITE_IP;
456 susp_flag= SFF_WRITE_SUSP;
457 }
458
459 assert (loc_fd->srf_flags & ip_flag);
If count = 0 then wake up the user process. The integer result returned to the
user is offset. Then any remaining messages in the message queue is also processed.
460 if (!count)
461 {
462 m= *head_ptr;
463 *head_ptr= NULL;
464 tail= *tail_ptr;
465 assert(m);
466 mq= m->mq_next;
467 result= (int)offset;
468 sr_reply (m, result, 1);
469 suspended= (loc_fd->srf_flags & susp_flag);
470 loc_fd->srf_flags &= ~(ip_flag|susp_flag);
471 if (suspended)
472 {
473 process_req_q(mq, tail, tail_ptr);
474 }
475 else
476 {
477 assert(!mq);
478 }
479 return NULL;
480 }
src = address of buffer in user process space.
481 src= (*head_ptr)->mq_mess.ADDRESS + offset;
Copy data in buffer from user process space to inet space.
482 result= cp_u2b ((*head_ptr)->mq_mess.PROC_NR, src, &acc, count);
Return copied data if there is any. Otherwise return NULL (ie 0).
483 return result<0 ? NULL : acc;
484 }
sr_put_userdata() does 1 of 2 things.
If count > 0 then sr_put_userdata() copies data to an array in another process space
(typically an array in user process space) from an array in the inet space. sr_put_userdata()
is typically used by a minor device specific function to send the data received by inet
in a system call to the user process eg put the data in the buf array in read(fd, buf, size).
sr_put_userdata() is used by the minor device specific functions called in a read
system call. If count = 0,
sr_put_userdata() wakes up the process which was suspended on the system call to inet.
The integer result returned to the user process (in the case count = 0) is the offset.
In the read system call the integer result is typically the number of bytes returned.
For an ioctl call (ie for_ioctl = 1), you can return an integer result to the user process
either by calling sr_put_userdata(x, y, 0, 1) or sr_get_userdata(x, y, 0, 1).
485 PRIVATE int sr_put_userdata (fd, offset, data, for_ioctl)
486 int fd;
487 vir_bytes offset;
488 acc_t *data;
489 int for_ioctl;
490 {
491 sr_fd_t *loc_fd;
492 mq_t **head_ptr, **tail_ptr, *m, *tail, *mq;
493 int ip_flag, susp_flag;
494 int result;
495 int suspended;
496 char *dst;
497 loc_fd= &sr_fd_table[fd];
Point head_ptr and tail_ptr to the message queue for the system call.
If for_ioctl = 1, then they point to the ioctl message queue.
Otherwise they point to the read message queue.
498 if (for_ioctl)
499 {
500 head_ptr= &loc_fd->srf_ioctl_q;
501 tail_ptr= &loc_fd->srf_ioctl_q_tail;
502 ip_flag= SFF_IOCTL_IP;
503 susp_flag= SFF_IOCTL_SUSP;
504 }
505 else
506 {
507 head_ptr= &loc_fd->srf_read_q;
508 tail_ptr= &loc_fd->srf_read_q_tail;
509 ip_flag= SFF_READ_IP;
510 susp_flag= SFF_READ_SUSP;
511 }
512
513 assert (loc_fd->srf_flags & ip_flag);
If data = NULL then wake up the user process. Any data which is returned to the user
should have already been copied to the user process space. The integer result returned
to the user is offset. Then any remaining messages in the message queue is also processed.
514 if (!data)
515 {
516 m= *head_ptr;
517 assert(m);
518 *head_ptr= NULL;
519 tail= *tail_ptr;
520 mq= m->mq_next;
521 result= (int)offset;
522 sr_reply (m, result, 1);
523 suspended= (loc_fd->srf_flags & susp_flag);
524 loc_fd->srf_flags &= ~(ip_flag|susp_flag);
525 if (suspended)
526 {
527 process_req_q(mq, tail, tail_ptr);
528 }
529 else
530 {
531 assert(!mq);
532 }
533 return OK;
534 }
dst = address of buffer in user process space.
535 dst= (*head_ptr)->mq_mess.ADDRESS + offset;
Copy data in inet space to buffer from user process space.
536 return cp_b2u (data, (*head_ptr)->mq_mess.PROC_NR, dst);
537 }
process_req_q() processes suspended requests. mq is the head of the list of suspended
requests. tail is the end of the list. tail_ptr is a pointer to tail.
538 PRIVATE void process_req_q(mq, tail, tail_ptr)
539 mq_t *mq, *tail, **tail_ptr;
540 {
541 mq_t *m;
542 int result;
543 for(;mq;)
544 {
545 m= mq;
546 mq= mq->mq_next;
547 DBLOCK(1, printf("calling rwio\n"));
548 result= sr_rwio(m);
result == SUSPEND means to suspend request.
549 if (result == SUSPEND)
550 {
551 if (mq)
552 {
*tail_ptr might have been changed while processing the requests
(in *q_tail_ptr= *q_head_ptr= m in sr_rwio()) so we have to point tail_ptr
to the right place again ie point it to tail.
553 (*tail_ptr)->mq_next= mq;
554 *tail_ptr= tail;
555 }
556 return;
557 }
558 }
559 return;
560 }
cp_u2b() copies the data at address src in the process space of process proc to
the space of inet. cp_u2b() sets var_acc_ptr to point to the acc structure which
holds the data.
561 PRIVATE int cp_u2b (proc, src, var_acc_ptr, size)
562 int proc;
563 char *src;
564 acc_t **var_acc_ptr;
565 int size;
566 {
567 static message mess;
568 acc_t *acc;
569 int i;
570 acc= bf_memreq(size);
571 *var_acc_ptr= acc;
572 i=0;
573 while (acc)
574 {
575 size= (vir_bytes)acc->acc_length;
576 cpvec[i].cpv_src= (vir_bytes)src;
577 cpvec[i].cpv_dst= (vir_bytes)ptr2acc_data(acc);
578 cpvec[i].cpv_size= size;
579 src += size;
580 acc= acc->acc_next;
581 i++;
582 if (i == CPVEC_NR || acc == NULL)
583 {
584 mess.m_type= SYS_VCOPY;
585 mess.m1_i1= proc;
586 mess.m1_i2= this_proc;
587 mess.m1_i3= i;
588 mess.m1_p1= (char *)cpvec;
589 if (sendrec(SYSTASK, &mess) <0)
590 ip_panic(("unable to sendrec"));
591 if (mess.m_type <0)
592 {
593 bf_afree(*var_acc_ptr);
594 *var_acc_ptr= 0;
595 return mess.m_type;
596 }
597 i= 0;
598 }
599 }
600 return OK;
601 }
cp_b2u() copies the data to address dest in the process space of process proc from
the space of inet. var_acc_ptr points to the acc structure which holds the data
which is to be copied.
602 PRIVATE int cp_b2u (acc_ptr, proc, dest)
603 acc_t *acc_ptr;
604 int proc;
605 char *dest;
606 {
607 static message mess;
608 acc_t *acc;
609 int i, size;
610 acc= acc_ptr;
611 i=0;
612 while (acc)
613 {
614 size= (vir_bytes)acc->acc_length;
615 if (size)
616 {
617 cpvec[i].cpv_src= (vir_bytes)ptr2acc_data(acc);
618 cpvec[i].cpv_dst= (vir_bytes)dest;
619 cpvec[i].cpv_size= size;
620 i++;
621 }
622 dest += size;
623 acc= acc->acc_next;
624 if (i == CPVEC_NR || acc == NULL)
625 {
626 mess.m_type= SYS_VCOPY;
627 mess.m1_i1= this_proc;
628 mess.m1_i2= proc;
629 mess.m1_i3= i;
630 mess.m1_p1= (char *)cpvec;
631 if (sendrec(SYSTASK, &mess) <0)
632 ip_panic(("unable to sendrec"));
633 if (mess.m_type <0)
634 {
635 bf_afree(acc_ptr);
636 return mess.m_type;
637 }
638 i= 0;
639 }
640 }
641 bf_afree(acc_ptr);
642 return OK;
643 }
644 PRIVATE int sr_repl_queue(proc, ref, operation)
645 int proc;
646 int ref;
647 int operation;
648 {
649 mq_t *m, *m_cancel, *m_tmp;
650 int result;
651 m_cancel= NULL;
652 for (m= repl_queue; m;)
653 {
654 if (m->mq_mess.REP_PROC_NR == proc)
655 {
656 assert(!m_cancel);
657 m_cancel= m;
658 m= m->mq_next;
659 continue;
660 }
661 assert(m->mq_mess.m_source != MM_PROC_NR);
662 assert(m->mq_mess.m_type == REVIVE);
663 result= send(m->mq_mess.m_source, &m->mq_mess);
664 if (result != OK)
665 ip_panic(("unable to send: %d", result));
666 m_tmp= m;
667 m= m->mq_next;
668 mq_free(m_tmp);
669 }
670 repl_queue= NULL;
671 if (m_cancel)
672 {
673 assert(m_cancel->mq_mess.m_source != MM_PROC_NR);
674 assert(m_cancel->mq_mess.m_type == REVIVE);
675 result= send(m_cancel->mq_mess.m_source, &m_cancel->mq_mess);
676 if (result != OK)
677 ip_panic(("unable to send: %d", result));
678 mq_free(m_cancel);
679 return 1;
680 }
681 return 0;
682 }
683 /*
684 * $PchId: sr.c,v 1.9 1996/05/07 21:11:14 philip Exp $
685 */
sr.c is called by main() to handle messages sent by the file system process fs.
The object which primarily handles the messages is the array sr_fd_table.
The minor number of the device is an index in to the array sr_fd_table.