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 /*===========================================================================* 86e3b8d4bbSDavid van Moolenbroek * check_fds * 87e3b8d4bbSDavid van Moolenbroek *===========================================================================*/ 88e3b8d4bbSDavid van Moolenbroek int check_fds(struct fproc *rfp, int nfds) 89e3b8d4bbSDavid van Moolenbroek { 90e3b8d4bbSDavid van Moolenbroek /* Check whether at least 'nfds' file descriptors can be created in the process 91e3b8d4bbSDavid van Moolenbroek * 'rfp'. Return OK on success, or otherwise an appropriate error code. 92e3b8d4bbSDavid van Moolenbroek */ 93e3b8d4bbSDavid van Moolenbroek int i; 94e3b8d4bbSDavid van Moolenbroek 95e3b8d4bbSDavid van Moolenbroek assert(nfds >= 1); 96e3b8d4bbSDavid van Moolenbroek 97e3b8d4bbSDavid van Moolenbroek for (i = 0; i < OPEN_MAX; i++) { 98e3b8d4bbSDavid van Moolenbroek if (rfp->fp_filp[i] == NULL) { 99e3b8d4bbSDavid van Moolenbroek if (--nfds == 0) 100e3b8d4bbSDavid van Moolenbroek return OK; 101e3b8d4bbSDavid van Moolenbroek } 102e3b8d4bbSDavid van Moolenbroek } 103e3b8d4bbSDavid van Moolenbroek 104e3b8d4bbSDavid van Moolenbroek return EMFILE; 105e3b8d4bbSDavid van Moolenbroek } 106e3b8d4bbSDavid van Moolenbroek 107e3b8d4bbSDavid van Moolenbroek /*===========================================================================* 108433d6423SLionel Sambuc * get_fd * 109433d6423SLionel Sambuc *===========================================================================*/ 110433d6423SLionel Sambuc int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt) 111433d6423SLionel Sambuc { 112433d6423SLionel Sambuc /* Look for a free file descriptor and a free filp slot. Fill in the mode word 113433d6423SLionel Sambuc * in the latter, but don't claim either one yet, since the open() or creat() 114433d6423SLionel Sambuc * may yet fail. 115433d6423SLionel Sambuc */ 116433d6423SLionel Sambuc 117433d6423SLionel Sambuc register struct filp *f; 118433d6423SLionel Sambuc register int i; 119433d6423SLionel Sambuc 120433d6423SLionel Sambuc /* Search the fproc fp_filp table for a free file descriptor. */ 121433d6423SLionel Sambuc for (i = start; i < OPEN_MAX; i++) { 122433d6423SLionel Sambuc if (rfp->fp_filp[i] == NULL) { 123433d6423SLionel Sambuc /* A file descriptor has been located. */ 124433d6423SLionel Sambuc *k = i; 125433d6423SLionel Sambuc break; 126433d6423SLionel Sambuc } 127433d6423SLionel Sambuc } 128433d6423SLionel Sambuc 129433d6423SLionel Sambuc /* Check to see if a file descriptor has been found. */ 130433d6423SLionel Sambuc if (i >= OPEN_MAX) return(EMFILE); 131433d6423SLionel Sambuc 132433d6423SLionel Sambuc /* If we don't care about a filp, return now */ 133433d6423SLionel Sambuc if (fpt == NULL) return(OK); 134433d6423SLionel Sambuc 135433d6423SLionel Sambuc /* Now that a file descriptor has been found, look for a free filp slot. */ 136433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 137433d6423SLionel Sambuc assert(f->filp_count >= 0); 138433d6423SLionel Sambuc if (f->filp_count == 0 && mutex_trylock(&f->filp_lock) == 0) { 139433d6423SLionel Sambuc f->filp_mode = bits; 140433d6423SLionel Sambuc f->filp_pos = 0; 141433d6423SLionel Sambuc f->filp_selectors = 0; 142433d6423SLionel Sambuc f->filp_select_ops = 0; 143433d6423SLionel Sambuc f->filp_pipe_select_ops = 0; 144e3b8d4bbSDavid van Moolenbroek f->filp_select_dev = NO_DEV; 145433d6423SLionel Sambuc f->filp_flags = 0; 146433d6423SLionel Sambuc f->filp_select_flags = 0; 147433d6423SLionel Sambuc f->filp_softlock = NULL; 148433d6423SLionel Sambuc f->filp_ioctl_fp = NULL; 149433d6423SLionel Sambuc *fpt = f; 150433d6423SLionel Sambuc return(OK); 151433d6423SLionel Sambuc } 152433d6423SLionel Sambuc } 153433d6423SLionel Sambuc 154433d6423SLionel Sambuc /* If control passes here, the filp table must be full. Report that back. */ 155433d6423SLionel Sambuc return(ENFILE); 156433d6423SLionel Sambuc } 157433d6423SLionel Sambuc 158433d6423SLionel Sambuc 159433d6423SLionel Sambuc /*===========================================================================* 160433d6423SLionel Sambuc * get_filp * 161433d6423SLionel Sambuc *===========================================================================*/ 162a0814afbSRichard Sailer struct filp * 163a0814afbSRichard Sailer get_filp( 164a0814afbSRichard Sailer int fild, /* file descriptor */ 165a0814afbSRichard Sailer tll_access_t locktype 166a0814afbSRichard Sailer ) 167433d6423SLionel Sambuc { 168433d6423SLionel Sambuc /* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */ 169433d6423SLionel Sambuc 170433d6423SLionel Sambuc return get_filp2(fp, fild, locktype); 171433d6423SLionel Sambuc } 172433d6423SLionel Sambuc 173433d6423SLionel Sambuc 174433d6423SLionel Sambuc /*===========================================================================* 175433d6423SLionel Sambuc * get_filp2 * 176433d6423SLionel Sambuc *===========================================================================*/ 177a0814afbSRichard Sailer struct filp * 178a0814afbSRichard Sailer get_filp2( 179a0814afbSRichard Sailer register struct fproc *rfp, 180a0814afbSRichard Sailer int fild, /* file descriptor */ 181a0814afbSRichard Sailer tll_access_t locktype 182a0814afbSRichard Sailer ) 183433d6423SLionel Sambuc { 184433d6423SLionel Sambuc /* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */ 185433d6423SLionel Sambuc struct filp *filp; 186433d6423SLionel Sambuc 187433d6423SLionel Sambuc filp = NULL; 188433d6423SLionel Sambuc if (fild < 0 || fild >= OPEN_MAX) 189433d6423SLionel Sambuc err_code = EBADF; 190433d6423SLionel Sambuc else if (locktype != VNODE_OPCL && rfp->fp_filp[fild] != NULL && 191433d6423SLionel Sambuc rfp->fp_filp[fild]->filp_mode == FILP_CLOSED) 192433d6423SLionel Sambuc err_code = EIO; /* disallow all use except close(2) */ 193433d6423SLionel Sambuc else if ((filp = rfp->fp_filp[fild]) == NULL) 194433d6423SLionel Sambuc err_code = EBADF; 195433d6423SLionel Sambuc else if (locktype != VNODE_NONE) /* Only lock the filp if requested */ 196433d6423SLionel Sambuc lock_filp(filp, locktype); /* All is fine */ 197433d6423SLionel Sambuc 198433d6423SLionel Sambuc return(filp); /* may also be NULL */ 199433d6423SLionel Sambuc } 200433d6423SLionel Sambuc 201433d6423SLionel Sambuc 202433d6423SLionel Sambuc /*===========================================================================* 203433d6423SLionel Sambuc * find_filp * 204433d6423SLionel Sambuc *===========================================================================*/ 205433d6423SLionel Sambuc struct filp *find_filp(struct vnode *vp, mode_t bits) 206433d6423SLionel Sambuc { 207433d6423SLionel Sambuc /* Find a filp slot that refers to the vnode 'vp' in a way as described 208433d6423SLionel Sambuc * by the mode bit 'bits'. Used for determining whether somebody is still 209433d6423SLionel Sambuc * interested in either end of a pipe. Also used when opening a FIFO to 210433d6423SLionel Sambuc * find partners to share a filp field with (to shared the file position). 211433d6423SLionel Sambuc * Like 'get_fd' it performs its job by linear search through the filp table. 212433d6423SLionel Sambuc */ 213433d6423SLionel Sambuc 214433d6423SLionel Sambuc struct filp *f; 215433d6423SLionel Sambuc 216433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 217433d6423SLionel Sambuc if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)) { 218433d6423SLionel Sambuc return(f); 219433d6423SLionel Sambuc } 220433d6423SLionel Sambuc } 221433d6423SLionel Sambuc 222433d6423SLionel Sambuc /* If control passes here, the filp wasn't there. Report that back. */ 223433d6423SLionel Sambuc return(NULL); 224433d6423SLionel Sambuc } 225433d6423SLionel Sambuc 226433d6423SLionel Sambuc /*===========================================================================* 227e3b8d4bbSDavid van Moolenbroek * find_filp_by_sock_dev * 228e3b8d4bbSDavid van Moolenbroek *===========================================================================*/ 229e3b8d4bbSDavid van Moolenbroek struct filp *find_filp_by_sock_dev(dev_t dev) 230e3b8d4bbSDavid van Moolenbroek { 231e3b8d4bbSDavid van Moolenbroek /* See if there is a file pointer for a socket with the given socket device 232e3b8d4bbSDavid van Moolenbroek * number. 233e3b8d4bbSDavid van Moolenbroek */ 234e3b8d4bbSDavid van Moolenbroek struct filp *f; 235e3b8d4bbSDavid van Moolenbroek 236e3b8d4bbSDavid van Moolenbroek for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 237e3b8d4bbSDavid van Moolenbroek if (f->filp_count != 0 && f->filp_vno != NULL && 238e3b8d4bbSDavid van Moolenbroek S_ISSOCK(f->filp_vno->v_mode) && f->filp_vno->v_sdev == dev && 239e3b8d4bbSDavid van Moolenbroek f->filp_mode != FILP_CLOSED) { 240e3b8d4bbSDavid van Moolenbroek return f; 241e3b8d4bbSDavid van Moolenbroek } 242e3b8d4bbSDavid van Moolenbroek } 243e3b8d4bbSDavid van Moolenbroek 244e3b8d4bbSDavid van Moolenbroek return NULL; 245e3b8d4bbSDavid van Moolenbroek } 246e3b8d4bbSDavid van Moolenbroek 247e3b8d4bbSDavid van Moolenbroek /*===========================================================================* 248433d6423SLionel Sambuc * invalidate_filp * 249433d6423SLionel Sambuc *===========================================================================*/ 250433d6423SLionel Sambuc void invalidate_filp(struct filp *rfilp) 251433d6423SLionel Sambuc { 252433d6423SLionel Sambuc /* Invalidate filp. */ 253433d6423SLionel Sambuc 254433d6423SLionel Sambuc rfilp->filp_mode = FILP_CLOSED; 255433d6423SLionel Sambuc } 256433d6423SLionel Sambuc 257433d6423SLionel Sambuc /*===========================================================================* 258433d6423SLionel Sambuc * invalidate_filp_by_char_major * 259433d6423SLionel Sambuc *===========================================================================*/ 2603b468884SDavid van Moolenbroek void invalidate_filp_by_char_major(devmajor_t major) 261433d6423SLionel Sambuc { 262433d6423SLionel Sambuc struct filp *f; 263433d6423SLionel Sambuc 264433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 265433d6423SLionel Sambuc if (f->filp_count != 0 && f->filp_vno != NULL) { 266433d6423SLionel Sambuc if (major(f->filp_vno->v_sdev) == major && 267433d6423SLionel Sambuc S_ISCHR(f->filp_vno->v_mode)) { 268433d6423SLionel Sambuc invalidate_filp(f); 269433d6423SLionel Sambuc } 270433d6423SLionel Sambuc } 271433d6423SLionel Sambuc } 272433d6423SLionel Sambuc } 273433d6423SLionel Sambuc 274433d6423SLionel Sambuc /*===========================================================================* 275e3b8d4bbSDavid van Moolenbroek * invalidate_filp_by_sock_drv * 276e3b8d4bbSDavid van Moolenbroek *===========================================================================*/ 277e3b8d4bbSDavid van Moolenbroek void invalidate_filp_by_sock_drv(unsigned int num) 278e3b8d4bbSDavid van Moolenbroek { 279e3b8d4bbSDavid van Moolenbroek /* Invalidate all file pointers for sockets owned by the socket driver with the 280e3b8d4bbSDavid van Moolenbroek * smap number 'num'. 281e3b8d4bbSDavid van Moolenbroek */ 282e3b8d4bbSDavid van Moolenbroek struct filp *f; 283e3b8d4bbSDavid van Moolenbroek struct smap *sp; 284e3b8d4bbSDavid van Moolenbroek 285e3b8d4bbSDavid van Moolenbroek for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 286e3b8d4bbSDavid van Moolenbroek if (f->filp_count != 0 && f->filp_vno != NULL) { 287e3b8d4bbSDavid van Moolenbroek if (S_ISSOCK(f->filp_vno->v_mode) && 288e3b8d4bbSDavid van Moolenbroek (sp = get_smap_by_dev(f->filp_vno->v_sdev, NULL)) != NULL 289e3b8d4bbSDavid van Moolenbroek && sp->smap_num == num) 290e3b8d4bbSDavid van Moolenbroek invalidate_filp(f); 291e3b8d4bbSDavid van Moolenbroek } 292e3b8d4bbSDavid van Moolenbroek } 293e3b8d4bbSDavid van Moolenbroek } 294e3b8d4bbSDavid van Moolenbroek 295e3b8d4bbSDavid van Moolenbroek /*===========================================================================* 296433d6423SLionel Sambuc * invalidate_filp_by_endpt * 297433d6423SLionel Sambuc *===========================================================================*/ 298433d6423SLionel Sambuc void invalidate_filp_by_endpt(endpoint_t proc_e) 299433d6423SLionel Sambuc { 300433d6423SLionel Sambuc struct filp *f; 301433d6423SLionel Sambuc 302433d6423SLionel Sambuc for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { 303433d6423SLionel Sambuc if (f->filp_count != 0 && f->filp_vno != NULL) { 304433d6423SLionel Sambuc if (f->filp_vno->v_fs_e == proc_e) 305433d6423SLionel Sambuc invalidate_filp(f); 306433d6423SLionel Sambuc } 307433d6423SLionel Sambuc } 308433d6423SLionel Sambuc } 309433d6423SLionel Sambuc 310433d6423SLionel Sambuc /*===========================================================================* 311433d6423SLionel Sambuc * lock_filp * 312433d6423SLionel Sambuc *===========================================================================*/ 313a0814afbSRichard Sailer void 314a0814afbSRichard Sailer lock_filp(struct filp *filp, tll_access_t locktype) 315433d6423SLionel Sambuc { 316433d6423SLionel Sambuc struct worker_thread *org_self; 317433d6423SLionel Sambuc struct vnode *vp; 318433d6423SLionel Sambuc 319433d6423SLionel Sambuc assert(filp->filp_count > 0); 320433d6423SLionel Sambuc vp = filp->filp_vno; 321433d6423SLionel Sambuc assert(vp != NULL); 322433d6423SLionel Sambuc 323433d6423SLionel Sambuc /* Lock vnode only if we haven't already locked it. If already locked by us, 324433d6423SLionel Sambuc * we're allowed to have one additional 'soft' lock. */ 325433d6423SLionel Sambuc if (tll_locked_by_me(&vp->v_lock)) { 326433d6423SLionel Sambuc assert(filp->filp_softlock == NULL); 327433d6423SLionel Sambuc filp->filp_softlock = fp; 328433d6423SLionel Sambuc } else { 329433d6423SLionel Sambuc /* We have to make an exception for vnodes belonging to pipes. Even 330433d6423SLionel Sambuc * read(2) operations on pipes change the vnode and therefore require 331433d6423SLionel Sambuc * exclusive access. 332433d6423SLionel Sambuc */ 333433d6423SLionel Sambuc if (S_ISFIFO(vp->v_mode) && locktype == VNODE_READ) 334433d6423SLionel Sambuc locktype = VNODE_WRITE; 335433d6423SLionel Sambuc lock_vnode(vp, locktype); 336433d6423SLionel Sambuc } 337433d6423SLionel Sambuc 338433d6423SLionel Sambuc assert(vp->v_ref_count > 0); /* vnode still in use? */ 339433d6423SLionel Sambuc assert(filp->filp_vno == vp); /* vnode still what we think it is? */ 340433d6423SLionel Sambuc 341433d6423SLionel Sambuc /* First try to get filp lock right off the bat */ 342433d6423SLionel Sambuc if (mutex_trylock(&filp->filp_lock) != 0) { 343433d6423SLionel Sambuc 344433d6423SLionel Sambuc /* Already in use, let's wait for our turn */ 345433d6423SLionel Sambuc org_self = worker_suspend(); 346433d6423SLionel Sambuc 347433d6423SLionel Sambuc if (mutex_lock(&filp->filp_lock) != 0) 348433d6423SLionel Sambuc panic("unable to obtain lock on filp"); 349433d6423SLionel Sambuc 350433d6423SLionel Sambuc worker_resume(org_self); 351433d6423SLionel Sambuc } 352433d6423SLionel Sambuc } 353433d6423SLionel Sambuc 354433d6423SLionel Sambuc /*===========================================================================* 355433d6423SLionel Sambuc * unlock_filp * 356433d6423SLionel Sambuc *===========================================================================*/ 357a0814afbSRichard Sailer void 358a0814afbSRichard Sailer unlock_filp(struct filp *filp) 359433d6423SLionel Sambuc { 360433d6423SLionel Sambuc /* If this filp holds a soft lock on the vnode, we must be the owner */ 361433d6423SLionel Sambuc if (filp->filp_softlock != NULL) 362433d6423SLionel Sambuc assert(filp->filp_softlock == fp); 363433d6423SLionel Sambuc 364433d6423SLionel Sambuc if (filp->filp_count > 0) { 365433d6423SLionel Sambuc /* Only unlock vnode if filp is still in use */ 366433d6423SLionel Sambuc 367433d6423SLionel Sambuc /* and if we don't hold a soft lock */ 368433d6423SLionel Sambuc if (filp->filp_softlock == NULL) { 369433d6423SLionel Sambuc assert(tll_islocked(&(filp->filp_vno->v_lock))); 370433d6423SLionel Sambuc unlock_vnode(filp->filp_vno); 371433d6423SLionel Sambuc } 372433d6423SLionel Sambuc } 373433d6423SLionel Sambuc 374433d6423SLionel Sambuc filp->filp_softlock = NULL; 375433d6423SLionel Sambuc if (mutex_unlock(&filp->filp_lock) != 0) 376433d6423SLionel Sambuc panic("unable to release lock on filp"); 377433d6423SLionel Sambuc } 378433d6423SLionel Sambuc 379433d6423SLionel Sambuc /*===========================================================================* 380433d6423SLionel Sambuc * unlock_filps * 381433d6423SLionel Sambuc *===========================================================================*/ 382a0814afbSRichard Sailer void 383a0814afbSRichard Sailer unlock_filps(struct filp *filp1, struct filp *filp2) 384433d6423SLionel Sambuc { 385433d6423SLionel Sambuc /* Unlock two filps that are tied to the same vnode. As a thread can lock a 386433d6423SLionel Sambuc * vnode only once, unlocking the vnode twice would result in an error. */ 387433d6423SLionel Sambuc 388433d6423SLionel Sambuc /* No NULL pointers and not equal */ 389433d6423SLionel Sambuc assert(filp1); 390433d6423SLionel Sambuc assert(filp2); 391433d6423SLionel Sambuc assert(filp1 != filp2); 392433d6423SLionel Sambuc 393433d6423SLionel Sambuc /* Must be tied to the same vnode and not NULL */ 394433d6423SLionel Sambuc assert(filp1->filp_vno == filp2->filp_vno); 395433d6423SLionel Sambuc assert(filp1->filp_vno != NULL); 396433d6423SLionel Sambuc 397433d6423SLionel Sambuc if (filp1->filp_count > 0 && filp2->filp_count > 0) { 398433d6423SLionel Sambuc /* Only unlock vnode if filps are still in use */ 399433d6423SLionel Sambuc unlock_vnode(filp1->filp_vno); 400433d6423SLionel Sambuc } 401433d6423SLionel Sambuc 402433d6423SLionel Sambuc filp1->filp_softlock = NULL; 403433d6423SLionel Sambuc filp2->filp_softlock = NULL; 404433d6423SLionel Sambuc if (mutex_unlock(&filp2->filp_lock) != 0) 405433d6423SLionel Sambuc panic("unable to release filp lock on filp2"); 406433d6423SLionel Sambuc if (mutex_unlock(&filp1->filp_lock) != 0) 407433d6423SLionel Sambuc panic("unable to release filp lock on filp1"); 408433d6423SLionel Sambuc } 409433d6423SLionel Sambuc 410433d6423SLionel Sambuc /*===========================================================================* 411433d6423SLionel Sambuc * close_filp * 412433d6423SLionel Sambuc *===========================================================================*/ 413491d647aSDavid van Moolenbroek int 414491d647aSDavid van Moolenbroek close_filp(struct filp * f, int may_suspend) 415433d6423SLionel Sambuc { 416491d647aSDavid van Moolenbroek /* Close a file. Will also unlock filp when done. The 'may_suspend' flag 417491d647aSDavid van Moolenbroek * indicates whether the current process may be suspended closing a socket. 418491d647aSDavid van Moolenbroek * That is currently supported only when the user issued a close(2), and (only) 419491d647aSDavid van Moolenbroek * in that case may this function return SUSPEND instead of OK. In all other 420491d647aSDavid van Moolenbroek * cases, this function will always return OK. It will never return another 421491d647aSDavid van Moolenbroek * error code, for reasons explained below. 422491d647aSDavid van Moolenbroek */ 423491d647aSDavid van Moolenbroek int r, rw; 424433d6423SLionel Sambuc dev_t dev; 425433d6423SLionel Sambuc struct vnode *vp; 426433d6423SLionel Sambuc 427433d6423SLionel Sambuc /* Must be locked */ 428433d6423SLionel Sambuc assert(mutex_trylock(&f->filp_lock) == -EDEADLK); 429433d6423SLionel Sambuc assert(tll_islocked(&f->filp_vno->v_lock)); 430433d6423SLionel Sambuc 431433d6423SLionel Sambuc vp = f->filp_vno; 432433d6423SLionel Sambuc 433491d647aSDavid van Moolenbroek r = OK; 434491d647aSDavid van Moolenbroek 435433d6423SLionel Sambuc if (f->filp_count - 1 == 0 && f->filp_mode != FILP_CLOSED) { 436433d6423SLionel Sambuc /* Check to see if the file is special. */ 437e3b8d4bbSDavid van Moolenbroek if (S_ISCHR(vp->v_mode) || S_ISBLK(vp->v_mode) || 438e3b8d4bbSDavid van Moolenbroek S_ISSOCK(vp->v_mode)) { 439433d6423SLionel Sambuc dev = vp->v_sdev; 440433d6423SLionel Sambuc if (S_ISBLK(vp->v_mode)) { 441433d6423SLionel Sambuc lock_bsf(); 44271cd1dd4SDavid van Moolenbroek if (vp->v_bfs_e == ROOT_FS_E && dev != ROOT_DEV) { 443433d6423SLionel Sambuc /* Invalidate the cache unless the special is 44471cd1dd4SDavid van Moolenbroek * mounted. Be careful not to flush the root 44571cd1dd4SDavid van Moolenbroek * file system either. 446433d6423SLionel Sambuc */ 44771cd1dd4SDavid van Moolenbroek (void) req_flush(vp->v_bfs_e, dev); 448433d6423SLionel Sambuc } 449433d6423SLionel Sambuc unlock_bsf(); 450433d6423SLionel Sambuc 451433d6423SLionel Sambuc (void) bdev_close(dev); /* Ignore errors */ 452e3b8d4bbSDavid van Moolenbroek } else if (S_ISCHR(vp->v_mode)) { 453433d6423SLionel Sambuc (void) cdev_close(dev); /* Ignore errors */ 454e3b8d4bbSDavid van Moolenbroek } else { 455e3b8d4bbSDavid van Moolenbroek /* 456491d647aSDavid van Moolenbroek * Sockets may take a while to be closed (SO_LINGER), 457491d647aSDavid van Moolenbroek * and thus, we may issue a suspending close to a 458e3b8d4bbSDavid van Moolenbroek * socket driver. Getting this working for close(2) is 459491d647aSDavid van Moolenbroek * the easy case, and that is all we support for now. 460491d647aSDavid van Moolenbroek * However, there is also eg dup2(2), which if 461491d647aSDavid van Moolenbroek * interrupted by a signal should technically fail 462491d647aSDavid van Moolenbroek * without closing the file descriptor. Then there are 463491d647aSDavid van Moolenbroek * cases where the close should never block: process 464491d647aSDavid van Moolenbroek * exit and close-on-exec for example. Getting all 465491d647aSDavid van Moolenbroek * such cases right is left to future work; currently 466491d647aSDavid van Moolenbroek * they all perform thread-blocking socket closes and 467491d647aSDavid van Moolenbroek * thus cause the socket to perform lingering in the 468491d647aSDavid van Moolenbroek * background if at all. 469e3b8d4bbSDavid van Moolenbroek */ 470491d647aSDavid van Moolenbroek assert(!may_suspend || job_call_nr == VFS_CLOSE); 471491d647aSDavid van Moolenbroek 472491d647aSDavid van Moolenbroek if (f->filp_flags & O_NONBLOCK) 473491d647aSDavid van Moolenbroek may_suspend = FALSE; 474491d647aSDavid van Moolenbroek 475491d647aSDavid van Moolenbroek r = sdev_close(dev, may_suspend); 476491d647aSDavid van Moolenbroek 477491d647aSDavid van Moolenbroek /* 478491d647aSDavid van Moolenbroek * Returning a non-OK error is a bad idea, because it 479491d647aSDavid van Moolenbroek * will leave the application wondering whether closing 480491d647aSDavid van Moolenbroek * the file descriptor actually succeeded. 481491d647aSDavid van Moolenbroek */ 482491d647aSDavid van Moolenbroek if (r != SUSPEND) 483491d647aSDavid van Moolenbroek r = OK; 484433d6423SLionel Sambuc } 485433d6423SLionel Sambuc 486433d6423SLionel Sambuc f->filp_mode = FILP_CLOSED; 487433d6423SLionel Sambuc } 488433d6423SLionel Sambuc } 489433d6423SLionel Sambuc 490433d6423SLionel Sambuc /* If the inode being closed is a pipe, release everyone hanging on it. */ 491433d6423SLionel Sambuc if (S_ISFIFO(vp->v_mode)) { 492433d6423SLionel Sambuc rw = (f->filp_mode & R_BIT ? VFS_WRITE : VFS_READ); 493433d6423SLionel Sambuc release(vp, rw, susp_count); 494433d6423SLionel Sambuc } 495433d6423SLionel Sambuc 496433d6423SLionel Sambuc if (--f->filp_count == 0) { 497433d6423SLionel Sambuc if (S_ISFIFO(vp->v_mode)) { 498433d6423SLionel Sambuc /* Last reader or writer is going. Tell PFS about latest 499433d6423SLionel Sambuc * pipe size. 500433d6423SLionel Sambuc */ 501433d6423SLionel Sambuc truncate_vnode(vp, vp->v_size); 502433d6423SLionel Sambuc } 503433d6423SLionel Sambuc 504433d6423SLionel Sambuc unlock_vnode(f->filp_vno); 505433d6423SLionel Sambuc put_vnode(f->filp_vno); 506433d6423SLionel Sambuc f->filp_vno = NULL; 507433d6423SLionel Sambuc f->filp_mode = FILP_CLOSED; 508433d6423SLionel Sambuc f->filp_count = 0; 509433d6423SLionel Sambuc } else if (f->filp_count < 0) { 510433d6423SLionel Sambuc panic("VFS: invalid filp count: %d ino %llx/%llu", f->filp_count, 511433d6423SLionel Sambuc vp->v_dev, vp->v_inode_nr); 512433d6423SLionel Sambuc } else { 513433d6423SLionel Sambuc unlock_vnode(f->filp_vno); 514433d6423SLionel Sambuc } 515433d6423SLionel Sambuc 516433d6423SLionel Sambuc mutex_unlock(&f->filp_lock); 517491d647aSDavid van Moolenbroek 518491d647aSDavid van Moolenbroek return r; 519433d6423SLionel Sambuc } 520433d6423SLionel Sambuc 521433d6423SLionel Sambuc /*===========================================================================* 522433d6423SLionel Sambuc * do_copyfd * 523433d6423SLionel Sambuc *===========================================================================*/ 524433d6423SLionel Sambuc int do_copyfd(void) 525433d6423SLionel Sambuc { 526433d6423SLionel Sambuc /* Copy a file descriptor between processes, or close a remote file descriptor. 527433d6423SLionel Sambuc * This call is used as back-call by device drivers (UDS, VND), and is expected 528433d6423SLionel Sambuc * to be used in response to an IOCTL to such device drivers. 529433d6423SLionel Sambuc */ 530433d6423SLionel Sambuc struct fproc *rfp; 531433d6423SLionel Sambuc struct filp *rfilp; 532c344203eSDavid van Moolenbroek struct vnode *vp; 533c344203eSDavid van Moolenbroek struct smap *sp; 534433d6423SLionel Sambuc endpoint_t endpt; 535*45443f35SDavid van Moolenbroek int r, fd, what, flags, slot; 536433d6423SLionel Sambuc 537433d6423SLionel Sambuc /* This should be replaced with an ACL check. */ 538433d6423SLionel Sambuc if (!super_user) return(EPERM); 539433d6423SLionel Sambuc 540433d6423SLionel Sambuc endpt = job_m_in.m_lsys_vfs_copyfd.endpt; 541433d6423SLionel Sambuc fd = job_m_in.m_lsys_vfs_copyfd.fd; 542433d6423SLionel Sambuc what = job_m_in.m_lsys_vfs_copyfd.what; 543433d6423SLionel Sambuc 544*45443f35SDavid van Moolenbroek flags = what & COPYFD_FLAGS; 545*45443f35SDavid van Moolenbroek what &= ~COPYFD_FLAGS; 546*45443f35SDavid van Moolenbroek 547433d6423SLionel Sambuc if (isokendpt(endpt, &slot) != OK) return(EINVAL); 548433d6423SLionel Sambuc rfp = &fproc[slot]; 549433d6423SLionel Sambuc 550433d6423SLionel Sambuc /* FIXME: we should now check that the user process is indeed blocked on an 551433d6423SLionel Sambuc * IOCTL call, so that we can safely mess with its file descriptors. We 552433d6423SLionel Sambuc * currently do not have the necessary state to verify this, so we assume 553433d6423SLionel Sambuc * that the call is always used in the right way. 554433d6423SLionel Sambuc */ 555433d6423SLionel Sambuc 556433d6423SLionel Sambuc /* Depending on the operation, get the file descriptor from the caller or the 557433d6423SLionel Sambuc * user process. Do not lock the filp yet: we first need to make sure that 558433d6423SLionel Sambuc * locking it will not result in a deadlock. 559433d6423SLionel Sambuc */ 560433d6423SLionel Sambuc rfilp = get_filp2((what == COPYFD_TO) ? fp : rfp, fd, VNODE_NONE); 561433d6423SLionel Sambuc if (rfilp == NULL) 562433d6423SLionel Sambuc return(err_code); 563433d6423SLionel Sambuc 564433d6423SLionel Sambuc /* If the filp is involved in an IOCTL by the user process, locking the filp 565433d6423SLionel Sambuc * here would result in a deadlock. This would happen if a user process 566433d6423SLionel Sambuc * passes in the file descriptor to the device node on which it is performing 567433d6423SLionel Sambuc * the IOCTL. We do not allow manipulation of such device nodes. In 568433d6423SLionel Sambuc * practice, this only applies to block-special files (and thus VND), because 569433d6423SLionel Sambuc * character-special files (as used by UDS) are unlocked during the IOCTL. 570433d6423SLionel Sambuc */ 571433d6423SLionel Sambuc if (rfilp->filp_ioctl_fp == rfp) 572433d6423SLionel Sambuc return(EBADF); 573433d6423SLionel Sambuc 574433d6423SLionel Sambuc /* Now we can safely lock the filp, copy or close it, and unlock it again. */ 575433d6423SLionel Sambuc lock_filp(rfilp, VNODE_READ); 576433d6423SLionel Sambuc 577433d6423SLionel Sambuc switch (what) { 578433d6423SLionel Sambuc case COPYFD_FROM: 579c344203eSDavid van Moolenbroek /* 580c344203eSDavid van Moolenbroek * If the caller is a socket driver (namely, UDS) and the file 581c344203eSDavid van Moolenbroek * descriptor being copied in is a socket for that socket driver, then 582c344203eSDavid van Moolenbroek * deny the call, because of at least two known issues. Both issues 583c344203eSDavid van Moolenbroek * are related to UDS having an in-flight file descriptor that is the 584c344203eSDavid van Moolenbroek * last reference to a UDS socket: 585c344203eSDavid van Moolenbroek * 586c344203eSDavid van Moolenbroek * 1) if UDS tries to close the file descriptor, this will prompt VFS 587c344203eSDavid van Moolenbroek * to close the underlying object, which is a UDS socket. As a 588c344203eSDavid van Moolenbroek * result, while UDS is blocked in the close(2), VFS will try to 589c344203eSDavid van Moolenbroek * send a request to UDS to close the socket. This results in a 590c344203eSDavid van Moolenbroek * deadlock of the UDS service. 591c344203eSDavid van Moolenbroek * 592c344203eSDavid van Moolenbroek * 2) if a file descriptor for a UDS socket is sent across that same 593c344203eSDavid van Moolenbroek * UDS socket, the socket will remain referenced by UDS, thus open 594c344203eSDavid van Moolenbroek * in VFS, and therefore also open in UDS. The socket and file 595c344203eSDavid van Moolenbroek * descriptor will both remain in use for the rest of UDS' lifetime. 596c344203eSDavid van Moolenbroek * This can easily result in denial-of-service in the UDS service. 597c344203eSDavid van Moolenbroek * The same problem can be triggered using multiple sockets that 598c344203eSDavid van Moolenbroek * have in-flight file descriptors referencing each other. 599c344203eSDavid van Moolenbroek * 600c344203eSDavid van Moolenbroek * A proper solution for these problems may consist of some form of 601c344203eSDavid van Moolenbroek * "soft reference counting" where VFS does not count UDS having a 602c344203eSDavid van Moolenbroek * filp open as a real reference. That is tricky business, so for now 603c344203eSDavid van Moolenbroek * we prevent any such problems with the check here. 604c344203eSDavid van Moolenbroek */ 605c344203eSDavid van Moolenbroek if ((vp = rfilp->filp_vno) != NULL && S_ISSOCK(vp->v_mode) && 606c344203eSDavid van Moolenbroek (sp = get_smap_by_dev(vp->v_sdev, NULL)) != NULL && 607c344203eSDavid van Moolenbroek sp->smap_endpt == who_e) { 608c344203eSDavid van Moolenbroek r = EDEADLK; 609c344203eSDavid van Moolenbroek 610c344203eSDavid van Moolenbroek break; 611c344203eSDavid van Moolenbroek } 612c344203eSDavid van Moolenbroek 613433d6423SLionel Sambuc rfp = fp; 614*45443f35SDavid van Moolenbroek flags &= ~COPYFD_CLOEXEC; 615433d6423SLionel Sambuc 616433d6423SLionel Sambuc /* FALLTHROUGH */ 617433d6423SLionel Sambuc case COPYFD_TO: 618433d6423SLionel Sambuc /* Find a free file descriptor slot in the local or remote process. */ 619433d6423SLionel Sambuc for (fd = 0; fd < OPEN_MAX; fd++) 620433d6423SLionel Sambuc if (rfp->fp_filp[fd] == NULL) 621433d6423SLionel Sambuc break; 622433d6423SLionel Sambuc 623433d6423SLionel Sambuc /* If found, fill the slot and return the slot number. */ 624433d6423SLionel Sambuc if (fd < OPEN_MAX) { 625433d6423SLionel Sambuc rfp->fp_filp[fd] = rfilp; 626*45443f35SDavid van Moolenbroek if (flags & COPYFD_CLOEXEC) 627*45443f35SDavid van Moolenbroek FD_SET(fd, &rfp->fp_cloexec_set); 628433d6423SLionel Sambuc rfilp->filp_count++; 629433d6423SLionel Sambuc r = fd; 630433d6423SLionel Sambuc } else 631433d6423SLionel Sambuc r = EMFILE; 632433d6423SLionel Sambuc 633433d6423SLionel Sambuc break; 634433d6423SLionel Sambuc 635433d6423SLionel Sambuc case COPYFD_CLOSE: 636433d6423SLionel Sambuc /* This should be used ONLY to revert a successful copy-to operation, 637433d6423SLionel Sambuc * and assumes that the filp is still in use by the caller as well. 638433d6423SLionel Sambuc */ 639433d6423SLionel Sambuc if (rfilp->filp_count > 1) { 640433d6423SLionel Sambuc rfilp->filp_count--; 641433d6423SLionel Sambuc rfp->fp_filp[fd] = NULL; 642433d6423SLionel Sambuc r = OK; 643433d6423SLionel Sambuc } else 644433d6423SLionel Sambuc r = EBADF; 645433d6423SLionel Sambuc 646433d6423SLionel Sambuc break; 647433d6423SLionel Sambuc 648433d6423SLionel Sambuc default: 649433d6423SLionel Sambuc r = EINVAL; 650433d6423SLionel Sambuc } 651433d6423SLionel Sambuc 652433d6423SLionel Sambuc unlock_filp(rfilp); 653433d6423SLionel Sambuc 654433d6423SLionel Sambuc return(r); 655433d6423SLionel Sambuc } 656