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