xref: /minix/minix/servers/vfs/pipe.c (revision 0a6a1f1d)
1 /* This file deals with the suspension and revival of processes.  A process can
2  * be suspended because it wants to read or write from a pipe and can't, or
3  * because it wants to read or write from a special file and can't.  When a
4  * process can't continue it is suspended, and revived later when it is able
5  * to continue.
6  *
7  * The entry points into this file are
8  *   do_pipe2:	  perform the PIPE2 system call
9  *   pipe_check:  check to see that a read or write on a pipe is feasible now
10  *   suspend:	  suspend a process that cannot do a requested read or write
11  *   release:	  check to see if a suspended process can be released and do
12  *                it
13  *   revive:	  mark a suspended process as able to run again
14  *   unsuspend_by_endpt: revive all processes blocking on a given process
15  *   do_unpause:  a signal has been sent to a process; see if it suspended
16  */
17 
18 #include "fs.h"
19 #include <fcntl.h>
20 #include <signal.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <minix/callnr.h>
24 #include <minix/endpoint.h>
25 #include <minix/com.h>
26 #include <minix/u64.h>
27 #include <sys/select.h>
28 #include <sys/time.h>
29 #include "file.h"
30 #include <minix/vfsif.h>
31 #include "vnode.h"
32 #include "vmnt.h"
33 
34 static int create_pipe(int fil_des[2], int flags);
35 
36 /*===========================================================================*
37  *				do_pipe2				     *
38  *===========================================================================*/
39 int do_pipe2(void)
40 {
41 /* Perform the pipe2(fil_des[2], flags) system call. */
42   int r, flags;
43   int fil_des[2];		/* reply goes here */
44 
45   flags = job_m_in.m_lc_vfs_pipe2.flags;
46 
47   r = create_pipe(fil_des, flags);
48   if (r == OK) {
49 	job_m_out.m_lc_vfs_pipe2.fd0 = fil_des[0];
50 	job_m_out.m_lc_vfs_pipe2.fd1 = fil_des[1];
51   }
52 
53   return r;
54 }
55 
56 /*===========================================================================*
57  *				create_pipe				     *
58  *===========================================================================*/
59 static int create_pipe(int fil_des[2], int flags)
60 {
61   register struct fproc *rfp;
62   int r;
63   struct filp *fil_ptr0, *fil_ptr1;
64   struct vnode *vp;
65   struct vmnt *vmp;
66   struct node_details res;
67 
68   /* Get a lock on PFS */
69   if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone");
70   if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) return(r);
71 
72   /* See if a free vnode is available */
73   if ((vp = get_free_vnode()) == NULL) {
74 	unlock_vmnt(vmp);
75 	return(err_code);
76   }
77   lock_vnode(vp, VNODE_OPCL);
78 
79   /* Acquire two file descriptors. */
80   rfp = fp;
81   if ((r = get_fd(fp, 0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) {
82 	unlock_vnode(vp);
83 	unlock_vmnt(vmp);
84 	return(r);
85   }
86   rfp->fp_filp[fil_des[0]] = fil_ptr0;
87   fil_ptr0->filp_count = 1;		/* mark filp in use */
88   if ((r = get_fd(fp, 0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
89 	rfp->fp_filp[fil_des[0]] = NULL;
90 	fil_ptr0->filp_count = 0;	/* mark filp free */
91 	unlock_filp(fil_ptr0);
92 	unlock_vnode(vp);
93 	unlock_vmnt(vmp);
94 	return(r);
95   }
96   rfp->fp_filp[fil_des[1]] = fil_ptr1;
97   fil_ptr1->filp_count = 1;
98 
99   /* Create a named pipe inode on PipeFS */
100   r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE,
101 		  NO_DEV, &res);
102 
103   if (r != OK) {
104 	rfp->fp_filp[fil_des[0]] = NULL;
105 	fil_ptr0->filp_count = 0;
106 	rfp->fp_filp[fil_des[1]] = NULL;
107 	fil_ptr1->filp_count = 0;
108 	unlock_filp(fil_ptr1);
109 	unlock_filp(fil_ptr0);
110 	unlock_vnode(vp);
111 	unlock_vmnt(vmp);
112 	return(r);
113   }
114 
115   /* Fill in vnode */
116   vp->v_fs_e = res.fs_e;
117   vp->v_mapfs_e = res.fs_e;
118   vp->v_inode_nr = res.inode_nr;
119   vp->v_mapinode_nr = res.inode_nr;
120   vp->v_mode = res.fmode;
121   vp->v_fs_count = 1;
122   vp->v_mapfs_count = 1;
123   vp->v_ref_count = 1;
124   vp->v_size = 0;
125   vp->v_vmnt = NULL;
126   vp->v_dev = NO_DEV;
127 
128   /* Fill in filp objects */
129   fil_ptr0->filp_vno = vp;
130   dup_vnode(vp);
131   fil_ptr1->filp_vno = vp;
132   fil_ptr0->filp_flags = O_RDONLY | (flags & ~O_ACCMODE);
133   fil_ptr1->filp_flags = O_WRONLY | (flags & ~O_ACCMODE);
134   if (flags & O_CLOEXEC) {
135 	FD_SET(fil_des[0], &rfp->fp_cloexec_set);
136 	FD_SET(fil_des[1], &rfp->fp_cloexec_set);
137   }
138 
139   unlock_filps(fil_ptr0, fil_ptr1);
140   unlock_vmnt(vmp);
141 
142   return(OK);
143 }
144 
145 
146 /*===========================================================================*
147  *				map_vnode				     *
148  *===========================================================================*/
149 int map_vnode(vp, map_to_fs_e)
150 struct vnode *vp;
151 endpoint_t map_to_fs_e;
152 {
153   int r;
154   struct vmnt *vmp;
155   struct node_details res;
156 
157   if(vp->v_mapfs_e != NONE) return(OK);	/* Already mapped; nothing to do. */
158 
159   if ((vmp = find_vmnt(map_to_fs_e)) == NULL)
160 	panic("Can't map to unknown endpoint");
161   if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) {
162 	if (r == EBUSY)
163 		vmp = NULL;	/* Already locked, do not unlock */
164 	else
165 		return(r);
166 
167   }
168 
169   /* Create a temporary mapping of this inode to another FS. Read and write
170    * operations on data will be handled by that FS. The rest by the 'original'
171    * FS that holds the inode. */
172   if ((r = req_newnode(map_to_fs_e, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE,
173 		       vp->v_dev, &res)) == OK) {
174 	vp->v_mapfs_e = res.fs_e;
175 	vp->v_mapinode_nr = res.inode_nr;
176 	vp->v_mapfs_count = 1;
177   }
178 
179   if (vmp) unlock_vmnt(vmp);
180 
181   return(r);
182 }
183 
184 /*===========================================================================*
185  *				pipe_check				     *
186  *===========================================================================*/
187 int pipe_check(
188 struct filp *filp,	/* the filp of the pipe */
189 int rw_flag,		/* READING or WRITING */
190 int oflags,		/* flags set by open or fcntl */
191 int bytes,		/* bytes to be read or written (all chunks) */
192 int notouch		/* check only */
193 )
194 {
195 /* Pipes are a little different.  If a process reads from an empty pipe for
196  * which a writer still exists, suspend the reader.  If the pipe is empty
197  * and there is no writer, return 0 bytes.  If a process is writing to a
198  * pipe and no one is reading from it, give a broken pipe error.
199  */
200   struct vnode *vp;
201   off_t pos;
202   int r = OK;
203 
204   vp = filp->filp_vno;
205 
206   /* Reads start at the beginning; writes append to pipes */
207   if (notouch) /* In this case we don't actually care whether data transfer
208 		* would succeed. See POSIX 1003.1-2008 */
209 	pos = 0;
210   else if (rw_flag == READING)
211 	pos = 0;
212   else {
213 	pos = vp->v_size;
214   }
215 
216   /* If reading, check for empty pipe. */
217   if (rw_flag == READING) {
218 	if (vp->v_size == 0) {
219 		/* Process is reading from an empty pipe. */
220 		if (find_filp(vp, W_BIT) != NULL) {
221 			/* Writer exists */
222 			if (oflags & O_NONBLOCK)
223 				r = EAGAIN;
224 			else
225 				r = SUSPEND;
226 
227 			/* If need be, activate sleeping writers. */
228 			/* We ignore notouch voluntary here. */
229 			if (susp_count > 0)
230 				release(vp, VFS_WRITE, susp_count);
231 		}
232 		return(r);
233 	}
234 	return(bytes);
235   }
236 
237   /* Process is writing to a pipe. */
238   if (find_filp(vp, R_BIT) == NULL) {
239 	return(EPIPE);
240   }
241 
242   /* Calculate how many bytes can be written. */
243   if (pos + bytes > PIPE_BUF) {
244 	if (oflags & O_NONBLOCK) {
245 		if (bytes <= PIPE_BUF) {
246 			/* Write has to be atomic */
247 			return(EAGAIN);
248 		}
249 
250 		/* Compute available space */
251 		bytes = PIPE_BUF - pos;
252 
253 		if (bytes > 0)  {
254 			/* Do a partial write. Need to wakeup reader */
255 			if (!notouch)
256 				release(vp, VFS_READ, susp_count);
257 			return(bytes);
258 		} else {
259 			/* Pipe is full */
260 			return(EAGAIN);
261 		}
262 	}
263 
264 	if (bytes > PIPE_BUF) {
265 		/* Compute available space */
266 		bytes = PIPE_BUF - pos;
267 
268 		if (bytes > 0) {
269 			/* Do a partial write. Need to wakeup reader
270 			 * since we'll suspend ourself in read_write()
271 			 */
272 			if (!notouch)
273 				release(vp, VFS_READ, susp_count);
274 			return(bytes);
275 		}
276 	}
277 
278 	/* Pipe is full */
279 	return(SUSPEND);
280   }
281 
282   /* Writing to an empty pipe.  Search for suspended reader. */
283   if (pos == 0 && !notouch)
284 	release(vp, VFS_READ, susp_count);
285 
286   /* Requested amount fits */
287   return(bytes);
288 }
289 
290 
291 /*===========================================================================*
292  *				suspend					     *
293  *===========================================================================*/
294 void suspend(int why)
295 {
296 /* Take measures to suspend the processing of the present system call.
297  * Store the parameters to be used upon resuming in the process table.
298  * (Actually they are not used when a process is waiting for an I/O device,
299  * but they are needed for pipes, and it is not worth making the distinction.)
300  * The SUSPEND pseudo error should be returned after calling suspend().
301  */
302 
303   if (why == FP_BLOCKED_ON_POPEN || why == FP_BLOCKED_ON_PIPE)
304 	/* #procs susp'ed on pipe*/
305 	susp_count++;
306 
307   fp->fp_blocked_on = why;
308   assert(fp->fp_grant == GRANT_INVALID || !GRANT_VALID(fp->fp_grant));
309   fp->fp_block_callnr = job_call_nr;
310 }
311 
312 /*===========================================================================*
313  *				wait_for				     *
314  *===========================================================================*/
315 void wait_for(endpoint_t who)
316 {
317   if(who == NONE || who == ANY)
318 	panic("suspend on NONE or ANY");
319   suspend(FP_BLOCKED_ON_OTHER);
320   fp->fp_task = who;
321 }
322 
323 
324 /*===========================================================================*
325  *				pipe_suspend				     *
326  *===========================================================================*/
327 void pipe_suspend(struct filp * filp __unused, vir_bytes buf, size_t size)
328 {
329 /* Take measures to suspend the processing of the present system call.
330  * Store the parameters to be used upon resuming in the process table.
331  */
332 
333   /* We can only get here through an I/O call, which comes with a file
334    * descriptor, and that file descriptor must therefore correspond to the
335    * target file pointer of the I/O request. The process is blocked on the I/O
336    * call, and thus, the file descriptor will remain valid. Therefore, we can,
337    * and will, use the file descriptor to get the file pointer again later.
338    */
339   assert(fp->fp_filp[fp->fp_fd] == filp);
340 
341   fp->fp_io_buffer = buf;
342   fp->fp_io_nbytes = size;
343   suspend(FP_BLOCKED_ON_PIPE);
344 }
345 
346 
347 /*===========================================================================*
348  *				unsuspend_by_endpt			     *
349  *===========================================================================*/
350 void unsuspend_by_endpt(endpoint_t proc_e)
351 {
352 /* Revive processes waiting for drivers (SUSPENDed) that have disappeared with
353  * return code EAGAIN.
354  */
355   struct fproc *rp;
356 
357   for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) {
358 	if (rp->fp_pid == PID_FREE) continue;
359 	if (rp->fp_blocked_on == FP_BLOCKED_ON_OTHER && rp->fp_task == proc_e)
360 		revive(rp->fp_endpoint, EIO);
361   }
362 
363   /* Revive processes waiting in drivers on select()s with EAGAIN too */
364   select_unsuspend_by_endpt(proc_e);
365 
366   return;
367 }
368 
369 
370 /*===========================================================================*
371  *				release					     *
372  *===========================================================================*/
373 void release(vp, op, count)
374 register struct vnode *vp;	/* inode of pipe */
375 int op;				/* VFS_READ, VFS_WRITE, or VFS_OPEN */
376 int count;			/* max number of processes to release */
377 {
378 /* Check to see if any process is hanging on vnode 'vp'. If one is, and it
379  * was trying to perform the call indicated by 'op', release it.
380  */
381 
382   register struct fproc *rp;
383   struct filp *f;
384   int selop;
385 
386   /* Trying to perform the call also includes SELECTing on it with that
387    * operation.
388    */
389   if (op == VFS_READ || op == VFS_WRITE) {
390 	if (op == VFS_READ)
391 		selop = SEL_RD;
392 	else
393 		selop = SEL_WR;
394 
395 	for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
396 		if (f->filp_count < 1 || !(f->filp_pipe_select_ops & selop) ||
397 		    f->filp_vno != vp)
398 			continue;
399 
400 		select_callback(f, selop);
401 
402 		f->filp_pipe_select_ops &= ~selop;
403 	}
404   }
405 
406   /* Search the proc table. */
407   for (rp = &fproc[0]; rp < &fproc[NR_PROCS] && count > 0; rp++) {
408 	if (rp->fp_pid != PID_FREE && fp_is_blocked(rp) &&
409 	    !(rp->fp_flags & FP_REVIVED) && rp->fp_block_callnr == op) {
410 		/* Find the vnode. Depending on the reason the process was
411 		 * suspended, there are different ways of finding it.
412 		 */
413 
414 		if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN ||
415 		    rp->fp_blocked_on == FP_BLOCKED_ON_PIPE ||
416 		    rp->fp_blocked_on == FP_BLOCKED_ON_LOCK ||
417 		    rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) {
418 			f = rp->fp_filp[rp->fp_fd];
419 			if (f == NULL || f->filp_mode == FILP_CLOSED)
420 				continue;
421 			if (f->filp_vno != vp)
422 				continue;
423 		} else
424 			continue;
425 
426 		/* We found the vnode. Revive process. */
427 		revive(rp->fp_endpoint, 0);
428 		susp_count--;	/* keep track of who is suspended */
429 		if(susp_count < 0)
430 			panic("susp_count now negative: %d", susp_count);
431 		if (--count == 0) return;
432 	}
433   }
434 }
435 
436 
437 /*===========================================================================*
438  *				revive					     *
439  *===========================================================================*/
440 void revive(endpoint_t proc_e, int returned)
441 {
442 /* Revive a previously blocked process. When a process hangs on tty, this
443  * is the way it is eventually released. For processes blocked on _SELECT and
444  * _OTHER, this function MUST NOT block its calling thread.
445  */
446   struct fproc *rfp;
447   int blocked_on;
448   int fd_nr, slot;
449 
450   if (proc_e == NONE || isokendpt(proc_e, &slot) != OK) return;
451 
452   rfp = &fproc[slot];
453   if (!fp_is_blocked(rfp) || (rfp->fp_flags & FP_REVIVED)) return;
454 
455   /* The 'reviving' flag only applies to pipes.  Processes waiting for TTY get
456    * a message right away.  The revival process is different for TTY and pipes.
457    * For select and TTY revival, the work is already done, for pipes it is not:
458    * the proc must be restarted so it can try again.
459    */
460   blocked_on = rfp->fp_blocked_on;
461   fd_nr = rfp->fp_fd;
462   if (blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_LOCK) {
463 	/* Revive a process suspended on a pipe or lock. */
464 	rfp->fp_flags |= FP_REVIVED;
465 	reviving++;		/* process was waiting on pipe or lock */
466   } else {
467 	rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
468 	/* TODO: we could reset rfp->fp_fd to (e.g.) -1 here, but since its
469 	 * value is not always bounds checked elsewhere, this might do more
470 	 * harm than good right now.
471 	 */
472 	if (blocked_on == FP_BLOCKED_ON_POPEN) {
473 		/* process blocked in open or create */
474 		replycode(proc_e, fd_nr);
475 	} else if (blocked_on == FP_BLOCKED_ON_SELECT) {
476 		replycode(proc_e, returned);
477 	} else {
478 		/* Revive a process suspended on TTY or other device.
479 		 * Pretend it wants only what there is.
480 		 */
481 		rfp->fp_io_nbytes = returned;
482 		/* If a grant has been issued by FS for this I/O, revoke
483 		 * it again now that I/O is done.
484 		 */
485 		if (GRANT_VALID(rfp->fp_grant)) {
486 			if(cpf_revoke(rfp->fp_grant)) {
487 				panic("VFS: revoke failed for grant: %d",
488 					rfp->fp_grant);
489 			}
490 			rfp->fp_grant = GRANT_INVALID;
491 		}
492 		replycode(proc_e, returned);/* unblock the process */
493 	}
494   }
495 }
496 
497 
498 /*===========================================================================*
499  *				unpause					     *
500  *===========================================================================*/
501 void unpause(void)
502 {
503 /* A signal has been sent to a user who is paused on the file system.
504  * Abort the system call with the EINTR error message.
505  */
506   int blocked_on, fild, status = EINTR;
507   struct filp *f;
508   dev_t dev;
509   int wasreviving = 0;
510 
511   if (!fp_is_blocked(fp)) return;
512   blocked_on = fp->fp_blocked_on;
513 
514   /* Clear the block status now. The procedure below might make blocking calls
515    * and it is imperative that while at least cdev_cancel() is executing, other
516    * parts of VFS do not perceive this process as blocked on something.
517    */
518   fp->fp_blocked_on = FP_BLOCKED_ON_NONE;
519 
520   if (fp->fp_flags & FP_REVIVED) {
521 	fp->fp_flags &= ~FP_REVIVED;
522 	reviving--;
523 	wasreviving = 1;
524   }
525 
526   switch (blocked_on) {
527 	case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */
528 		/* If the operation succeeded partially, return the bytes
529 		 * processed so far, and clear the remembered state. Otherwise,
530 		 * return EINTR as usual.
531 		 */
532 		if (fp->fp_cum_io_partial > 0) {
533 			status = fp->fp_cum_io_partial;
534 
535 			fp->fp_cum_io_partial = 0;
536 		}
537 		break;
538 
539 	case FP_BLOCKED_ON_LOCK:/* process trying to set a lock with FCNTL */
540 		break;
541 
542 	case FP_BLOCKED_ON_SELECT:/* process blocking on select() */
543 		select_forget();
544 		break;
545 
546 	case FP_BLOCKED_ON_POPEN:	/* process trying to open a fifo */
547 		break;
548 
549 	case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/
550 		fild = fp->fp_fd;
551 		if (fild < 0 || fild >= OPEN_MAX)
552 			panic("file descriptor out-of-range");
553 		f = fp->fp_filp[fild];
554 		if(!f) {
555 			sys_diagctl_stacktrace(fp->fp_endpoint);
556 			panic("process %d blocked on empty fd %d",
557 				fp->fp_endpoint, fild);
558 		}
559 		dev = f->filp_vno->v_sdev;	/* device hung on */
560 
561 		status = cdev_cancel(dev);
562 
563 		break;
564 	default :
565 		panic("VFS: unknown block reason: %d", blocked_on);
566   }
567 
568   if ((blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_POPEN)&&
569 	!wasreviving) {
570 	susp_count--;
571   }
572 
573   replycode(fp->fp_endpoint, status);	/* signal interrupted call */
574 }
575