1433d6423SLionel Sambuc /* This file contains the procedures that manipulate file descriptors. 2433d6423SLionel Sambuc * 3433d6423SLionel Sambuc * The entry points into this file are 4433d6423SLionel Sambuc * get_fd: look for free file descriptor and free filp slots 5433d6423SLionel Sambuc * get_filp: look up the filp entry for a given file descriptor 6433d6423SLionel Sambuc * find_filp: find a filp slot that points to a given vnode 7433d6423SLionel Sambuc * inval_filp: invalidate a filp and associated fd's, only let close() 8433d6423SLionel Sambuc * happen on it 9433d6423SLionel Sambuc * do_copyfd: copies a file descriptor from or to another endpoint 10433d6423SLionel Sambuc */ 11433d6423SLionel Sambuc 12433d6423SLionel Sambuc #include <sys/select.h> 13433d6423SLionel Sambuc #include <minix/callnr.h> 14433d6423SLionel Sambuc #include <minix/u64.h> 15433d6423SLionel Sambuc #include <assert.h> 16433d6423SLionel Sambuc #include <sys/stat.h> 17433d6423SLionel Sambuc #include "fs.h" 18433d6423SLionel Sambuc #include "file.h" 19433d6423SLionel Sambuc #include "vnode.h" 20433d6423SLionel Sambuc 21433d6423SLionel Sambuc 22433d6423SLionel Sambuc #if LOCK_DEBUG 23433d6423SLionel Sambuc /*===========================================================================* 24433d6423SLionel Sambuc * check_filp_locks * 25433d6423SLionel Sambuc *===========================================================================*/ 26433d6423SLionel Sambuc void check_filp_locks_by_me(void) 27433d6423SLionel Sambuc { 28433d6423SLionel Sambuc /* Check whether this thread still has filp locks held */ 29433d6423SLionel Sambuc struct filp *f; 30433d6423SLionel Sambuc int r; 31433d6423SLionel Sambuc 32433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 33433d6423SLionel Sambuc r = mutex_trylock(&f->filp_lock); 34433d6423SLionel Sambuc if (r == -EDEADLK) 35433d6423SLionel Sambuc panic("Thread %d still holds filp lock on filp %p call_nr=%d\n", 36433d6423SLionel Sambuc mthread_self(), f, job_call_nr); 37433d6423SLionel Sambuc else if (r == 0) { 38433d6423SLionel Sambuc /* We just obtained the lock, release it */ 39433d6423SLionel Sambuc mutex_unlock(&f->filp_lock); 40433d6423SLionel Sambuc } 41433d6423SLionel Sambuc } 42433d6423SLionel Sambuc } 43433d6423SLionel Sambuc #endif 44433d6423SLionel Sambuc 45433d6423SLionel Sambuc /*===========================================================================* 46433d6423SLionel Sambuc * check_filp_locks * 47433d6423SLionel Sambuc *===========================================================================*/ 48433d6423SLionel Sambuc void check_filp_locks(void) 49433d6423SLionel Sambuc { 50433d6423SLionel Sambuc struct filp *f; 51433d6423SLionel Sambuc int r, count = 0; 52433d6423SLionel Sambuc 53433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 54433d6423SLionel Sambuc r = mutex_trylock(&f->filp_lock); 55433d6423SLionel Sambuc if (r == -EBUSY) { 56433d6423SLionel Sambuc /* Mutex is still locked */ 57433d6423SLionel Sambuc count++; 58433d6423SLionel Sambuc } else if (r == 0) { 59433d6423SLionel Sambuc /* We just obtained a lock, don't want it */ 60433d6423SLionel Sambuc mutex_unlock(&f->filp_lock); 61433d6423SLionel Sambuc } else 62433d6423SLionel Sambuc panic("filp_lock weird state"); 63433d6423SLionel Sambuc } 64433d6423SLionel Sambuc if (count) panic("locked filps"); 65433d6423SLionel Sambuc #if 0 66433d6423SLionel Sambuc else printf("check_filp_locks OK\n"); 67433d6423SLionel Sambuc #endif 68433d6423SLionel Sambuc } 69433d6423SLionel Sambuc 70433d6423SLionel Sambuc /*===========================================================================* 71433d6423SLionel Sambuc * init_filps * 72433d6423SLionel Sambuc *===========================================================================*/ 73433d6423SLionel Sambuc void init_filps(void) 74433d6423SLionel Sambuc { 75433d6423SLionel Sambuc /* Initialize filps */ 76433d6423SLionel Sambuc struct filp *f; 77433d6423SLionel Sambuc 78433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 79433d6423SLionel Sambuc if (mutex_init(&f->filp_lock, NULL) != 0) 80433d6423SLionel Sambuc panic("Failed to initialize filp mutex"); 81433d6423SLionel Sambuc } 82433d6423SLionel Sambuc 83433d6423SLionel Sambuc } 84433d6423SLionel Sambuc 85433d6423SLionel Sambuc /*===========================================================================* 86433d6423SLionel Sambuc * get_fd * 87433d6423SLionel Sambuc *===========================================================================*/ 88433d6423SLionel Sambuc int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt) 89433d6423SLionel Sambuc { 90433d6423SLionel Sambuc /* Look for a free file descriptor and a free filp slot. Fill in the mode word 91433d6423SLionel Sambuc * in the latter, but don't claim either one yet, since the open() or creat() 92433d6423SLionel Sambuc * may yet fail. 93433d6423SLionel Sambuc */ 94433d6423SLionel Sambuc 95433d6423SLionel Sambuc register struct filp *f; 96433d6423SLionel Sambuc register int i; 97433d6423SLionel Sambuc 98433d6423SLionel Sambuc /* Search the fproc fp_filp table for a free file descriptor. */ 99433d6423SLionel Sambuc for (i = start; i < OPEN_MAX; i++) { 100433d6423SLionel Sambuc if (rfp->fp_filp[i] == NULL) { 101433d6423SLionel Sambuc /* A file descriptor has been located. */ 102433d6423SLionel Sambuc *k = i; 103433d6423SLionel Sambuc break; 104433d6423SLionel Sambuc } 105433d6423SLionel Sambuc } 106433d6423SLionel Sambuc 107433d6423SLionel Sambuc /* Check to see if a file descriptor has been found. */ 108433d6423SLionel Sambuc if (i >= OPEN_MAX) return(EMFILE); 109433d6423SLionel Sambuc 110433d6423SLionel Sambuc /* If we don't care about a filp, return now */ 111433d6423SLionel Sambuc if (fpt == NULL) return(OK); 112433d6423SLionel Sambuc 113433d6423SLionel Sambuc /* Now that a file descriptor has been found, look for a free filp slot. */ 114433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 115433d6423SLionel Sambuc assert(f->filp_count >= 0); 116433d6423SLionel Sambuc if (f->filp_count == 0 && mutex_trylock(&f->filp_lock) == 0) { 117433d6423SLionel Sambuc f->filp_mode = bits; 118433d6423SLionel Sambuc f->filp_pos = 0; 119433d6423SLionel Sambuc f->filp_selectors = 0; 120433d6423SLionel Sambuc f->filp_select_ops = 0; 121433d6423SLionel Sambuc f->filp_pipe_select_ops = 0; 12227d0ecdbSDavid van Moolenbroek f->filp_char_select_dev = NO_DEV; 123433d6423SLionel Sambuc f->filp_flags = 0; 124433d6423SLionel Sambuc f->filp_select_flags = 0; 125433d6423SLionel Sambuc f->filp_softlock = NULL; 126433d6423SLionel Sambuc f->filp_ioctl_fp = NULL; 127433d6423SLionel Sambuc *fpt = f; 128433d6423SLionel Sambuc return(OK); 129433d6423SLionel Sambuc } 130433d6423SLionel Sambuc } 131433d6423SLionel Sambuc 132433d6423SLionel Sambuc /* If control passes here, the filp table must be full. Report that back. */ 133433d6423SLionel Sambuc return(ENFILE); 134433d6423SLionel Sambuc } 135433d6423SLionel Sambuc 136433d6423SLionel Sambuc 137433d6423SLionel Sambuc /*===========================================================================* 138433d6423SLionel Sambuc * get_filp * 139433d6423SLionel Sambuc *===========================================================================*/ 140433d6423SLionel Sambuc struct filp *get_filp(fild, locktype) 141433d6423SLionel Sambuc int fild; /* file descriptor */ 142433d6423SLionel Sambuc tll_access_t locktype; 143433d6423SLionel Sambuc { 144433d6423SLionel Sambuc /* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */ 145433d6423SLionel Sambuc 146433d6423SLionel Sambuc return get_filp2(fp, fild, locktype); 147433d6423SLionel Sambuc } 148433d6423SLionel Sambuc 149433d6423SLionel Sambuc 150433d6423SLionel Sambuc /*===========================================================================* 151433d6423SLionel Sambuc * get_filp2 * 152433d6423SLionel Sambuc *===========================================================================*/ 153433d6423SLionel Sambuc struct filp *get_filp2(rfp, fild, locktype) 154433d6423SLionel Sambuc register struct fproc *rfp; 155433d6423SLionel Sambuc int fild; /* file descriptor */ 156433d6423SLionel Sambuc tll_access_t locktype; 157433d6423SLionel Sambuc { 158433d6423SLionel Sambuc /* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */ 159433d6423SLionel Sambuc struct filp *filp; 160433d6423SLionel Sambuc 161433d6423SLionel Sambuc filp = NULL; 162433d6423SLionel Sambuc if (fild < 0 || fild >= OPEN_MAX) 163433d6423SLionel Sambuc err_code = EBADF; 164433d6423SLionel Sambuc else if (locktype != VNODE_OPCL && rfp->fp_filp[fild] != NULL && 165433d6423SLionel Sambuc rfp->fp_filp[fild]->filp_mode == FILP_CLOSED) 166433d6423SLionel Sambuc err_code = EIO; /* disallow all use except close(2) */ 167433d6423SLionel Sambuc else if ((filp = rfp->fp_filp[fild]) == NULL) 168433d6423SLionel Sambuc err_code = EBADF; 169433d6423SLionel Sambuc else if (locktype != VNODE_NONE) /* Only lock the filp if requested */ 170433d6423SLionel Sambuc lock_filp(filp, locktype); /* All is fine */ 171433d6423SLionel Sambuc 172433d6423SLionel Sambuc return(filp); /* may also be NULL */ 173433d6423SLionel Sambuc } 174433d6423SLionel Sambuc 175433d6423SLionel Sambuc 176433d6423SLionel Sambuc /*===========================================================================* 177433d6423SLionel Sambuc * find_filp * 178433d6423SLionel Sambuc *===========================================================================*/ 179433d6423SLionel Sambuc struct filp *find_filp(struct vnode *vp, mode_t bits) 180433d6423SLionel Sambuc { 181433d6423SLionel Sambuc /* Find a filp slot that refers to the vnode 'vp' in a way as described 182433d6423SLionel Sambuc * by the mode bit 'bits'. Used for determining whether somebody is still 183433d6423SLionel Sambuc * interested in either end of a pipe. Also used when opening a FIFO to 184433d6423SLionel Sambuc * find partners to share a filp field with (to shared the file position). 185433d6423SLionel Sambuc * Like 'get_fd' it performs its job by linear search through the filp table. 186433d6423SLionel Sambuc */ 187433d6423SLionel Sambuc 188433d6423SLionel Sambuc struct filp *f; 189433d6423SLionel Sambuc 190433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 191433d6423SLionel Sambuc if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)) { 192433d6423SLionel Sambuc return(f); 193433d6423SLionel Sambuc } 194433d6423SLionel Sambuc } 195433d6423SLionel Sambuc 196433d6423SLionel Sambuc /* If control passes here, the filp wasn't there. Report that back. */ 197433d6423SLionel Sambuc return(NULL); 198433d6423SLionel Sambuc } 199433d6423SLionel Sambuc 200433d6423SLionel Sambuc /*===========================================================================* 201433d6423SLionel Sambuc * invalidate_filp * 202433d6423SLionel Sambuc *===========================================================================*/ 203433d6423SLionel Sambuc void invalidate_filp(struct filp *rfilp) 204433d6423SLionel Sambuc { 205433d6423SLionel Sambuc /* Invalidate filp. */ 206433d6423SLionel Sambuc 207433d6423SLionel Sambuc rfilp->filp_mode = FILP_CLOSED; 208433d6423SLionel Sambuc } 209433d6423SLionel Sambuc 210433d6423SLionel Sambuc /*===========================================================================* 211433d6423SLionel Sambuc * invalidate_filp_by_char_major * 212433d6423SLionel Sambuc *===========================================================================*/ 2133b468884SDavid van Moolenbroek void invalidate_filp_by_char_major(devmajor_t major) 214433d6423SLionel Sambuc { 215433d6423SLionel Sambuc struct filp *f; 216433d6423SLionel Sambuc 217433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 218433d6423SLionel Sambuc if (f->filp_count != 0 && f->filp_vno != NULL) { 219433d6423SLionel Sambuc if (major(f->filp_vno->v_sdev) == major && 220433d6423SLionel Sambuc S_ISCHR(f->filp_vno->v_mode)) { 221433d6423SLionel Sambuc invalidate_filp(f); 222433d6423SLionel Sambuc } 223433d6423SLionel Sambuc } 224433d6423SLionel Sambuc } 225433d6423SLionel Sambuc } 226433d6423SLionel Sambuc 227433d6423SLionel Sambuc /*===========================================================================* 228433d6423SLionel Sambuc * invalidate_filp_by_endpt * 229433d6423SLionel Sambuc *===========================================================================*/ 230433d6423SLionel Sambuc void invalidate_filp_by_endpt(endpoint_t proc_e) 231433d6423SLionel Sambuc { 232433d6423SLionel Sambuc struct filp *f; 233433d6423SLionel Sambuc 234433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 235433d6423SLionel Sambuc if (f->filp_count != 0 && f->filp_vno != NULL) { 236433d6423SLionel Sambuc if (f->filp_vno->v_fs_e == proc_e) 237433d6423SLionel Sambuc invalidate_filp(f); 238433d6423SLionel Sambuc } 239433d6423SLionel Sambuc } 240433d6423SLionel Sambuc } 241433d6423SLionel Sambuc 242433d6423SLionel Sambuc /*===========================================================================* 243433d6423SLionel Sambuc * lock_filp * 244433d6423SLionel Sambuc *===========================================================================*/ 245433d6423SLionel Sambuc void lock_filp(filp, locktype) 246433d6423SLionel Sambuc struct filp *filp; 247433d6423SLionel Sambuc tll_access_t locktype; 248433d6423SLionel Sambuc { 249433d6423SLionel Sambuc struct worker_thread *org_self; 250433d6423SLionel Sambuc struct vnode *vp; 251433d6423SLionel Sambuc 252433d6423SLionel Sambuc assert(filp->filp_count > 0); 253433d6423SLionel Sambuc vp = filp->filp_vno; 254433d6423SLionel Sambuc assert(vp != NULL); 255433d6423SLionel Sambuc 256433d6423SLionel Sambuc /* Lock vnode only if we haven't already locked it. If already locked by us, 257433d6423SLionel Sambuc * we're allowed to have one additional 'soft' lock. */ 258433d6423SLionel Sambuc if (tll_locked_by_me(&vp->v_lock)) { 259433d6423SLionel Sambuc assert(filp->filp_softlock == NULL); 260433d6423SLionel Sambuc filp->filp_softlock = fp; 261433d6423SLionel Sambuc } else { 262433d6423SLionel Sambuc /* We have to make an exception for vnodes belonging to pipes. Even 263433d6423SLionel Sambuc * read(2) operations on pipes change the vnode and therefore require 264433d6423SLionel Sambuc * exclusive access. 265433d6423SLionel Sambuc */ 266433d6423SLionel Sambuc if (S_ISFIFO(vp->v_mode) && locktype == VNODE_READ) 267433d6423SLionel Sambuc locktype = VNODE_WRITE; 268433d6423SLionel Sambuc lock_vnode(vp, locktype); 269433d6423SLionel Sambuc } 270433d6423SLionel Sambuc 271433d6423SLionel Sambuc assert(vp->v_ref_count > 0); /* vnode still in use? */ 272433d6423SLionel Sambuc assert(filp->filp_vno == vp); /* vnode still what we think it is? */ 273433d6423SLionel Sambuc 274433d6423SLionel Sambuc /* First try to get filp lock right off the bat */ 275433d6423SLionel Sambuc if (mutex_trylock(&filp->filp_lock) != 0) { 276433d6423SLionel Sambuc 277433d6423SLionel Sambuc /* Already in use, let's wait for our turn */ 278433d6423SLionel Sambuc org_self = worker_suspend(); 279433d6423SLionel Sambuc 280433d6423SLionel Sambuc if (mutex_lock(&filp->filp_lock) != 0) 281433d6423SLionel Sambuc panic("unable to obtain lock on filp"); 282433d6423SLionel Sambuc 283433d6423SLionel Sambuc worker_resume(org_self); 284433d6423SLionel Sambuc } 285433d6423SLionel Sambuc } 286433d6423SLionel Sambuc 287433d6423SLionel Sambuc /*===========================================================================* 288433d6423SLionel Sambuc * unlock_filp * 289433d6423SLionel Sambuc *===========================================================================*/ 290433d6423SLionel Sambuc void unlock_filp(filp) 291433d6423SLionel Sambuc struct filp *filp; 292433d6423SLionel Sambuc { 293433d6423SLionel Sambuc /* If this filp holds a soft lock on the vnode, we must be the owner */ 294433d6423SLionel Sambuc if (filp->filp_softlock != NULL) 295433d6423SLionel Sambuc assert(filp->filp_softlock == fp); 296433d6423SLionel Sambuc 297433d6423SLionel Sambuc if (filp->filp_count > 0) { 298433d6423SLionel Sambuc /* Only unlock vnode if filp is still in use */ 299433d6423SLionel Sambuc 300433d6423SLionel Sambuc /* and if we don't hold a soft lock */ 301433d6423SLionel Sambuc if (filp->filp_softlock == NULL) { 302433d6423SLionel Sambuc assert(tll_islocked(&(filp->filp_vno->v_lock))); 303433d6423SLionel Sambuc unlock_vnode(filp->filp_vno); 304433d6423SLionel Sambuc } 305433d6423SLionel Sambuc } 306433d6423SLionel Sambuc 307433d6423SLionel Sambuc filp->filp_softlock = NULL; 308433d6423SLionel Sambuc if (mutex_unlock(&filp->filp_lock) != 0) 309433d6423SLionel Sambuc panic("unable to release lock on filp"); 310433d6423SLionel Sambuc } 311433d6423SLionel Sambuc 312433d6423SLionel Sambuc /*===========================================================================* 313433d6423SLionel Sambuc * unlock_filps * 314433d6423SLionel Sambuc *===========================================================================*/ 315433d6423SLionel Sambuc void unlock_filps(filp1, filp2) 316433d6423SLionel Sambuc struct filp *filp1; 317433d6423SLionel Sambuc struct filp *filp2; 318433d6423SLionel Sambuc { 319433d6423SLionel Sambuc /* Unlock two filps that are tied to the same vnode. As a thread can lock a 320433d6423SLionel Sambuc * vnode only once, unlocking the vnode twice would result in an error. */ 321433d6423SLionel Sambuc 322433d6423SLionel Sambuc /* No NULL pointers and not equal */ 323433d6423SLionel Sambuc assert(filp1); 324433d6423SLionel Sambuc assert(filp2); 325433d6423SLionel Sambuc assert(filp1 != filp2); 326433d6423SLionel Sambuc 327433d6423SLionel Sambuc /* Must be tied to the same vnode and not NULL */ 328433d6423SLionel Sambuc assert(filp1->filp_vno == filp2->filp_vno); 329433d6423SLionel Sambuc assert(filp1->filp_vno != NULL); 330433d6423SLionel Sambuc 331433d6423SLionel Sambuc if (filp1->filp_count > 0 && filp2->filp_count > 0) { 332433d6423SLionel Sambuc /* Only unlock vnode if filps are still in use */ 333433d6423SLionel Sambuc unlock_vnode(filp1->filp_vno); 334433d6423SLionel Sambuc } 335433d6423SLionel Sambuc 336433d6423SLionel Sambuc filp1->filp_softlock = NULL; 337433d6423SLionel Sambuc filp2->filp_softlock = NULL; 338433d6423SLionel Sambuc if (mutex_unlock(&filp2->filp_lock) != 0) 339433d6423SLionel Sambuc panic("unable to release filp lock on filp2"); 340433d6423SLionel Sambuc if (mutex_unlock(&filp1->filp_lock) != 0) 341433d6423SLionel Sambuc panic("unable to release filp lock on filp1"); 342433d6423SLionel Sambuc } 343433d6423SLionel Sambuc 344433d6423SLionel Sambuc /*===========================================================================* 345433d6423SLionel Sambuc * close_filp * 346433d6423SLionel Sambuc *===========================================================================*/ 347433d6423SLionel Sambuc void close_filp(f) 348433d6423SLionel Sambuc struct filp *f; 349433d6423SLionel Sambuc { 350433d6423SLionel Sambuc /* Close a file. Will also unlock filp when done */ 351433d6423SLionel Sambuc 352433d6423SLionel Sambuc int rw; 353433d6423SLionel Sambuc dev_t dev; 354433d6423SLionel Sambuc struct vnode *vp; 355433d6423SLionel Sambuc 356433d6423SLionel Sambuc /* Must be locked */ 357433d6423SLionel Sambuc assert(mutex_trylock(&f->filp_lock) == -EDEADLK); 358433d6423SLionel Sambuc assert(tll_islocked(&f->filp_vno->v_lock)); 359433d6423SLionel Sambuc 360433d6423SLionel Sambuc vp = f->filp_vno; 361433d6423SLionel Sambuc 362433d6423SLionel Sambuc if (f->filp_count - 1 == 0 && f->filp_mode != FILP_CLOSED) { 363433d6423SLionel Sambuc /* Check to see if the file is special. */ 364433d6423SLionel Sambuc if (S_ISCHR(vp->v_mode) || S_ISBLK(vp->v_mode)) { 365433d6423SLionel Sambuc dev = vp->v_sdev; 366433d6423SLionel Sambuc if (S_ISBLK(vp->v_mode)) { 367433d6423SLionel Sambuc lock_bsf(); 368*71cd1dd4SDavid van Moolenbroek if (vp->v_bfs_e == ROOT_FS_E && dev != ROOT_DEV) { 369433d6423SLionel Sambuc /* Invalidate the cache unless the special is 370*71cd1dd4SDavid van Moolenbroek * mounted. Be careful not to flush the root 371*71cd1dd4SDavid van Moolenbroek * file system either. 372433d6423SLionel Sambuc */ 373*71cd1dd4SDavid van Moolenbroek (void) req_flush(vp->v_bfs_e, dev); 374433d6423SLionel Sambuc } 375433d6423SLionel Sambuc unlock_bsf(); 376433d6423SLionel Sambuc 377433d6423SLionel Sambuc (void) bdev_close(dev); /* Ignore errors */ 378433d6423SLionel Sambuc } else { 379433d6423SLionel Sambuc (void) cdev_close(dev); /* Ignore errors */ 380433d6423SLionel Sambuc } 381433d6423SLionel Sambuc 382433d6423SLionel Sambuc f->filp_mode = FILP_CLOSED; 383433d6423SLionel Sambuc } 384433d6423SLionel Sambuc } 385433d6423SLionel Sambuc 386433d6423SLionel Sambuc /* If the inode being closed is a pipe, release everyone hanging on it. */ 387433d6423SLionel Sambuc if (S_ISFIFO(vp->v_mode)) { 388433d6423SLionel Sambuc rw = (f->filp_mode & R_BIT ? VFS_WRITE : VFS_READ); 389433d6423SLionel Sambuc release(vp, rw, susp_count); 390433d6423SLionel Sambuc } 391433d6423SLionel Sambuc 392433d6423SLionel Sambuc if (--f->filp_count == 0) { 393433d6423SLionel Sambuc if (S_ISFIFO(vp->v_mode)) { 394433d6423SLionel Sambuc /* Last reader or writer is going. Tell PFS about latest 395433d6423SLionel Sambuc * pipe size. 396433d6423SLionel Sambuc */ 397433d6423SLionel Sambuc truncate_vnode(vp, vp->v_size); 398433d6423SLionel Sambuc } 399433d6423SLionel Sambuc 400433d6423SLionel Sambuc unlock_vnode(f->filp_vno); 401433d6423SLionel Sambuc put_vnode(f->filp_vno); 402433d6423SLionel Sambuc f->filp_vno = NULL; 403433d6423SLionel Sambuc f->filp_mode = FILP_CLOSED; 404433d6423SLionel Sambuc f->filp_count = 0; 405433d6423SLionel Sambuc } else if (f->filp_count < 0) { 406433d6423SLionel Sambuc panic("VFS: invalid filp count: %d ino %llx/%llu", f->filp_count, 407433d6423SLionel Sambuc vp->v_dev, vp->v_inode_nr); 408433d6423SLionel Sambuc } else { 409433d6423SLionel Sambuc unlock_vnode(f->filp_vno); 410433d6423SLionel Sambuc } 411433d6423SLionel Sambuc 412433d6423SLionel Sambuc mutex_unlock(&f->filp_lock); 413433d6423SLionel Sambuc } 414433d6423SLionel Sambuc 415433d6423SLionel Sambuc /*===========================================================================* 416433d6423SLionel Sambuc * do_copyfd * 417433d6423SLionel Sambuc *===========================================================================*/ 418433d6423SLionel Sambuc int do_copyfd(void) 419433d6423SLionel Sambuc { 420433d6423SLionel Sambuc /* Copy a file descriptor between processes, or close a remote file descriptor. 421433d6423SLionel Sambuc * This call is used as back-call by device drivers (UDS, VND), and is expected 422433d6423SLionel Sambuc * to be used in response to an IOCTL to such device drivers. 423433d6423SLionel Sambuc */ 424433d6423SLionel Sambuc struct fproc *rfp; 425433d6423SLionel Sambuc struct filp *rfilp; 426433d6423SLionel Sambuc endpoint_t endpt; 427433d6423SLionel Sambuc int r, fd, what, slot; 428433d6423SLionel Sambuc 429433d6423SLionel Sambuc /* This should be replaced with an ACL check. */ 430433d6423SLionel Sambuc if (!super_user) return(EPERM); 431433d6423SLionel Sambuc 432433d6423SLionel Sambuc endpt = job_m_in.m_lsys_vfs_copyfd.endpt; 433433d6423SLionel Sambuc fd = job_m_in.m_lsys_vfs_copyfd.fd; 434433d6423SLionel Sambuc what = job_m_in.m_lsys_vfs_copyfd.what; 435433d6423SLionel Sambuc 436433d6423SLionel Sambuc if (isokendpt(endpt, &slot) != OK) return(EINVAL); 437433d6423SLionel Sambuc rfp = &fproc[slot]; 438433d6423SLionel Sambuc 439433d6423SLionel Sambuc /* FIXME: we should now check that the user process is indeed blocked on an 440433d6423SLionel Sambuc * IOCTL call, so that we can safely mess with its file descriptors. We 441433d6423SLionel Sambuc * currently do not have the necessary state to verify this, so we assume 442433d6423SLionel Sambuc * that the call is always used in the right way. 443433d6423SLionel Sambuc */ 444433d6423SLionel Sambuc 445433d6423SLionel Sambuc /* Depending on the operation, get the file descriptor from the caller or the 446433d6423SLionel Sambuc * user process. Do not lock the filp yet: we first need to make sure that 447433d6423SLionel Sambuc * locking it will not result in a deadlock. 448433d6423SLionel Sambuc */ 449433d6423SLionel Sambuc rfilp = get_filp2((what == COPYFD_TO) ? fp : rfp, fd, VNODE_NONE); 450433d6423SLionel Sambuc if (rfilp == NULL) 451433d6423SLionel Sambuc return(err_code); 452433d6423SLionel Sambuc 453433d6423SLionel Sambuc /* If the filp is involved in an IOCTL by the user process, locking the filp 454433d6423SLionel Sambuc * here would result in a deadlock. This would happen if a user process 455433d6423SLionel Sambuc * passes in the file descriptor to the device node on which it is performing 456433d6423SLionel Sambuc * the IOCTL. We do not allow manipulation of such device nodes. In 457433d6423SLionel Sambuc * practice, this only applies to block-special files (and thus VND), because 458433d6423SLionel Sambuc * character-special files (as used by UDS) are unlocked during the IOCTL. 459433d6423SLionel Sambuc */ 460433d6423SLionel Sambuc if (rfilp->filp_ioctl_fp == rfp) 461433d6423SLionel Sambuc return(EBADF); 462433d6423SLionel Sambuc 463433d6423SLionel Sambuc /* Now we can safely lock the filp, copy or close it, and unlock it again. */ 464433d6423SLionel Sambuc lock_filp(rfilp, VNODE_READ); 465433d6423SLionel Sambuc 466433d6423SLionel Sambuc switch (what) { 467433d6423SLionel Sambuc case COPYFD_FROM: 468433d6423SLionel Sambuc rfp = fp; 469433d6423SLionel Sambuc 470433d6423SLionel Sambuc /* FALLTHROUGH */ 471433d6423SLionel Sambuc case COPYFD_TO: 472433d6423SLionel Sambuc /* Find a free file descriptor slot in the local or remote process. */ 473433d6423SLionel Sambuc for (fd = 0; fd < OPEN_MAX; fd++) 474433d6423SLionel Sambuc if (rfp->fp_filp[fd] == NULL) 475433d6423SLionel Sambuc break; 476433d6423SLionel Sambuc 477433d6423SLionel Sambuc /* If found, fill the slot and return the slot number. */ 478433d6423SLionel Sambuc if (fd < OPEN_MAX) { 479433d6423SLionel Sambuc rfp->fp_filp[fd] = rfilp; 480433d6423SLionel Sambuc rfilp->filp_count++; 481433d6423SLionel Sambuc r = fd; 482433d6423SLionel Sambuc } else 483433d6423SLionel Sambuc r = EMFILE; 484433d6423SLionel Sambuc 485433d6423SLionel Sambuc break; 486433d6423SLionel Sambuc 487433d6423SLionel Sambuc case COPYFD_CLOSE: 488433d6423SLionel Sambuc /* This should be used ONLY to revert a successful copy-to operation, 489433d6423SLionel Sambuc * and assumes that the filp is still in use by the caller as well. 490433d6423SLionel Sambuc */ 491433d6423SLionel Sambuc if (rfilp->filp_count > 1) { 492433d6423SLionel Sambuc rfilp->filp_count--; 493433d6423SLionel Sambuc rfp->fp_filp[fd] = NULL; 494433d6423SLionel Sambuc r = OK; 495433d6423SLionel Sambuc } else 496433d6423SLionel Sambuc r = EBADF; 497433d6423SLionel Sambuc 498433d6423SLionel Sambuc break; 499433d6423SLionel Sambuc 500433d6423SLionel Sambuc default: 501433d6423SLionel Sambuc r = EINVAL; 502433d6423SLionel Sambuc } 503433d6423SLionel Sambuc 504433d6423SLionel Sambuc unlock_filp(rfilp); 505433d6423SLionel Sambuc 506433d6423SLionel Sambuc return(r); 507433d6423SLionel Sambuc } 508