123405Smckusick /* 251502Sbostic * Copyright (c) 1986, 1989, 1991 Regents of the University of California. 337737Smckusick * All rights reserved. 423405Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*53593Sheideman * @(#)lfs_vnops.c 7.82 (Berkeley) 05/15/92 823405Smckusick */ 937Sbill 1051482Sbostic #include <sys/param.h> 1151482Sbostic #include <sys/systm.h> 1251482Sbostic #include <sys/namei.h> 1351482Sbostic #include <sys/resourcevar.h> 1451482Sbostic #include <sys/kernel.h> 1551482Sbostic #include <sys/file.h> 1651482Sbostic #include <sys/stat.h> 1751482Sbostic #include <sys/buf.h> 1851482Sbostic #include <sys/proc.h> 1951482Sbostic #include <sys/conf.h> 2051482Sbostic #include <sys/mount.h> 2151482Sbostic #include <sys/vnode.h> 2251482Sbostic #include <sys/specdev.h> 2351482Sbostic #include <sys/fifo.h> 2451482Sbostic #include <sys/malloc.h> 2537Sbill 2653321Smckusick #include <vm/vm.h> 2753321Smckusick 2851502Sbostic #include <ufs/ufs/quota.h> 2951502Sbostic #include <ufs/ufs/inode.h> 3051502Sbostic #include <ufs/ufs/dir.h> 3151502Sbostic #include <ufs/ufs/ufs_extern.h> 3247571Skarels 3351502Sbostic #include <ufs/lfs/lfs.h> 3451502Sbostic #include <ufs/lfs/lfs_extern.h> 3551134Sbostic 3651482Sbostic /* Global vfs data structures for lfs. */ 3753533Sheideman int (**lfs_vnodeop_p)(); 3853533Sheideman struct vnodeopv_entry_desc lfs_vnodeop_entries[] = { 3953533Sheideman { &vop_default_desc, vn_default_error }, 4053533Sheideman { &vop_lookup_desc, ufs_lookup }, /* lookup */ 4153533Sheideman { &vop_create_desc, ufs_create }, /* create */ 4253533Sheideman { &vop_mknod_desc, ufs_mknod }, /* mknod */ 4353533Sheideman { &vop_open_desc, ufs_open }, /* open */ 4453533Sheideman { &vop_close_desc, ufs_close }, /* close */ 4553533Sheideman { &vop_access_desc, ufs_access }, /* access */ 4653533Sheideman { &vop_getattr_desc, ufs_getattr }, /* getattr */ 4753533Sheideman { &vop_setattr_desc, ufs_setattr }, /* setattr */ 4853533Sheideman { &vop_read_desc, lfs_read }, /* read */ 4953533Sheideman { &vop_write_desc, lfs_write }, /* write */ 5053533Sheideman { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 5153533Sheideman { &vop_select_desc, ufs_select }, /* select */ 5253533Sheideman { &vop_mmap_desc, ufs_mmap }, /* mmap */ 5353533Sheideman { &vop_fsync_desc, lfs_fsync }, /* fsync */ 5453533Sheideman { &vop_seek_desc, ufs_seek }, /* seek */ 5553533Sheideman { &vop_remove_desc, ufs_remove }, /* remove */ 5653533Sheideman { &vop_link_desc, ufs_link }, /* link */ 5753533Sheideman { &vop_rename_desc, ufs_rename }, /* rename */ 5853533Sheideman { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */ 5953533Sheideman { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */ 6053533Sheideman { &vop_symlink_desc, ufs_symlink }, /* symlink */ 6153533Sheideman { &vop_readdir_desc, ufs_readdir }, /* readdir */ 6253533Sheideman { &vop_readlink_desc, ufs_readlink }, /* readlink */ 6353533Sheideman { &vop_abortop_desc, ufs_abortop }, /* abortop */ 6453533Sheideman { &vop_inactive_desc, lfs_inactive }, /* inactive */ 6553533Sheideman { &vop_reclaim_desc, ufs_reclaim }, /* reclaim */ 6653533Sheideman { &vop_lock_desc, ufs_lock }, /* lock */ 6753533Sheideman { &vop_unlock_desc, ufs_unlock }, /* unlock */ 6853533Sheideman { &vop_bmap_desc, lfs_bmap }, /* bmap */ 6953533Sheideman { &vop_strategy_desc, ufs_strategy }, /* strategy */ 7053533Sheideman { &vop_print_desc, ufs_print }, /* print */ 7153533Sheideman { &vop_islocked_desc, ufs_islocked }, /* islocked */ 7253533Sheideman { &vop_advlock_desc, ufs_advlock }, /* advlock */ 7353533Sheideman { &vop_blkatoff_desc, lfs_blkatoff }, /* blkatoff */ 7453533Sheideman { &vop_vget_desc, lfs_vget }, /* vget */ 7553533Sheideman { &vop_valloc_desc, lfs_valloc }, /* valloc */ 7653533Sheideman { &vop_vfree_desc, lfs_vfree }, /* vfree */ 7753533Sheideman { &vop_truncate_desc, lfs_truncate }, /* truncate */ 7853533Sheideman { &vop_update_desc, lfs_update }, /* update */ 7953533Sheideman { &vop_bwrite_desc, lfs_bwrite }, /* bwrite */ 8053533Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 8151482Sbostic }; 8253533Sheideman struct vnodeopv_desc lfs_vnodeop_opv_desc = 8353533Sheideman { &lfs_vnodeop_p, lfs_vnodeop_entries }; 846254Sroot 8553533Sheideman int (**lfs_specop_p)(); 8653533Sheideman struct vnodeopv_entry_desc lfs_specop_entries[] = { 8753533Sheideman { &vop_default_desc, vn_default_error }, 8853533Sheideman { &vop_lookup_desc, spec_lookup }, /* lookup */ 8953533Sheideman { &vop_create_desc, spec_create }, /* create */ 9053533Sheideman { &vop_mknod_desc, spec_mknod }, /* mknod */ 9153533Sheideman { &vop_open_desc, spec_open }, /* open */ 9253533Sheideman { &vop_close_desc, ufsspec_close }, /* close */ 9353533Sheideman { &vop_access_desc, ufs_access }, /* access */ 9453533Sheideman { &vop_getattr_desc, ufs_getattr }, /* getattr */ 9553533Sheideman { &vop_setattr_desc, ufs_setattr }, /* setattr */ 9653533Sheideman { &vop_read_desc, ufsspec_read }, /* read */ 9753533Sheideman { &vop_write_desc, ufsspec_write }, /* write */ 9853533Sheideman { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 9953533Sheideman { &vop_select_desc, spec_select }, /* select */ 10053533Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */ 10153533Sheideman { &vop_fsync_desc, spec_fsync }, /* fsync */ 10253533Sheideman { &vop_seek_desc, spec_seek }, /* seek */ 10353533Sheideman { &vop_remove_desc, spec_remove }, /* remove */ 10453533Sheideman { &vop_link_desc, spec_link }, /* link */ 10553533Sheideman { &vop_rename_desc, spec_rename }, /* rename */ 10653533Sheideman { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 10753533Sheideman { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 10853533Sheideman { &vop_symlink_desc, spec_symlink }, /* symlink */ 10953533Sheideman { &vop_readdir_desc, spec_readdir }, /* readdir */ 11053533Sheideman { &vop_readlink_desc, spec_readlink }, /* readlink */ 11153533Sheideman { &vop_abortop_desc, spec_abortop }, /* abortop */ 11253533Sheideman { &vop_inactive_desc, lfs_inactive }, /* inactive */ 11353533Sheideman { &vop_reclaim_desc, ufs_reclaim }, /* reclaim */ 11453533Sheideman { &vop_lock_desc, ufs_lock }, /* lock */ 11553533Sheideman { &vop_unlock_desc, ufs_unlock }, /* unlock */ 11653533Sheideman { &vop_bmap_desc, spec_bmap }, /* bmap */ 11753533Sheideman { &vop_strategy_desc, spec_strategy }, /* strategy */ 11853533Sheideman { &vop_print_desc, ufs_print }, /* print */ 11953533Sheideman { &vop_islocked_desc, ufs_islocked }, /* islocked */ 12053533Sheideman { &vop_advlock_desc, spec_advlock }, /* advlock */ 12153533Sheideman { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 12253533Sheideman { &vop_vget_desc, spec_vget }, /* vget */ 12353533Sheideman { &vop_valloc_desc, spec_valloc }, /* valloc */ 12453533Sheideman { &vop_vfree_desc, spec_vfree }, /* vfree */ 12553533Sheideman { &vop_truncate_desc, spec_truncate }, /* truncate */ 12653533Sheideman { &vop_update_desc, lfs_update }, /* update */ 12753533Sheideman { &vop_bwrite_desc, lfs_bwrite }, /* bwrite */ 12853533Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 12951558Smckusick }; 13053533Sheideman struct vnodeopv_desc lfs_specop_opv_desc = 13153533Sheideman { &lfs_specop_p, lfs_specop_entries }; 13251558Smckusick 13351558Smckusick #ifdef FIFO 13453533Sheideman int (**lfs_fifoop_p)(); 13553533Sheideman struct vnodeopv_entry_desc lfs_fifoop_entries[] = { 13653533Sheideman { &vop_default_desc, vn_default_error }, 13753533Sheideman { &vop_lookup_desc, fifo_lookup }, /* lookup */ 13853533Sheideman { &vop_create_desc, fifo_create }, /* create */ 13953533Sheideman { &vop_mknod_desc, fifo_mknod }, /* mknod */ 14053533Sheideman { &vop_open_desc, fifo_open }, /* open */ 14153533Sheideman { &vop_close_desc, ufsfifo_close }, /* close */ 14253533Sheideman { &vop_access_desc, ufs_access }, /* access */ 14353533Sheideman { &vop_getattr_desc, ufs_getattr }, /* getattr */ 14453533Sheideman { &vop_setattr_desc, ufs_setattr }, /* setattr */ 14553533Sheideman { &vop_read_desc, ufsfifo_read }, /* read */ 14653533Sheideman { &vop_write_desc, ufsfifo_write }, /* write */ 14753533Sheideman { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 14853533Sheideman { &vop_select_desc, fifo_select }, /* select */ 14953533Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */ 15053533Sheideman { &vop_fsync_desc, fifo_fsync }, /* fsync */ 15153533Sheideman { &vop_seek_desc, fifo_seek }, /* seek */ 15253533Sheideman { &vop_remove_desc, fifo_remove }, /* remove */ 15353533Sheideman { &vop_link_desc, fifo_link }, /* link */ 15453533Sheideman { &vop_rename_desc, fifo_rename }, /* rename */ 15553533Sheideman { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 15653533Sheideman { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 15753533Sheideman { &vop_symlink_desc, fifo_symlink }, /* symlink */ 15853533Sheideman { &vop_readdir_desc, fifo_readdir }, /* readdir */ 15953533Sheideman { &vop_readlink_desc, fifo_readlink }, /* readlink */ 16053533Sheideman { &vop_abortop_desc, fifo_abortop }, /* abortop */ 16153533Sheideman { &vop_inactive_desc, lfs_inactive }, /* inactive */ 16253533Sheideman { &vop_reclaim_desc, ufs_reclaim }, /* reclaim */ 16353533Sheideman { &vop_lock_desc, ufs_lock }, /* lock */ 16453533Sheideman { &vop_unlock_desc, ufs_unlock }, /* unlock */ 16553533Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */ 16653533Sheideman { &vop_strategy_desc, fifo_strategy }, /* strategy */ 16753533Sheideman { &vop_print_desc, ufs_print }, /* print */ 16853533Sheideman { &vop_islocked_desc, ufs_islocked }, /* islocked */ 16953533Sheideman { &vop_advlock_desc, fifo_advlock }, /* advlock */ 17053533Sheideman { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 17153533Sheideman { &vop_vget_desc, fifo_vget }, /* vget */ 17253533Sheideman { &vop_valloc_desc, fifo_valloc }, /* valloc */ 17353533Sheideman { &vop_vfree_desc, fifo_vfree }, /* vfree */ 17453533Sheideman { &vop_truncate_desc, fifo_truncate }, /* truncate */ 17553533Sheideman { &vop_update_desc, lfs_update }, /* update */ 17653533Sheideman { &vop_bwrite_desc, lfs_bwrite }, /* bwrite */ 17753533Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 17851558Smckusick }; 17953533Sheideman struct vnodeopv_desc lfs_fifoop_opv_desc = 18053533Sheideman { &lfs_fifoop_p, lfs_fifoop_entries }; 18151558Smckusick #endif /* FIFO */ 18251558Smckusick 18337Sbill /* 18439608Smckusick * Vnode op for reading. 18539608Smckusick */ 18637737Smckusick /* ARGSUSED */ 18753533Sheideman lfs_read (ap) 18853533Sheideman struct vop_read_args *ap; 18939608Smckusick { 190*53593Sheideman register struct inode *ip = VTOI(ap->a_vp); 19151502Sbostic register struct lfs *fs; /* LFS */ 19239608Smckusick struct buf *bp; 19339608Smckusick daddr_t lbn, bn, rablock; 19453233Smckusick int size, error = 0; 19539608Smckusick long n, on, type; 19653233Smckusick off_t diff; 19739608Smckusick 19851852Sbostic #ifdef VERBOSE 19951852Sbostic printf("lfs_read: ino %d\n", ip->i_number); 20051852Sbostic #endif 20148039Smckusick #ifdef DIAGNOSTIC 202*53593Sheideman if (ap->a_uio->uio_rw != UIO_READ) 20339608Smckusick panic("ufs_read mode"); 20439608Smckusick type = ip->i_mode & IFMT; 20539608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 20639608Smckusick panic("ufs_read type"); 20748039Smckusick #endif 208*53593Sheideman if (ap->a_uio->uio_resid == 0) 20939608Smckusick return (0); 210*53593Sheideman if (ap->a_uio->uio_offset < 0) 21139608Smckusick return (EINVAL); 21239608Smckusick ip->i_flag |= IACC; 21351155Sbostic 21451155Sbostic fs = ip->i_lfs; /* LFS */ 21539608Smckusick do { 216*53593Sheideman lbn = lblkno(fs, ap->a_uio->uio_offset); 217*53593Sheideman on = blkoff(fs, ap->a_uio->uio_offset); 218*53593Sheideman n = MIN((unsigned)(fs->lfs_bsize - on), ap->a_uio->uio_resid); 219*53593Sheideman diff = ip->i_size - ap->a_uio->uio_offset; 22039608Smckusick if (diff <= 0) 22139608Smckusick return (0); 22239608Smckusick if (diff < n) 22339608Smckusick n = diff; 22451155Sbostic size = blksize(fs); /* LFS */ 22539674Smckusick rablock = lbn + 1; 226*53593Sheideman if (ap->a_vp->v_lastr + 1 == lbn && 22739896Smckusick lblktosize(fs, rablock) < ip->i_size) 22852195Smckusick error = breadn(ITOV(ip), lbn, size, &rablock, 22952195Smckusick &size, 1, NOCRED, &bp); 23039608Smckusick else 23139674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 232*53593Sheideman ap->a_vp->v_lastr = lbn; 23339608Smckusick n = MIN(n, size - bp->b_resid); 23439608Smckusick if (error) { 23539608Smckusick brelse(bp); 23639608Smckusick return (error); 23739608Smckusick } 238*53593Sheideman error = uiomove(bp->b_un.b_addr + on, (int)n, ap->a_uio); 239*53593Sheideman if (n + on == fs->lfs_bsize || ap->a_uio->uio_offset == ip->i_size) 24039608Smckusick bp->b_flags |= B_AGE; 24139608Smckusick brelse(bp); 242*53593Sheideman } while (error == 0 && ap->a_uio->uio_resid > 0 && n != 0); 24339608Smckusick return (error); 24439608Smckusick } 24539608Smckusick 24639608Smckusick /* 24739608Smckusick * Vnode op for writing. 24839608Smckusick */ 24953533Sheideman lfs_write (ap) 25053533Sheideman struct vop_write_args *ap; 25139608Smckusick { 25253533Sheideman USES_VOP_TRUNCATE; 25353533Sheideman USES_VOP_UPDATE; 254*53593Sheideman struct proc *p = ap->a_uio->uio_procp; 255*53593Sheideman register struct inode *ip = VTOI(ap->a_vp); 25652091Sbostic register struct lfs *fs; 25739608Smckusick struct buf *bp; 25852091Sbostic daddr_t lbn; 25953233Smckusick off_t osize; 26052091Sbostic int n, on, flags, newblock; 26145722Smckusick int size, resid, error = 0; 26239608Smckusick 26351852Sbostic #ifdef VERBOSE 26451852Sbostic printf("lfs_write ino %d\n", ip->i_number); 26551852Sbostic #endif 26648039Smckusick #ifdef DIAGNOSTIC 267*53593Sheideman if (ap->a_uio->uio_rw != UIO_WRITE) 26852091Sbostic panic("lfs_write mode"); 26948039Smckusick #endif 270*53593Sheideman switch (ap->a_vp->v_type) { 27139608Smckusick case VREG: 272*53593Sheideman if (ap->a_ioflag & IO_APPEND) 273*53593Sheideman ap->a_uio->uio_offset = ip->i_size; 27439608Smckusick /* fall through */ 27539608Smckusick case VLNK: 27639608Smckusick break; 27739608Smckusick 27839608Smckusick case VDIR: 27952091Sbostic /* XXX This may not be correct for LFS. */ 280*53593Sheideman if ((ap->a_ioflag & IO_SYNC) == 0) 28152091Sbostic panic("lfs_write nonsync dir write"); 28239608Smckusick break; 28339608Smckusick 28439608Smckusick default: 28552091Sbostic panic("lfs_write type"); 28639608Smckusick } 287*53593Sheideman if (ap->a_uio->uio_offset < 0) 28839608Smckusick return (EINVAL); 289*53593Sheideman if (ap->a_uio->uio_resid == 0) 29039608Smckusick return (0); 29139608Smckusick /* 29239608Smckusick * Maybe this should be above the vnode op call, but so long as 29339608Smckusick * file servers have no limits, i don't think it matters 29439608Smckusick */ 295*53593Sheideman if (ap->a_vp->v_type == VREG && p && 296*53593Sheideman ap->a_uio->uio_offset + ap->a_uio->uio_resid > 29747571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 29847571Skarels psignal(p, SIGXFSZ); 29939608Smckusick return (EFBIG); 30039608Smckusick } 301*53593Sheideman resid = ap->a_uio->uio_resid; 30239608Smckusick osize = ip->i_size; 30351183Sbostic fs = ip->i_lfs; /* LFS */ 30439674Smckusick flags = 0; 30551183Sbostic #ifdef NOTLFS 306*53593Sheideman if (ap->a_ioflag & IO_SYNC) 30739674Smckusick flags = B_SYNC; 30851183Sbostic #endif 30939608Smckusick do { 310*53593Sheideman lbn = lblkno(fs, ap->a_uio->uio_offset); 311*53593Sheideman on = blkoff(fs, ap->a_uio->uio_offset); 312*53593Sheideman n = MIN((unsigned)(fs->lfs_bsize - on), ap->a_uio->uio_resid); 313*53593Sheideman if (error = lfs_balloc(ap->a_vp, n, lbn, &bp)) 31439608Smckusick break; 315*53593Sheideman if (ap->a_uio->uio_offset + n > ip->i_size) { 316*53593Sheideman ip->i_size = ap->a_uio->uio_offset + n; 317*53593Sheideman vnode_pager_setsize(ap->a_vp, (u_long)ip->i_size); 31845722Smckusick } 31951183Sbostic size = blksize(fs); 320*53593Sheideman (void) vnode_pager_uncache(ap->a_vp); 32139608Smckusick n = MIN(n, size - bp->b_resid); 322*53593Sheideman error = uiomove(bp->b_un.b_addr + on, n, ap->a_uio); 32351183Sbostic #ifdef NOTLFS /* LFS */ 324*53593Sheideman if (ap->a_ioflag & IO_SYNC) 32539608Smckusick (void) bwrite(bp); 32639608Smckusick else if (n + on == fs->fs_bsize) { 32739608Smckusick bp->b_flags |= B_AGE; 32839608Smckusick bawrite(bp); 32939608Smckusick } else 33039608Smckusick bdwrite(bp); 33152091Sbostic ip->i_flag |= IUPD|ICHG; 33251183Sbostic #else 33352091Sbostic /* XXX This doesn't handle IO_SYNC. */ 33452091Sbostic LFS_UBWRITE(bp); 33551183Sbostic #endif 336*53593Sheideman if (ap->a_cred->cr_uid != 0) 33739608Smckusick ip->i_mode &= ~(ISUID|ISGID); 338*53593Sheideman } while (error == 0 && ap->a_uio->uio_resid > 0 && n != 0); 339*53593Sheideman if (error && (ap->a_ioflag & IO_UNIT)) { 340*53593Sheideman (void)VOP_TRUNCATE(ap->a_vp, osize, ap->a_ioflag & IO_SYNC, ap->a_cred); 341*53593Sheideman ap->a_uio->uio_offset -= resid - ap->a_uio->uio_resid; 342*53593Sheideman ap->a_uio->uio_resid = resid; 34339608Smckusick } 344*53593Sheideman if (!error && (ap->a_ioflag & IO_SYNC)) 345*53593Sheideman error = VOP_UPDATE(ap->a_vp, &time, &time, 1); 34639608Smckusick return (error); 34739608Smckusick } 34839608Smckusick 3499167Ssam /* 35037737Smckusick * Synch an open file. 3519167Ssam */ 35237737Smckusick /* ARGSUSED */ 35353533Sheideman lfs_fsync (ap) 35453533Sheideman struct vop_fsync_args *ap; 3557701Ssam { 35653533Sheideman USES_VOP_UPDATE; 35751852Sbostic struct inode *ip; 3587701Ssam 35951852Sbostic #ifdef VERBOSE 36051852Sbostic printf("lfs_fsync\n"); 36151852Sbostic #endif 362*53593Sheideman ip = VTOI(ap->a_vp); 363*53593Sheideman if (ap->a_fflags & FWRITE) 36437737Smckusick ip->i_flag |= ICHG; 365*53593Sheideman return (VOP_UPDATE(ap->a_vp, &time, &time, ap->a_waitfor == MNT_WAIT)); 36637737Smckusick } 36751558Smckusick 36851558Smckusick /* 36951558Smckusick * Last reference to an inode, write the inode out and if necessary, 37051558Smckusick * truncate and deallocate the file. 37151558Smckusick */ 37251558Smckusick int 37353533Sheideman lfs_inactive (ap) 37453533Sheideman struct vop_inactive_args *ap; 37551558Smckusick { 37653533Sheideman USES_VOP_TRUNCATE; 37753533Sheideman USES_VOP_UPDATE; 37853533Sheideman USES_VOP_VFREE; 37951852Sbostic extern int prtactive; 38051558Smckusick register struct inode *ip; 38151558Smckusick int mode, error; 38251558Smckusick 38351852Sbostic #ifdef VERBOSE 38451852Sbostic printf("lfs_inactive\n"); 38551852Sbostic #endif 386*53593Sheideman if (prtactive && ap->a_vp->v_usecount != 0) 387*53593Sheideman vprint("lfs_inactive: pushing active", ap->a_vp); 38851558Smckusick 38951558Smckusick /* Get rid of inodes related to stale file handles. */ 390*53593Sheideman ip = VTOI(ap->a_vp); 39151558Smckusick if (ip->i_mode == 0) { 392*53593Sheideman if ((ap->a_vp->v_flag & VXLOCK) == 0) 393*53593Sheideman vgone(ap->a_vp); 39451558Smckusick return (0); 39551558Smckusick } 39651558Smckusick 39751558Smckusick error = 0; 39851558Smckusick ILOCK(ip); 399*53593Sheideman if (ip->i_nlink <= 0 && (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 40051558Smckusick #ifdef QUOTA 40151558Smckusick if (!getinoquota(ip)) 40251558Smckusick (void)chkiq(ip, -1, NOCRED, 0); 40351558Smckusick #endif 404*53593Sheideman error = VOP_TRUNCATE(ap->a_vp, (off_t)0, 0, NOCRED); 40551558Smckusick mode = ip->i_mode; 40651558Smckusick ip->i_mode = 0; 40751558Smckusick ip->i_rdev = 0; 40851558Smckusick ip->i_flag |= IUPD|ICHG; 409*53593Sheideman VOP_VFREE(ap->a_vp, ip->i_number, mode); 41051558Smckusick } 41151558Smckusick if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) 412*53593Sheideman VOP_UPDATE(ap->a_vp, &time, &time, 0); 41351558Smckusick IUNLOCK(ip); 41451558Smckusick ip->i_flag = 0; 41551558Smckusick /* 41651558Smckusick * If we are done with the inode, reclaim it 41751558Smckusick * so that it can be reused immediately. 41851558Smckusick */ 419*53593Sheideman if (ap->a_vp->v_usecount == 0 && ip->i_mode == 0) 420*53593Sheideman vgone(ap->a_vp); 42151558Smckusick return (error); 42251558Smckusick } 423