1 /* This file contains the procedures for creating, opening, closing, and 2 * seeking on files. 3 * 4 * The entry points into this file are 5 * do_open: perform the OPEN system call 6 * do_mknod: perform the MKNOD system call 7 * do_mkdir: perform the MKDIR system call 8 * do_close: perform the CLOSE system call 9 * do_lseek: perform the LSEEK system call 10 */ 11 12 #include "fs.h" 13 #include <sys/stat.h> 14 #include <fcntl.h> 15 #include <string.h> 16 #include <unistd.h> 17 #include <minix/callnr.h> 18 #include <minix/com.h> 19 #include <minix/u64.h> 20 #include "file.h" 21 #include "lock.h" 22 #include <sys/dirent.h> 23 #include <assert.h> 24 #include <minix/vfsif.h> 25 #include "vnode.h" 26 #include "vmnt.h" 27 #include "path.h" 28 29 static char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0}; 30 31 static struct vnode *new_node(struct lookup *resolve, int oflags, 32 mode_t bits); 33 static int pipe_open(int fd, struct vnode *vp, mode_t bits, int oflags); 34 35 /*===========================================================================* 36 * do_open * 37 *===========================================================================*/ 38 int do_open(void) 39 { 40 /* Perform the open(name, flags) system call with O_CREAT *not* set. */ 41 int open_flags; 42 char fullpath[PATH_MAX]; 43 44 open_flags = job_m_in.m_lc_vfs_path.flags; 45 46 if (open_flags & O_CREAT) 47 return EINVAL; 48 49 if (copy_path(fullpath, sizeof(fullpath)) != OK) 50 return(err_code); 51 52 return common_open(fullpath, open_flags, 0 /*omode*/, FALSE /*for_exec*/); 53 } 54 55 /*===========================================================================* 56 * do_creat * 57 *===========================================================================*/ 58 int do_creat(void) 59 { 60 /* Perform the open(name, flags, mode) system call with O_CREAT set. */ 61 int open_flags, create_mode; 62 char fullpath[PATH_MAX]; 63 vir_bytes vname; 64 size_t vname_length; 65 66 vname = job_m_in.m_lc_vfs_creat.name; 67 vname_length = job_m_in.m_lc_vfs_creat.len; 68 open_flags = job_m_in.m_lc_vfs_creat.flags; 69 create_mode = job_m_in.m_lc_vfs_creat.mode; 70 71 if (!(open_flags & O_CREAT)) 72 return(EINVAL); 73 74 if (fetch_name(vname, vname_length, fullpath) != OK) 75 return(err_code); 76 77 return common_open(fullpath, open_flags, create_mode, FALSE /*for_exec*/); 78 } 79 80 /*===========================================================================* 81 * common_open * 82 *===========================================================================*/ 83 int common_open(char path[PATH_MAX], int oflags, mode_t omode, int for_exec) 84 { 85 /* Common code from do_creat and do_open. */ 86 int b, r, exist = TRUE; 87 devmajor_t major_dev; 88 dev_t dev; 89 mode_t bits; 90 struct filp *filp, *filp2; 91 struct vnode *vp; 92 struct vmnt *vmp; 93 struct dmap *dp; 94 struct lookup resolve; 95 int fd, start = 0; 96 97 /* Remap the bottom two bits of oflags. */ 98 bits = (mode_t) mode_map[oflags & O_ACCMODE]; 99 if (!bits) return(EINVAL); 100 101 /* See if file descriptor and filp slots are available. */ 102 if ((r = get_fd(fp, start, bits, &fd, &filp)) != OK) 103 return(r); 104 105 lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp); 106 107 /* If O_CREATE is set, try to make the file. */ 108 if (oflags & O_CREAT) { 109 omode = I_REGULAR | (omode & ALLPERMS & fp->fp_umask); 110 vp = new_node(&resolve, oflags, omode); 111 r = err_code; 112 if (r == OK) exist = FALSE; /* We just created the file */ 113 else if (r != EEXIST) { /* other error */ 114 if (vp) unlock_vnode(vp); 115 unlock_filp(filp); 116 return(r); 117 } 118 else exist = !(oflags & O_EXCL);/* file exists, if the O_EXCL 119 flag is set this is an error */ 120 } else { 121 /* Scan path name */ 122 resolve.l_vmnt_lock = VMNT_READ; 123 resolve.l_vnode_lock = VNODE_OPCL; 124 if ((vp = eat_path(&resolve, fp)) == NULL) { 125 unlock_filp(filp); 126 return(err_code); 127 } 128 129 if (vmp != NULL) unlock_vmnt(vmp); 130 } 131 132 /* Claim the file descriptor and filp slot and fill them in. */ 133 fp->fp_filp[fd] = filp; 134 filp->filp_count = 1; 135 filp->filp_vno = vp; 136 filp->filp_flags = oflags; 137 if (oflags & O_CLOEXEC) 138 FD_SET(fd, &fp->fp_cloexec_set); 139 140 /* Only do the normal open code if we didn't just create the file. */ 141 if (exist) { 142 /* Check permissions based on the given open flags, except when we are 143 * opening an executable for the purpose of passing a file descriptor 144 * to its interpreter for execution, in which case we check the X bit. 145 */ 146 if ((r = forbidden(fp, vp, for_exec ? X_BIT : bits)) == OK) { 147 /* Opening reg. files, directories, and special files differ */ 148 switch (vp->v_mode & S_IFMT) { 149 case S_IFREG: 150 /* Truncate regular file if O_TRUNC. */ 151 if (oflags & O_TRUNC) { 152 if ((r = forbidden(fp, vp, W_BIT)) != OK) 153 break; 154 upgrade_vnode_lock(vp); 155 truncate_vnode(vp, 0); 156 } 157 break; 158 case S_IFDIR: 159 /* Directories may be read but not written. */ 160 r = (bits & W_BIT ? EISDIR : OK); 161 break; 162 case S_IFCHR: 163 /* Invoke the driver for special processing. */ 164 dev = vp->v_sdev; 165 /* TTY needs to know about the O_NOCTTY flag. */ 166 r = cdev_open(fd, dev, bits | (oflags & O_NOCTTY)); 167 vp = filp->filp_vno; /* Might be updated by 168 * cdev_open after cloning */ 169 break; 170 case S_IFBLK: 171 172 lock_bsf(); 173 174 /* Invoke the driver for special processing. */ 175 dev = vp->v_sdev; 176 r = bdev_open(dev, bits); 177 if (r != OK) { 178 unlock_bsf(); 179 break; 180 } 181 182 major_dev = major(vp->v_sdev); 183 dp = &dmap[major_dev]; 184 if (dp->dmap_driver == NONE) { 185 printf("VFS: block driver disappeared!\n"); 186 unlock_bsf(); 187 r = ENXIO; 188 break; 189 } 190 191 /* Check whether the device is mounted or not. If so, 192 * then that FS is responsible for this device. 193 * Otherwise we default to ROOT_FS. 194 */ 195 vp->v_bfs_e = ROOT_FS_E; /* By default */ 196 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) 197 if (vmp->m_dev == vp->v_sdev && 198 !(vmp->m_flags & VMNT_FORCEROOTBSF)) { 199 vp->v_bfs_e = vmp->m_fs_e; 200 } 201 202 /* Send the driver label to the file system that will 203 * handle the block I/O requests (even when its label 204 * and endpoint are known already), but only when it is 205 * the root file system. Other file systems will 206 * already have it anyway. 207 */ 208 if (vp->v_bfs_e != ROOT_FS_E) { 209 unlock_bsf(); 210 break; 211 } 212 213 if (req_newdriver(vp->v_bfs_e, vp->v_sdev, 214 dp->dmap_label) != OK) { 215 printf("VFS: error sending driver label\n"); 216 bdev_close(dev); 217 r = ENXIO; 218 } 219 unlock_bsf(); 220 break; 221 222 case S_IFIFO: 223 /* Create a mapped inode on PFS which handles reads 224 and writes to this named pipe. */ 225 upgrade_vnode_lock(vp); 226 r = map_vnode(vp, PFS_PROC_NR); 227 if (r == OK) { 228 if (vp->v_ref_count == 1) { 229 if (vp->v_size != 0) 230 r = truncate_vnode(vp, 0); 231 } 232 oflags |= O_APPEND; /* force append mode */ 233 filp->filp_flags = oflags; 234 } 235 if (r == OK) { 236 r = pipe_open(fd, vp, bits, oflags); 237 } 238 if (r != ENXIO) { 239 /* See if someone else is doing a rd or wt on 240 * the FIFO. If so, use its filp entry so the 241 * file position will be automatically shared. 242 */ 243 b = (bits & R_BIT ? R_BIT : W_BIT); 244 filp->filp_count = 0; /* don't find self */ 245 if ((filp2 = find_filp(vp, b)) != NULL) { 246 /* Co-reader or writer found. Use it.*/ 247 fp->fp_filp[fd] = filp2; 248 filp2->filp_count++; 249 filp2->filp_vno = vp; 250 filp2->filp_flags = oflags; 251 252 /* v_count was incremented after the vnode 253 * has been found. i_count was incremented 254 * incorrectly in FS, not knowing that we 255 * were going to use an existing filp 256 * entry. Correct this error. 257 */ 258 unlock_vnode(vp); 259 put_vnode(vp); 260 } else { 261 /* Nobody else found. Restore filp. */ 262 filp->filp_count = 1; 263 } 264 } 265 break; 266 case S_IFSOCK: 267 r = EOPNOTSUPP; 268 break; 269 default: 270 printf("VFS: attempt to open file <%llu,%llu> of " 271 "type 0%o\n", vp->v_dev, vp->v_inode_nr, 272 vp->v_mode & S_IFMT); 273 r = EIO; 274 } 275 } 276 } 277 278 unlock_filp(filp); 279 280 /* If error, release inode. */ 281 if (r != OK) { 282 if (r != SUSPEND) { 283 fp->fp_filp[fd] = NULL; 284 filp->filp_count = 0; 285 filp->filp_vno = NULL; 286 put_vnode(vp); 287 } 288 } else { 289 r = fd; 290 } 291 292 return(r); 293 } 294 295 296 /*===========================================================================* 297 * new_node * 298 *===========================================================================*/ 299 static struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits) 300 { 301 /* Try to create a new inode and return a pointer to it. If the inode already 302 exists, return a pointer to it as well, but set err_code accordingly. 303 NULL is returned if the path cannot be resolved up to the last 304 directory, or when the inode cannot be created due to permissions or 305 otherwise. */ 306 struct vnode *dirp, *vp; 307 struct vmnt *dir_vmp, *vp_vmp; 308 int r; 309 struct node_details res; 310 struct lookup findnode; 311 char *path; 312 313 path = resolve->l_path; /* For easy access */ 314 315 lookup_init(&findnode, path, resolve->l_flags, &dir_vmp, &dirp); 316 findnode.l_vmnt_lock = VMNT_WRITE; 317 findnode.l_vnode_lock = VNODE_WRITE; /* dir node */ 318 319 /* When O_CREAT and O_EXCL flags are set, the path may not be named by a 320 * symbolic link. */ 321 if (oflags & O_EXCL) findnode.l_flags |= PATH_RET_SYMLINK; 322 323 /* See if the path can be opened down to the last directory. */ 324 if ((dirp = last_dir(&findnode, fp)) == NULL) return(NULL); 325 326 /* The final directory is accessible. Get final component of the path. */ 327 lookup_init(&findnode, findnode.l_path, findnode.l_flags, &vp_vmp, &vp); 328 findnode.l_vmnt_lock = VMNT_WRITE; 329 findnode.l_vnode_lock = (oflags & O_TRUNC) ? VNODE_WRITE : VNODE_OPCL; 330 vp = advance(dirp, &findnode, fp); 331 assert(vp_vmp == NULL); /* Lookup to last dir should have yielded lock 332 * on vmp or final component does not exist. 333 * Either way, vp_vmp ought to be not set. 334 */ 335 336 /* The combination of a symlink with absolute path followed by a danglink 337 * symlink results in a new path that needs to be re-resolved entirely. */ 338 if (path[0] == '/') { 339 unlock_vnode(dirp); 340 unlock_vmnt(dir_vmp); 341 put_vnode(dirp); 342 if (vp != NULL) { 343 unlock_vnode(vp); 344 put_vnode(vp); 345 } 346 return new_node(resolve, oflags, bits); 347 } 348 349 if (vp == NULL && err_code == ENOENT) { 350 /* Last path component does not exist. Make a new directory entry. */ 351 if ((vp = get_free_vnode()) == NULL) { 352 /* Can't create new entry: out of vnodes. */ 353 unlock_vnode(dirp); 354 unlock_vmnt(dir_vmp); 355 put_vnode(dirp); 356 return(NULL); 357 } 358 359 lock_vnode(vp, VNODE_OPCL); 360 upgrade_vmnt_lock(dir_vmp); /* Creating file, need exclusive access */ 361 362 if ((r = forbidden(fp, dirp, W_BIT|X_BIT)) != OK || 363 (r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid, 364 fp->fp_effgid, path, &res)) != OK ) { 365 /* Can't create inode either due to permissions or some other 366 * problem. In case r is EEXIST, we might be dealing with a 367 * dangling symlink.*/ 368 369 /* Downgrade lock to prevent deadlock during symlink resolving*/ 370 downgrade_vmnt_lock(dir_vmp); 371 372 if (r == EEXIST) { 373 struct vnode *slp, *old_wd; 374 375 376 /* Resolve path up to symlink */ 377 findnode.l_flags = PATH_RET_SYMLINK; 378 findnode.l_vnode_lock = VNODE_READ; 379 findnode.l_vnode = &slp; 380 slp = advance(dirp, &findnode, fp); 381 if (slp != NULL) { 382 if (S_ISLNK(slp->v_mode)) { 383 /* Get contents of link */ 384 385 r = req_rdlink(slp->v_fs_e, 386 slp->v_inode_nr, 387 VFS_PROC_NR, 388 (vir_bytes) path, 389 PATH_MAX - 1, 0); 390 if (r < 0) { 391 /* Failed to read link */ 392 unlock_vnode(slp); 393 unlock_vnode(dirp); 394 unlock_vmnt(dir_vmp); 395 put_vnode(slp); 396 put_vnode(dirp); 397 err_code = r; 398 return(NULL); 399 } 400 path[r] = '\0'; /* Terminate path */ 401 } 402 unlock_vnode(slp); 403 put_vnode(slp); 404 } 405 406 /* Try to create the inode the dangling symlink was 407 * pointing to. We have to use dirp as starting point 408 * as there might be multiple successive symlinks 409 * crossing multiple mountpoints. 410 * Unlock vnodes and vmnts as we're going to recurse. 411 */ 412 unlock_vnode(dirp); 413 unlock_vnode(vp); 414 unlock_vmnt(dir_vmp); 415 416 old_wd = fp->fp_wd; /* Save orig. working dirp */ 417 fp->fp_wd = dirp; 418 vp = new_node(resolve, oflags, bits); 419 fp->fp_wd = old_wd; /* Restore */ 420 421 if (vp != NULL) { 422 put_vnode(dirp); 423 *(resolve->l_vnode) = vp; 424 return(vp); 425 } 426 r = err_code; 427 } 428 429 if (r == EEXIST) 430 err_code = EIO; /* Impossible, we have verified that 431 * the last component doesn't exist and 432 * is not a dangling symlink. */ 433 else 434 err_code = r; 435 436 unlock_vmnt(dir_vmp); 437 unlock_vnode(dirp); 438 unlock_vnode(vp); 439 put_vnode(dirp); 440 return(NULL); 441 } 442 443 /* Store results and mark vnode in use */ 444 445 vp->v_fs_e = res.fs_e; 446 vp->v_inode_nr = res.inode_nr; 447 vp->v_mode = res.fmode; 448 vp->v_size = res.fsize; 449 vp->v_uid = res.uid; 450 vp->v_gid = res.gid; 451 vp->v_sdev = res.dev; 452 vp->v_vmnt = dirp->v_vmnt; 453 vp->v_dev = vp->v_vmnt->m_dev; 454 vp->v_fs_count = 1; 455 vp->v_ref_count = 1; 456 } else { 457 /* Either last component exists, or there is some other problem. */ 458 if (vp != NULL) { 459 r = EEXIST; /* File exists or a symlink names a file while 460 * O_EXCL is set. */ 461 } else 462 r = err_code; /* Other problem. */ 463 } 464 465 err_code = r; 466 /* When dirp equals vp, we shouldn't release the lock as a vp is locked only 467 * once. Releasing the lock would cause the resulting vp not be locked and 468 * cause mayhem later on. */ 469 if (dirp != vp) { 470 unlock_vnode(dirp); 471 } 472 unlock_vmnt(dir_vmp); 473 put_vnode(dirp); 474 475 *(resolve->l_vnode) = vp; 476 return(vp); 477 } 478 479 480 /*===========================================================================* 481 * pipe_open * 482 *===========================================================================*/ 483 static int pipe_open(int fd, struct vnode *vp, mode_t bits, int oflags) 484 { 485 /* This function is called from common_open. It checks if 486 * there is at least one reader/writer pair for the pipe, if not 487 * it suspends the caller, otherwise it revives all other blocked 488 * processes hanging on the pipe. 489 */ 490 491 if ((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) return(ENXIO); 492 493 /* Find the reader/writer at the other end of the pipe */ 494 if (find_filp(vp, bits & W_BIT ? R_BIT : W_BIT) == NULL) { 495 /* Not found */ 496 if (oflags & O_NONBLOCK) { 497 if (bits & W_BIT) return(ENXIO); 498 } else { 499 /* Let's wait for the other side to show up */ 500 fp->fp_popen.fd = fd; 501 suspend(FP_BLOCKED_ON_POPEN); 502 return(SUSPEND); 503 } 504 } else if (susp_count > 0) { /* revive blocked processes */ 505 release(vp, VFS_OPEN, susp_count); 506 } 507 return(OK); 508 } 509 510 511 /*===========================================================================* 512 * do_mknod * 513 *===========================================================================*/ 514 int do_mknod(void) 515 { 516 /* Perform the mknod(name, mode, addr) system call. */ 517 register mode_t bits, mode_bits; 518 int r; 519 struct vnode *vp; 520 struct vmnt *vmp; 521 char fullpath[PATH_MAX]; 522 struct lookup resolve; 523 vir_bytes vname1; 524 size_t vname1_length; 525 dev_t dev; 526 527 vname1 = job_m_in.m_lc_vfs_mknod.name; 528 vname1_length = job_m_in.m_lc_vfs_mknod.len; 529 mode_bits = job_m_in.m_lc_vfs_mknod.mode; 530 dev = job_m_in.m_lc_vfs_mknod.device; 531 532 /* If the path names a symbolic link, mknod() shall fail with EEXIST. */ 533 lookup_init(&resolve, fullpath, PATH_RET_SYMLINK, &vmp, &vp); 534 resolve.l_vmnt_lock = VMNT_WRITE; 535 resolve.l_vnode_lock = VNODE_WRITE; 536 537 /* Only the super_user may make nodes other than fifos. */ 538 if (!super_user && (!S_ISFIFO(mode_bits) && !S_ISSOCK(mode_bits))) { 539 return(EPERM); 540 } 541 bits = (mode_bits & S_IFMT) | (mode_bits & ACCESSPERMS & fp->fp_umask); 542 543 /* Open directory that's going to hold the new node. */ 544 if (fetch_name(vname1, vname1_length, fullpath) != OK) return(err_code); 545 if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code); 546 547 /* Make sure that the object is a directory */ 548 if (!S_ISDIR(vp->v_mode)) { 549 r = ENOTDIR; 550 } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { 551 r = req_mknod(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid, 552 fp->fp_effgid, bits, dev); 553 } 554 555 unlock_vnode(vp); 556 unlock_vmnt(vmp); 557 put_vnode(vp); 558 return(r); 559 } 560 561 /*===========================================================================* 562 * do_mkdir * 563 *===========================================================================*/ 564 int do_mkdir(void) 565 { 566 /* Perform the mkdir(name, mode) system call. */ 567 mode_t bits; /* mode bits for the new inode */ 568 int r; 569 struct vnode *vp; 570 struct vmnt *vmp; 571 char fullpath[PATH_MAX]; 572 struct lookup resolve; 573 mode_t dirmode; 574 575 if (copy_path(fullpath, sizeof(fullpath)) != OK) 576 return(err_code); 577 dirmode = job_m_in.m_lc_vfs_path.mode; 578 579 lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); 580 resolve.l_vmnt_lock = VMNT_WRITE; 581 resolve.l_vnode_lock = VNODE_WRITE; 582 583 bits = I_DIRECTORY | (dirmode & RWX_MODES & fp->fp_umask); 584 if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code); 585 586 /* Make sure that the object is a directory */ 587 if (!S_ISDIR(vp->v_mode)) { 588 r = ENOTDIR; 589 } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) { 590 r = req_mkdir(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid, 591 fp->fp_effgid, bits); 592 } 593 594 unlock_vnode(vp); 595 unlock_vmnt(vmp); 596 put_vnode(vp); 597 return(r); 598 } 599 600 /*===========================================================================* 601 * actual_lseek * 602 *===========================================================================*/ 603 int actual_lseek(struct fproc *rfp, int seekfd, int seekwhence, off_t offset, 604 off_t *newposp) 605 { 606 register struct filp *rfilp; 607 int r = OK; 608 off_t pos, newpos; 609 610 /* Check to see if the file descriptor is valid. */ 611 if ( (rfilp = get_filp2(rfp, seekfd, VNODE_READ)) == NULL) { 612 return(err_code); 613 } 614 615 /* No lseek on pipes. */ 616 if (S_ISFIFO(rfilp->filp_vno->v_mode)) { 617 unlock_filp(rfilp); 618 return(ESPIPE); 619 } 620 621 /* The value of 'whence' determines the start position to use. */ 622 switch(seekwhence) { 623 case SEEK_SET: pos = 0; break; 624 case SEEK_CUR: pos = rfilp->filp_pos; break; 625 case SEEK_END: pos = rfilp->filp_vno->v_size; break; 626 default: unlock_filp(rfilp); return(EINVAL); 627 } 628 629 newpos = pos + offset; 630 631 /* Check for overflow. */ 632 if ((offset > 0) && (newpos <= pos)) { 633 r = EOVERFLOW; 634 } else if ((offset < 0) && (newpos >= pos)) { 635 r = EOVERFLOW; 636 } else { 637 if (newposp != NULL) *newposp = newpos; 638 639 if (newpos != rfilp->filp_pos) { 640 rfilp->filp_pos = newpos; 641 642 /* Inhibit read ahead request */ 643 r = req_inhibread(rfilp->filp_vno->v_fs_e, 644 rfilp->filp_vno->v_inode_nr); 645 } 646 } 647 648 unlock_filp(rfilp); 649 return(r); 650 } 651 652 /*===========================================================================* 653 * do_lseek * 654 *===========================================================================*/ 655 int do_lseek(void) 656 { 657 /* Perform the lseek(2) system call. */ 658 off_t newpos = 0; 659 int r; 660 661 if ((r = actual_lseek(fp, job_m_in.m_lc_vfs_lseek.fd, 662 job_m_in.m_lc_vfs_lseek.whence, job_m_in.m_lc_vfs_lseek.offset, 663 &newpos)) != OK) 664 return r; 665 666 /* insert the new position into the output message */ 667 job_m_out.m_vfs_lc_lseek.offset = newpos; 668 return OK; 669 } 670 671 /*===========================================================================* 672 * do_close * 673 *===========================================================================*/ 674 int do_close(void) 675 { 676 /* Perform the close(fd) system call. */ 677 int thefd = job_m_in.m_lc_vfs_close.fd; 678 return close_fd(fp, thefd); 679 } 680 681 682 /*===========================================================================* 683 * close_fd * 684 *===========================================================================*/ 685 int 686 close_fd(struct fproc *rfp, int fd_nr) 687 { 688 /* Perform the close(fd) system call. */ 689 register struct filp *rfilp; 690 register struct vnode *vp; 691 struct file_lock *flp; 692 int lock_count; 693 694 /* First locate the vnode that belongs to the file descriptor. */ 695 if ( (rfilp = get_filp2(rfp, fd_nr, VNODE_OPCL)) == NULL) return(err_code); 696 697 vp = rfilp->filp_vno; 698 699 /* first, make all future get_filp2()'s fail; otherwise 700 * we might try to close the same fd in different threads 701 */ 702 rfp->fp_filp[fd_nr] = NULL; 703 704 close_filp(rfilp); 705 706 FD_CLR(fd_nr, &rfp->fp_cloexec_set); 707 708 /* Check to see if the file is locked. If so, release all locks. */ 709 if (nr_locks > 0) { 710 lock_count = nr_locks; /* save count of locks */ 711 for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) { 712 if (flp->lock_type == 0) continue; /* slot not in use */ 713 if (flp->lock_vnode == vp && flp->lock_pid == rfp->fp_pid) { 714 flp->lock_type = 0; 715 nr_locks--; 716 } 717 } 718 if (nr_locks < lock_count) 719 lock_revive(); /* one or more locks released */ 720 } 721 722 return(OK); 723 } 724