xref: /minix3/minix/servers/vfs/pipe.c (revision c33d6ef39285e101533230264f0905e546e2296c)
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;
46*c33d6ef3SDavid 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) {
50*c33d6ef3SDavid van Moolenbroek 	job_m_out.m_vfs_lc_fdpair.fd0 = fil_des[0];
51*c33d6ef3SDavid 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  *===========================================================================*/
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  *===========================================================================*/
150433d6423SLionel Sambuc int map_vnode(vp, map_to_fs_e)
151433d6423SLionel Sambuc struct vnode *vp;
152433d6423SLionel Sambuc endpoint_t map_to_fs_e;
153433d6423SLionel Sambuc {
154433d6423SLionel Sambuc   int r;
155433d6423SLionel Sambuc   struct vmnt *vmp;
156433d6423SLionel Sambuc   struct node_details res;
157433d6423SLionel Sambuc 
158433d6423SLionel Sambuc   if(vp->v_mapfs_e != NONE) return(OK);	/* Already mapped; nothing to do. */
159433d6423SLionel Sambuc 
160433d6423SLionel Sambuc   if ((vmp = find_vmnt(map_to_fs_e)) == NULL)
161433d6423SLionel Sambuc 	panic("Can't map to unknown endpoint");
162433d6423SLionel Sambuc   if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) {
163433d6423SLionel Sambuc 	if (r == EBUSY)
164433d6423SLionel Sambuc 		vmp = NULL;	/* Already locked, do not unlock */
165433d6423SLionel Sambuc 	else
166433d6423SLionel Sambuc 		return(r);
167433d6423SLionel Sambuc 
168433d6423SLionel Sambuc   }
169433d6423SLionel Sambuc 
170433d6423SLionel Sambuc   /* Create a temporary mapping of this inode to another FS. Read and write
171433d6423SLionel Sambuc    * operations on data will be handled by that FS. The rest by the 'original'
172433d6423SLionel Sambuc    * FS that holds the inode. */
173433d6423SLionel Sambuc   if ((r = req_newnode(map_to_fs_e, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE,
174433d6423SLionel Sambuc 		       vp->v_dev, &res)) == OK) {
175433d6423SLionel Sambuc 	vp->v_mapfs_e = res.fs_e;
176433d6423SLionel Sambuc 	vp->v_mapinode_nr = res.inode_nr;
177433d6423SLionel Sambuc 	vp->v_mapfs_count = 1;
178433d6423SLionel Sambuc   }
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc   if (vmp) unlock_vmnt(vmp);
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc   return(r);
183433d6423SLionel Sambuc }
184433d6423SLionel Sambuc 
185433d6423SLionel Sambuc /*===========================================================================*
186433d6423SLionel Sambuc  *				pipe_check				     *
187433d6423SLionel Sambuc  *===========================================================================*/
188433d6423SLionel Sambuc int pipe_check(
189433d6423SLionel Sambuc struct filp *filp,	/* the filp of the pipe */
190433d6423SLionel Sambuc int rw_flag,		/* READING or WRITING */
191433d6423SLionel Sambuc int oflags,		/* flags set by open or fcntl */
192433d6423SLionel Sambuc int bytes,		/* bytes to be read or written (all chunks) */
193433d6423SLionel Sambuc int notouch		/* check only */
194433d6423SLionel Sambuc )
195433d6423SLionel Sambuc {
196433d6423SLionel Sambuc /* Pipes are a little different.  If a process reads from an empty pipe for
197433d6423SLionel Sambuc  * which a writer still exists, suspend the reader.  If the pipe is empty
198433d6423SLionel Sambuc  * and there is no writer, return 0 bytes.  If a process is writing to a
199433d6423SLionel Sambuc  * pipe and no one is reading from it, give a broken pipe error.
200433d6423SLionel Sambuc  */
201433d6423SLionel Sambuc   struct vnode *vp;
202433d6423SLionel Sambuc   off_t pos;
203433d6423SLionel Sambuc   int r = OK;
204433d6423SLionel Sambuc 
205433d6423SLionel Sambuc   vp = filp->filp_vno;
206433d6423SLionel Sambuc 
207433d6423SLionel Sambuc   /* Reads start at the beginning; writes append to pipes */
208433d6423SLionel Sambuc   if (notouch) /* In this case we don't actually care whether data transfer
209433d6423SLionel Sambuc 		* would succeed. See POSIX 1003.1-2008 */
210433d6423SLionel Sambuc 	pos = 0;
211433d6423SLionel Sambuc   else if (rw_flag == READING)
212433d6423SLionel Sambuc 	pos = 0;
213433d6423SLionel Sambuc   else {
214433d6423SLionel Sambuc 	pos = vp->v_size;
215433d6423SLionel Sambuc   }
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc   /* If reading, check for empty pipe. */
218433d6423SLionel Sambuc   if (rw_flag == READING) {
219433d6423SLionel Sambuc 	if (vp->v_size == 0) {
220433d6423SLionel Sambuc 		/* Process is reading from an empty pipe. */
221433d6423SLionel Sambuc 		if (find_filp(vp, W_BIT) != NULL) {
222433d6423SLionel Sambuc 			/* Writer exists */
223433d6423SLionel Sambuc 			if (oflags & O_NONBLOCK)
224433d6423SLionel Sambuc 				r = EAGAIN;
225433d6423SLionel Sambuc 			else
226433d6423SLionel Sambuc 				r = SUSPEND;
227433d6423SLionel Sambuc 
228433d6423SLionel Sambuc 			/* If need be, activate sleeping writers. */
229433d6423SLionel Sambuc 			/* We ignore notouch voluntary here. */
230433d6423SLionel Sambuc 			if (susp_count > 0)
231433d6423SLionel Sambuc 				release(vp, VFS_WRITE, susp_count);
232433d6423SLionel Sambuc 		}
233433d6423SLionel Sambuc 		return(r);
234433d6423SLionel Sambuc 	}
235433d6423SLionel Sambuc 	return(bytes);
236433d6423SLionel Sambuc   }
237433d6423SLionel Sambuc 
238433d6423SLionel Sambuc   /* Process is writing to a pipe. */
239433d6423SLionel Sambuc   if (find_filp(vp, R_BIT) == NULL) {
240433d6423SLionel Sambuc 	return(EPIPE);
241433d6423SLionel Sambuc   }
242433d6423SLionel Sambuc 
243433d6423SLionel Sambuc   /* Calculate how many bytes can be written. */
244433d6423SLionel Sambuc   if (pos + bytes > PIPE_BUF) {
245433d6423SLionel Sambuc 	if (oflags & O_NONBLOCK) {
246433d6423SLionel Sambuc 		if (bytes <= PIPE_BUF) {
247433d6423SLionel Sambuc 			/* Write has to be atomic */
248433d6423SLionel Sambuc 			return(EAGAIN);
249433d6423SLionel Sambuc 		}
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc 		/* Compute available space */
252433d6423SLionel Sambuc 		bytes = PIPE_BUF - pos;
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc 		if (bytes > 0)  {
255433d6423SLionel Sambuc 			/* Do a partial write. Need to wakeup reader */
256433d6423SLionel Sambuc 			if (!notouch)
257433d6423SLionel Sambuc 				release(vp, VFS_READ, susp_count);
258433d6423SLionel Sambuc 			return(bytes);
259433d6423SLionel Sambuc 		} else {
260433d6423SLionel Sambuc 			/* Pipe is full */
261433d6423SLionel Sambuc 			return(EAGAIN);
262433d6423SLionel Sambuc 		}
263433d6423SLionel Sambuc 	}
264433d6423SLionel Sambuc 
265433d6423SLionel Sambuc 	if (bytes > PIPE_BUF) {
266433d6423SLionel Sambuc 		/* Compute available space */
267433d6423SLionel Sambuc 		bytes = PIPE_BUF - pos;
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc 		if (bytes > 0) {
270433d6423SLionel Sambuc 			/* Do a partial write. Need to wakeup reader
271433d6423SLionel Sambuc 			 * since we'll suspend ourself in read_write()
272433d6423SLionel Sambuc 			 */
273433d6423SLionel Sambuc 			if (!notouch)
274433d6423SLionel Sambuc 				release(vp, VFS_READ, susp_count);
275433d6423SLionel Sambuc 			return(bytes);
276433d6423SLionel Sambuc 		}
277433d6423SLionel Sambuc 	}
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc 	/* Pipe is full */
280433d6423SLionel Sambuc 	return(SUSPEND);
281433d6423SLionel Sambuc   }
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc   /* Writing to an empty pipe.  Search for suspended reader. */
284433d6423SLionel Sambuc   if (pos == 0 && !notouch)
285433d6423SLionel Sambuc 	release(vp, VFS_READ, susp_count);
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc   /* Requested amount fits */
288433d6423SLionel Sambuc   return(bytes);
289433d6423SLionel Sambuc }
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc /*===========================================================================*
293433d6423SLionel Sambuc  *				suspend					     *
294433d6423SLionel Sambuc  *===========================================================================*/
295433d6423SLionel Sambuc void suspend(int why)
296433d6423SLionel Sambuc {
297433d6423SLionel Sambuc /* Take measures to suspend the processing of the present system call.
298433d6423SLionel Sambuc  * Store the parameters to be used upon resuming in the process table.
299433d6423SLionel Sambuc  * (Actually they are not used when a process is waiting for an I/O device,
300433d6423SLionel Sambuc  * but they are needed for pipes, and it is not worth making the distinction.)
301433d6423SLionel Sambuc  * The SUSPEND pseudo error should be returned after calling suspend().
302433d6423SLionel Sambuc  */
303433d6423SLionel Sambuc 
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   assert(fp->fp_grant == GRANT_INVALID || !GRANT_VALID(fp->fp_grant));
310433d6423SLionel Sambuc   fp->fp_block_callnr = job_call_nr;
311433d6423SLionel Sambuc }
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc /*===========================================================================*
314433d6423SLionel Sambuc  *				wait_for				     *
315433d6423SLionel Sambuc  *===========================================================================*/
316433d6423SLionel Sambuc void wait_for(endpoint_t who)
317433d6423SLionel Sambuc {
318433d6423SLionel Sambuc   if(who == NONE || who == ANY)
319433d6423SLionel Sambuc 	panic("suspend on NONE or ANY");
320433d6423SLionel Sambuc   suspend(FP_BLOCKED_ON_OTHER);
321433d6423SLionel Sambuc   fp->fp_task = who;
322433d6423SLionel Sambuc }
323433d6423SLionel Sambuc 
324433d6423SLionel Sambuc 
325433d6423SLionel Sambuc /*===========================================================================*
326433d6423SLionel Sambuc  *				pipe_suspend				     *
327433d6423SLionel Sambuc  *===========================================================================*/
32881b1f871SLionel Sambuc void pipe_suspend(struct filp * filp __unused, vir_bytes buf, size_t size)
329433d6423SLionel Sambuc {
330433d6423SLionel Sambuc /* Take measures to suspend the processing of the present system call.
331433d6423SLionel Sambuc  * Store the parameters to be used upon resuming in the process table.
332433d6423SLionel Sambuc  */
333433d6423SLionel Sambuc 
334bd851af4SDavid van Moolenbroek   /* We can only get here through an I/O call, which comes with a file
335bd851af4SDavid van Moolenbroek    * descriptor, and that file descriptor must therefore correspond to the
336bd851af4SDavid van Moolenbroek    * target file pointer of the I/O request. The process is blocked on the I/O
337bd851af4SDavid van Moolenbroek    * call, and thus, the file descriptor will remain valid. Therefore, we can,
338bd851af4SDavid van Moolenbroek    * and will, use the file descriptor to get the file pointer again later.
339bd851af4SDavid van Moolenbroek    */
340bd851af4SDavid van Moolenbroek   assert(fp->fp_filp[fp->fp_fd] == filp);
341bd851af4SDavid van Moolenbroek 
342bd851af4SDavid van Moolenbroek   fp->fp_io_buffer = buf;
343bd851af4SDavid van Moolenbroek   fp->fp_io_nbytes = size;
344433d6423SLionel Sambuc   suspend(FP_BLOCKED_ON_PIPE);
345433d6423SLionel Sambuc }
346433d6423SLionel Sambuc 
347433d6423SLionel Sambuc 
348433d6423SLionel Sambuc /*===========================================================================*
349433d6423SLionel Sambuc  *				unsuspend_by_endpt			     *
350433d6423SLionel Sambuc  *===========================================================================*/
351433d6423SLionel Sambuc void unsuspend_by_endpt(endpoint_t proc_e)
352433d6423SLionel Sambuc {
353433d6423SLionel Sambuc /* Revive processes waiting for drivers (SUSPENDed) that have disappeared with
354433d6423SLionel Sambuc  * return code EAGAIN.
355433d6423SLionel Sambuc  */
356433d6423SLionel Sambuc   struct fproc *rp;
357433d6423SLionel Sambuc 
358433d6423SLionel Sambuc   for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) {
359433d6423SLionel Sambuc 	if (rp->fp_pid == PID_FREE) continue;
360433d6423SLionel Sambuc 	if (rp->fp_blocked_on == FP_BLOCKED_ON_OTHER && rp->fp_task == proc_e)
361433d6423SLionel Sambuc 		revive(rp->fp_endpoint, EIO);
362433d6423SLionel Sambuc   }
363433d6423SLionel Sambuc 
364433d6423SLionel Sambuc   /* Revive processes waiting in drivers on select()s with EAGAIN too */
365433d6423SLionel Sambuc   select_unsuspend_by_endpt(proc_e);
366433d6423SLionel Sambuc 
367433d6423SLionel Sambuc   return;
368433d6423SLionel Sambuc }
369433d6423SLionel Sambuc 
370433d6423SLionel Sambuc 
371433d6423SLionel Sambuc /*===========================================================================*
372433d6423SLionel Sambuc  *				release					     *
373433d6423SLionel Sambuc  *===========================================================================*/
374433d6423SLionel Sambuc void release(vp, op, count)
375433d6423SLionel Sambuc register struct vnode *vp;	/* inode of pipe */
376433d6423SLionel Sambuc int op;				/* VFS_READ, VFS_WRITE, or VFS_OPEN */
377433d6423SLionel Sambuc int count;			/* max number of processes to release */
378433d6423SLionel Sambuc {
379433d6423SLionel Sambuc /* Check to see if any process is hanging on vnode 'vp'. If one is, and it
380433d6423SLionel Sambuc  * was trying to perform the call indicated by 'op', release it.
381433d6423SLionel Sambuc  */
382433d6423SLionel Sambuc 
383433d6423SLionel Sambuc   register struct fproc *rp;
384433d6423SLionel Sambuc   struct filp *f;
385433d6423SLionel Sambuc   int selop;
386433d6423SLionel Sambuc 
387433d6423SLionel Sambuc   /* Trying to perform the call also includes SELECTing on it with that
388433d6423SLionel Sambuc    * operation.
389433d6423SLionel Sambuc    */
390433d6423SLionel Sambuc   if (op == VFS_READ || op == VFS_WRITE) {
391433d6423SLionel Sambuc 	if (op == VFS_READ)
392433d6423SLionel Sambuc 		selop = SEL_RD;
393433d6423SLionel Sambuc 	else
394433d6423SLionel Sambuc 		selop = SEL_WR;
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc 	for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
397433d6423SLionel Sambuc 		if (f->filp_count < 1 || !(f->filp_pipe_select_ops & selop) ||
398433d6423SLionel Sambuc 		    f->filp_vno != vp)
399433d6423SLionel Sambuc 			continue;
400433d6423SLionel Sambuc 
401433d6423SLionel Sambuc 		select_callback(f, selop);
402433d6423SLionel Sambuc 
403433d6423SLionel Sambuc 		f->filp_pipe_select_ops &= ~selop;
404433d6423SLionel Sambuc 	}
405433d6423SLionel Sambuc   }
406433d6423SLionel Sambuc 
407433d6423SLionel Sambuc   /* Search the proc table. */
408433d6423SLionel Sambuc   for (rp = &fproc[0]; rp < &fproc[NR_PROCS] && count > 0; rp++) {
409433d6423SLionel Sambuc 	if (rp->fp_pid != PID_FREE && fp_is_blocked(rp) &&
410433d6423SLionel Sambuc 	    !(rp->fp_flags & FP_REVIVED) && rp->fp_block_callnr == op) {
411433d6423SLionel Sambuc 		/* Find the vnode. Depending on the reason the process was
412433d6423SLionel Sambuc 		 * suspended, there are different ways of finding it.
413433d6423SLionel Sambuc 		 */
414433d6423SLionel Sambuc 
415433d6423SLionel Sambuc 		if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN ||
416bd851af4SDavid van Moolenbroek 		    rp->fp_blocked_on == FP_BLOCKED_ON_PIPE ||
417433d6423SLionel Sambuc 		    rp->fp_blocked_on == FP_BLOCKED_ON_LOCK ||
418433d6423SLionel Sambuc 		    rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) {
419bd851af4SDavid van Moolenbroek 			f = rp->fp_filp[rp->fp_fd];
420433d6423SLionel Sambuc 			if (f == NULL || f->filp_mode == FILP_CLOSED)
421433d6423SLionel Sambuc 				continue;
422bd851af4SDavid van Moolenbroek 			if (f->filp_vno != vp)
423433d6423SLionel Sambuc 				continue;
424433d6423SLionel Sambuc 		} else
425433d6423SLionel Sambuc 			continue;
426433d6423SLionel Sambuc 
427433d6423SLionel Sambuc 		/* We found the vnode. Revive process. */
428433d6423SLionel Sambuc 		revive(rp->fp_endpoint, 0);
429433d6423SLionel Sambuc 		susp_count--;	/* keep track of who is suspended */
430433d6423SLionel Sambuc 		if(susp_count < 0)
431433d6423SLionel Sambuc 			panic("susp_count now negative: %d", susp_count);
432433d6423SLionel Sambuc 		if (--count == 0) return;
433433d6423SLionel Sambuc 	}
434433d6423SLionel Sambuc   }
435433d6423SLionel Sambuc }
436433d6423SLionel Sambuc 
437433d6423SLionel Sambuc 
438433d6423SLionel Sambuc /*===========================================================================*
439433d6423SLionel Sambuc  *				revive					     *
440433d6423SLionel Sambuc  *===========================================================================*/
441433d6423SLionel Sambuc void revive(endpoint_t proc_e, int returned)
442433d6423SLionel Sambuc {
443433d6423SLionel Sambuc /* Revive a previously blocked process. When a process hangs on tty, this
444433d6423SLionel Sambuc  * is the way it is eventually released. For processes blocked on _SELECT and
445433d6423SLionel Sambuc  * _OTHER, this function MUST NOT block its calling thread.
446433d6423SLionel Sambuc  */
447433d6423SLionel Sambuc   struct fproc *rfp;
448433d6423SLionel Sambuc   int blocked_on;
449433d6423SLionel Sambuc   int fd_nr, slot;
450433d6423SLionel Sambuc 
451433d6423SLionel Sambuc   if (proc_e == NONE || isokendpt(proc_e, &slot) != OK) return;
452433d6423SLionel Sambuc 
453433d6423SLionel Sambuc   rfp = &fproc[slot];
454433d6423SLionel Sambuc   if (!fp_is_blocked(rfp) || (rfp->fp_flags & FP_REVIVED)) return;
455433d6423SLionel Sambuc 
456433d6423SLionel Sambuc   /* The 'reviving' flag only applies to pipes.  Processes waiting for TTY get
457433d6423SLionel Sambuc    * a message right away.  The revival process is different for TTY and pipes.
458433d6423SLionel Sambuc    * For select and TTY revival, the work is already done, for pipes it is not:
459433d6423SLionel Sambuc    * the proc must be restarted so it can try again.
460433d6423SLionel Sambuc    */
461433d6423SLionel Sambuc   blocked_on = rfp->fp_blocked_on;
462bd851af4SDavid van Moolenbroek   fd_nr = rfp->fp_fd;
463433d6423SLionel Sambuc   if (blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_LOCK) {
464433d6423SLionel Sambuc 	/* Revive a process suspended on a pipe or lock. */
465433d6423SLionel Sambuc 	rfp->fp_flags |= FP_REVIVED;
466433d6423SLionel Sambuc 	reviving++;		/* process was waiting on pipe or lock */
467433d6423SLionel Sambuc   } else {
468433d6423SLionel Sambuc 	rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
469bd851af4SDavid van Moolenbroek 	/* TODO: we could reset rfp->fp_fd to (e.g.) -1 here, but since its
470bd851af4SDavid van Moolenbroek 	 * value is not always bounds checked elsewhere, this might do more
471bd851af4SDavid van Moolenbroek 	 * harm than good right now.
472bd851af4SDavid van Moolenbroek 	 */
473433d6423SLionel Sambuc 	if (blocked_on == FP_BLOCKED_ON_POPEN) {
474433d6423SLionel Sambuc 		/* process blocked in open or create */
475433d6423SLionel Sambuc 		replycode(proc_e, fd_nr);
476433d6423SLionel Sambuc 	} else if (blocked_on == FP_BLOCKED_ON_SELECT) {
477433d6423SLionel Sambuc 		replycode(proc_e, returned);
478433d6423SLionel Sambuc 	} else {
479433d6423SLionel Sambuc 		/* Revive a process suspended on TTY or other device.
480433d6423SLionel Sambuc 		 * Pretend it wants only what there is.
481433d6423SLionel Sambuc 		 */
482bd851af4SDavid van Moolenbroek 		rfp->fp_io_nbytes = returned;
483433d6423SLionel Sambuc 		/* If a grant has been issued by FS for this I/O, revoke
484433d6423SLionel Sambuc 		 * it again now that I/O is done.
485433d6423SLionel Sambuc 		 */
486433d6423SLionel Sambuc 		if (GRANT_VALID(rfp->fp_grant)) {
48710b7016bSDavid van Moolenbroek 			if(cpf_revoke(rfp->fp_grant) == -1) {
488433d6423SLionel Sambuc 				panic("VFS: revoke failed for grant: %d",
489433d6423SLionel Sambuc 					rfp->fp_grant);
490433d6423SLionel Sambuc 			}
491433d6423SLionel Sambuc 			rfp->fp_grant = GRANT_INVALID;
492433d6423SLionel Sambuc 		}
493433d6423SLionel Sambuc 		replycode(proc_e, returned);/* unblock the process */
494433d6423SLionel Sambuc 	}
495433d6423SLionel Sambuc   }
496433d6423SLionel Sambuc }
497433d6423SLionel Sambuc 
498433d6423SLionel Sambuc 
499433d6423SLionel Sambuc /*===========================================================================*
500433d6423SLionel Sambuc  *				unpause					     *
501433d6423SLionel Sambuc  *===========================================================================*/
502433d6423SLionel Sambuc void unpause(void)
503433d6423SLionel Sambuc {
504433d6423SLionel Sambuc /* A signal has been sent to a user who is paused on the file system.
505433d6423SLionel Sambuc  * Abort the system call with the EINTR error message.
506433d6423SLionel Sambuc  */
507433d6423SLionel Sambuc   int blocked_on, fild, status = EINTR;
508433d6423SLionel Sambuc   struct filp *f;
509433d6423SLionel Sambuc   dev_t dev;
510433d6423SLionel Sambuc   int wasreviving = 0;
511433d6423SLionel Sambuc 
512433d6423SLionel Sambuc   if (!fp_is_blocked(fp)) return;
513433d6423SLionel Sambuc   blocked_on = fp->fp_blocked_on;
514433d6423SLionel Sambuc 
515433d6423SLionel Sambuc   /* Clear the block status now. The procedure below might make blocking calls
516433d6423SLionel Sambuc    * and it is imperative that while at least cdev_cancel() is executing, other
517433d6423SLionel Sambuc    * parts of VFS do not perceive this process as blocked on something.
518433d6423SLionel Sambuc    */
519433d6423SLionel Sambuc   fp->fp_blocked_on = FP_BLOCKED_ON_NONE;
520433d6423SLionel Sambuc 
521433d6423SLionel Sambuc   if (fp->fp_flags & FP_REVIVED) {
522433d6423SLionel Sambuc 	fp->fp_flags &= ~FP_REVIVED;
523433d6423SLionel Sambuc 	reviving--;
524433d6423SLionel Sambuc 	wasreviving = 1;
525433d6423SLionel Sambuc   }
526433d6423SLionel Sambuc 
527433d6423SLionel Sambuc   switch (blocked_on) {
528433d6423SLionel Sambuc 	case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */
529433d6423SLionel Sambuc 		/* If the operation succeeded partially, return the bytes
530433d6423SLionel Sambuc 		 * processed so far, and clear the remembered state. Otherwise,
531433d6423SLionel Sambuc 		 * return EINTR as usual.
532433d6423SLionel Sambuc 		 */
533433d6423SLionel Sambuc 		if (fp->fp_cum_io_partial > 0) {
534433d6423SLionel Sambuc 			status = fp->fp_cum_io_partial;
535433d6423SLionel Sambuc 
536433d6423SLionel Sambuc 			fp->fp_cum_io_partial = 0;
537433d6423SLionel Sambuc 		}
538433d6423SLionel Sambuc 		break;
539433d6423SLionel Sambuc 
540433d6423SLionel Sambuc 	case FP_BLOCKED_ON_LOCK:/* process trying to set a lock with FCNTL */
541433d6423SLionel Sambuc 		break;
542433d6423SLionel Sambuc 
543433d6423SLionel Sambuc 	case FP_BLOCKED_ON_SELECT:/* process blocking on select() */
544433d6423SLionel Sambuc 		select_forget();
545433d6423SLionel Sambuc 		break;
546433d6423SLionel Sambuc 
547433d6423SLionel Sambuc 	case FP_BLOCKED_ON_POPEN:	/* process trying to open a fifo */
548433d6423SLionel Sambuc 		break;
549433d6423SLionel Sambuc 
550433d6423SLionel Sambuc 	case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/
551bd851af4SDavid van Moolenbroek 		fild = fp->fp_fd;
552433d6423SLionel Sambuc 		if (fild < 0 || fild >= OPEN_MAX)
553433d6423SLionel Sambuc 			panic("file descriptor out-of-range");
554433d6423SLionel Sambuc 		f = fp->fp_filp[fild];
555433d6423SLionel Sambuc 		if(!f) {
556433d6423SLionel Sambuc 			sys_diagctl_stacktrace(fp->fp_endpoint);
557433d6423SLionel Sambuc 			panic("process %d blocked on empty fd %d",
558433d6423SLionel Sambuc 				fp->fp_endpoint, fild);
559433d6423SLionel Sambuc 		}
560433d6423SLionel Sambuc 		dev = f->filp_vno->v_sdev;	/* device hung on */
561433d6423SLionel Sambuc 
562433d6423SLionel Sambuc 		status = cdev_cancel(dev);
563433d6423SLionel Sambuc 
564433d6423SLionel Sambuc 		break;
565433d6423SLionel Sambuc 	default :
566433d6423SLionel Sambuc 		panic("VFS: unknown block reason: %d", blocked_on);
567433d6423SLionel Sambuc   }
568433d6423SLionel Sambuc 
569433d6423SLionel Sambuc   if ((blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_POPEN)&&
570433d6423SLionel Sambuc 	!wasreviving) {
571433d6423SLionel Sambuc 	susp_count--;
572433d6423SLionel Sambuc   }
573433d6423SLionel Sambuc 
574433d6423SLionel Sambuc   replycode(fp->fp_endpoint, status);	/* signal interrupted call */
575433d6423SLionel Sambuc }
576