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*53867Sheideman * @(#)lfs_vnops.c 7.83 (Berkeley) 06/04/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*53867Sheideman register struct uio *uio = ap->a_uio; 19153593Sheideman register struct inode *ip = VTOI(ap->a_vp); 19251502Sbostic register struct lfs *fs; /* LFS */ 19339608Smckusick struct buf *bp; 19439608Smckusick daddr_t lbn, bn, rablock; 19553233Smckusick int size, error = 0; 19639608Smckusick long n, on, type; 19753233Smckusick off_t diff; 19839608Smckusick 19951852Sbostic #ifdef VERBOSE 20051852Sbostic printf("lfs_read: ino %d\n", ip->i_number); 20151852Sbostic #endif 20248039Smckusick #ifdef DIAGNOSTIC 203*53867Sheideman if (uio->uio_rw != UIO_READ) 20439608Smckusick panic("ufs_read mode"); 20539608Smckusick type = ip->i_mode & IFMT; 20639608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 20739608Smckusick panic("ufs_read type"); 20848039Smckusick #endif 209*53867Sheideman if (uio->uio_resid == 0) 21039608Smckusick return (0); 211*53867Sheideman if (uio->uio_offset < 0) 21239608Smckusick return (EINVAL); 21339608Smckusick ip->i_flag |= IACC; 21451155Sbostic 21551155Sbostic fs = ip->i_lfs; /* LFS */ 21639608Smckusick do { 217*53867Sheideman lbn = lblkno(fs, uio->uio_offset); 218*53867Sheideman on = blkoff(fs, uio->uio_offset); 219*53867Sheideman n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 220*53867Sheideman diff = ip->i_size - uio->uio_offset; 22139608Smckusick if (diff <= 0) 22239608Smckusick return (0); 22339608Smckusick if (diff < n) 22439608Smckusick n = diff; 22551155Sbostic size = blksize(fs); /* LFS */ 22639674Smckusick rablock = lbn + 1; 22753593Sheideman if (ap->a_vp->v_lastr + 1 == lbn && 22839896Smckusick lblktosize(fs, rablock) < ip->i_size) 22952195Smckusick error = breadn(ITOV(ip), lbn, size, &rablock, 23052195Smckusick &size, 1, NOCRED, &bp); 23139608Smckusick else 23239674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 23353593Sheideman ap->a_vp->v_lastr = lbn; 23439608Smckusick n = MIN(n, size - bp->b_resid); 23539608Smckusick if (error) { 23639608Smckusick brelse(bp); 23739608Smckusick return (error); 23839608Smckusick } 239*53867Sheideman error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 240*53867Sheideman if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size) 24139608Smckusick bp->b_flags |= B_AGE; 24239608Smckusick brelse(bp); 243*53867Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 24439608Smckusick return (error); 24539608Smckusick } 24639608Smckusick 24739608Smckusick /* 24839608Smckusick * Vnode op for writing. 24939608Smckusick */ 25053533Sheideman lfs_write (ap) 25153533Sheideman struct vop_write_args *ap; 25239608Smckusick { 25353533Sheideman USES_VOP_TRUNCATE; 25453533Sheideman USES_VOP_UPDATE; 255*53867Sheideman register struct vnode *vp = ap->a_vp; 25653593Sheideman struct proc *p = ap->a_uio->uio_procp; 257*53867Sheideman register struct inode *ip = VTOI(vp); 25852091Sbostic register struct lfs *fs; 25939608Smckusick struct buf *bp; 26052091Sbostic daddr_t lbn; 26153233Smckusick off_t osize; 26252091Sbostic int n, on, flags, newblock; 26345722Smckusick int size, resid, error = 0; 26439608Smckusick 26551852Sbostic #ifdef VERBOSE 26651852Sbostic printf("lfs_write ino %d\n", ip->i_number); 26751852Sbostic #endif 26848039Smckusick #ifdef DIAGNOSTIC 26953593Sheideman if (ap->a_uio->uio_rw != UIO_WRITE) 27052091Sbostic panic("lfs_write mode"); 27148039Smckusick #endif 272*53867Sheideman switch (vp->v_type) { 27339608Smckusick case VREG: 27453593Sheideman if (ap->a_ioflag & IO_APPEND) 27553593Sheideman ap->a_uio->uio_offset = ip->i_size; 27639608Smckusick /* fall through */ 27739608Smckusick case VLNK: 27839608Smckusick break; 27939608Smckusick 28039608Smckusick case VDIR: 28152091Sbostic /* XXX This may not be correct for LFS. */ 28253593Sheideman if ((ap->a_ioflag & IO_SYNC) == 0) 28352091Sbostic panic("lfs_write nonsync dir write"); 28439608Smckusick break; 28539608Smckusick 28639608Smckusick default: 28752091Sbostic panic("lfs_write type"); 28839608Smckusick } 28953593Sheideman if (ap->a_uio->uio_offset < 0) 29039608Smckusick return (EINVAL); 29153593Sheideman if (ap->a_uio->uio_resid == 0) 29239608Smckusick return (0); 29339608Smckusick /* 29439608Smckusick * Maybe this should be above the vnode op call, but so long as 29539608Smckusick * file servers have no limits, i don't think it matters 29639608Smckusick */ 297*53867Sheideman if (vp->v_type == VREG && p && 29853593Sheideman ap->a_uio->uio_offset + ap->a_uio->uio_resid > 29947571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 30047571Skarels psignal(p, SIGXFSZ); 30139608Smckusick return (EFBIG); 30239608Smckusick } 30353593Sheideman resid = ap->a_uio->uio_resid; 30439608Smckusick osize = ip->i_size; 30551183Sbostic fs = ip->i_lfs; /* LFS */ 30639674Smckusick flags = 0; 30751183Sbostic #ifdef NOTLFS 30853593Sheideman if (ap->a_ioflag & IO_SYNC) 30939674Smckusick flags = B_SYNC; 31051183Sbostic #endif 31139608Smckusick do { 31253593Sheideman lbn = lblkno(fs, ap->a_uio->uio_offset); 31353593Sheideman on = blkoff(fs, ap->a_uio->uio_offset); 31453593Sheideman n = MIN((unsigned)(fs->lfs_bsize - on), ap->a_uio->uio_resid); 315*53867Sheideman if (error = lfs_balloc(vp, n, lbn, &bp)) 31639608Smckusick break; 31753593Sheideman if (ap->a_uio->uio_offset + n > ip->i_size) { 31853593Sheideman ip->i_size = ap->a_uio->uio_offset + n; 319*53867Sheideman vnode_pager_setsize(vp, (u_long)ip->i_size); 32045722Smckusick } 32151183Sbostic size = blksize(fs); 322*53867Sheideman (void) vnode_pager_uncache(vp); 32339608Smckusick n = MIN(n, size - bp->b_resid); 32453593Sheideman error = uiomove(bp->b_un.b_addr + on, n, ap->a_uio); 32551183Sbostic #ifdef NOTLFS /* LFS */ 32653593Sheideman if (ap->a_ioflag & IO_SYNC) 32739608Smckusick (void) bwrite(bp); 32839608Smckusick else if (n + on == fs->fs_bsize) { 32939608Smckusick bp->b_flags |= B_AGE; 33039608Smckusick bawrite(bp); 33139608Smckusick } else 33239608Smckusick bdwrite(bp); 33352091Sbostic ip->i_flag |= IUPD|ICHG; 33451183Sbostic #else 33552091Sbostic /* XXX This doesn't handle IO_SYNC. */ 33652091Sbostic LFS_UBWRITE(bp); 33751183Sbostic #endif 33853593Sheideman if (ap->a_cred->cr_uid != 0) 33939608Smckusick ip->i_mode &= ~(ISUID|ISGID); 34053593Sheideman } while (error == 0 && ap->a_uio->uio_resid > 0 && n != 0); 34153593Sheideman if (error && (ap->a_ioflag & IO_UNIT)) { 342*53867Sheideman (void)VOP_TRUNCATE(vp, osize, ap->a_ioflag & IO_SYNC, ap->a_cred); 34353593Sheideman ap->a_uio->uio_offset -= resid - ap->a_uio->uio_resid; 34453593Sheideman ap->a_uio->uio_resid = resid; 34539608Smckusick } 34653593Sheideman if (!error && (ap->a_ioflag & IO_SYNC)) 347*53867Sheideman error = VOP_UPDATE(vp, &time, &time, 1); 34839608Smckusick return (error); 34939608Smckusick } 35039608Smckusick 3519167Ssam /* 35237737Smckusick * Synch an open file. 3539167Ssam */ 35437737Smckusick /* ARGSUSED */ 35553533Sheideman lfs_fsync (ap) 35653533Sheideman struct vop_fsync_args *ap; 3577701Ssam { 35853533Sheideman USES_VOP_UPDATE; 35951852Sbostic struct inode *ip; 3607701Ssam 36151852Sbostic #ifdef VERBOSE 36251852Sbostic printf("lfs_fsync\n"); 36351852Sbostic #endif 36453593Sheideman ip = VTOI(ap->a_vp); 36553593Sheideman if (ap->a_fflags & FWRITE) 36637737Smckusick ip->i_flag |= ICHG; 36753593Sheideman return (VOP_UPDATE(ap->a_vp, &time, &time, ap->a_waitfor == MNT_WAIT)); 36837737Smckusick } 36951558Smckusick 37051558Smckusick /* 37151558Smckusick * Last reference to an inode, write the inode out and if necessary, 37251558Smckusick * truncate and deallocate the file. 37351558Smckusick */ 37451558Smckusick int 37553533Sheideman lfs_inactive (ap) 37653533Sheideman struct vop_inactive_args *ap; 37751558Smckusick { 37853533Sheideman USES_VOP_TRUNCATE; 37953533Sheideman USES_VOP_UPDATE; 38053533Sheideman USES_VOP_VFREE; 38151852Sbostic extern int prtactive; 38251558Smckusick register struct inode *ip; 38351558Smckusick int mode, error; 38451558Smckusick 38551852Sbostic #ifdef VERBOSE 38651852Sbostic printf("lfs_inactive\n"); 38751852Sbostic #endif 38853593Sheideman if (prtactive && ap->a_vp->v_usecount != 0) 38953593Sheideman vprint("lfs_inactive: pushing active", ap->a_vp); 39051558Smckusick 39151558Smckusick /* Get rid of inodes related to stale file handles. */ 39253593Sheideman ip = VTOI(ap->a_vp); 39351558Smckusick if (ip->i_mode == 0) { 39453593Sheideman if ((ap->a_vp->v_flag & VXLOCK) == 0) 39553593Sheideman vgone(ap->a_vp); 39651558Smckusick return (0); 39751558Smckusick } 39851558Smckusick 39951558Smckusick error = 0; 40051558Smckusick ILOCK(ip); 40153593Sheideman if (ip->i_nlink <= 0 && (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 40251558Smckusick #ifdef QUOTA 40351558Smckusick if (!getinoquota(ip)) 40451558Smckusick (void)chkiq(ip, -1, NOCRED, 0); 40551558Smckusick #endif 40653593Sheideman error = VOP_TRUNCATE(ap->a_vp, (off_t)0, 0, NOCRED); 40751558Smckusick mode = ip->i_mode; 40851558Smckusick ip->i_mode = 0; 40951558Smckusick ip->i_rdev = 0; 41051558Smckusick ip->i_flag |= IUPD|ICHG; 41153593Sheideman VOP_VFREE(ap->a_vp, ip->i_number, mode); 41251558Smckusick } 41351558Smckusick if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) 41453593Sheideman VOP_UPDATE(ap->a_vp, &time, &time, 0); 41551558Smckusick IUNLOCK(ip); 41651558Smckusick ip->i_flag = 0; 41751558Smckusick /* 41851558Smckusick * If we are done with the inode, reclaim it 41951558Smckusick * so that it can be reused immediately. 42051558Smckusick */ 42153593Sheideman if (ap->a_vp->v_usecount == 0 && ip->i_mode == 0) 42253593Sheideman vgone(ap->a_vp); 42351558Smckusick return (error); 42451558Smckusick } 425