xref: /minix3/minix/servers/vfs/pipe.c (revision e3b8d4bb58a799dc7fd563ac39bf3015762af03b)
1433d6423SLionel Sambuc /* This file deals with the suspension and revival of processes.  A process can
2433d6423SLionel Sambuc  * be suspended because it wants to read or write from a pipe and can't, or
3433d6423SLionel Sambuc  * because it wants to read or write from a special file and can't.  When a
4433d6423SLionel Sambuc  * process can't continue it is suspended, and revived later when it is able
5433d6423SLionel Sambuc  * to continue.
6433d6423SLionel Sambuc  *
7433d6423SLionel Sambuc  * The entry points into this file are
8433d6423SLionel Sambuc  *   do_pipe2:	  perform the PIPE2 system call
9433d6423SLionel Sambuc  *   pipe_check:  check to see that a read or write on a pipe is feasible now
10433d6423SLionel Sambuc  *   suspend:	  suspend a process that cannot do a requested read or write
11433d6423SLionel Sambuc  *   release:	  check to see if a suspended process can be released and do
12433d6423SLionel Sambuc  *                it
13433d6423SLionel Sambuc  *   revive:	  mark a suspended process as able to run again
14433d6423SLionel Sambuc  *   unsuspend_by_endpt: revive all processes blocking on a given process
15433d6423SLionel Sambuc  *   do_unpause:  a signal has been sent to a process; see if it suspended
16433d6423SLionel Sambuc  */
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc #include "fs.h"
19433d6423SLionel Sambuc #include <fcntl.h>
20433d6423SLionel Sambuc #include <signal.h>
21433d6423SLionel Sambuc #include <string.h>
22433d6423SLionel Sambuc #include <assert.h>
23433d6423SLionel Sambuc #include <minix/callnr.h>
24433d6423SLionel Sambuc #include <minix/endpoint.h>
25433d6423SLionel Sambuc #include <minix/com.h>
26433d6423SLionel Sambuc #include <minix/u64.h>
27433d6423SLionel Sambuc #include <sys/select.h>
28433d6423SLionel Sambuc #include <sys/time.h>
29433d6423SLionel Sambuc #include "file.h"
30433d6423SLionel Sambuc #include <minix/vfsif.h>
31433d6423SLionel Sambuc #include "vnode.h"
32433d6423SLionel Sambuc #include "vmnt.h"
33433d6423SLionel Sambuc 
34433d6423SLionel Sambuc static int create_pipe(int fil_des[2], int flags);
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc /*===========================================================================*
37433d6423SLionel Sambuc  *				do_pipe2				     *
38433d6423SLionel Sambuc  *===========================================================================*/
do_pipe2(void)39433d6423SLionel Sambuc int do_pipe2(void)
40433d6423SLionel Sambuc {
41433d6423SLionel Sambuc /* Perform the pipe2(fil_des[2], flags) system call. */
42433d6423SLionel Sambuc   int r, flags;
43433d6423SLionel Sambuc   int fil_des[2];		/* reply goes here */
44433d6423SLionel Sambuc 
45433d6423SLionel Sambuc   flags = job_m_in.m_lc_vfs_pipe2.flags;
46c33d6ef3SDavid van Moolenbroek   flags |= job_m_in.m_lc_vfs_pipe2.oflags;	/* backward compatibility */
47433d6423SLionel Sambuc 
48433d6423SLionel Sambuc   r = create_pipe(fil_des, flags);
49433d6423SLionel Sambuc   if (r == OK) {
50c33d6ef3SDavid van Moolenbroek 	job_m_out.m_vfs_lc_fdpair.fd0 = fil_des[0];
51c33d6ef3SDavid van Moolenbroek 	job_m_out.m_vfs_lc_fdpair.fd1 = fil_des[1];
52433d6423SLionel Sambuc   }
53433d6423SLionel Sambuc 
54433d6423SLionel Sambuc   return r;
55433d6423SLionel Sambuc }
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc /*===========================================================================*
58433d6423SLionel Sambuc  *				create_pipe				     *
59433d6423SLionel Sambuc  *===========================================================================*/
create_pipe(int fil_des[2],int flags)60433d6423SLionel Sambuc static int create_pipe(int fil_des[2], int flags)
61433d6423SLionel Sambuc {
62433d6423SLionel Sambuc   register struct fproc *rfp;
63433d6423SLionel Sambuc   int r;
64433d6423SLionel Sambuc   struct filp *fil_ptr0, *fil_ptr1;
65433d6423SLionel Sambuc   struct vnode *vp;
66433d6423SLionel Sambuc   struct vmnt *vmp;
67433d6423SLionel Sambuc   struct node_details res;
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc   /* Get a lock on PFS */
70433d6423SLionel Sambuc   if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone");
71433d6423SLionel Sambuc   if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) return(r);
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc   /* See if a free vnode is available */
74433d6423SLionel Sambuc   if ((vp = get_free_vnode()) == NULL) {
75433d6423SLionel Sambuc 	unlock_vmnt(vmp);
76433d6423SLionel Sambuc 	return(err_code);
77433d6423SLionel Sambuc   }
78433d6423SLionel Sambuc   lock_vnode(vp, VNODE_OPCL);
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc   /* Acquire two file descriptors. */
81433d6423SLionel Sambuc   rfp = fp;
82433d6423SLionel Sambuc   if ((r = get_fd(fp, 0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) {
83433d6423SLionel Sambuc 	unlock_vnode(vp);
84433d6423SLionel Sambuc 	unlock_vmnt(vmp);
85433d6423SLionel Sambuc 	return(r);
86433d6423SLionel Sambuc   }
87433d6423SLionel Sambuc   rfp->fp_filp[fil_des[0]] = fil_ptr0;
88433d6423SLionel Sambuc   fil_ptr0->filp_count = 1;		/* mark filp in use */
89433d6423SLionel Sambuc   if ((r = get_fd(fp, 0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
90433d6423SLionel Sambuc 	rfp->fp_filp[fil_des[0]] = NULL;
91433d6423SLionel Sambuc 	fil_ptr0->filp_count = 0;	/* mark filp free */
92433d6423SLionel Sambuc 	unlock_filp(fil_ptr0);
93433d6423SLionel Sambuc 	unlock_vnode(vp);
94433d6423SLionel Sambuc 	unlock_vmnt(vmp);
95433d6423SLionel Sambuc 	return(r);
96433d6423SLionel Sambuc   }
97433d6423SLionel Sambuc   rfp->fp_filp[fil_des[1]] = fil_ptr1;
98433d6423SLionel Sambuc   fil_ptr1->filp_count = 1;
99433d6423SLionel Sambuc 
100433d6423SLionel Sambuc   /* Create a named pipe inode on PipeFS */
101433d6423SLionel Sambuc   r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE,
102433d6423SLionel Sambuc 		  NO_DEV, &res);
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc   if (r != OK) {
105433d6423SLionel Sambuc 	rfp->fp_filp[fil_des[0]] = NULL;
106433d6423SLionel Sambuc 	fil_ptr0->filp_count = 0;
107433d6423SLionel Sambuc 	rfp->fp_filp[fil_des[1]] = NULL;
108433d6423SLionel Sambuc 	fil_ptr1->filp_count = 0;
109433d6423SLionel Sambuc 	unlock_filp(fil_ptr1);
110433d6423SLionel Sambuc 	unlock_filp(fil_ptr0);
111433d6423SLionel Sambuc 	unlock_vnode(vp);
112433d6423SLionel Sambuc 	unlock_vmnt(vmp);
113433d6423SLionel Sambuc 	return(r);
114433d6423SLionel Sambuc   }
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc   /* Fill in vnode */
117433d6423SLionel Sambuc   vp->v_fs_e = res.fs_e;
118433d6423SLionel Sambuc   vp->v_mapfs_e = res.fs_e;
119433d6423SLionel Sambuc   vp->v_inode_nr = res.inode_nr;
120433d6423SLionel Sambuc   vp->v_mapinode_nr = res.inode_nr;
121433d6423SLionel Sambuc   vp->v_mode = res.fmode;
122433d6423SLionel Sambuc   vp->v_fs_count = 1;
123433d6423SLionel Sambuc   vp->v_mapfs_count = 1;
124433d6423SLionel Sambuc   vp->v_ref_count = 1;
125433d6423SLionel Sambuc   vp->v_size = 0;
126433d6423SLionel Sambuc   vp->v_vmnt = NULL;
127433d6423SLionel Sambuc   vp->v_dev = NO_DEV;
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc   /* Fill in filp objects */
130433d6423SLionel Sambuc   fil_ptr0->filp_vno = vp;
131433d6423SLionel Sambuc   dup_vnode(vp);
132433d6423SLionel Sambuc   fil_ptr1->filp_vno = vp;
133433d6423SLionel Sambuc   fil_ptr0->filp_flags = O_RDONLY | (flags & ~O_ACCMODE);
134433d6423SLionel Sambuc   fil_ptr1->filp_flags = O_WRONLY | (flags & ~O_ACCMODE);
135433d6423SLionel Sambuc   if (flags & O_CLOEXEC) {
136433d6423SLionel Sambuc 	FD_SET(fil_des[0], &rfp->fp_cloexec_set);
137433d6423SLionel Sambuc 	FD_SET(fil_des[1], &rfp->fp_cloexec_set);
138433d6423SLionel Sambuc   }
139433d6423SLionel Sambuc 
140433d6423SLionel Sambuc   unlock_filps(fil_ptr0, fil_ptr1);
141433d6423SLionel Sambuc   unlock_vmnt(vmp);
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc   return(OK);
144433d6423SLionel Sambuc }
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc /*===========================================================================*
148433d6423SLionel Sambuc  *				map_vnode				     *
149433d6423SLionel Sambuc  *===========================================================================*/
150a0814afbSRichard Sailer int
map_vnode(struct vnode * vp,endpoint_t map_to_fs_e)151a0814afbSRichard Sailer map_vnode(struct vnode *vp, endpoint_t map_to_fs_e)
152433d6423SLionel Sambuc {
153433d6423SLionel Sambuc   int r;
154433d6423SLionel Sambuc   struct vmnt *vmp;
155433d6423SLionel Sambuc   struct node_details res;
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc   if(vp->v_mapfs_e != NONE) return(OK);	/* Already mapped; nothing to do. */
158433d6423SLionel Sambuc 
159433d6423SLionel Sambuc   if ((vmp = find_vmnt(map_to_fs_e)) == NULL)
160433d6423SLionel Sambuc 	panic("Can't map to unknown endpoint");
161433d6423SLionel Sambuc   if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) {
162433d6423SLionel Sambuc 	if (r == EBUSY)
163433d6423SLionel Sambuc 		vmp = NULL;	/* Already locked, do not unlock */
164433d6423SLionel Sambuc 	else
165433d6423SLionel Sambuc 		return(r);
166433d6423SLionel Sambuc 
167433d6423SLionel Sambuc   }
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc   /* Create a temporary mapping of this inode to another FS. Read and write
170433d6423SLionel Sambuc    * operations on data will be handled by that FS. The rest by the 'original'
171433d6423SLionel Sambuc    * FS that holds the inode. */
172433d6423SLionel Sambuc   if ((r = req_newnode(map_to_fs_e, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE,
173433d6423SLionel Sambuc 		       vp->v_dev, &res)) == OK) {
174433d6423SLionel Sambuc 	vp->v_mapfs_e = res.fs_e;
175433d6423SLionel Sambuc 	vp->v_mapinode_nr = res.inode_nr;
176433d6423SLionel Sambuc 	vp->v_mapfs_count = 1;
177433d6423SLionel Sambuc   }
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc   if (vmp) unlock_vmnt(vmp);
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc   return(r);
182433d6423SLionel Sambuc }
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc /*===========================================================================*
185433d6423SLionel Sambuc  *				pipe_check				     *
186433d6423SLionel Sambuc  *===========================================================================*/
pipe_check(struct filp * filp,int rw_flag,int oflags,int bytes,int notouch)187433d6423SLionel Sambuc int pipe_check(
188433d6423SLionel Sambuc struct filp *filp,	/* the filp of the pipe */
189433d6423SLionel Sambuc int rw_flag,		/* READING or WRITING */
190433d6423SLionel Sambuc int oflags,		/* flags set by open or fcntl */
191433d6423SLionel Sambuc int bytes,		/* bytes to be read or written (all chunks) */
192433d6423SLionel Sambuc int notouch		/* check only */
193433d6423SLionel Sambuc )
194433d6423SLionel Sambuc {
195433d6423SLionel Sambuc /* Pipes are a little different.  If a process reads from an empty pipe for
196433d6423SLionel Sambuc  * which a writer still exists, suspend the reader.  If the pipe is empty
197433d6423SLionel Sambuc  * and there is no writer, return 0 bytes.  If a process is writing to a
198433d6423SLionel Sambuc  * pipe and no one is reading from it, give a broken pipe error.
199433d6423SLionel Sambuc  */
200433d6423SLionel Sambuc   struct vnode *vp;
201433d6423SLionel Sambuc   off_t pos;
202433d6423SLionel Sambuc   int r = OK;
203433d6423SLionel Sambuc 
204433d6423SLionel Sambuc   vp = filp->filp_vno;
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc   /* Reads start at the beginning; writes append to pipes */
207433d6423SLionel Sambuc   if (notouch) /* In this case we don't actually care whether data transfer
208433d6423SLionel Sambuc 		* would succeed. See POSIX 1003.1-2008 */
209433d6423SLionel Sambuc 	pos = 0;
210433d6423SLionel Sambuc   else if (rw_flag == READING)
211433d6423SLionel Sambuc 	pos = 0;
212433d6423SLionel Sambuc   else {
213433d6423SLionel Sambuc 	pos = vp->v_size;
214433d6423SLionel Sambuc   }
215433d6423SLionel Sambuc 
216433d6423SLionel Sambuc   /* If reading, check for empty pipe. */
217433d6423SLionel Sambuc   if (rw_flag == READING) {
218433d6423SLionel Sambuc 	if (vp->v_size == 0) {
219433d6423SLionel Sambuc 		/* Process is reading from an empty pipe. */
220433d6423SLionel Sambuc 		if (find_filp(vp, W_BIT) != NULL) {
221433d6423SLionel Sambuc 			/* Writer exists */
222433d6423SLionel Sambuc 			if (oflags & O_NONBLOCK)
223433d6423SLionel Sambuc 				r = EAGAIN;
224433d6423SLionel Sambuc 			else
225433d6423SLionel Sambuc 				r = SUSPEND;
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc 			/* If need be, activate sleeping writers. */
228433d6423SLionel Sambuc 			/* We ignore notouch voluntary here. */
229433d6423SLionel Sambuc 			if (susp_count > 0)
230433d6423SLionel Sambuc 				release(vp, VFS_WRITE, susp_count);
231433d6423SLionel Sambuc 		}
232433d6423SLionel Sambuc 		return(r);
233433d6423SLionel Sambuc 	}
234433d6423SLionel Sambuc 	return(bytes);
235433d6423SLionel Sambuc   }
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc   /* Process is writing to a pipe. */
238433d6423SLionel Sambuc   if (find_filp(vp, R_BIT) == NULL) {
239433d6423SLionel Sambuc 	return(EPIPE);
240433d6423SLionel Sambuc   }
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc   /* Calculate how many bytes can be written. */
243433d6423SLionel Sambuc   if (pos + bytes > PIPE_BUF) {
244433d6423SLionel Sambuc 	if (oflags & O_NONBLOCK) {
245433d6423SLionel Sambuc 		if (bytes <= PIPE_BUF) {
246433d6423SLionel Sambuc 			/* Write has to be atomic */
247433d6423SLionel Sambuc 			return(EAGAIN);
248433d6423SLionel Sambuc 		}
249433d6423SLionel Sambuc 
250433d6423SLionel Sambuc 		/* Compute available space */
251433d6423SLionel Sambuc 		bytes = PIPE_BUF - pos;
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc 		if (bytes > 0)  {
254433d6423SLionel Sambuc 			/* Do a partial write. Need to wakeup reader */
255433d6423SLionel Sambuc 			if (!notouch)
256433d6423SLionel Sambuc 				release(vp, VFS_READ, susp_count);
257433d6423SLionel Sambuc 			return(bytes);
258433d6423SLionel Sambuc 		} else {
259433d6423SLionel Sambuc 			/* Pipe is full */
260433d6423SLionel Sambuc 			return(EAGAIN);
261433d6423SLionel Sambuc 		}
262433d6423SLionel Sambuc 	}
263433d6423SLionel Sambuc 
264433d6423SLionel Sambuc 	if (bytes > PIPE_BUF) {
265433d6423SLionel Sambuc 		/* Compute available space */
266433d6423SLionel Sambuc 		bytes = PIPE_BUF - pos;
267433d6423SLionel Sambuc 
268433d6423SLionel Sambuc 		if (bytes > 0) {
269433d6423SLionel Sambuc 			/* Do a partial write. Need to wakeup reader
270433d6423SLionel Sambuc 			 * since we'll suspend ourself in read_write()
271433d6423SLionel Sambuc 			 */
272433d6423SLionel Sambuc 			if (!notouch)
273433d6423SLionel Sambuc 				release(vp, VFS_READ, susp_count);
274433d6423SLionel Sambuc 			return(bytes);
275433d6423SLionel Sambuc 		}
276433d6423SLionel Sambuc 	}
277433d6423SLionel Sambuc 
278433d6423SLionel Sambuc 	/* Pipe is full */
279433d6423SLionel Sambuc 	return(SUSPEND);
280433d6423SLionel Sambuc   }
281433d6423SLionel Sambuc 
282433d6423SLionel Sambuc   /* Writing to an empty pipe.  Search for suspended reader. */
283433d6423SLionel Sambuc   if (pos == 0 && !notouch)
284433d6423SLionel Sambuc 	release(vp, VFS_READ, susp_count);
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc   /* Requested amount fits */
287433d6423SLionel Sambuc   return(bytes);
288433d6423SLionel Sambuc }
289433d6423SLionel Sambuc 
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc /*===========================================================================*
292433d6423SLionel Sambuc  *				suspend					     *
293433d6423SLionel Sambuc  *===========================================================================*/
suspend(int why)294433d6423SLionel Sambuc void suspend(int why)
295433d6423SLionel Sambuc {
296232819ddSDavid van Moolenbroek /* Take measures to suspend the processing of the present system call.  The
297232819ddSDavid van Moolenbroek  * caller must store the parameters to be used upon resuming in the process
298232819ddSDavid van Moolenbroek  * table as appropriate.  The SUSPEND pseudo error should be returned after
299232819ddSDavid van Moolenbroek  * calling suspend().
300433d6423SLionel Sambuc  */
301433d6423SLionel Sambuc 
302232819ddSDavid van Moolenbroek   assert(fp->fp_blocked_on == FP_BLOCKED_ON_NONE);
303232819ddSDavid van Moolenbroek 
304433d6423SLionel Sambuc   if (why == FP_BLOCKED_ON_POPEN || why == FP_BLOCKED_ON_PIPE)
305433d6423SLionel Sambuc 	/* #procs susp'ed on pipe*/
306433d6423SLionel Sambuc 	susp_count++;
307433d6423SLionel Sambuc 
308433d6423SLionel Sambuc   fp->fp_blocked_on = why;
309433d6423SLionel Sambuc }
310433d6423SLionel Sambuc 
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc /*===========================================================================*
313433d6423SLionel Sambuc  *				pipe_suspend				     *
314433d6423SLionel Sambuc  *===========================================================================*/
pipe_suspend(int callnr,int fd,vir_bytes buf,size_t size,size_t cum_io)315232819ddSDavid van Moolenbroek void pipe_suspend(int callnr, int fd, vir_bytes buf, size_t size,
316232819ddSDavid van Moolenbroek 	size_t cum_io)
317433d6423SLionel Sambuc {
318433d6423SLionel Sambuc /* Take measures to suspend the processing of the present system call.
319433d6423SLionel Sambuc  * Store the parameters to be used upon resuming in the process table.
320433d6423SLionel Sambuc  */
321433d6423SLionel Sambuc 
322232819ddSDavid van Moolenbroek   fp->fp_pipe.callnr = callnr;
323232819ddSDavid van Moolenbroek   fp->fp_pipe.fd = fd;
324232819ddSDavid van Moolenbroek   fp->fp_pipe.buf = buf;
325232819ddSDavid van Moolenbroek   fp->fp_pipe.nbytes = size;
326232819ddSDavid van Moolenbroek   fp->fp_pipe.cum_io = cum_io;
327433d6423SLionel Sambuc   suspend(FP_BLOCKED_ON_PIPE);
328433d6423SLionel Sambuc }
329433d6423SLionel Sambuc 
330433d6423SLionel Sambuc 
331433d6423SLionel Sambuc /*===========================================================================*
332433d6423SLionel Sambuc  *				unsuspend_by_endpt			     *
333433d6423SLionel Sambuc  *===========================================================================*/
unsuspend_by_endpt(endpoint_t proc_e)334433d6423SLionel Sambuc void unsuspend_by_endpt(endpoint_t proc_e)
335433d6423SLionel Sambuc {
336232819ddSDavid van Moolenbroek /* Revive processes waiting for drivers (SUSPENDed) that have disappeared, with
337232819ddSDavid van Moolenbroek  * return code EIO.
338433d6423SLionel Sambuc  */
339433d6423SLionel Sambuc   struct fproc *rp;
340*e3b8d4bbSDavid van Moolenbroek   struct smap *sp;
341433d6423SLionel Sambuc 
342433d6423SLionel Sambuc   for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) {
343433d6423SLionel Sambuc 	if (rp->fp_pid == PID_FREE) continue;
344232819ddSDavid van Moolenbroek 	if (rp->fp_blocked_on == FP_BLOCKED_ON_CDEV &&
345232819ddSDavid van Moolenbroek 	    rp->fp_cdev.endpt == proc_e)
346433d6423SLionel Sambuc 		revive(rp->fp_endpoint, EIO);
347*e3b8d4bbSDavid van Moolenbroek 	else if (rp->fp_blocked_on == FP_BLOCKED_ON_SDEV &&
348*e3b8d4bbSDavid van Moolenbroek 	    (sp = get_smap_by_dev(rp->fp_sdev.dev, NULL)) != NULL &&
349*e3b8d4bbSDavid van Moolenbroek 	    sp->smap_endpt == proc_e)
350*e3b8d4bbSDavid van Moolenbroek 		sdev_stop(rp);
351433d6423SLionel Sambuc   }
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc   /* Revive processes waiting in drivers on select()s with EAGAIN too */
354433d6423SLionel Sambuc   select_unsuspend_by_endpt(proc_e);
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc   return;
357433d6423SLionel Sambuc }
358433d6423SLionel Sambuc 
359433d6423SLionel Sambuc 
360433d6423SLionel Sambuc /*===========================================================================*
361433d6423SLionel Sambuc  *				release					     *
362433d6423SLionel Sambuc  *===========================================================================*/
release(struct vnode * vp,int op,int count)363232819ddSDavid van Moolenbroek void release(struct vnode * vp, int op, int count)
364433d6423SLionel Sambuc {
365232819ddSDavid van Moolenbroek /* Check to see if any process is hanging on pipe vnode 'vp'. If one is, and it
366232819ddSDavid van Moolenbroek  * was trying to perform the call indicated by 'op' - one of VFS_OPEN,
367232819ddSDavid van Moolenbroek  * VFS_READ, or VFS_WRITE - release it.  The 'count' parameter indicates the
368232819ddSDavid van Moolenbroek  * maximum number of processes to release, which allows us to stop searching
369232819ddSDavid van Moolenbroek  * early in some cases.
370433d6423SLionel Sambuc  */
371433d6423SLionel Sambuc 
372433d6423SLionel Sambuc   register struct fproc *rp;
373433d6423SLionel Sambuc   struct filp *f;
374232819ddSDavid van Moolenbroek   int fd, selop;
375433d6423SLionel Sambuc 
376433d6423SLionel Sambuc   /* Trying to perform the call also includes SELECTing on it with that
377433d6423SLionel Sambuc    * operation.
378433d6423SLionel Sambuc    */
379433d6423SLionel Sambuc   if (op == VFS_READ || op == VFS_WRITE) {
380433d6423SLionel Sambuc 	if (op == VFS_READ)
381433d6423SLionel Sambuc 		selop = SEL_RD;
382433d6423SLionel Sambuc 	else
383433d6423SLionel Sambuc 		selop = SEL_WR;
384433d6423SLionel Sambuc 
385433d6423SLionel Sambuc 	for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
386433d6423SLionel Sambuc 		if (f->filp_count < 1 || !(f->filp_pipe_select_ops & selop) ||
387433d6423SLionel Sambuc 		    f->filp_vno != vp)
388433d6423SLionel Sambuc 			continue;
389433d6423SLionel Sambuc 
390433d6423SLionel Sambuc 		select_callback(f, selop);
391433d6423SLionel Sambuc 
392433d6423SLionel Sambuc 		f->filp_pipe_select_ops &= ~selop;
393433d6423SLionel Sambuc 	}
394433d6423SLionel Sambuc   }
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc   /* Search the proc table. */
397433d6423SLionel Sambuc   for (rp = &fproc[0]; rp < &fproc[NR_PROCS] && count > 0; rp++) {
398232819ddSDavid van Moolenbroek 	/* Just to make sure:
399232819ddSDavid van Moolenbroek 	 * - FP_BLOCKED_ON_POPEN implies the original request was VFS_OPEN;
400232819ddSDavid van Moolenbroek 	 * - FP_BLOCKED_ON_PIPE may be the result of VFS_READ and VFS_WRITE,
401232819ddSDavid van Moolenbroek 	 *   and one of those two numbers is stored in fp_pipe.callnr.
402232819ddSDavid van Moolenbroek 	 */
403433d6423SLionel Sambuc 	if (rp->fp_pid != PID_FREE && fp_is_blocked(rp) &&
404232819ddSDavid van Moolenbroek 	    !(rp->fp_flags & FP_REVIVED) &&
405232819ddSDavid van Moolenbroek 	    ((op == VFS_OPEN && rp->fp_blocked_on == FP_BLOCKED_ON_POPEN) ||
406232819ddSDavid van Moolenbroek 	     (op != VFS_OPEN && rp->fp_blocked_on == FP_BLOCKED_ON_PIPE &&
407232819ddSDavid van Moolenbroek 	      op == rp->fp_pipe.callnr))) {
408433d6423SLionel Sambuc 		/* Find the vnode. Depending on the reason the process was
409433d6423SLionel Sambuc 		 * suspended, there are different ways of finding it.
410433d6423SLionel Sambuc 		 */
411232819ddSDavid van Moolenbroek 		if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN)
412232819ddSDavid van Moolenbroek 			fd = rp->fp_popen.fd;
413232819ddSDavid van Moolenbroek 		else
414232819ddSDavid van Moolenbroek 			fd = rp->fp_pipe.fd;
415232819ddSDavid van Moolenbroek 		f = rp->fp_filp[fd];
416433d6423SLionel Sambuc 		if (f == NULL || f->filp_mode == FILP_CLOSED)
417433d6423SLionel Sambuc 			continue;
418bd851af4SDavid van Moolenbroek 		if (f->filp_vno != vp)
419433d6423SLionel Sambuc 			continue;
420433d6423SLionel Sambuc 
421433d6423SLionel Sambuc 		/* We found the vnode. Revive process. */
422433d6423SLionel Sambuc 		revive(rp->fp_endpoint, 0);
423433d6423SLionel Sambuc 		susp_count--;	/* keep track of who is suspended */
424433d6423SLionel Sambuc 		if(susp_count < 0)
425433d6423SLionel Sambuc 			panic("susp_count now negative: %d", susp_count);
426433d6423SLionel Sambuc 		if (--count == 0) return;
427433d6423SLionel Sambuc 	}
428433d6423SLionel Sambuc   }
429433d6423SLionel Sambuc }
430433d6423SLionel Sambuc 
431433d6423SLionel Sambuc 
432433d6423SLionel Sambuc /*===========================================================================*
433433d6423SLionel Sambuc  *				revive					     *
434433d6423SLionel Sambuc  *===========================================================================*/
revive(endpoint_t proc_e,int returned)435433d6423SLionel Sambuc void revive(endpoint_t proc_e, int returned)
436433d6423SLionel Sambuc {
437433d6423SLionel Sambuc /* Revive a previously blocked process. When a process hangs on tty, this
438*e3b8d4bbSDavid van Moolenbroek  * is the way it is eventually released. For processes blocked on _SELECT,
439*e3b8d4bbSDavid van Moolenbroek  * _CDEV, or _SDEV, this function MUST NOT block its calling thread.
440433d6423SLionel Sambuc  */
441433d6423SLionel Sambuc   struct fproc *rfp;
442433d6423SLionel Sambuc   int blocked_on;
443232819ddSDavid van Moolenbroek   int slot;
444433d6423SLionel Sambuc 
445433d6423SLionel Sambuc   if (proc_e == NONE || isokendpt(proc_e, &slot) != OK) return;
446433d6423SLionel Sambuc 
447433d6423SLionel Sambuc   rfp = &fproc[slot];
448433d6423SLionel Sambuc   if (!fp_is_blocked(rfp) || (rfp->fp_flags & FP_REVIVED)) return;
449433d6423SLionel Sambuc 
450232819ddSDavid van Moolenbroek   /* The 'reviving' flag applies to pipe I/O and file locks.  Processes waiting
451232819ddSDavid van Moolenbroek    * on those suspension types need more processing, and will be unblocked from
452232819ddSDavid van Moolenbroek    * the main loop later.  Processes suspended for other reasons get a reply
453232819ddSDavid van Moolenbroek    * right away, and as such, have their suspension cleared right here as well.
454433d6423SLionel Sambuc    */
455433d6423SLionel Sambuc   blocked_on = rfp->fp_blocked_on;
456232819ddSDavid van Moolenbroek   if (blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_FLOCK) {
457433d6423SLionel Sambuc 	/* Revive a process suspended on a pipe or lock. */
458433d6423SLionel Sambuc 	rfp->fp_flags |= FP_REVIVED;
459433d6423SLionel Sambuc 	reviving++;		/* process was waiting on pipe or lock */
460433d6423SLionel Sambuc   } else {
461433d6423SLionel Sambuc 	rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
462*e3b8d4bbSDavid van Moolenbroek 	switch (blocked_on) {
463*e3b8d4bbSDavid van Moolenbroek 	case FP_BLOCKED_ON_POPEN:
464433d6423SLionel Sambuc 		/* process blocked in open or create */
465232819ddSDavid van Moolenbroek 		replycode(proc_e, rfp->fp_popen.fd);
466*e3b8d4bbSDavid van Moolenbroek 		break;
467*e3b8d4bbSDavid van Moolenbroek 	case FP_BLOCKED_ON_SELECT:
468433d6423SLionel Sambuc 		replycode(proc_e, returned);
469*e3b8d4bbSDavid van Moolenbroek 		break;
470*e3b8d4bbSDavid van Moolenbroek 	case FP_BLOCKED_ON_CDEV:
471433d6423SLionel Sambuc 		/* If a grant has been issued by FS for this I/O, revoke
472433d6423SLionel Sambuc 		 * it again now that I/O is done.
473433d6423SLionel Sambuc 		 */
474232819ddSDavid van Moolenbroek 		if (GRANT_VALID(rfp->fp_cdev.grant)) {
475232819ddSDavid van Moolenbroek 			if (cpf_revoke(rfp->fp_cdev.grant) == -1) {
476433d6423SLionel Sambuc 				panic("VFS: revoke failed for grant: %d",
477232819ddSDavid van Moolenbroek 				    rfp->fp_cdev.grant);
478433d6423SLionel Sambuc 			}
479433d6423SLionel Sambuc 		}
480433d6423SLionel Sambuc 		replycode(proc_e, returned);/* unblock the process */
481*e3b8d4bbSDavid van Moolenbroek 		break;
482*e3b8d4bbSDavid van Moolenbroek 	case FP_BLOCKED_ON_SDEV:
483*e3b8d4bbSDavid van Moolenbroek 		/*
484*e3b8d4bbSDavid van Moolenbroek 		 * Cleaning up socket requests is too complex to put here, and
485*e3b8d4bbSDavid van Moolenbroek 		 * neither sdev_reply() nor sdev_stop() call revive().
486*e3b8d4bbSDavid van Moolenbroek 		 */
487*e3b8d4bbSDavid van Moolenbroek 		panic("revive should not be used for socket calls");
488*e3b8d4bbSDavid van Moolenbroek 	default:
489*e3b8d4bbSDavid van Moolenbroek 		panic("unknown block state %d", blocked_on);
490433d6423SLionel Sambuc 	}
491433d6423SLionel Sambuc   }
492433d6423SLionel Sambuc }
493433d6423SLionel Sambuc 
494433d6423SLionel Sambuc 
495433d6423SLionel Sambuc /*===========================================================================*
496433d6423SLionel Sambuc  *				unpause					     *
497433d6423SLionel Sambuc  *===========================================================================*/
unpause(void)498433d6423SLionel Sambuc void unpause(void)
499433d6423SLionel Sambuc {
500433d6423SLionel Sambuc /* A signal has been sent to a user who is paused on the file system.
501433d6423SLionel Sambuc  * Abort the system call with the EINTR error message.
502433d6423SLionel Sambuc  */
503232819ddSDavid van Moolenbroek   int blocked_on, status = EINTR;
504433d6423SLionel Sambuc   int wasreviving = 0;
505433d6423SLionel Sambuc 
506433d6423SLionel Sambuc   if (!fp_is_blocked(fp)) return;
507433d6423SLionel Sambuc   blocked_on = fp->fp_blocked_on;
508433d6423SLionel Sambuc 
509433d6423SLionel Sambuc   /* Clear the block status now. The procedure below might make blocking calls
510*e3b8d4bbSDavid van Moolenbroek    * and it is imperative that while at least cdev_cancel() or sdev_cancel()
511*e3b8d4bbSDavid van Moolenbroek    * are executing, other parts of VFS do not perceive this process as blocked
512*e3b8d4bbSDavid van Moolenbroek    * on something.
513433d6423SLionel Sambuc    */
514433d6423SLionel Sambuc   fp->fp_blocked_on = FP_BLOCKED_ON_NONE;
515433d6423SLionel Sambuc 
516433d6423SLionel Sambuc   if (fp->fp_flags & FP_REVIVED) {
517433d6423SLionel Sambuc 	fp->fp_flags &= ~FP_REVIVED;
518433d6423SLionel Sambuc 	reviving--;
519433d6423SLionel Sambuc 	wasreviving = 1;
520433d6423SLionel Sambuc   }
521433d6423SLionel Sambuc 
522433d6423SLionel Sambuc   switch (blocked_on) {
523433d6423SLionel Sambuc 	case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */
524433d6423SLionel Sambuc 		/* If the operation succeeded partially, return the bytes
525232819ddSDavid van Moolenbroek 		 * processed so far.  Otherwise, return EINTR as usual.
526433d6423SLionel Sambuc 		 */
527232819ddSDavid van Moolenbroek 		if (fp->fp_pipe.cum_io > 0)
528232819ddSDavid van Moolenbroek 			status = fp->fp_pipe.cum_io;
529433d6423SLionel Sambuc 		break;
530433d6423SLionel Sambuc 
531232819ddSDavid van Moolenbroek 	case FP_BLOCKED_ON_FLOCK:/* process trying to set a lock with FCNTL */
532433d6423SLionel Sambuc 		break;
533433d6423SLionel Sambuc 
534433d6423SLionel Sambuc 	case FP_BLOCKED_ON_SELECT:/* process blocking on select() */
535433d6423SLionel Sambuc 		select_forget();
536433d6423SLionel Sambuc 		break;
537433d6423SLionel Sambuc 
538433d6423SLionel Sambuc 	case FP_BLOCKED_ON_POPEN:	/* process trying to open a fifo */
539433d6423SLionel Sambuc 		break;
540433d6423SLionel Sambuc 
541232819ddSDavid van Moolenbroek 	case FP_BLOCKED_ON_CDEV: /* process blocked on character device I/O */
542232819ddSDavid van Moolenbroek 		status = cdev_cancel(fp->fp_cdev.dev, fp->fp_cdev.endpt,
543232819ddSDavid van Moolenbroek 		    fp->fp_cdev.grant);
544433d6423SLionel Sambuc 
545433d6423SLionel Sambuc 		break;
546*e3b8d4bbSDavid van Moolenbroek 
547*e3b8d4bbSDavid van Moolenbroek 	case FP_BLOCKED_ON_SDEV:	/* process blocked on socket I/O */
548*e3b8d4bbSDavid van Moolenbroek 		sdev_cancel();
549*e3b8d4bbSDavid van Moolenbroek 		return;			/* sdev_cancel() sends its own reply */
550*e3b8d4bbSDavid van Moolenbroek 
551433d6423SLionel Sambuc 	default :
552433d6423SLionel Sambuc 		panic("VFS: unknown block reason: %d", blocked_on);
553433d6423SLionel Sambuc   }
554433d6423SLionel Sambuc 
555433d6423SLionel Sambuc   if ((blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_POPEN)&&
556433d6423SLionel Sambuc 	!wasreviving) {
557433d6423SLionel Sambuc 	susp_count--;
558433d6423SLionel Sambuc   }
559433d6423SLionel Sambuc 
560433d6423SLionel Sambuc   replycode(fp->fp_endpoint, status);	/* signal interrupted call */
561433d6423SLionel Sambuc }
562