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