1433d6423SLionel Sambuc /* This file deals with the suspension and revival of processes. A process can 2433d6423SLionel Sambuc * be suspended because it wants to read or write from a pipe and can't, or 3433d6423SLionel Sambuc * because it wants to read or write from a special file and can't. When a 4433d6423SLionel Sambuc * process can't continue it is suspended, and revived later when it is able 5433d6423SLionel Sambuc * to continue. 6433d6423SLionel Sambuc * 7433d6423SLionel Sambuc * The entry points into this file are 8433d6423SLionel Sambuc * do_pipe2: perform the PIPE2 system call 9433d6423SLionel Sambuc * pipe_check: check to see that a read or write on a pipe is feasible now 10433d6423SLionel Sambuc * suspend: suspend a process that cannot do a requested read or write 11433d6423SLionel Sambuc * release: check to see if a suspended process can be released and do 12433d6423SLionel Sambuc * it 13433d6423SLionel Sambuc * revive: mark a suspended process as able to run again 14433d6423SLionel Sambuc * unsuspend_by_endpt: revive all processes blocking on a given process 15433d6423SLionel Sambuc * do_unpause: a signal has been sent to a process; see if it suspended 16433d6423SLionel Sambuc */ 17433d6423SLionel Sambuc 18433d6423SLionel Sambuc #include "fs.h" 19433d6423SLionel Sambuc #include <fcntl.h> 20433d6423SLionel Sambuc #include <signal.h> 21433d6423SLionel Sambuc #include <string.h> 22433d6423SLionel Sambuc #include <assert.h> 23433d6423SLionel Sambuc #include <minix/callnr.h> 24433d6423SLionel Sambuc #include <minix/endpoint.h> 25433d6423SLionel Sambuc #include <minix/com.h> 26433d6423SLionel Sambuc #include <minix/u64.h> 27433d6423SLionel Sambuc #include <sys/select.h> 28433d6423SLionel Sambuc #include <sys/time.h> 29433d6423SLionel Sambuc #include "file.h" 30433d6423SLionel Sambuc #include <minix/vfsif.h> 31433d6423SLionel Sambuc #include "vnode.h" 32433d6423SLionel Sambuc #include "vmnt.h" 33433d6423SLionel Sambuc 34433d6423SLionel Sambuc static int create_pipe(int fil_des[2], int flags); 35433d6423SLionel Sambuc 36433d6423SLionel Sambuc /*===========================================================================* 37433d6423SLionel Sambuc * do_pipe2 * 38433d6423SLionel Sambuc *===========================================================================*/ 39433d6423SLionel Sambuc int do_pipe2(void) 40433d6423SLionel Sambuc { 41433d6423SLionel Sambuc /* Perform the pipe2(fil_des[2], flags) system call. */ 42433d6423SLionel Sambuc int r, flags; 43433d6423SLionel Sambuc int fil_des[2]; /* reply goes here */ 44433d6423SLionel Sambuc 45433d6423SLionel Sambuc flags = job_m_in.m_lc_vfs_pipe2.flags; 46433d6423SLionel Sambuc 47433d6423SLionel Sambuc r = create_pipe(fil_des, flags); 48433d6423SLionel Sambuc if (r == OK) { 49433d6423SLionel Sambuc job_m_out.m_lc_vfs_pipe2.fd0 = fil_des[0]; 50433d6423SLionel Sambuc job_m_out.m_lc_vfs_pipe2.fd1 = fil_des[1]; 51433d6423SLionel Sambuc } 52433d6423SLionel Sambuc 53433d6423SLionel Sambuc return r; 54433d6423SLionel Sambuc } 55433d6423SLionel Sambuc 56433d6423SLionel Sambuc /*===========================================================================* 57433d6423SLionel Sambuc * create_pipe * 58433d6423SLionel Sambuc *===========================================================================*/ 59433d6423SLionel Sambuc static int create_pipe(int fil_des[2], int flags) 60433d6423SLionel Sambuc { 61433d6423SLionel Sambuc register struct fproc *rfp; 62433d6423SLionel Sambuc int r; 63433d6423SLionel Sambuc struct filp *fil_ptr0, *fil_ptr1; 64433d6423SLionel Sambuc struct vnode *vp; 65433d6423SLionel Sambuc struct vmnt *vmp; 66433d6423SLionel Sambuc struct node_details res; 67433d6423SLionel Sambuc 68433d6423SLionel Sambuc /* Get a lock on PFS */ 69433d6423SLionel Sambuc if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone"); 70433d6423SLionel Sambuc if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) return(r); 71433d6423SLionel Sambuc 72433d6423SLionel Sambuc /* See if a free vnode is available */ 73433d6423SLionel Sambuc if ((vp = get_free_vnode()) == NULL) { 74433d6423SLionel Sambuc unlock_vmnt(vmp); 75433d6423SLionel Sambuc return(err_code); 76433d6423SLionel Sambuc } 77433d6423SLionel Sambuc lock_vnode(vp, VNODE_OPCL); 78433d6423SLionel Sambuc 79433d6423SLionel Sambuc /* Acquire two file descriptors. */ 80433d6423SLionel Sambuc rfp = fp; 81433d6423SLionel Sambuc if ((r = get_fd(fp, 0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) { 82433d6423SLionel Sambuc unlock_vnode(vp); 83433d6423SLionel Sambuc unlock_vmnt(vmp); 84433d6423SLionel Sambuc return(r); 85433d6423SLionel Sambuc } 86433d6423SLionel Sambuc rfp->fp_filp[fil_des[0]] = fil_ptr0; 87433d6423SLionel Sambuc fil_ptr0->filp_count = 1; /* mark filp in use */ 88433d6423SLionel Sambuc if ((r = get_fd(fp, 0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) { 89433d6423SLionel Sambuc rfp->fp_filp[fil_des[0]] = NULL; 90433d6423SLionel Sambuc fil_ptr0->filp_count = 0; /* mark filp free */ 91433d6423SLionel Sambuc unlock_filp(fil_ptr0); 92433d6423SLionel Sambuc unlock_vnode(vp); 93433d6423SLionel Sambuc unlock_vmnt(vmp); 94433d6423SLionel Sambuc return(r); 95433d6423SLionel Sambuc } 96433d6423SLionel Sambuc rfp->fp_filp[fil_des[1]] = fil_ptr1; 97433d6423SLionel Sambuc fil_ptr1->filp_count = 1; 98433d6423SLionel Sambuc 99433d6423SLionel Sambuc /* Create a named pipe inode on PipeFS */ 100433d6423SLionel Sambuc r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, 101433d6423SLionel Sambuc NO_DEV, &res); 102433d6423SLionel Sambuc 103433d6423SLionel Sambuc if (r != OK) { 104433d6423SLionel Sambuc rfp->fp_filp[fil_des[0]] = NULL; 105433d6423SLionel Sambuc fil_ptr0->filp_count = 0; 106433d6423SLionel Sambuc rfp->fp_filp[fil_des[1]] = NULL; 107433d6423SLionel Sambuc fil_ptr1->filp_count = 0; 108433d6423SLionel Sambuc unlock_filp(fil_ptr1); 109433d6423SLionel Sambuc unlock_filp(fil_ptr0); 110433d6423SLionel Sambuc unlock_vnode(vp); 111433d6423SLionel Sambuc unlock_vmnt(vmp); 112433d6423SLionel Sambuc return(r); 113433d6423SLionel Sambuc } 114433d6423SLionel Sambuc 115433d6423SLionel Sambuc /* Fill in vnode */ 116433d6423SLionel Sambuc vp->v_fs_e = res.fs_e; 117433d6423SLionel Sambuc vp->v_mapfs_e = res.fs_e; 118433d6423SLionel Sambuc vp->v_inode_nr = res.inode_nr; 119433d6423SLionel Sambuc vp->v_mapinode_nr = res.inode_nr; 120433d6423SLionel Sambuc vp->v_mode = res.fmode; 121433d6423SLionel Sambuc vp->v_fs_count = 1; 122433d6423SLionel Sambuc vp->v_mapfs_count = 1; 123433d6423SLionel Sambuc vp->v_ref_count = 1; 124433d6423SLionel Sambuc vp->v_size = 0; 125433d6423SLionel Sambuc vp->v_vmnt = NULL; 126433d6423SLionel Sambuc vp->v_dev = NO_DEV; 127433d6423SLionel Sambuc 128433d6423SLionel Sambuc /* Fill in filp objects */ 129433d6423SLionel Sambuc fil_ptr0->filp_vno = vp; 130433d6423SLionel Sambuc dup_vnode(vp); 131433d6423SLionel Sambuc fil_ptr1->filp_vno = vp; 132433d6423SLionel Sambuc fil_ptr0->filp_flags = O_RDONLY | (flags & ~O_ACCMODE); 133433d6423SLionel Sambuc fil_ptr1->filp_flags = O_WRONLY | (flags & ~O_ACCMODE); 134433d6423SLionel Sambuc if (flags & O_CLOEXEC) { 135433d6423SLionel Sambuc FD_SET(fil_des[0], &rfp->fp_cloexec_set); 136433d6423SLionel Sambuc FD_SET(fil_des[1], &rfp->fp_cloexec_set); 137433d6423SLionel Sambuc } 138433d6423SLionel Sambuc 139433d6423SLionel Sambuc unlock_filps(fil_ptr0, fil_ptr1); 140433d6423SLionel Sambuc unlock_vmnt(vmp); 141433d6423SLionel Sambuc 142433d6423SLionel Sambuc return(OK); 143433d6423SLionel Sambuc } 144433d6423SLionel Sambuc 145433d6423SLionel Sambuc 146433d6423SLionel Sambuc /*===========================================================================* 147433d6423SLionel Sambuc * map_vnode * 148433d6423SLionel Sambuc *===========================================================================*/ 149433d6423SLionel Sambuc int map_vnode(vp, map_to_fs_e) 150433d6423SLionel Sambuc struct vnode *vp; 151433d6423SLionel Sambuc endpoint_t map_to_fs_e; 152433d6423SLionel Sambuc { 153433d6423SLionel Sambuc int r; 154433d6423SLionel Sambuc struct vmnt *vmp; 155433d6423SLionel Sambuc struct node_details res; 156433d6423SLionel Sambuc 157433d6423SLionel Sambuc if(vp->v_mapfs_e != NONE) return(OK); /* Already mapped; nothing to do. */ 158433d6423SLionel Sambuc 159433d6423SLionel Sambuc if ((vmp = find_vmnt(map_to_fs_e)) == NULL) 160433d6423SLionel Sambuc panic("Can't map to unknown endpoint"); 161433d6423SLionel Sambuc if ((r = lock_vmnt(vmp, VMNT_WRITE)) != OK) { 162433d6423SLionel Sambuc if (r == EBUSY) 163433d6423SLionel Sambuc vmp = NULL; /* Already locked, do not unlock */ 164433d6423SLionel Sambuc else 165433d6423SLionel Sambuc return(r); 166433d6423SLionel Sambuc 167433d6423SLionel Sambuc } 168433d6423SLionel Sambuc 169433d6423SLionel Sambuc /* Create a temporary mapping of this inode to another FS. Read and write 170433d6423SLionel Sambuc * operations on data will be handled by that FS. The rest by the 'original' 171433d6423SLionel Sambuc * FS that holds the inode. */ 172433d6423SLionel Sambuc if ((r = req_newnode(map_to_fs_e, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, 173433d6423SLionel Sambuc vp->v_dev, &res)) == OK) { 174433d6423SLionel Sambuc vp->v_mapfs_e = res.fs_e; 175433d6423SLionel Sambuc vp->v_mapinode_nr = res.inode_nr; 176433d6423SLionel Sambuc vp->v_mapfs_count = 1; 177433d6423SLionel Sambuc } 178433d6423SLionel Sambuc 179433d6423SLionel Sambuc if (vmp) unlock_vmnt(vmp); 180433d6423SLionel Sambuc 181433d6423SLionel Sambuc return(r); 182433d6423SLionel Sambuc } 183433d6423SLionel Sambuc 184433d6423SLionel Sambuc /*===========================================================================* 185433d6423SLionel Sambuc * pipe_check * 186433d6423SLionel Sambuc *===========================================================================*/ 187433d6423SLionel Sambuc int pipe_check( 188433d6423SLionel Sambuc struct filp *filp, /* the filp of the pipe */ 189433d6423SLionel Sambuc int rw_flag, /* READING or WRITING */ 190433d6423SLionel Sambuc int oflags, /* flags set by open or fcntl */ 191433d6423SLionel Sambuc int bytes, /* bytes to be read or written (all chunks) */ 192433d6423SLionel Sambuc int notouch /* check only */ 193433d6423SLionel Sambuc ) 194433d6423SLionel Sambuc { 195433d6423SLionel Sambuc /* Pipes are a little different. If a process reads from an empty pipe for 196433d6423SLionel Sambuc * which a writer still exists, suspend the reader. If the pipe is empty 197433d6423SLionel Sambuc * and there is no writer, return 0 bytes. If a process is writing to a 198433d6423SLionel Sambuc * pipe and no one is reading from it, give a broken pipe error. 199433d6423SLionel Sambuc */ 200433d6423SLionel Sambuc struct vnode *vp; 201433d6423SLionel Sambuc off_t pos; 202433d6423SLionel Sambuc int r = OK; 203433d6423SLionel Sambuc 204433d6423SLionel Sambuc vp = filp->filp_vno; 205433d6423SLionel Sambuc 206433d6423SLionel Sambuc /* Reads start at the beginning; writes append to pipes */ 207433d6423SLionel Sambuc if (notouch) /* In this case we don't actually care whether data transfer 208433d6423SLionel Sambuc * would succeed. See POSIX 1003.1-2008 */ 209433d6423SLionel Sambuc pos = 0; 210433d6423SLionel Sambuc else if (rw_flag == READING) 211433d6423SLionel Sambuc pos = 0; 212433d6423SLionel Sambuc else { 213433d6423SLionel Sambuc pos = vp->v_size; 214433d6423SLionel Sambuc } 215433d6423SLionel Sambuc 216433d6423SLionel Sambuc /* If reading, check for empty pipe. */ 217433d6423SLionel Sambuc if (rw_flag == READING) { 218433d6423SLionel Sambuc if (vp->v_size == 0) { 219433d6423SLionel Sambuc /* Process is reading from an empty pipe. */ 220433d6423SLionel Sambuc if (find_filp(vp, W_BIT) != NULL) { 221433d6423SLionel Sambuc /* Writer exists */ 222433d6423SLionel Sambuc if (oflags & O_NONBLOCK) 223433d6423SLionel Sambuc r = EAGAIN; 224433d6423SLionel Sambuc else 225433d6423SLionel Sambuc r = SUSPEND; 226433d6423SLionel Sambuc 227433d6423SLionel Sambuc /* If need be, activate sleeping writers. */ 228433d6423SLionel Sambuc /* We ignore notouch voluntary here. */ 229433d6423SLionel Sambuc if (susp_count > 0) 230433d6423SLionel Sambuc release(vp, VFS_WRITE, susp_count); 231433d6423SLionel Sambuc } 232433d6423SLionel Sambuc return(r); 233433d6423SLionel Sambuc } 234433d6423SLionel Sambuc return(bytes); 235433d6423SLionel Sambuc } 236433d6423SLionel Sambuc 237433d6423SLionel Sambuc /* Process is writing to a pipe. */ 238433d6423SLionel Sambuc if (find_filp(vp, R_BIT) == NULL) { 239433d6423SLionel Sambuc return(EPIPE); 240433d6423SLionel Sambuc } 241433d6423SLionel Sambuc 242433d6423SLionel Sambuc /* Calculate how many bytes can be written. */ 243433d6423SLionel Sambuc if (pos + bytes > PIPE_BUF) { 244433d6423SLionel Sambuc if (oflags & O_NONBLOCK) { 245433d6423SLionel Sambuc if (bytes <= PIPE_BUF) { 246433d6423SLionel Sambuc /* Write has to be atomic */ 247433d6423SLionel Sambuc return(EAGAIN); 248433d6423SLionel Sambuc } 249433d6423SLionel Sambuc 250433d6423SLionel Sambuc /* Compute available space */ 251433d6423SLionel Sambuc bytes = PIPE_BUF - pos; 252433d6423SLionel Sambuc 253433d6423SLionel Sambuc if (bytes > 0) { 254433d6423SLionel Sambuc /* Do a partial write. Need to wakeup reader */ 255433d6423SLionel Sambuc if (!notouch) 256433d6423SLionel Sambuc release(vp, VFS_READ, susp_count); 257433d6423SLionel Sambuc return(bytes); 258433d6423SLionel Sambuc } else { 259433d6423SLionel Sambuc /* Pipe is full */ 260433d6423SLionel Sambuc return(EAGAIN); 261433d6423SLionel Sambuc } 262433d6423SLionel Sambuc } 263433d6423SLionel Sambuc 264433d6423SLionel Sambuc if (bytes > PIPE_BUF) { 265433d6423SLionel Sambuc /* Compute available space */ 266433d6423SLionel Sambuc bytes = PIPE_BUF - pos; 267433d6423SLionel Sambuc 268433d6423SLionel Sambuc if (bytes > 0) { 269433d6423SLionel Sambuc /* Do a partial write. Need to wakeup reader 270433d6423SLionel Sambuc * since we'll suspend ourself in read_write() 271433d6423SLionel Sambuc */ 272433d6423SLionel Sambuc if (!notouch) 273433d6423SLionel Sambuc release(vp, VFS_READ, susp_count); 274433d6423SLionel Sambuc return(bytes); 275433d6423SLionel Sambuc } 276433d6423SLionel Sambuc } 277433d6423SLionel Sambuc 278433d6423SLionel Sambuc /* Pipe is full */ 279433d6423SLionel Sambuc return(SUSPEND); 280433d6423SLionel Sambuc } 281433d6423SLionel Sambuc 282433d6423SLionel Sambuc /* Writing to an empty pipe. Search for suspended reader. */ 283433d6423SLionel Sambuc if (pos == 0 && !notouch) 284433d6423SLionel Sambuc release(vp, VFS_READ, susp_count); 285433d6423SLionel Sambuc 286433d6423SLionel Sambuc /* Requested amount fits */ 287433d6423SLionel Sambuc return(bytes); 288433d6423SLionel Sambuc } 289433d6423SLionel Sambuc 290433d6423SLionel Sambuc 291433d6423SLionel Sambuc /*===========================================================================* 292433d6423SLionel Sambuc * suspend * 293433d6423SLionel Sambuc *===========================================================================*/ 294433d6423SLionel Sambuc void suspend(int why) 295433d6423SLionel Sambuc { 296433d6423SLionel Sambuc /* Take measures to suspend the processing of the present system call. 297433d6423SLionel Sambuc * Store the parameters to be used upon resuming in the process table. 298433d6423SLionel Sambuc * (Actually they are not used when a process is waiting for an I/O device, 299433d6423SLionel Sambuc * but they are needed for pipes, and it is not worth making the distinction.) 300433d6423SLionel Sambuc * The SUSPEND pseudo error should be returned after calling suspend(). 301433d6423SLionel Sambuc */ 302433d6423SLionel Sambuc 303433d6423SLionel Sambuc if (why == FP_BLOCKED_ON_POPEN || why == FP_BLOCKED_ON_PIPE) 304433d6423SLionel Sambuc /* #procs susp'ed on pipe*/ 305433d6423SLionel Sambuc susp_count++; 306433d6423SLionel Sambuc 307433d6423SLionel Sambuc fp->fp_blocked_on = why; 308433d6423SLionel Sambuc assert(fp->fp_grant == GRANT_INVALID || !GRANT_VALID(fp->fp_grant)); 309433d6423SLionel Sambuc fp->fp_block_callnr = job_call_nr; 310433d6423SLionel Sambuc } 311433d6423SLionel Sambuc 312433d6423SLionel Sambuc /*===========================================================================* 313433d6423SLionel Sambuc * wait_for * 314433d6423SLionel Sambuc *===========================================================================*/ 315433d6423SLionel Sambuc void wait_for(endpoint_t who) 316433d6423SLionel Sambuc { 317433d6423SLionel Sambuc if(who == NONE || who == ANY) 318433d6423SLionel Sambuc panic("suspend on NONE or ANY"); 319433d6423SLionel Sambuc suspend(FP_BLOCKED_ON_OTHER); 320433d6423SLionel Sambuc fp->fp_task = who; 321433d6423SLionel Sambuc } 322433d6423SLionel Sambuc 323433d6423SLionel Sambuc 324433d6423SLionel Sambuc /*===========================================================================* 325433d6423SLionel Sambuc * pipe_suspend * 326433d6423SLionel Sambuc *===========================================================================*/ 327433d6423SLionel Sambuc void pipe_suspend(filp, buf, size) 328433d6423SLionel Sambuc struct filp *filp; 329433d6423SLionel Sambuc vir_bytes buf; 330433d6423SLionel Sambuc size_t size; 331433d6423SLionel Sambuc { 332433d6423SLionel Sambuc /* Take measures to suspend the processing of the present system call. 333433d6423SLionel Sambuc * Store the parameters to be used upon resuming in the process table. 334433d6423SLionel Sambuc */ 335433d6423SLionel Sambuc 336*bd851af4SDavid van Moolenbroek /* We can only get here through an I/O call, which comes with a file 337*bd851af4SDavid van Moolenbroek * descriptor, and that file descriptor must therefore correspond to the 338*bd851af4SDavid van Moolenbroek * target file pointer of the I/O request. The process is blocked on the I/O 339*bd851af4SDavid van Moolenbroek * call, and thus, the file descriptor will remain valid. Therefore, we can, 340*bd851af4SDavid van Moolenbroek * and will, use the file descriptor to get the file pointer again later. 341*bd851af4SDavid van Moolenbroek */ 342*bd851af4SDavid van Moolenbroek assert(fp->fp_filp[fp->fp_fd] == filp); 343*bd851af4SDavid van Moolenbroek 344*bd851af4SDavid van Moolenbroek fp->fp_io_buffer = buf; 345*bd851af4SDavid van Moolenbroek fp->fp_io_nbytes = size; 346433d6423SLionel Sambuc suspend(FP_BLOCKED_ON_PIPE); 347433d6423SLionel Sambuc } 348433d6423SLionel Sambuc 349433d6423SLionel Sambuc 350433d6423SLionel Sambuc /*===========================================================================* 351433d6423SLionel Sambuc * unsuspend_by_endpt * 352433d6423SLionel Sambuc *===========================================================================*/ 353433d6423SLionel Sambuc void unsuspend_by_endpt(endpoint_t proc_e) 354433d6423SLionel Sambuc { 355433d6423SLionel Sambuc /* Revive processes waiting for drivers (SUSPENDed) that have disappeared with 356433d6423SLionel Sambuc * return code EAGAIN. 357433d6423SLionel Sambuc */ 358433d6423SLionel Sambuc struct fproc *rp; 359433d6423SLionel Sambuc 360433d6423SLionel Sambuc for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) { 361433d6423SLionel Sambuc if (rp->fp_pid == PID_FREE) continue; 362433d6423SLionel Sambuc if (rp->fp_blocked_on == FP_BLOCKED_ON_OTHER && rp->fp_task == proc_e) 363433d6423SLionel Sambuc revive(rp->fp_endpoint, EIO); 364433d6423SLionel Sambuc } 365433d6423SLionel Sambuc 366433d6423SLionel Sambuc /* Revive processes waiting in drivers on select()s with EAGAIN too */ 367433d6423SLionel Sambuc select_unsuspend_by_endpt(proc_e); 368433d6423SLionel Sambuc 369433d6423SLionel Sambuc return; 370433d6423SLionel Sambuc } 371433d6423SLionel Sambuc 372433d6423SLionel Sambuc 373433d6423SLionel Sambuc /*===========================================================================* 374433d6423SLionel Sambuc * release * 375433d6423SLionel Sambuc *===========================================================================*/ 376433d6423SLionel Sambuc void release(vp, op, count) 377433d6423SLionel Sambuc register struct vnode *vp; /* inode of pipe */ 378433d6423SLionel Sambuc int op; /* VFS_READ, VFS_WRITE, or VFS_OPEN */ 379433d6423SLionel Sambuc int count; /* max number of processes to release */ 380433d6423SLionel Sambuc { 381433d6423SLionel Sambuc /* Check to see if any process is hanging on vnode 'vp'. If one is, and it 382433d6423SLionel Sambuc * was trying to perform the call indicated by 'op', release it. 383433d6423SLionel Sambuc */ 384433d6423SLionel Sambuc 385433d6423SLionel Sambuc register struct fproc *rp; 386433d6423SLionel Sambuc struct filp *f; 387433d6423SLionel Sambuc int selop; 388433d6423SLionel Sambuc 389433d6423SLionel Sambuc /* Trying to perform the call also includes SELECTing on it with that 390433d6423SLionel Sambuc * operation. 391433d6423SLionel Sambuc */ 392433d6423SLionel Sambuc if (op == VFS_READ || op == VFS_WRITE) { 393433d6423SLionel Sambuc if (op == VFS_READ) 394433d6423SLionel Sambuc selop = SEL_RD; 395433d6423SLionel Sambuc else 396433d6423SLionel Sambuc selop = SEL_WR; 397433d6423SLionel Sambuc 398433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 399433d6423SLionel Sambuc if (f->filp_count < 1 || !(f->filp_pipe_select_ops & selop) || 400433d6423SLionel Sambuc f->filp_vno != vp) 401433d6423SLionel Sambuc continue; 402433d6423SLionel Sambuc 403433d6423SLionel Sambuc select_callback(f, selop); 404433d6423SLionel Sambuc 405433d6423SLionel Sambuc f->filp_pipe_select_ops &= ~selop; 406433d6423SLionel Sambuc } 407433d6423SLionel Sambuc } 408433d6423SLionel Sambuc 409433d6423SLionel Sambuc /* Search the proc table. */ 410433d6423SLionel Sambuc for (rp = &fproc[0]; rp < &fproc[NR_PROCS] && count > 0; rp++) { 411433d6423SLionel Sambuc if (rp->fp_pid != PID_FREE && fp_is_blocked(rp) && 412433d6423SLionel Sambuc !(rp->fp_flags & FP_REVIVED) && rp->fp_block_callnr == op) { 413433d6423SLionel Sambuc /* Find the vnode. Depending on the reason the process was 414433d6423SLionel Sambuc * suspended, there are different ways of finding it. 415433d6423SLionel Sambuc */ 416433d6423SLionel Sambuc 417433d6423SLionel Sambuc if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN || 418*bd851af4SDavid van Moolenbroek rp->fp_blocked_on == FP_BLOCKED_ON_PIPE || 419433d6423SLionel Sambuc rp->fp_blocked_on == FP_BLOCKED_ON_LOCK || 420433d6423SLionel Sambuc rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) { 421*bd851af4SDavid van Moolenbroek f = rp->fp_filp[rp->fp_fd]; 422433d6423SLionel Sambuc if (f == NULL || f->filp_mode == FILP_CLOSED) 423433d6423SLionel Sambuc continue; 424*bd851af4SDavid van Moolenbroek if (f->filp_vno != vp) 425433d6423SLionel Sambuc continue; 426433d6423SLionel Sambuc } else 427433d6423SLionel Sambuc continue; 428433d6423SLionel Sambuc 429433d6423SLionel Sambuc /* We found the vnode. Revive process. */ 430433d6423SLionel Sambuc revive(rp->fp_endpoint, 0); 431433d6423SLionel Sambuc susp_count--; /* keep track of who is suspended */ 432433d6423SLionel Sambuc if(susp_count < 0) 433433d6423SLionel Sambuc panic("susp_count now negative: %d", susp_count); 434433d6423SLionel Sambuc if (--count == 0) return; 435433d6423SLionel Sambuc } 436433d6423SLionel Sambuc } 437433d6423SLionel Sambuc } 438433d6423SLionel Sambuc 439433d6423SLionel Sambuc 440433d6423SLionel Sambuc /*===========================================================================* 441433d6423SLionel Sambuc * revive * 442433d6423SLionel Sambuc *===========================================================================*/ 443433d6423SLionel Sambuc void revive(endpoint_t proc_e, int returned) 444433d6423SLionel Sambuc { 445433d6423SLionel Sambuc /* Revive a previously blocked process. When a process hangs on tty, this 446433d6423SLionel Sambuc * is the way it is eventually released. For processes blocked on _SELECT and 447433d6423SLionel Sambuc * _OTHER, this function MUST NOT block its calling thread. 448433d6423SLionel Sambuc */ 449433d6423SLionel Sambuc struct fproc *rfp; 450433d6423SLionel Sambuc int blocked_on; 451433d6423SLionel Sambuc int fd_nr, slot; 452433d6423SLionel Sambuc 453433d6423SLionel Sambuc if (proc_e == NONE || isokendpt(proc_e, &slot) != OK) return; 454433d6423SLionel Sambuc 455433d6423SLionel Sambuc rfp = &fproc[slot]; 456433d6423SLionel Sambuc if (!fp_is_blocked(rfp) || (rfp->fp_flags & FP_REVIVED)) return; 457433d6423SLionel Sambuc 458433d6423SLionel Sambuc /* The 'reviving' flag only applies to pipes. Processes waiting for TTY get 459433d6423SLionel Sambuc * a message right away. The revival process is different for TTY and pipes. 460433d6423SLionel Sambuc * For select and TTY revival, the work is already done, for pipes it is not: 461433d6423SLionel Sambuc * the proc must be restarted so it can try again. 462433d6423SLionel Sambuc */ 463433d6423SLionel Sambuc blocked_on = rfp->fp_blocked_on; 464*bd851af4SDavid van Moolenbroek fd_nr = rfp->fp_fd; 465433d6423SLionel Sambuc if (blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_LOCK) { 466433d6423SLionel Sambuc /* Revive a process suspended on a pipe or lock. */ 467433d6423SLionel Sambuc rfp->fp_flags |= FP_REVIVED; 468433d6423SLionel Sambuc reviving++; /* process was waiting on pipe or lock */ 469433d6423SLionel Sambuc } else { 470433d6423SLionel Sambuc rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; 471*bd851af4SDavid van Moolenbroek /* TODO: we could reset rfp->fp_fd to (e.g.) -1 here, but since its 472*bd851af4SDavid van Moolenbroek * value is not always bounds checked elsewhere, this might do more 473*bd851af4SDavid van Moolenbroek * harm than good right now. 474*bd851af4SDavid van Moolenbroek */ 475433d6423SLionel Sambuc if (blocked_on == FP_BLOCKED_ON_POPEN) { 476433d6423SLionel Sambuc /* process blocked in open or create */ 477433d6423SLionel Sambuc replycode(proc_e, fd_nr); 478433d6423SLionel Sambuc } else if (blocked_on == FP_BLOCKED_ON_SELECT) { 479433d6423SLionel Sambuc replycode(proc_e, returned); 480433d6423SLionel Sambuc } else { 481433d6423SLionel Sambuc /* Revive a process suspended on TTY or other device. 482433d6423SLionel Sambuc * Pretend it wants only what there is. 483433d6423SLionel Sambuc */ 484*bd851af4SDavid van Moolenbroek rfp->fp_io_nbytes = returned; 485433d6423SLionel Sambuc /* If a grant has been issued by FS for this I/O, revoke 486433d6423SLionel Sambuc * it again now that I/O is done. 487433d6423SLionel Sambuc */ 488433d6423SLionel Sambuc if (GRANT_VALID(rfp->fp_grant)) { 489433d6423SLionel Sambuc if(cpf_revoke(rfp->fp_grant)) { 490433d6423SLionel Sambuc panic("VFS: revoke failed for grant: %d", 491433d6423SLionel Sambuc rfp->fp_grant); 492433d6423SLionel Sambuc } 493433d6423SLionel Sambuc rfp->fp_grant = GRANT_INVALID; 494433d6423SLionel Sambuc } 495433d6423SLionel Sambuc replycode(proc_e, returned);/* unblock the process */ 496433d6423SLionel Sambuc } 497433d6423SLionel Sambuc } 498433d6423SLionel Sambuc } 499433d6423SLionel Sambuc 500433d6423SLionel Sambuc 501433d6423SLionel Sambuc /*===========================================================================* 502433d6423SLionel Sambuc * unpause * 503433d6423SLionel Sambuc *===========================================================================*/ 504433d6423SLionel Sambuc void unpause(void) 505433d6423SLionel Sambuc { 506433d6423SLionel Sambuc /* A signal has been sent to a user who is paused on the file system. 507433d6423SLionel Sambuc * Abort the system call with the EINTR error message. 508433d6423SLionel Sambuc */ 509433d6423SLionel Sambuc int blocked_on, fild, status = EINTR; 510433d6423SLionel Sambuc struct filp *f; 511433d6423SLionel Sambuc dev_t dev; 512433d6423SLionel Sambuc int wasreviving = 0; 513433d6423SLionel Sambuc 514433d6423SLionel Sambuc if (!fp_is_blocked(fp)) return; 515433d6423SLionel Sambuc blocked_on = fp->fp_blocked_on; 516433d6423SLionel Sambuc 517433d6423SLionel Sambuc /* Clear the block status now. The procedure below might make blocking calls 518433d6423SLionel Sambuc * and it is imperative that while at least cdev_cancel() is executing, other 519433d6423SLionel Sambuc * parts of VFS do not perceive this process as blocked on something. 520433d6423SLionel Sambuc */ 521433d6423SLionel Sambuc fp->fp_blocked_on = FP_BLOCKED_ON_NONE; 522433d6423SLionel Sambuc 523433d6423SLionel Sambuc if (fp->fp_flags & FP_REVIVED) { 524433d6423SLionel Sambuc fp->fp_flags &= ~FP_REVIVED; 525433d6423SLionel Sambuc reviving--; 526433d6423SLionel Sambuc wasreviving = 1; 527433d6423SLionel Sambuc } 528433d6423SLionel Sambuc 529433d6423SLionel Sambuc switch (blocked_on) { 530433d6423SLionel Sambuc case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */ 531433d6423SLionel Sambuc /* If the operation succeeded partially, return the bytes 532433d6423SLionel Sambuc * processed so far, and clear the remembered state. Otherwise, 533433d6423SLionel Sambuc * return EINTR as usual. 534433d6423SLionel Sambuc */ 535433d6423SLionel Sambuc if (fp->fp_cum_io_partial > 0) { 536433d6423SLionel Sambuc status = fp->fp_cum_io_partial; 537433d6423SLionel Sambuc 538433d6423SLionel Sambuc fp->fp_cum_io_partial = 0; 539433d6423SLionel Sambuc } 540433d6423SLionel Sambuc break; 541433d6423SLionel Sambuc 542433d6423SLionel Sambuc case FP_BLOCKED_ON_LOCK:/* process trying to set a lock with FCNTL */ 543433d6423SLionel Sambuc break; 544433d6423SLionel Sambuc 545433d6423SLionel Sambuc case FP_BLOCKED_ON_SELECT:/* process blocking on select() */ 546433d6423SLionel Sambuc select_forget(); 547433d6423SLionel Sambuc break; 548433d6423SLionel Sambuc 549433d6423SLionel Sambuc case FP_BLOCKED_ON_POPEN: /* process trying to open a fifo */ 550433d6423SLionel Sambuc break; 551433d6423SLionel Sambuc 552433d6423SLionel Sambuc case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/ 553*bd851af4SDavid van Moolenbroek fild = fp->fp_fd; 554433d6423SLionel Sambuc if (fild < 0 || fild >= OPEN_MAX) 555433d6423SLionel Sambuc panic("file descriptor out-of-range"); 556433d6423SLionel Sambuc f = fp->fp_filp[fild]; 557433d6423SLionel Sambuc if(!f) { 558433d6423SLionel Sambuc sys_diagctl_stacktrace(fp->fp_endpoint); 559433d6423SLionel Sambuc panic("process %d blocked on empty fd %d", 560433d6423SLionel Sambuc fp->fp_endpoint, fild); 561433d6423SLionel Sambuc } 562433d6423SLionel Sambuc dev = f->filp_vno->v_sdev; /* device hung on */ 563433d6423SLionel Sambuc 564433d6423SLionel Sambuc status = cdev_cancel(dev); 565433d6423SLionel Sambuc 566433d6423SLionel Sambuc break; 567433d6423SLionel Sambuc default : 568433d6423SLionel Sambuc panic("VFS: unknown block reason: %d", blocked_on); 569433d6423SLionel Sambuc } 570433d6423SLionel Sambuc 571433d6423SLionel Sambuc if ((blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_POPEN)&& 572433d6423SLionel Sambuc !wasreviving) { 573433d6423SLionel Sambuc susp_count--; 574433d6423SLionel Sambuc } 575433d6423SLionel Sambuc 576433d6423SLionel Sambuc replycode(fp->fp_endpoint, status); /* signal interrupted call */ 577433d6423SLionel Sambuc } 578