Title: sr_reply()


sr_reply(mq, status, can_enqueue) attempts to send a REVIVE message back to the file system (FS) (which is what the FS expects to receive). sr_reply() is called from sr_rec() and from sr_get_userdata() and sr_put_userdata().

If called from sr_rec(), there are two scenarios. If the message mq (sr_reply()'s first parameter) was a request for a DEV_OPEN, DEV_CLOSE, or CANCEL, a reply is guaranteed to succeed and therefore there is no need to enqueue the message in repl_queue. If the message mq was a request for a DEV_READ, DEV_WRITE, or DEV_IOCTL operation that was suspended, a reply is also guaranteed to succeed. In both of these scenarios, it is not necessary to queue the message in repl_queue and, therefore, can_enqueue is FALSE if called from sr_rec().

However, if sr_reply() is called from sr_get_userdata() or sr_put_userdata(), the message may fail due to deadlock. Also, the message must eventually reach the file system so that the user process may be unblocked. Therefore, the reply message must be placed in repl_queue if the message doesn't succeed due to deadlock. For this reason, can_enqueue is TRUE if called from sr_get_userdata() or sr_put_userdata().

It is important to understand why deadlocks can occur. During the initialization of the network service, the network service calls svrctl() (which calls do_svrctl()) to initialize itself with the FS. do_svrctl() sets the fields of the network service's dmap[] entry to gen_io() for read, write, and ioctl requests and clone_opcl() for open and close requests. For this reason, whenever a read, write, or ioctl requests for a network file is received by the file system, gen_io() is called and whenever an open or close request is received by the file system, clone_opcl() is called (note that clone_opcl() calls gen_io()).

If gen_io() calls sendrec() to send a message to the network service and there is a deadlock because the the network service also attempted to send a message to the file system (i.e., sendrec() returned ELOCKED), gen_io() will call receive() instead.

If the read, write, or ioctl request could not be immediately satisfied, the network service will later send() another REVIVE message after the read, write, or ioctl operation has completed (successfully or unsuccessfully). However, the file system will not necessarily handle any deadlock that occurs (since
the main loop in the file system may possibly handle the message) and so, if a deadlock occurs, the network service must later attempt to send the REVIVE message that was not successful due to the deadlock. The network service does this by placing the message in the repl_queue. The messages in repl_queue will be sent again the next time that sr_repl_queue() is called.