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*56068Sbostic * @(#)lfs_vnops.c 7.94 (Berkeley) 08/27/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/malloc.h> 2337Sbill 2453321Smckusick #include <vm/vm.h> 2553321Smckusick 2655460Sbostic #include <miscfs/specfs/specdev.h> 2755460Sbostic #include <miscfs/fifofs/fifo.h> 2855460Sbostic 2951502Sbostic #include <ufs/ufs/quota.h> 3051502Sbostic #include <ufs/ufs/inode.h> 3151502Sbostic #include <ufs/ufs/dir.h> 3255936Sbostic #include <ufs/ufs/ufsmount.h> 3351502Sbostic #include <ufs/ufs/ufs_extern.h> 3447571Skarels 3551502Sbostic #include <ufs/lfs/lfs.h> 3651502Sbostic #include <ufs/lfs/lfs_extern.h> 3751134Sbostic 3851482Sbostic /* Global vfs data structures for lfs. */ 3953533Sheideman int (**lfs_vnodeop_p)(); 4053533Sheideman struct vnodeopv_entry_desc lfs_vnodeop_entries[] = { 4153533Sheideman { &vop_default_desc, vn_default_error }, 4253533Sheideman { &vop_lookup_desc, ufs_lookup }, /* lookup */ 4354264Sbostic { &vop_create_desc, lfs_create }, /* create */ 4454264Sbostic { &vop_mknod_desc, lfs_mknod }, /* mknod */ 4554030Smckusick { &vop_open_desc, ufs_open }, /* open */ 4656053Sbostic { &vop_close_desc, lfs_close }, /* close */ 4753533Sheideman { &vop_access_desc, ufs_access }, /* access */ 4855936Sbostic { &vop_getattr_desc, lfs_getattr }, /* getattr */ 4953533Sheideman { &vop_setattr_desc, ufs_setattr }, /* setattr */ 5054030Smckusick { &vop_read_desc, lfs_read }, /* read */ 5154030Smckusick { &vop_write_desc, lfs_write }, /* write */ 5254030Smckusick { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 5353533Sheideman { &vop_select_desc, ufs_select }, /* select */ 5454030Smckusick { &vop_mmap_desc, ufs_mmap }, /* mmap */ 5554030Smckusick { &vop_fsync_desc, lfs_fsync }, /* fsync */ 5654030Smckusick { &vop_seek_desc, ufs_seek }, /* seek */ 5754264Sbostic { &vop_remove_desc, lfs_remove }, /* remove */ 5854264Sbostic { &vop_link_desc, lfs_link }, /* link */ 5954264Sbostic { &vop_rename_desc, lfs_rename }, /* rename */ 6054264Sbostic { &vop_mkdir_desc, lfs_mkdir }, /* mkdir */ 6154264Sbostic { &vop_rmdir_desc, lfs_rmdir }, /* rmdir */ 6254264Sbostic { &vop_symlink_desc, lfs_symlink }, /* symlink */ 6353533Sheideman { &vop_readdir_desc, ufs_readdir }, /* readdir */ 6453533Sheideman { &vop_readlink_desc, ufs_readlink }, /* readlink */ 6553533Sheideman { &vop_abortop_desc, ufs_abortop }, /* abortop */ 6653533Sheideman { &vop_inactive_desc, lfs_inactive }, /* inactive */ 6753533Sheideman { &vop_reclaim_desc, ufs_reclaim }, /* reclaim */ 6854030Smckusick { &vop_lock_desc, ufs_lock }, /* lock */ 6953533Sheideman { &vop_unlock_desc, ufs_unlock }, /* unlock */ 7054030Smckusick { &vop_bmap_desc, lfs_bmap }, /* bmap */ 7153533Sheideman { &vop_strategy_desc, ufs_strategy }, /* strategy */ 7254030Smckusick { &vop_print_desc, ufs_print }, /* print */ 7353533Sheideman { &vop_islocked_desc, ufs_islocked }, /* islocked */ 7453533Sheideman { &vop_advlock_desc, ufs_advlock }, /* advlock */ 7553533Sheideman { &vop_blkatoff_desc, lfs_blkatoff }, /* blkatoff */ 7653533Sheideman { &vop_valloc_desc, lfs_valloc }, /* valloc */ 7754030Smckusick { &vop_vfree_desc, lfs_vfree }, /* vfree */ 7853533Sheideman { &vop_truncate_desc, lfs_truncate }, /* truncate */ 7953533Sheideman { &vop_update_desc, lfs_update }, /* update */ 8053533Sheideman { &vop_bwrite_desc, lfs_bwrite }, /* bwrite */ 8153533Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 8251482Sbostic }; 8353533Sheideman struct vnodeopv_desc lfs_vnodeop_opv_desc = 8453533Sheideman { &lfs_vnodeop_p, lfs_vnodeop_entries }; 856254Sroot 8653533Sheideman int (**lfs_specop_p)(); 8753533Sheideman struct vnodeopv_entry_desc lfs_specop_entries[] = { 8853533Sheideman { &vop_default_desc, vn_default_error }, 8953533Sheideman { &vop_lookup_desc, spec_lookup }, /* lookup */ 9053533Sheideman { &vop_create_desc, spec_create }, /* create */ 9153533Sheideman { &vop_mknod_desc, spec_mknod }, /* mknod */ 9254030Smckusick { &vop_open_desc, spec_open }, /* open */ 9353533Sheideman { &vop_close_desc, ufsspec_close }, /* close */ 9453533Sheideman { &vop_access_desc, ufs_access }, /* access */ 9555936Sbostic { &vop_getattr_desc, lfs_getattr }, /* getattr */ 9653533Sheideman { &vop_setattr_desc, ufs_setattr }, /* setattr */ 9753533Sheideman { &vop_read_desc, ufsspec_read }, /* read */ 9853533Sheideman { &vop_write_desc, ufsspec_write }, /* write */ 9953533Sheideman { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 10053533Sheideman { &vop_select_desc, spec_select }, /* select */ 10154030Smckusick { &vop_mmap_desc, spec_mmap }, /* mmap */ 10253533Sheideman { &vop_fsync_desc, spec_fsync }, /* fsync */ 10354030Smckusick { &vop_seek_desc, spec_seek }, /* seek */ 10453533Sheideman { &vop_remove_desc, spec_remove }, /* remove */ 10554030Smckusick { &vop_link_desc, spec_link }, /* link */ 10653533Sheideman { &vop_rename_desc, spec_rename }, /* rename */ 10753533Sheideman { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 10853533Sheideman { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 10953533Sheideman { &vop_symlink_desc, spec_symlink }, /* symlink */ 11053533Sheideman { &vop_readdir_desc, spec_readdir }, /* readdir */ 11153533Sheideman { &vop_readlink_desc, spec_readlink }, /* readlink */ 11253533Sheideman { &vop_abortop_desc, spec_abortop }, /* abortop */ 11353533Sheideman { &vop_inactive_desc, lfs_inactive }, /* inactive */ 11453533Sheideman { &vop_reclaim_desc, ufs_reclaim }, /* reclaim */ 11554030Smckusick { &vop_lock_desc, ufs_lock }, /* lock */ 11653533Sheideman { &vop_unlock_desc, ufs_unlock }, /* unlock */ 11754030Smckusick { &vop_bmap_desc, spec_bmap }, /* bmap */ 11853533Sheideman { &vop_strategy_desc, spec_strategy }, /* strategy */ 11954030Smckusick { &vop_print_desc, ufs_print }, /* print */ 12053533Sheideman { &vop_islocked_desc, ufs_islocked }, /* islocked */ 12153533Sheideman { &vop_advlock_desc, spec_advlock }, /* advlock */ 12253533Sheideman { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 12353533Sheideman { &vop_valloc_desc, spec_valloc }, /* valloc */ 12454030Smckusick { &vop_vfree_desc, lfs_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 */ 14054030Smckusick { &vop_open_desc, fifo_open }, /* open */ 14153533Sheideman { &vop_close_desc, ufsfifo_close }, /* close */ 14253533Sheideman { &vop_access_desc, ufs_access }, /* access */ 14355936Sbostic { &vop_getattr_desc, lfs_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 */ 14954030Smckusick { &vop_mmap_desc, fifo_mmap }, /* mmap */ 15053533Sheideman { &vop_fsync_desc, fifo_fsync }, /* fsync */ 15154030Smckusick { &vop_seek_desc, fifo_seek }, /* seek */ 15253533Sheideman { &vop_remove_desc, fifo_remove }, /* remove */ 15354030Smckusick { &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 */ 16354030Smckusick { &vop_lock_desc, ufs_lock }, /* lock */ 16453533Sheideman { &vop_unlock_desc, ufs_unlock }, /* unlock */ 16554030Smckusick { &vop_bmap_desc, fifo_bmap }, /* bmap */ 16653533Sheideman { &vop_strategy_desc, fifo_strategy }, /* strategy */ 16754030Smckusick { &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_valloc_desc, fifo_valloc }, /* valloc */ 17254030Smckusick { &vop_vfree_desc, lfs_vfree }, /* vfree */ 17353533Sheideman { &vop_truncate_desc, fifo_truncate }, /* truncate */ 17453533Sheideman { &vop_update_desc, lfs_update }, /* update */ 17553533Sheideman { &vop_bwrite_desc, lfs_bwrite }, /* bwrite */ 17653533Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 17751558Smckusick }; 17853533Sheideman struct vnodeopv_desc lfs_fifoop_opv_desc = 17953533Sheideman { &lfs_fifoop_p, lfs_fifoop_entries }; 18051558Smckusick #endif /* FIFO */ 18151558Smckusick 18237Sbill /* 18339608Smckusick * Vnode op for reading. 18439608Smckusick */ 18537737Smckusick /* ARGSUSED */ 18654030Smckusick lfs_read(ap) 18754692Sbostic struct vop_read_args /* { 18854692Sbostic struct vnode *a_vp; 18954692Sbostic struct uio *a_uio; 19054692Sbostic int a_ioflag; 19154692Sbostic struct ucred *a_cred; 19254692Sbostic } */ *ap; 19339608Smckusick { 19455460Sbostic register struct vnode *vp = ap->a_vp; 19555460Sbostic register struct inode *ip = VTOI(vp); 19653867Sheideman register struct uio *uio = ap->a_uio; 19755460Sbostic register struct lfs *fs; 198*56068Sbostic struct buf *bp1, *bp2; 19939608Smckusick daddr_t lbn, bn, rablock; 20053233Smckusick off_t diff; 20155460Sbostic int error = 0, size; 20255460Sbostic long n, on; 20339608Smckusick 20448039Smckusick #ifdef DIAGNOSTIC 20555460Sbostic int type; 20653867Sheideman if (uio->uio_rw != UIO_READ) 20755460Sbostic panic("lfs_read mode"); 20839608Smckusick type = ip->i_mode & IFMT; 20939608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 21055460Sbostic panic("lfs_read type"); 21155460Sbostic if (type == IFLNK && (int)ip->i_size < vp->v_mount->mnt_maxsymlinklen) 21255460Sbostic panic("read short symlink"); 21348039Smckusick #endif 21453867Sheideman if (uio->uio_resid == 0) 21539608Smckusick return (0); 21655460Sbostic fs = ip->i_lfs; 21755460Sbostic if (uio->uio_offset < 0 || 21855460Sbostic (u_quad_t)uio->uio_offset + uio->uio_resid > fs->lfs_maxfilesize) 21955460Sbostic return (EFBIG); 22039608Smckusick ip->i_flag |= IACC; 221*56068Sbostic bp1 = bp2 = NULL; 222*56068Sbostic IUNLOCK(ip); 22339608Smckusick do { 22453867Sheideman lbn = lblkno(fs, uio->uio_offset); 22553867Sheideman on = blkoff(fs, uio->uio_offset); 22655460Sbostic n = min((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 22753867Sheideman diff = ip->i_size - uio->uio_offset; 22839608Smckusick if (diff <= 0) 229*56068Sbostic break; 23039608Smckusick if (diff < n) 23139608Smckusick n = diff; 23255460Sbostic size = blksize(fs); 23339674Smckusick rablock = lbn + 1; 23455936Sbostic lfs_check(vp, lbn); 23555460Sbostic if (vp->v_lastr + 1 == lbn && 23639896Smckusick lblktosize(fs, rablock) < ip->i_size) 23752195Smckusick error = breadn(ITOV(ip), lbn, size, &rablock, 238*56068Sbostic &size, 1, NOCRED, &bp1); 23939608Smckusick else 240*56068Sbostic error = bread(ITOV(ip), lbn, size, NOCRED, &bp1); 241*56068Sbostic if (bp2) 242*56068Sbostic brelse(bp2); 243*56068Sbostic bp2 = bp1; 24455460Sbostic vp->v_lastr = lbn; 245*56068Sbostic n = min(n, size - bp2->b_resid); 246*56068Sbostic if (error) 247*56068Sbostic break; 248*56068Sbostic error = uiomove(bp2->b_un.b_addr + on, (int)n, uio); 24953867Sheideman if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size) 250*56068Sbostic bp2->b_flags |= B_AGE; 25153867Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 252*56068Sbostic if (bp2) 253*56068Sbostic brelse(bp2); 254*56068Sbostic ILOCK(ip); 25539608Smckusick return (error); 25639608Smckusick } 25739608Smckusick 25839608Smckusick /* 25939608Smckusick * Vnode op for writing. 26039608Smckusick */ 26154030Smckusick lfs_write(ap) 26254692Sbostic struct vop_write_args /* { 26354692Sbostic struct vnode *a_vp; 26454692Sbostic struct uio *a_uio; 26554692Sbostic int a_ioflag; 26654692Sbostic struct ucred *a_cred; 26754692Sbostic } */ *ap; 26839608Smckusick { 26953867Sheideman register struct vnode *vp = ap->a_vp; 27054030Smckusick register struct uio *uio = ap->a_uio; 27154030Smckusick struct proc *p = uio->uio_procp; 27253867Sheideman register struct inode *ip = VTOI(vp); 27352091Sbostic register struct lfs *fs; 27454030Smckusick register ioflag = ap->a_ioflag; 27554765Smckusick struct timeval tv; 276*56068Sbostic struct buf *bp1, *bp2; 27752091Sbostic daddr_t lbn; 27853233Smckusick off_t osize; 27952091Sbostic int n, on, flags, newblock; 28045722Smckusick int size, resid, error = 0; 28139608Smckusick 28248039Smckusick #ifdef DIAGNOSTIC 28354030Smckusick if (uio->uio_rw != UIO_WRITE) 28452091Sbostic panic("lfs_write mode"); 28548039Smckusick #endif 28653867Sheideman switch (vp->v_type) { 28739608Smckusick case VREG: 28854030Smckusick if (ioflag & IO_APPEND) 28954030Smckusick uio->uio_offset = ip->i_size; 29039608Smckusick /* fall through */ 29139608Smckusick case VLNK: 29239608Smckusick break; 29339608Smckusick 29439608Smckusick case VDIR: 29552091Sbostic /* XXX This may not be correct for LFS. */ 29654030Smckusick if ((ioflag & IO_SYNC) == 0) 29752091Sbostic panic("lfs_write nonsync dir write"); 29839608Smckusick break; 29939608Smckusick 30039608Smckusick default: 30152091Sbostic panic("lfs_write type"); 30239608Smckusick } 30354030Smckusick if (uio->uio_offset < 0) 30439608Smckusick return (EINVAL); 30554030Smckusick if (uio->uio_resid == 0) 30639608Smckusick return (0); 30739608Smckusick /* 30839608Smckusick * Maybe this should be above the vnode op call, but so long as 30939608Smckusick * file servers have no limits, i don't think it matters 31039608Smckusick */ 31153867Sheideman if (vp->v_type == VREG && p && 31254030Smckusick uio->uio_offset + uio->uio_resid > 31347571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 31447571Skarels psignal(p, SIGXFSZ); 31539608Smckusick return (EFBIG); 31639608Smckusick } 31754030Smckusick resid = uio->uio_resid; 31839608Smckusick osize = ip->i_size; 31951183Sbostic fs = ip->i_lfs; /* LFS */ 32055460Sbostic if (uio->uio_offset < 0 || 32155460Sbostic (u_quad_t)uio->uio_offset + uio->uio_resid > fs->lfs_maxfilesize) 32255460Sbostic return (EFBIG); 323*56068Sbostic 324*56068Sbostic /* 325*56068Sbostic * XXX 326*56068Sbostic * FFS uses the VOP_LOCK to provide serializability of multi-block 327*56068Sbostic * reads and writes. Since the cleaner may need to interrupt and 328*56068Sbostic * clean a vnode, this isn't such a good idea for us. We use 329*56068Sbostic * ordered locking instead. Hold buffer N busy until buffer N+1 330*56068Sbostic * has been obtained. We get much better concurrency that way. 331*56068Sbostic */ 332*56068Sbostic bp1 = bp2 = NULL; 333*56068Sbostic IUNLOCK(ip); 33439608Smckusick do { 33554030Smckusick lbn = lblkno(fs, uio->uio_offset); 33654030Smckusick on = blkoff(fs, uio->uio_offset); 33755460Sbostic n = min((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 33855936Sbostic lfs_check(vp, lbn); 339*56068Sbostic if (error = lfs_balloc(vp, n, lbn, &bp1)) 34039608Smckusick break; 341*56068Sbostic if (bp2) 342*56068Sbostic error = VOP_BWRITE(bp2); 343*56068Sbostic bp2 = NULL; 344*56068Sbostic if (error) 345*56068Sbostic break; 34654030Smckusick if (uio->uio_offset + n > ip->i_size) { 34754030Smckusick ip->i_size = uio->uio_offset + n; 34853867Sheideman vnode_pager_setsize(vp, (u_long)ip->i_size); 34945722Smckusick } 35051183Sbostic size = blksize(fs); 35153867Sheideman (void) vnode_pager_uncache(vp); 352*56068Sbostic n = min(n, size - bp1->b_resid); 353*56068Sbostic error = uiomove(bp1->b_un.b_addr + on, n, uio); 354*56068Sbostic /* XXX Why is this in the loop? */ 35553593Sheideman if (ap->a_cred->cr_uid != 0) 35639608Smckusick ip->i_mode &= ~(ISUID|ISGID); 357*56068Sbostic bp2 = bp1; 358*56068Sbostic bp1 = NULL; 35954030Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 360*56068Sbostic if (bp1) 361*56068Sbostic brelse(bp1); 362*56068Sbostic if (bp2) 363*56068Sbostic error = VOP_BWRITE(bp2); 364*56068Sbostic 36555936Sbostic if (error) { 36655936Sbostic if (ioflag & IO_UNIT) { 36755936Sbostic (void)VOP_TRUNCATE(vp, osize, ioflag & IO_SYNC, 36855936Sbostic ap->a_cred, uio->uio_procp); 36955936Sbostic uio->uio_offset -= resid - uio->uio_resid; 37055936Sbostic uio->uio_resid = resid; 37155936Sbostic } 372*56068Sbostic } 373*56068Sbostic 37454765Smckusick if (!error && (ioflag & IO_SYNC)) { 37554765Smckusick tv = time; 37655936Sbostic if (!(error = VOP_UPDATE(vp, &tv, &tv, 1))) 37755936Sbostic error = VOP_FSYNC(vp, ap->a_cred, MNT_WAIT, 37855936Sbostic uio->uio_procp); 37954765Smckusick } 380*56068Sbostic ILOCK(ip); 38139608Smckusick return (error); 38239608Smckusick } 38339608Smckusick 3849167Ssam /* 38537737Smckusick * Synch an open file. 3869167Ssam */ 38737737Smckusick /* ARGSUSED */ 38854030Smckusick lfs_fsync(ap) 38954692Sbostic struct vop_fsync_args /* { 39054692Sbostic struct vnode *a_vp; 39154692Sbostic struct ucred *a_cred; 39254692Sbostic int a_waitfor; 39354692Sbostic struct proc *a_p; 39454692Sbostic } */ *ap; 3957701Ssam { 39654765Smckusick struct timeval tv; 3977701Ssam 39854765Smckusick tv = time; 39955547Sbostic return (VOP_UPDATE(ap->a_vp, &tv, &tv, 40055547Sbostic ap->a_waitfor == MNT_WAIT ? LFS_SYNC : 0)); 40137737Smckusick } 40251558Smckusick 40351558Smckusick /* 40451558Smckusick * Last reference to an inode, write the inode out and if necessary, 40551558Smckusick * truncate and deallocate the file. 40651558Smckusick */ 40751558Smckusick int 40854030Smckusick lfs_inactive(ap) 40954692Sbostic struct vop_inactive_args /* { 41054692Sbostic struct vnode *a_vp; 41154692Sbostic } */ *ap; 41251558Smckusick { 41351852Sbostic extern int prtactive; 41454030Smckusick register struct vnode *vp = ap->a_vp; 41551558Smckusick register struct inode *ip; 41654765Smckusick struct timeval tv; 41751558Smckusick int mode, error; 41851558Smckusick 41954030Smckusick if (prtactive && vp->v_usecount != 0) 42054030Smckusick vprint("lfs_inactive: pushing active", vp); 42151558Smckusick 42251558Smckusick /* Get rid of inodes related to stale file handles. */ 42354030Smckusick ip = VTOI(vp); 42451558Smckusick if (ip->i_mode == 0) { 42554030Smckusick if ((vp->v_flag & VXLOCK) == 0) 42654030Smckusick vgone(vp); 42751558Smckusick return (0); 42851558Smckusick } 42951558Smckusick 43051558Smckusick error = 0; 43151558Smckusick ILOCK(ip); 43254030Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 43351558Smckusick #ifdef QUOTA 43451558Smckusick if (!getinoquota(ip)) 43551558Smckusick (void)chkiq(ip, -1, NOCRED, 0); 43651558Smckusick #endif 43754692Sbostic error = VOP_TRUNCATE(vp, (off_t)0, 0, NOCRED, NULL); 43851558Smckusick mode = ip->i_mode; 43951558Smckusick ip->i_mode = 0; 44051558Smckusick ip->i_rdev = 0; 44151558Smckusick ip->i_flag |= IUPD|ICHG; 44254030Smckusick VOP_VFREE(vp, ip->i_number, mode); 44351558Smckusick } 44454765Smckusick if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) { 44554765Smckusick tv = time; 44654765Smckusick VOP_UPDATE(vp, &tv, &tv, 0); 44754765Smckusick } 44851558Smckusick IUNLOCK(ip); 44951558Smckusick /* 45051558Smckusick * If we are done with the inode, reclaim it 45151558Smckusick * so that it can be reused immediately. 45251558Smckusick */ 45354030Smckusick if (vp->v_usecount == 0 && ip->i_mode == 0) 45454030Smckusick vgone(vp); 45551558Smckusick return (error); 45651558Smckusick } 45754264Sbostic 45854264Sbostic /* 45954264Sbostic * These macros are used to bracket UFS directory ops, so that we can 46054264Sbostic * identify all the pages touched during directory ops which need to 46154264Sbostic * be ordered and flushed atomically, so that they may be recovered. 46254264Sbostic */ 46354264Sbostic #define SET_DIROP(fs) { \ 46454264Sbostic if ((fs)->lfs_writer) \ 46555547Sbostic tsleep(&(fs)->lfs_dirops, PRIBIO + 1, "lfs_dirop", 0); \ 46654264Sbostic ++(fs)->lfs_dirops; \ 46754264Sbostic (fs)->lfs_doifile = 1; \ 46854264Sbostic } 46954264Sbostic 47054264Sbostic #define SET_ENDOP(fs) { \ 47154264Sbostic --(fs)->lfs_dirops; \ 47254264Sbostic if (!(fs)->lfs_dirops) \ 47354264Sbostic wakeup(&(fs)->lfs_writer); \ 47454264Sbostic } 47554264Sbostic 47654264Sbostic #define MARK_VNODE(dvp) (dvp)->v_flag |= VDIROP 47754264Sbostic 47854264Sbostic int 47954264Sbostic lfs_symlink(ap) 48054692Sbostic struct vop_symlink_args /* { 48154692Sbostic struct vnode *a_dvp; 48254692Sbostic struct vnode **a_vpp; 48354692Sbostic struct componentname *a_cnp; 48454692Sbostic struct vattr *a_vap; 48554692Sbostic char *a_target; 48654692Sbostic } */ *ap; 48754264Sbostic { 48854264Sbostic int ret; 48954264Sbostic 49054264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 49154264Sbostic MARK_VNODE(ap->a_dvp); 49254264Sbostic ret = ufs_symlink(ap); 49354264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 49454264Sbostic return (ret); 49554264Sbostic } 49654264Sbostic 49754264Sbostic int 49854264Sbostic lfs_mknod(ap) 49954692Sbostic struct vop_mknod_args /* { 50054692Sbostic struct vnode *a_dvp; 50154692Sbostic struct vnode **a_vpp; 50254692Sbostic struct componentname *a_cnp; 50354692Sbostic struct vattr *a_vap; 50454692Sbostic } */ *ap; 50554264Sbostic { 50654264Sbostic int ret; 50754264Sbostic 50854264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 50954264Sbostic MARK_VNODE(ap->a_dvp); 51054264Sbostic ret = ufs_mknod(ap); 51154264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 51254264Sbostic return (ret); 51354264Sbostic } 51454264Sbostic 51554264Sbostic int 51654264Sbostic lfs_create(ap) 51754692Sbostic struct vop_create_args /* { 51854692Sbostic struct vnode *a_dvp; 51954692Sbostic struct vnode **a_vpp; 52054692Sbostic struct componentname *a_cnp; 52154692Sbostic struct vattr *a_vap; 52254692Sbostic } */ *ap; 52354264Sbostic { 52454264Sbostic int ret; 52554264Sbostic 52654264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 52754264Sbostic MARK_VNODE(ap->a_dvp); 52854264Sbostic ret = ufs_create(ap); 52954264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 53054264Sbostic return (ret); 53154264Sbostic } 53254264Sbostic 53354264Sbostic int 53454264Sbostic lfs_mkdir(ap) 53554692Sbostic struct vop_mkdir_args /* { 53654692Sbostic struct vnode *a_dvp; 53754692Sbostic struct vnode **a_vpp; 53854692Sbostic struct componentname *a_cnp; 53954692Sbostic struct vattr *a_vap; 54054692Sbostic } */ *ap; 54154264Sbostic { 54254264Sbostic int ret; 54354264Sbostic 54454264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 54554264Sbostic MARK_VNODE(ap->a_dvp); 54654264Sbostic ret = ufs_mkdir(ap); 54754264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 54854264Sbostic return (ret); 54954264Sbostic } 55054264Sbostic 55154264Sbostic int 55254264Sbostic lfs_remove(ap) 55354692Sbostic struct vop_remove_args /* { 55454692Sbostic struct vnode *a_dvp; 55554692Sbostic struct vnode *a_vp; 55654692Sbostic struct componentname *a_cnp; 55754692Sbostic } */ *ap; 55854264Sbostic { 55954264Sbostic int ret; 56054264Sbostic 56154264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 56254264Sbostic MARK_VNODE(ap->a_dvp); 56354264Sbostic MARK_VNODE(ap->a_vp); 56454264Sbostic ret = ufs_remove(ap); 56554264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 56654264Sbostic return (ret); 56754264Sbostic } 56854264Sbostic 56954264Sbostic int 57054264Sbostic lfs_rmdir(ap) 57154692Sbostic struct vop_rmdir_args /* { 57254692Sbostic struct vnodeop_desc *a_desc; 57354692Sbostic struct vnode *a_dvp; 57454692Sbostic struct vnode *a_vp; 57554692Sbostic struct componentname *a_cnp; 57654692Sbostic } */ *ap; 57754264Sbostic { 57854264Sbostic int ret; 57954264Sbostic 58054264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 58154264Sbostic MARK_VNODE(ap->a_dvp); 58254264Sbostic MARK_VNODE(ap->a_vp); 58354264Sbostic ret = ufs_rmdir(ap); 58454264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 58554264Sbostic return (ret); 58654264Sbostic } 58754264Sbostic 58854264Sbostic int 58954264Sbostic lfs_link(ap) 59054692Sbostic struct vop_link_args /* { 59154692Sbostic struct vnode *a_vp; 59254692Sbostic struct vnode *a_tdvp; 59354692Sbostic struct componentname *a_cnp; 59454692Sbostic } */ *ap; 59554264Sbostic { 59654264Sbostic int ret; 59754264Sbostic 59854264Sbostic SET_DIROP(VTOI(ap->a_vp)->i_lfs); 59954264Sbostic MARK_VNODE(ap->a_vp); 60054264Sbostic ret = ufs_link(ap); 60154264Sbostic SET_ENDOP(VTOI(ap->a_vp)->i_lfs); 60254264Sbostic return (ret); 60354264Sbostic } 60454264Sbostic 60554264Sbostic int 60654264Sbostic lfs_rename(ap) 60754692Sbostic struct vop_rename_args /* { 60854692Sbostic struct vnode *a_fdvp; 60954692Sbostic struct vnode *a_fvp; 61054692Sbostic struct componentname *a_fcnp; 61154692Sbostic struct vnode *a_tdvp; 61254692Sbostic struct vnode *a_tvp; 61354692Sbostic struct componentname *a_tcnp; 61454692Sbostic } */ *ap; 61554264Sbostic { 61654264Sbostic int ret; 61754264Sbostic 61854264Sbostic SET_DIROP(VTOI(ap->a_fdvp)->i_lfs); 61954264Sbostic MARK_VNODE(ap->a_fdvp); 62054264Sbostic MARK_VNODE(ap->a_tdvp); 62154264Sbostic ret = ufs_rename(ap); 62254264Sbostic SET_ENDOP(VTOI(ap->a_fdvp)->i_lfs); 62354264Sbostic return (ret); 62454264Sbostic } 62555936Sbostic /* XXX hack to avoid calling ITIMES in getattr */ 62655936Sbostic int 62755936Sbostic lfs_getattr(ap) 62855936Sbostic struct vop_getattr_args /* { 62955936Sbostic struct vnode *a_vp; 63055936Sbostic struct vattr *a_vap; 63155936Sbostic struct ucred *a_cred; 63255936Sbostic struct proc *a_p; 63355936Sbostic } */ *ap; 63455936Sbostic { 63555936Sbostic register struct vnode *vp = ap->a_vp; 63655936Sbostic register struct inode *ip = VTOI(vp); 63755936Sbostic register struct vattr *vap = ap->a_vap; 63855936Sbostic /* 63955936Sbostic * Copy from inode table 64055936Sbostic */ 64155936Sbostic vap->va_fsid = ip->i_dev; 64255936Sbostic vap->va_fileid = ip->i_number; 64355936Sbostic vap->va_mode = ip->i_mode & ~IFMT; 64455936Sbostic vap->va_nlink = ip->i_nlink; 64555936Sbostic vap->va_uid = ip->i_uid; 64655936Sbostic vap->va_gid = ip->i_gid; 64755936Sbostic vap->va_rdev = (dev_t)ip->i_rdev; 64855936Sbostic vap->va_size = ip->i_din.di_size; 64955936Sbostic vap->va_atime = ip->i_atime; 65055936Sbostic vap->va_mtime = ip->i_mtime; 65155936Sbostic vap->va_ctime = ip->i_ctime; 65255936Sbostic vap->va_flags = ip->i_flags; 65355936Sbostic vap->va_gen = ip->i_gen; 65455936Sbostic /* this doesn't belong here */ 65555936Sbostic if (vp->v_type == VBLK) 65655936Sbostic vap->va_blocksize = BLKDEV_IOSIZE; 65755936Sbostic else if (vp->v_type == VCHR) 65855936Sbostic vap->va_blocksize = MAXBSIZE; 65955936Sbostic else 66055936Sbostic vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; 66155936Sbostic vap->va_bytes = dbtob(ip->i_blocks); 66255936Sbostic vap->va_type = vp->v_type; 66355936Sbostic vap->va_filerev = ip->i_modrev; 66455936Sbostic return (0); 66555936Sbostic } 66656053Sbostic /* 66756053Sbostic * Close called 66856053Sbostic * 66956053Sbostic * XXX -- we were using ufs_close, but since it updates the 67056053Sbostic * times on the inode, we might need to bump the uinodes 67156053Sbostic * count. 67256053Sbostic */ 67356053Sbostic /* ARGSUSED */ 67456053Sbostic int 67556053Sbostic lfs_close(ap) 67656053Sbostic struct vop_close_args /* { 67756053Sbostic struct vnode *a_vp; 67856053Sbostic int a_fflag; 67956053Sbostic struct ucred *a_cred; 68056053Sbostic struct proc *a_p; 68156053Sbostic } */ *ap; 68256053Sbostic { 68356053Sbostic register struct vnode *vp = ap->a_vp; 68456053Sbostic register struct inode *ip = VTOI(vp); 68556053Sbostic int mod; 68656053Sbostic 68756053Sbostic if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) { 68856053Sbostic mod = ip->i_flag & IMOD; 68956053Sbostic ITIMES(ip, &time, &time); 69056053Sbostic if (!mod && ip->i_flag & IMOD) 69156053Sbostic ip->i_lfs->lfs_uinodes++; 69256053Sbostic } 69356053Sbostic return (0); 69456053Sbostic } 69556053Sbostic 696