xref: /minix3/minix/servers/vfs/pipe.c (revision bd851af48fd138dabb73c48d0f47ab094eee023a)
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  *===========================================================================*/
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;
46433d6423SLionel Sambuc 
47433d6423SLionel Sambuc   r = create_pipe(fil_des, flags);
48433d6423SLionel Sambuc   if (r == OK) {
49433d6423SLionel Sambuc 	job_m_out.m_lc_vfs_pipe2.fd0 = fil_des[0];
50433d6423SLionel Sambuc 	job_m_out.m_lc_vfs_pipe2.fd1 = fil_des[1];
51433d6423SLionel Sambuc   }
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc   return r;
54433d6423SLionel Sambuc }
55433d6423SLionel Sambuc 
56433d6423SLionel Sambuc /*===========================================================================*
57433d6423SLionel Sambuc  *				create_pipe				     *
58433d6423SLionel Sambuc  *===========================================================================*/
59433d6423SLionel Sambuc static int create_pipe(int fil_des[2], int flags)
60433d6423SLionel Sambuc {
61433d6423SLionel Sambuc   register struct fproc *rfp;
62433d6423SLionel Sambuc   int r;
63433d6423SLionel Sambuc   struct filp *fil_ptr0, *fil_ptr1;
64433d6423SLionel Sambuc   struct vnode *vp;
65433d6423SLionel Sambuc   struct vmnt *vmp;
66433d6423SLionel Sambuc   struct node_details res;
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc   /* Get a lock on PFS */
69433d6423SLionel Sambuc   if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone");
70433d6423SLionel Sambuc   if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) return(r);
71433d6423SLionel Sambuc 
72433d6423SLionel Sambuc   /* See if a free vnode is available */
73433d6423SLionel Sambuc   if ((vp = get_free_vnode()) == NULL) {
74433d6423SLionel Sambuc 	unlock_vmnt(vmp);
75433d6423SLionel Sambuc 	return(err_code);
76433d6423SLionel Sambuc   }
77433d6423SLionel Sambuc   lock_vnode(vp, VNODE_OPCL);
78433d6423SLionel Sambuc 
79433d6423SLionel Sambuc   /* Acquire two file descriptors. */
80433d6423SLionel Sambuc   rfp = fp;
81433d6423SLionel Sambuc   if ((r = get_fd(fp, 0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) {
82433d6423SLionel Sambuc 	unlock_vnode(vp);
83433d6423SLionel Sambuc 	unlock_vmnt(vmp);
84433d6423SLionel Sambuc 	return(r);
85433d6423SLionel Sambuc   }
86433d6423SLionel Sambuc   rfp->fp_filp[fil_des[0]] = fil_ptr0;
87433d6423SLionel Sambuc   fil_ptr0->filp_count = 1;		/* mark filp in use */
88433d6423SLionel Sambuc   if ((r = get_fd(fp, 0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
89433d6423SLionel Sambuc 	rfp->fp_filp[fil_des[0]] = NULL;
90433d6423SLionel Sambuc 	fil_ptr0->filp_count = 0;	/* mark filp free */
91433d6423SLionel Sambuc 	unlock_filp(fil_ptr0);
92433d6423SLionel Sambuc 	unlock_vnode(vp);
93433d6423SLionel Sambuc 	unlock_vmnt(vmp);
94433d6423SLionel Sambuc 	return(r);
95433d6423SLionel Sambuc   }
96433d6423SLionel Sambuc   rfp->fp_filp[fil_des[1]] = fil_ptr1;
97433d6423SLionel Sambuc   fil_ptr1->filp_count = 1;
98433d6423SLionel Sambuc 
99433d6423SLionel Sambuc   /* Create a named pipe inode on PipeFS */
100433d6423SLionel Sambuc   r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE,
101433d6423SLionel Sambuc 		  NO_DEV, &res);
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc   if (r != OK) {
104433d6423SLionel Sambuc 	rfp->fp_filp[fil_des[0]] = NULL;
105433d6423SLionel Sambuc 	fil_ptr0->filp_count = 0;
106433d6423SLionel Sambuc 	rfp->fp_filp[fil_des[1]] = NULL;
107433d6423SLionel Sambuc 	fil_ptr1->filp_count = 0;
108433d6423SLionel Sambuc 	unlock_filp(fil_ptr1);
109433d6423SLionel Sambuc 	unlock_filp(fil_ptr0);
110433d6423SLionel Sambuc 	unlock_vnode(vp);
111433d6423SLionel Sambuc 	unlock_vmnt(vmp);
112433d6423SLionel Sambuc 	return(r);
113433d6423SLionel Sambuc   }
114433d6423SLionel Sambuc 
115433d6423SLionel Sambuc   /* Fill in vnode */
116433d6423SLionel Sambuc   vp->v_fs_e = res.fs_e;
117433d6423SLionel Sambuc   vp->v_mapfs_e = res.fs_e;
118433d6423SLionel Sambuc   vp->v_inode_nr = res.inode_nr;
119433d6423SLionel Sambuc   vp->v_mapinode_nr = res.inode_nr;
120433d6423SLionel Sambuc   vp->v_mode = res.fmode;
121433d6423SLionel Sambuc   vp->v_fs_count = 1;
122433d6423SLionel Sambuc   vp->v_mapfs_count = 1;
123433d6423SLionel Sambuc   vp->v_ref_count = 1;
124433d6423SLionel Sambuc   vp->v_size = 0;
125433d6423SLionel Sambuc   vp->v_vmnt = NULL;
126433d6423SLionel Sambuc   vp->v_dev = NO_DEV;
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc   /* Fill in filp objects */
129433d6423SLionel Sambuc   fil_ptr0->filp_vno = vp;
130433d6423SLionel Sambuc   dup_vnode(vp);
131433d6423SLionel Sambuc   fil_ptr1->filp_vno = vp;
132433d6423SLionel Sambuc   fil_ptr0->filp_flags = O_RDONLY | (flags & ~O_ACCMODE);
133433d6423SLionel Sambuc   fil_ptr1->filp_flags = O_WRONLY | (flags & ~O_ACCMODE);
134433d6423SLionel Sambuc   if (flags & O_CLOEXEC) {
135433d6423SLionel Sambuc 	FD_SET(fil_des[0], &rfp->fp_cloexec_set);
136433d6423SLionel Sambuc 	FD_SET(fil_des[1], &rfp->fp_cloexec_set);
137433d6423SLionel Sambuc   }
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc   unlock_filps(fil_ptr0, fil_ptr1);
140433d6423SLionel Sambuc   unlock_vmnt(vmp);
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc   return(OK);
143433d6423SLionel Sambuc }
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc /*===========================================================================*
147433d6423SLionel Sambuc  *				map_vnode				     *
148433d6423SLionel Sambuc  *===========================================================================*/
149433d6423SLionel Sambuc int map_vnode(vp, map_to_fs_e)
150433d6423SLionel Sambuc struct vnode *vp;
151433d6423SLionel Sambuc 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  *===========================================================================*/
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  *===========================================================================*/
294433d6423SLionel Sambuc void suspend(int why)
295433d6423SLionel Sambuc {
296433d6423SLionel Sambuc /* Take measures to suspend the processing of the present system call.
297433d6423SLionel Sambuc  * Store the parameters to be used upon resuming in the process table.
298433d6423SLionel Sambuc  * (Actually they are not used when a process is waiting for an I/O device,
299433d6423SLionel Sambuc  * but they are needed for pipes, and it is not worth making the distinction.)
300433d6423SLionel Sambuc  * The SUSPEND pseudo error should be returned after calling suspend().
301433d6423SLionel Sambuc  */
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc   if (why == FP_BLOCKED_ON_POPEN || why == FP_BLOCKED_ON_PIPE)
304433d6423SLionel Sambuc 	/* #procs susp'ed on pipe*/
305433d6423SLionel Sambuc 	susp_count++;
306433d6423SLionel Sambuc 
307433d6423SLionel Sambuc   fp->fp_blocked_on = why;
308433d6423SLionel Sambuc   assert(fp->fp_grant == GRANT_INVALID || !GRANT_VALID(fp->fp_grant));
309433d6423SLionel Sambuc   fp->fp_block_callnr = job_call_nr;
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc /*===========================================================================*
313433d6423SLionel Sambuc  *				wait_for				     *
314433d6423SLionel Sambuc  *===========================================================================*/
315433d6423SLionel Sambuc void wait_for(endpoint_t who)
316433d6423SLionel Sambuc {
317433d6423SLionel Sambuc   if(who == NONE || who == ANY)
318433d6423SLionel Sambuc 	panic("suspend on NONE or ANY");
319433d6423SLionel Sambuc   suspend(FP_BLOCKED_ON_OTHER);
320433d6423SLionel Sambuc   fp->fp_task = who;
321433d6423SLionel Sambuc }
322433d6423SLionel Sambuc 
323433d6423SLionel Sambuc 
324433d6423SLionel Sambuc /*===========================================================================*
325433d6423SLionel Sambuc  *				pipe_suspend				     *
326433d6423SLionel Sambuc  *===========================================================================*/
327433d6423SLionel Sambuc void pipe_suspend(filp, buf, size)
328433d6423SLionel Sambuc struct filp *filp;
329433d6423SLionel Sambuc vir_bytes buf;
330433d6423SLionel Sambuc size_t size;
331433d6423SLionel Sambuc {
332433d6423SLionel Sambuc /* Take measures to suspend the processing of the present system call.
333433d6423SLionel Sambuc  * Store the parameters to be used upon resuming in the process table.
334433d6423SLionel Sambuc  */
335433d6423SLionel Sambuc 
336*bd851af4SDavid van Moolenbroek   /* We can only get here through an I/O call, which comes with a file
337*bd851af4SDavid van Moolenbroek    * descriptor, and that file descriptor must therefore correspond to the
338*bd851af4SDavid van Moolenbroek    * target file pointer of the I/O request. The process is blocked on the I/O
339*bd851af4SDavid van Moolenbroek    * call, and thus, the file descriptor will remain valid. Therefore, we can,
340*bd851af4SDavid van Moolenbroek    * and will, use the file descriptor to get the file pointer again later.
341*bd851af4SDavid van Moolenbroek    */
342*bd851af4SDavid van Moolenbroek   assert(fp->fp_filp[fp->fp_fd] == filp);
343*bd851af4SDavid van Moolenbroek 
344*bd851af4SDavid van Moolenbroek   fp->fp_io_buffer = buf;
345*bd851af4SDavid van Moolenbroek   fp->fp_io_nbytes = size;
346433d6423SLionel Sambuc   suspend(FP_BLOCKED_ON_PIPE);
347433d6423SLionel Sambuc }
348433d6423SLionel Sambuc 
349433d6423SLionel Sambuc 
350433d6423SLionel Sambuc /*===========================================================================*
351433d6423SLionel Sambuc  *				unsuspend_by_endpt			     *
352433d6423SLionel Sambuc  *===========================================================================*/
353433d6423SLionel Sambuc void unsuspend_by_endpt(endpoint_t proc_e)
354433d6423SLionel Sambuc {
355433d6423SLionel Sambuc /* Revive processes waiting for drivers (SUSPENDed) that have disappeared with
356433d6423SLionel Sambuc  * return code EAGAIN.
357433d6423SLionel Sambuc  */
358433d6423SLionel Sambuc   struct fproc *rp;
359433d6423SLionel Sambuc 
360433d6423SLionel Sambuc   for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) {
361433d6423SLionel Sambuc 	if (rp->fp_pid == PID_FREE) continue;
362433d6423SLionel Sambuc 	if (rp->fp_blocked_on == FP_BLOCKED_ON_OTHER && rp->fp_task == proc_e)
363433d6423SLionel Sambuc 		revive(rp->fp_endpoint, EIO);
364433d6423SLionel Sambuc   }
365433d6423SLionel Sambuc 
366433d6423SLionel Sambuc   /* Revive processes waiting in drivers on select()s with EAGAIN too */
367433d6423SLionel Sambuc   select_unsuspend_by_endpt(proc_e);
368433d6423SLionel Sambuc 
369433d6423SLionel Sambuc   return;
370433d6423SLionel Sambuc }
371433d6423SLionel Sambuc 
372433d6423SLionel Sambuc 
373433d6423SLionel Sambuc /*===========================================================================*
374433d6423SLionel Sambuc  *				release					     *
375433d6423SLionel Sambuc  *===========================================================================*/
376433d6423SLionel Sambuc void release(vp, op, count)
377433d6423SLionel Sambuc register struct vnode *vp;	/* inode of pipe */
378433d6423SLionel Sambuc int op;				/* VFS_READ, VFS_WRITE, or VFS_OPEN */
379433d6423SLionel Sambuc int count;			/* max number of processes to release */
380433d6423SLionel Sambuc {
381433d6423SLionel Sambuc /* Check to see if any process is hanging on vnode 'vp'. If one is, and it
382433d6423SLionel Sambuc  * was trying to perform the call indicated by 'op', release it.
383433d6423SLionel Sambuc  */
384433d6423SLionel Sambuc 
385433d6423SLionel Sambuc   register struct fproc *rp;
386433d6423SLionel Sambuc   struct filp *f;
387433d6423SLionel Sambuc   int selop;
388433d6423SLionel Sambuc 
389433d6423SLionel Sambuc   /* Trying to perform the call also includes SELECTing on it with that
390433d6423SLionel Sambuc    * operation.
391433d6423SLionel Sambuc    */
392433d6423SLionel Sambuc   if (op == VFS_READ || op == VFS_WRITE) {
393433d6423SLionel Sambuc 	if (op == VFS_READ)
394433d6423SLionel Sambuc 		selop = SEL_RD;
395433d6423SLionel Sambuc 	else
396433d6423SLionel Sambuc 		selop = SEL_WR;
397433d6423SLionel Sambuc 
398433d6423SLionel Sambuc 	for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
399433d6423SLionel Sambuc 		if (f->filp_count < 1 || !(f->filp_pipe_select_ops & selop) ||
400433d6423SLionel Sambuc 		    f->filp_vno != vp)
401433d6423SLionel Sambuc 			continue;
402433d6423SLionel Sambuc 
403433d6423SLionel Sambuc 		select_callback(f, selop);
404433d6423SLionel Sambuc 
405433d6423SLionel Sambuc 		f->filp_pipe_select_ops &= ~selop;
406433d6423SLionel Sambuc 	}
407433d6423SLionel Sambuc   }
408433d6423SLionel Sambuc 
409433d6423SLionel Sambuc   /* Search the proc table. */
410433d6423SLionel Sambuc   for (rp = &fproc[0]; rp < &fproc[NR_PROCS] && count > 0; rp++) {
411433d6423SLionel Sambuc 	if (rp->fp_pid != PID_FREE && fp_is_blocked(rp) &&
412433d6423SLionel Sambuc 	    !(rp->fp_flags & FP_REVIVED) && rp->fp_block_callnr == op) {
413433d6423SLionel Sambuc 		/* Find the vnode. Depending on the reason the process was
414433d6423SLionel Sambuc 		 * suspended, there are different ways of finding it.
415433d6423SLionel Sambuc 		 */
416433d6423SLionel Sambuc 
417433d6423SLionel Sambuc 		if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN ||
418*bd851af4SDavid van Moolenbroek 		    rp->fp_blocked_on == FP_BLOCKED_ON_PIPE ||
419433d6423SLionel Sambuc 		    rp->fp_blocked_on == FP_BLOCKED_ON_LOCK ||
420433d6423SLionel Sambuc 		    rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) {
421*bd851af4SDavid van Moolenbroek 			f = rp->fp_filp[rp->fp_fd];
422433d6423SLionel Sambuc 			if (f == NULL || f->filp_mode == FILP_CLOSED)
423433d6423SLionel Sambuc 				continue;
424*bd851af4SDavid van Moolenbroek 			if (f->filp_vno != vp)
425433d6423SLionel Sambuc 				continue;
426433d6423SLionel Sambuc 		} else
427433d6423SLionel Sambuc 			continue;
428433d6423SLionel Sambuc 
429433d6423SLionel Sambuc 		/* We found the vnode. Revive process. */
430433d6423SLionel Sambuc 		revive(rp->fp_endpoint, 0);
431433d6423SLionel Sambuc 		susp_count--;	/* keep track of who is suspended */
432433d6423SLionel Sambuc 		if(susp_count < 0)
433433d6423SLionel Sambuc 			panic("susp_count now negative: %d", susp_count);
434433d6423SLionel Sambuc 		if (--count == 0) return;
435433d6423SLionel Sambuc 	}
436433d6423SLionel Sambuc   }
437433d6423SLionel Sambuc }
438433d6423SLionel Sambuc 
439433d6423SLionel Sambuc 
440433d6423SLionel Sambuc /*===========================================================================*
441433d6423SLionel Sambuc  *				revive					     *
442433d6423SLionel Sambuc  *===========================================================================*/
443433d6423SLionel Sambuc void revive(endpoint_t proc_e, int returned)
444433d6423SLionel Sambuc {
445433d6423SLionel Sambuc /* Revive a previously blocked process. When a process hangs on tty, this
446433d6423SLionel Sambuc  * is the way it is eventually released. For processes blocked on _SELECT and
447433d6423SLionel Sambuc  * _OTHER, this function MUST NOT block its calling thread.
448433d6423SLionel Sambuc  */
449433d6423SLionel Sambuc   struct fproc *rfp;
450433d6423SLionel Sambuc   int blocked_on;
451433d6423SLionel Sambuc   int fd_nr, slot;
452433d6423SLionel Sambuc 
453433d6423SLionel Sambuc   if (proc_e == NONE || isokendpt(proc_e, &slot) != OK) return;
454433d6423SLionel Sambuc 
455433d6423SLionel Sambuc   rfp = &fproc[slot];
456433d6423SLionel Sambuc   if (!fp_is_blocked(rfp) || (rfp->fp_flags & FP_REVIVED)) return;
457433d6423SLionel Sambuc 
458433d6423SLionel Sambuc   /* The 'reviving' flag only applies to pipes.  Processes waiting for TTY get
459433d6423SLionel Sambuc    * a message right away.  The revival process is different for TTY and pipes.
460433d6423SLionel Sambuc    * For select and TTY revival, the work is already done, for pipes it is not:
461433d6423SLionel Sambuc    * the proc must be restarted so it can try again.
462433d6423SLionel Sambuc    */
463433d6423SLionel Sambuc   blocked_on = rfp->fp_blocked_on;
464*bd851af4SDavid van Moolenbroek   fd_nr = rfp->fp_fd;
465433d6423SLionel Sambuc   if (blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_LOCK) {
466433d6423SLionel Sambuc 	/* Revive a process suspended on a pipe or lock. */
467433d6423SLionel Sambuc 	rfp->fp_flags |= FP_REVIVED;
468433d6423SLionel Sambuc 	reviving++;		/* process was waiting on pipe or lock */
469433d6423SLionel Sambuc   } else {
470433d6423SLionel Sambuc 	rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
471*bd851af4SDavid van Moolenbroek 	/* TODO: we could reset rfp->fp_fd to (e.g.) -1 here, but since its
472*bd851af4SDavid van Moolenbroek 	 * value is not always bounds checked elsewhere, this might do more
473*bd851af4SDavid van Moolenbroek 	 * harm than good right now.
474*bd851af4SDavid van Moolenbroek 	 */
475433d6423SLionel Sambuc 	if (blocked_on == FP_BLOCKED_ON_POPEN) {
476433d6423SLionel Sambuc 		/* process blocked in open or create */
477433d6423SLionel Sambuc 		replycode(proc_e, fd_nr);
478433d6423SLionel Sambuc 	} else if (blocked_on == FP_BLOCKED_ON_SELECT) {
479433d6423SLionel Sambuc 		replycode(proc_e, returned);
480433d6423SLionel Sambuc 	} else {
481433d6423SLionel Sambuc 		/* Revive a process suspended on TTY or other device.
482433d6423SLionel Sambuc 		 * Pretend it wants only what there is.
483433d6423SLionel Sambuc 		 */
484*bd851af4SDavid van Moolenbroek 		rfp->fp_io_nbytes = returned;
485433d6423SLionel Sambuc 		/* If a grant has been issued by FS for this I/O, revoke
486433d6423SLionel Sambuc 		 * it again now that I/O is done.
487433d6423SLionel Sambuc 		 */
488433d6423SLionel Sambuc 		if (GRANT_VALID(rfp->fp_grant)) {
489433d6423SLionel Sambuc 			if(cpf_revoke(rfp->fp_grant)) {
490433d6423SLionel Sambuc 				panic("VFS: revoke failed for grant: %d",
491433d6423SLionel Sambuc 					rfp->fp_grant);
492433d6423SLionel Sambuc 			}
493433d6423SLionel Sambuc 			rfp->fp_grant = GRANT_INVALID;
494433d6423SLionel Sambuc 		}
495433d6423SLionel Sambuc 		replycode(proc_e, returned);/* unblock the process */
496433d6423SLionel Sambuc 	}
497433d6423SLionel Sambuc   }
498433d6423SLionel Sambuc }
499433d6423SLionel Sambuc 
500433d6423SLionel Sambuc 
501433d6423SLionel Sambuc /*===========================================================================*
502433d6423SLionel Sambuc  *				unpause					     *
503433d6423SLionel Sambuc  *===========================================================================*/
504433d6423SLionel Sambuc void unpause(void)
505433d6423SLionel Sambuc {
506433d6423SLionel Sambuc /* A signal has been sent to a user who is paused on the file system.
507433d6423SLionel Sambuc  * Abort the system call with the EINTR error message.
508433d6423SLionel Sambuc  */
509433d6423SLionel Sambuc   int blocked_on, fild, status = EINTR;
510433d6423SLionel Sambuc   struct filp *f;
511433d6423SLionel Sambuc   dev_t dev;
512433d6423SLionel Sambuc   int wasreviving = 0;
513433d6423SLionel Sambuc 
514433d6423SLionel Sambuc   if (!fp_is_blocked(fp)) return;
515433d6423SLionel Sambuc   blocked_on = fp->fp_blocked_on;
516433d6423SLionel Sambuc 
517433d6423SLionel Sambuc   /* Clear the block status now. The procedure below might make blocking calls
518433d6423SLionel Sambuc    * and it is imperative that while at least cdev_cancel() is executing, other
519433d6423SLionel Sambuc    * parts of VFS do not perceive this process as blocked on something.
520433d6423SLionel Sambuc    */
521433d6423SLionel Sambuc   fp->fp_blocked_on = FP_BLOCKED_ON_NONE;
522433d6423SLionel Sambuc 
523433d6423SLionel Sambuc   if (fp->fp_flags & FP_REVIVED) {
524433d6423SLionel Sambuc 	fp->fp_flags &= ~FP_REVIVED;
525433d6423SLionel Sambuc 	reviving--;
526433d6423SLionel Sambuc 	wasreviving = 1;
527433d6423SLionel Sambuc   }
528433d6423SLionel Sambuc 
529433d6423SLionel Sambuc   switch (blocked_on) {
530433d6423SLionel Sambuc 	case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */
531433d6423SLionel Sambuc 		/* If the operation succeeded partially, return the bytes
532433d6423SLionel Sambuc 		 * processed so far, and clear the remembered state. Otherwise,
533433d6423SLionel Sambuc 		 * return EINTR as usual.
534433d6423SLionel Sambuc 		 */
535433d6423SLionel Sambuc 		if (fp->fp_cum_io_partial > 0) {
536433d6423SLionel Sambuc 			status = fp->fp_cum_io_partial;
537433d6423SLionel Sambuc 
538433d6423SLionel Sambuc 			fp->fp_cum_io_partial = 0;
539433d6423SLionel Sambuc 		}
540433d6423SLionel Sambuc 		break;
541433d6423SLionel Sambuc 
542433d6423SLionel Sambuc 	case FP_BLOCKED_ON_LOCK:/* process trying to set a lock with FCNTL */
543433d6423SLionel Sambuc 		break;
544433d6423SLionel Sambuc 
545433d6423SLionel Sambuc 	case FP_BLOCKED_ON_SELECT:/* process blocking on select() */
546433d6423SLionel Sambuc 		select_forget();
547433d6423SLionel Sambuc 		break;
548433d6423SLionel Sambuc 
549433d6423SLionel Sambuc 	case FP_BLOCKED_ON_POPEN:	/* process trying to open a fifo */
550433d6423SLionel Sambuc 		break;
551433d6423SLionel Sambuc 
552433d6423SLionel Sambuc 	case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/
553*bd851af4SDavid van Moolenbroek 		fild = fp->fp_fd;
554433d6423SLionel Sambuc 		if (fild < 0 || fild >= OPEN_MAX)
555433d6423SLionel Sambuc 			panic("file descriptor out-of-range");
556433d6423SLionel Sambuc 		f = fp->fp_filp[fild];
557433d6423SLionel Sambuc 		if(!f) {
558433d6423SLionel Sambuc 			sys_diagctl_stacktrace(fp->fp_endpoint);
559433d6423SLionel Sambuc 			panic("process %d blocked on empty fd %d",
560433d6423SLionel Sambuc 				fp->fp_endpoint, fild);
561433d6423SLionel Sambuc 		}
562433d6423SLionel Sambuc 		dev = f->filp_vno->v_sdev;	/* device hung on */
563433d6423SLionel Sambuc 
564433d6423SLionel Sambuc 		status = cdev_cancel(dev);
565433d6423SLionel Sambuc 
566433d6423SLionel Sambuc 		break;
567433d6423SLionel Sambuc 	default :
568433d6423SLionel Sambuc 		panic("VFS: unknown block reason: %d", blocked_on);
569433d6423SLionel Sambuc   }
570433d6423SLionel Sambuc 
571433d6423SLionel Sambuc   if ((blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_POPEN)&&
572433d6423SLionel Sambuc 	!wasreviving) {
573433d6423SLionel Sambuc 	susp_count--;
574433d6423SLionel Sambuc   }
575433d6423SLionel Sambuc 
576433d6423SLionel Sambuc   replycode(fp->fp_endpoint, status);	/* signal interrupted call */
577433d6423SLionel Sambuc }
578