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