fifosubr.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
* Module linkage information for the kernel. * Define data structures within this file. * XXX should the hash size be configurable ? * In the interest of code sharing, we define a common fifodata structure * which consists of a fifolock and one or two fnodes. A fifo contains * one fnode; a pipe contains two. The fifolock is shared by the fnodes, * each of which points to it: * --> --> --------- --- --- * Since the fifolock is at the beginning of the fifodata structure, * the fifolock address is the same as the fifodata address. Thus, * we can determine the fifodata address from any of its member fnodes. * This is essential for fifo_inactive. * The fnode constructor is designed to handle any fifodata structure, * deducing the number of fnodes from the total size. Thus, the fnode * constructor does most of the work for the pipe constructor. * 32-bit stat(2) may fail if fn_ino isn't initialized * Reinitialize a FIFO vnode (uses normal vnode reinit, but ensures that * vnode type and flags are reset). * Save file system type/index, initialize vfs operations vector, get * unique device number for FIFOFS and initialize the FIFOFS hash. * Create and initialize a "generic" vfs pointer that will be placed * in the v_vfsp field of each pipe's vnode. * vnodes are cached aligned * Provide a shadow for a vnode. We create a new shadow before checking for an * existing one, to minimize the amount of time we need to hold ftable_lock. * If a vp already has a shadow in the hash list, return its shadow. If not, * we hash the new vnode and return its pointer to the caller. * Its possible that fifo nodes on different lofs mountpoints * shadow the same real filesystem fifo node. * In this case its necessary to get and store the realvp. * This way different fifo nodes sharing the same real vnode * can use realvp for communication. * initialize the times from vp. * Grab the VP here to avoid holding locks * whilst trying to acquire others. * Release the vnode and free up our pre-prepared fnode. * Zero the lock reference just to explicitly signal * Create a pipe end by... * allocating a vnode-fifonode pair and initializing the fifonode. * Attempt to establish a unique pipe id. Only un-named pipes use this * The FIFOCONNLD flag is used when CONNLD has been pushed on the stream. * If the flag is set, a new vnode is created by calling fifo_connld(). * Connld logic was moved to fifo_connld() to speed up the open * operation, simplify the connld/fifo interaction, and remove inherent * race conditions between the connld module and fifos. * This routine is single threaded for two reasons. * 1) connld requests are synchronous; that is, they must block * until the server does an I_RECVFD (oh, well). Single threading is * the simplest way to accomplish this. * 2) fifo_close() must not send M_HANGUP or M_ERROR while we are * in stropen. Stropen() has a tendency to reset things and * we would like streams to remember that a hangup occurred. * FIFO is in the process of opening. Wait for it * to complete before starting another open on it * This prevents races associated with connld open * The other end of the pipe is almost closed so * reject any other open on this end of the pipe * This only happens with a pipe mounted under namefs * can't allow close to happen while we are * in the middle of stropen(). * M_HANGUP and M_ERROR could leave the stream in a strange state * This is a reopen, so we should release the fifo lock * just in case some strange module pushed on connld * has some odd side effect. * Note: this stropen is on the oldvp. It will * have no impact on the connld vp returned and * strclose() will only be called when we release * streams open done, allow close on other end if * required. Do this now.. it could * be a very long time before fifo_connld returns. * we need to fake an open here so that if this * end of the pipe closes, we don't loose the * stream head (kind of like single threading * open and close for this end of the pipe) * We'll need to call fifo_close() to do clean * up in case this end of the pipe was closed * down while we were in fifo_connld() * Connld has been pushed onto the pipe * Create new pipe on behalf of connld * undo fake open. We need to call fifo_close * because some other thread could have done * a close and detach of the named pipe while * we were in fifo_connld(), so * we want to make sure the close completes (yuk) * fifo_connld has changed the vp, so we * need to re-initialize locals * release lock in case there are modules pushed that * could have some strange side effect * If this is the first open of a fifo (dotwist * will be non-zero) we will need to twist the queues. * twist the ends of the fifo together * Show that this open has succeeded * and allow closes or other opens to proceed * If this is a FIFO and has the close flag set * and there are now writers, clear the close flag * Note: close flag only gets set when last writer * Clean up the state of a FIFO and/or mounted pipe in the * event that a fifo_open() was interrupted while the * Insert a fifonode-vnode pair onto the fifoalloc hash list. * We don't need to hold fn_lock since we're holding ftable_lock and * this routine is only called right after we've allocated an fnode. * FIFO is inserted at head of NULL terminated doubly linked list. * Find a fifonode-vnode pair on the fifoalloc hash list. * vp is a vnode to be shadowed. If it's on the hash list, * it already has a shadow, therefore return its corresponding * Remove a fifonode-vnode pair from the fifoalloc hash list. * This routine is called from the fifo_inactive() routine when a * FIFO is being released. * If the link to be removed is the only link, set fifoalloc to NULL. * fast path... only 1 FIFO in this list entry * Flush all data from a fifo's message queue * Note: This routine is single threaded * Protected by FIFOOPEN flag (i.e. flk_lock is not held) * Upon successful completion, the original fifo is unlocked * and FIFOOPEN is cleared for the original vpp. * The new fifo returned has FIFOOPEN set. * Get two vnodes that will represent the pipe ends for the new pipe. * Allocate a file descriptor and file pointer for one of the pipe * ends. The file descriptor will be used to send that pipe end to * the process on the other end of this stream. Note that we get * the file structure only, there is no file list entry allocated. * Create two new stream heads and attach them to the two vnodes for * this will call fifo_close and VN_RELE on vp1 * twist the ends of the pipe together * Set our end to busy in open * Note: Don't need lock around this because we're the only * check to make sure neither end of pipe has gone away * this will call fifo_close and VN_RELE on vp1 * Tag the sender's credential on the pipe descriptor. * send the file descriptor to other end of pipe * this will call fifo_close and VN_RELE on vp1 * Wait for other end to receive file descriptor * FIFOCLOSE indicates that one or both sides of the pipe * If either end of pipe has gone away and the other end did not * receive pipe, reject the connld open /* FIFOSTAYFAST is set => FIFOFAST is set */ /* indicate someone is waiting to turn into stream mode */ /* as we may have relased the lock, test the FIFOFAST flag here */ * flk_lock must be held while calling fifo_fastturnoff() to * preserve data ordering (no reads or writes allowed) * Note: This end can't be closed if there * Don't need to drop flk_lock across the put() * since we're just moving the message from the fifo * node to the STREAM head... * Need to re-issue any pending poll requests * so that the STREAMS framework sees them * Writers would be waiting on fnp and readers on fn_dest * wake up any sleeping processes so they can notice we went * Alternative version of fifo_fastoff() * Wake any sleeping writers, poll and send signals if necessary * This module is only called when we drop below the hi water mark * FIFOWANTW indicates that a process is sleeping in fifo_write() * FIFOHIWATW indicates that we have either attempted a poll or * non-blocking write and were over the high water mark * This routine assumes a low water mark of 0. * FIFOPOLLW can't be set without setting FIFOHIWAT * This allows us to clear both here. * wake up any sleeping readers, poll or send signal if needed * FIFOWANTR indicates that a process is waiting in fifo_read() for data * FIFOSETSIG indicates that SIGPOLL should be sent to process * FIFOPOLLR indicates that a poll request for reading on the fifo was made