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   */