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*56474Smargo * @(#)lfs_vnops.c 7.95 (Berkeley) 10/08/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 */ 70*56474Smargo { &vop_bmap_desc, ufs_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; 19856068Sbostic struct buf *bp1, *bp2; 19939608Smckusick daddr_t lbn, bn, rablock; 20053233Smckusick off_t diff; 201*56474Smargo int error = 0, lock_on_enter, 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; 22156068Sbostic bp1 = bp2 = NULL; 222*56474Smargo if (lock_on_enter = ip->i_flag & ILOCKED) 223*56474Smargo IUNLOCK(ip); 22439608Smckusick do { 22553867Sheideman lbn = lblkno(fs, uio->uio_offset); 22653867Sheideman on = blkoff(fs, uio->uio_offset); 22755460Sbostic n = min((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 22853867Sheideman diff = ip->i_size - uio->uio_offset; 22939608Smckusick if (diff <= 0) 23056068Sbostic break; 23139608Smckusick if (diff < n) 23239608Smckusick n = diff; 23355460Sbostic size = blksize(fs); 234*56474Smargo lfs_check(vp, lbn); 235*56474Smargo /* */ 23639674Smckusick rablock = lbn + 1; 23755460Sbostic if (vp->v_lastr + 1 == lbn && 23839896Smckusick lblktosize(fs, rablock) < ip->i_size) 23952195Smckusick error = breadn(ITOV(ip), lbn, size, &rablock, 24056068Sbostic &size, 1, NOCRED, &bp1); 24139608Smckusick else 24256068Sbostic error = bread(ITOV(ip), lbn, size, NOCRED, &bp1); 243*56474Smargo /* 244*56474Smargo error = ufs_breada(vp, lbn, size, NOCRED, &bp1); 245*56474Smargo */ 24656068Sbostic if (bp2) 24756068Sbostic brelse(bp2); 24856068Sbostic bp2 = bp1; 24955460Sbostic vp->v_lastr = lbn; 25056068Sbostic n = min(n, size - bp2->b_resid); 25156068Sbostic if (error) 25256068Sbostic break; 25356068Sbostic error = uiomove(bp2->b_un.b_addr + on, (int)n, uio); 25453867Sheideman if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size) 25556068Sbostic bp2->b_flags |= B_AGE; 25653867Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 25756068Sbostic if (bp2) 25856068Sbostic brelse(bp2); 259*56474Smargo if (lock_on_enter) 260*56474Smargo ILOCK(ip); 26139608Smckusick return (error); 26239608Smckusick } 26339608Smckusick 26439608Smckusick /* 26539608Smckusick * Vnode op for writing. 26639608Smckusick */ 26754030Smckusick lfs_write(ap) 26854692Sbostic struct vop_write_args /* { 26954692Sbostic struct vnode *a_vp; 27054692Sbostic struct uio *a_uio; 27154692Sbostic int a_ioflag; 27254692Sbostic struct ucred *a_cred; 27354692Sbostic } */ *ap; 27439608Smckusick { 27553867Sheideman register struct vnode *vp = ap->a_vp; 27654030Smckusick register struct uio *uio = ap->a_uio; 27754030Smckusick struct proc *p = uio->uio_procp; 27853867Sheideman register struct inode *ip = VTOI(vp); 27952091Sbostic register struct lfs *fs; 28054030Smckusick register ioflag = ap->a_ioflag; 28154765Smckusick struct timeval tv; 28256068Sbostic struct buf *bp1, *bp2; 28352091Sbostic daddr_t lbn; 28453233Smckusick off_t osize; 28552091Sbostic int n, on, flags, newblock; 28645722Smckusick int size, resid, error = 0; 28739608Smckusick 28848039Smckusick #ifdef DIAGNOSTIC 28954030Smckusick if (uio->uio_rw != UIO_WRITE) 29052091Sbostic panic("lfs_write mode"); 29148039Smckusick #endif 29253867Sheideman switch (vp->v_type) { 29339608Smckusick case VREG: 29454030Smckusick if (ioflag & IO_APPEND) 29554030Smckusick uio->uio_offset = ip->i_size; 29639608Smckusick /* fall through */ 29739608Smckusick case VLNK: 29839608Smckusick break; 29939608Smckusick 30039608Smckusick case VDIR: 30152091Sbostic /* XXX This may not be correct for LFS. */ 30254030Smckusick if ((ioflag & IO_SYNC) == 0) 30352091Sbostic panic("lfs_write nonsync dir write"); 30439608Smckusick break; 30539608Smckusick 30639608Smckusick default: 30752091Sbostic panic("lfs_write type"); 30839608Smckusick } 30954030Smckusick if (uio->uio_offset < 0) 31039608Smckusick return (EINVAL); 31154030Smckusick if (uio->uio_resid == 0) 31239608Smckusick return (0); 31339608Smckusick /* 31439608Smckusick * Maybe this should be above the vnode op call, but so long as 31539608Smckusick * file servers have no limits, i don't think it matters 31639608Smckusick */ 31753867Sheideman if (vp->v_type == VREG && p && 31854030Smckusick uio->uio_offset + uio->uio_resid > 31947571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 32047571Skarels psignal(p, SIGXFSZ); 32139608Smckusick return (EFBIG); 32239608Smckusick } 32354030Smckusick resid = uio->uio_resid; 32439608Smckusick osize = ip->i_size; 32551183Sbostic fs = ip->i_lfs; /* LFS */ 32655460Sbostic if (uio->uio_offset < 0 || 32755460Sbostic (u_quad_t)uio->uio_offset + uio->uio_resid > fs->lfs_maxfilesize) 32855460Sbostic return (EFBIG); 32956068Sbostic 33056068Sbostic /* 33156068Sbostic * XXX 33256068Sbostic * FFS uses the VOP_LOCK to provide serializability of multi-block 33356068Sbostic * reads and writes. Since the cleaner may need to interrupt and 33456068Sbostic * clean a vnode, this isn't such a good idea for us. We use 33556068Sbostic * ordered locking instead. Hold buffer N busy until buffer N+1 33656068Sbostic * has been obtained. We get much better concurrency that way. 33756068Sbostic */ 33856068Sbostic bp1 = bp2 = NULL; 33956068Sbostic IUNLOCK(ip); 34039608Smckusick do { 34154030Smckusick lbn = lblkno(fs, uio->uio_offset); 34254030Smckusick on = blkoff(fs, uio->uio_offset); 34355460Sbostic n = min((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 34455936Sbostic lfs_check(vp, lbn); 34556068Sbostic if (error = lfs_balloc(vp, n, lbn, &bp1)) 34639608Smckusick break; 34756068Sbostic if (bp2) 34856068Sbostic error = VOP_BWRITE(bp2); 34956068Sbostic bp2 = NULL; 35056068Sbostic if (error) 35156068Sbostic break; 35254030Smckusick if (uio->uio_offset + n > ip->i_size) { 35354030Smckusick ip->i_size = uio->uio_offset + n; 35453867Sheideman vnode_pager_setsize(vp, (u_long)ip->i_size); 35545722Smckusick } 35651183Sbostic size = blksize(fs); 35753867Sheideman (void) vnode_pager_uncache(vp); 35856068Sbostic n = min(n, size - bp1->b_resid); 35956068Sbostic error = uiomove(bp1->b_un.b_addr + on, n, uio); 36056068Sbostic /* XXX Why is this in the loop? */ 36153593Sheideman if (ap->a_cred->cr_uid != 0) 36239608Smckusick ip->i_mode &= ~(ISUID|ISGID); 36356068Sbostic bp2 = bp1; 36456068Sbostic bp1 = NULL; 36554030Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 36656068Sbostic if (bp1) 36756068Sbostic brelse(bp1); 36856068Sbostic if (bp2) 36956068Sbostic error = VOP_BWRITE(bp2); 37056068Sbostic 37155936Sbostic if (error) { 37255936Sbostic if (ioflag & IO_UNIT) { 37355936Sbostic (void)VOP_TRUNCATE(vp, osize, ioflag & IO_SYNC, 37455936Sbostic ap->a_cred, uio->uio_procp); 37555936Sbostic uio->uio_offset -= resid - uio->uio_resid; 37655936Sbostic uio->uio_resid = resid; 37755936Sbostic } 37856068Sbostic } 37956068Sbostic 38054765Smckusick if (!error && (ioflag & IO_SYNC)) { 38154765Smckusick tv = time; 38255936Sbostic if (!(error = VOP_UPDATE(vp, &tv, &tv, 1))) 38355936Sbostic error = VOP_FSYNC(vp, ap->a_cred, MNT_WAIT, 38455936Sbostic uio->uio_procp); 38554765Smckusick } 38656068Sbostic ILOCK(ip); 38739608Smckusick return (error); 38839608Smckusick } 38939608Smckusick 3909167Ssam /* 39137737Smckusick * Synch an open file. 3929167Ssam */ 39337737Smckusick /* ARGSUSED */ 39454030Smckusick lfs_fsync(ap) 39554692Sbostic struct vop_fsync_args /* { 39654692Sbostic struct vnode *a_vp; 39754692Sbostic struct ucred *a_cred; 39854692Sbostic int a_waitfor; 39954692Sbostic struct proc *a_p; 40054692Sbostic } */ *ap; 4017701Ssam { 40254765Smckusick struct timeval tv; 4037701Ssam 40454765Smckusick tv = time; 40555547Sbostic return (VOP_UPDATE(ap->a_vp, &tv, &tv, 40655547Sbostic ap->a_waitfor == MNT_WAIT ? LFS_SYNC : 0)); 40737737Smckusick } 40851558Smckusick 40951558Smckusick /* 41051558Smckusick * Last reference to an inode, write the inode out and if necessary, 41151558Smckusick * truncate and deallocate the file. 41251558Smckusick */ 41351558Smckusick int 41454030Smckusick lfs_inactive(ap) 41554692Sbostic struct vop_inactive_args /* { 41654692Sbostic struct vnode *a_vp; 41754692Sbostic } */ *ap; 41851558Smckusick { 41951852Sbostic extern int prtactive; 42054030Smckusick register struct vnode *vp = ap->a_vp; 42151558Smckusick register struct inode *ip; 42254765Smckusick struct timeval tv; 42351558Smckusick int mode, error; 42451558Smckusick 42554030Smckusick if (prtactive && vp->v_usecount != 0) 42654030Smckusick vprint("lfs_inactive: pushing active", vp); 42751558Smckusick 42851558Smckusick /* Get rid of inodes related to stale file handles. */ 42954030Smckusick ip = VTOI(vp); 43051558Smckusick if (ip->i_mode == 0) { 43154030Smckusick if ((vp->v_flag & VXLOCK) == 0) 43254030Smckusick vgone(vp); 43351558Smckusick return (0); 43451558Smckusick } 43551558Smckusick 43651558Smckusick error = 0; 43751558Smckusick ILOCK(ip); 43854030Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 43951558Smckusick #ifdef QUOTA 44051558Smckusick if (!getinoquota(ip)) 44151558Smckusick (void)chkiq(ip, -1, NOCRED, 0); 44251558Smckusick #endif 44354692Sbostic error = VOP_TRUNCATE(vp, (off_t)0, 0, NOCRED, NULL); 44451558Smckusick mode = ip->i_mode; 44551558Smckusick ip->i_mode = 0; 44651558Smckusick ip->i_rdev = 0; 44751558Smckusick ip->i_flag |= IUPD|ICHG; 44854030Smckusick VOP_VFREE(vp, ip->i_number, mode); 44951558Smckusick } 45054765Smckusick if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) { 45154765Smckusick tv = time; 45254765Smckusick VOP_UPDATE(vp, &tv, &tv, 0); 45354765Smckusick } 45451558Smckusick IUNLOCK(ip); 45551558Smckusick /* 45651558Smckusick * If we are done with the inode, reclaim it 45751558Smckusick * so that it can be reused immediately. 45851558Smckusick */ 45954030Smckusick if (vp->v_usecount == 0 && ip->i_mode == 0) 46054030Smckusick vgone(vp); 46151558Smckusick return (error); 46251558Smckusick } 46354264Sbostic 46454264Sbostic /* 46554264Sbostic * These macros are used to bracket UFS directory ops, so that we can 46654264Sbostic * identify all the pages touched during directory ops which need to 46754264Sbostic * be ordered and flushed atomically, so that they may be recovered. 46854264Sbostic */ 46954264Sbostic #define SET_DIROP(fs) { \ 47054264Sbostic if ((fs)->lfs_writer) \ 47155547Sbostic tsleep(&(fs)->lfs_dirops, PRIBIO + 1, "lfs_dirop", 0); \ 47254264Sbostic ++(fs)->lfs_dirops; \ 47354264Sbostic (fs)->lfs_doifile = 1; \ 47454264Sbostic } 47554264Sbostic 47654264Sbostic #define SET_ENDOP(fs) { \ 47754264Sbostic --(fs)->lfs_dirops; \ 47854264Sbostic if (!(fs)->lfs_dirops) \ 47954264Sbostic wakeup(&(fs)->lfs_writer); \ 48054264Sbostic } 48154264Sbostic 48254264Sbostic #define MARK_VNODE(dvp) (dvp)->v_flag |= VDIROP 48354264Sbostic 48454264Sbostic int 48554264Sbostic lfs_symlink(ap) 48654692Sbostic struct vop_symlink_args /* { 48754692Sbostic struct vnode *a_dvp; 48854692Sbostic struct vnode **a_vpp; 48954692Sbostic struct componentname *a_cnp; 49054692Sbostic struct vattr *a_vap; 49154692Sbostic char *a_target; 49254692Sbostic } */ *ap; 49354264Sbostic { 49454264Sbostic int ret; 49554264Sbostic 49654264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 49754264Sbostic MARK_VNODE(ap->a_dvp); 49854264Sbostic ret = ufs_symlink(ap); 49954264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 50054264Sbostic return (ret); 50154264Sbostic } 50254264Sbostic 50354264Sbostic int 50454264Sbostic lfs_mknod(ap) 50554692Sbostic struct vop_mknod_args /* { 50654692Sbostic struct vnode *a_dvp; 50754692Sbostic struct vnode **a_vpp; 50854692Sbostic struct componentname *a_cnp; 50954692Sbostic struct vattr *a_vap; 51054692Sbostic } */ *ap; 51154264Sbostic { 51254264Sbostic int ret; 51354264Sbostic 51454264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 51554264Sbostic MARK_VNODE(ap->a_dvp); 51654264Sbostic ret = ufs_mknod(ap); 51754264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 51854264Sbostic return (ret); 51954264Sbostic } 52054264Sbostic 52154264Sbostic int 52254264Sbostic lfs_create(ap) 52354692Sbostic struct vop_create_args /* { 52454692Sbostic struct vnode *a_dvp; 52554692Sbostic struct vnode **a_vpp; 52654692Sbostic struct componentname *a_cnp; 52754692Sbostic struct vattr *a_vap; 52854692Sbostic } */ *ap; 52954264Sbostic { 53054264Sbostic int ret; 53154264Sbostic 53254264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 53354264Sbostic MARK_VNODE(ap->a_dvp); 53454264Sbostic ret = ufs_create(ap); 53554264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 53654264Sbostic return (ret); 53754264Sbostic } 53854264Sbostic 53954264Sbostic int 54054264Sbostic lfs_mkdir(ap) 54154692Sbostic struct vop_mkdir_args /* { 54254692Sbostic struct vnode *a_dvp; 54354692Sbostic struct vnode **a_vpp; 54454692Sbostic struct componentname *a_cnp; 54554692Sbostic struct vattr *a_vap; 54654692Sbostic } */ *ap; 54754264Sbostic { 54854264Sbostic int ret; 54954264Sbostic 55054264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 55154264Sbostic MARK_VNODE(ap->a_dvp); 55254264Sbostic ret = ufs_mkdir(ap); 55354264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 55454264Sbostic return (ret); 55554264Sbostic } 55654264Sbostic 55754264Sbostic int 55854264Sbostic lfs_remove(ap) 55954692Sbostic struct vop_remove_args /* { 56054692Sbostic struct vnode *a_dvp; 56154692Sbostic struct vnode *a_vp; 56254692Sbostic struct componentname *a_cnp; 56354692Sbostic } */ *ap; 56454264Sbostic { 56554264Sbostic int ret; 56654264Sbostic 56754264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 56854264Sbostic MARK_VNODE(ap->a_dvp); 56954264Sbostic MARK_VNODE(ap->a_vp); 57054264Sbostic ret = ufs_remove(ap); 57154264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 57254264Sbostic return (ret); 57354264Sbostic } 57454264Sbostic 57554264Sbostic int 57654264Sbostic lfs_rmdir(ap) 57754692Sbostic struct vop_rmdir_args /* { 57854692Sbostic struct vnodeop_desc *a_desc; 57954692Sbostic struct vnode *a_dvp; 58054692Sbostic struct vnode *a_vp; 58154692Sbostic struct componentname *a_cnp; 58254692Sbostic } */ *ap; 58354264Sbostic { 58454264Sbostic int ret; 58554264Sbostic 58654264Sbostic SET_DIROP(VTOI(ap->a_dvp)->i_lfs); 58754264Sbostic MARK_VNODE(ap->a_dvp); 58854264Sbostic MARK_VNODE(ap->a_vp); 58954264Sbostic ret = ufs_rmdir(ap); 59054264Sbostic SET_ENDOP(VTOI(ap->a_dvp)->i_lfs); 59154264Sbostic return (ret); 59254264Sbostic } 59354264Sbostic 59454264Sbostic int 59554264Sbostic lfs_link(ap) 59654692Sbostic struct vop_link_args /* { 59754692Sbostic struct vnode *a_vp; 59854692Sbostic struct vnode *a_tdvp; 59954692Sbostic struct componentname *a_cnp; 60054692Sbostic } */ *ap; 60154264Sbostic { 60254264Sbostic int ret; 60354264Sbostic 60454264Sbostic SET_DIROP(VTOI(ap->a_vp)->i_lfs); 60554264Sbostic MARK_VNODE(ap->a_vp); 60654264Sbostic ret = ufs_link(ap); 60754264Sbostic SET_ENDOP(VTOI(ap->a_vp)->i_lfs); 60854264Sbostic return (ret); 60954264Sbostic } 61054264Sbostic 61154264Sbostic int 61254264Sbostic lfs_rename(ap) 61354692Sbostic struct vop_rename_args /* { 61454692Sbostic struct vnode *a_fdvp; 61554692Sbostic struct vnode *a_fvp; 61654692Sbostic struct componentname *a_fcnp; 61754692Sbostic struct vnode *a_tdvp; 61854692Sbostic struct vnode *a_tvp; 61954692Sbostic struct componentname *a_tcnp; 62054692Sbostic } */ *ap; 62154264Sbostic { 62254264Sbostic int ret; 62354264Sbostic 62454264Sbostic SET_DIROP(VTOI(ap->a_fdvp)->i_lfs); 62554264Sbostic MARK_VNODE(ap->a_fdvp); 62654264Sbostic MARK_VNODE(ap->a_tdvp); 62754264Sbostic ret = ufs_rename(ap); 62854264Sbostic SET_ENDOP(VTOI(ap->a_fdvp)->i_lfs); 62954264Sbostic return (ret); 63054264Sbostic } 63155936Sbostic /* XXX hack to avoid calling ITIMES in getattr */ 63255936Sbostic int 63355936Sbostic lfs_getattr(ap) 63455936Sbostic struct vop_getattr_args /* { 63555936Sbostic struct vnode *a_vp; 63655936Sbostic struct vattr *a_vap; 63755936Sbostic struct ucred *a_cred; 63855936Sbostic struct proc *a_p; 63955936Sbostic } */ *ap; 64055936Sbostic { 64155936Sbostic register struct vnode *vp = ap->a_vp; 64255936Sbostic register struct inode *ip = VTOI(vp); 64355936Sbostic register struct vattr *vap = ap->a_vap; 64455936Sbostic /* 64555936Sbostic * Copy from inode table 64655936Sbostic */ 64755936Sbostic vap->va_fsid = ip->i_dev; 64855936Sbostic vap->va_fileid = ip->i_number; 64955936Sbostic vap->va_mode = ip->i_mode & ~IFMT; 65055936Sbostic vap->va_nlink = ip->i_nlink; 65155936Sbostic vap->va_uid = ip->i_uid; 65255936Sbostic vap->va_gid = ip->i_gid; 65355936Sbostic vap->va_rdev = (dev_t)ip->i_rdev; 65455936Sbostic vap->va_size = ip->i_din.di_size; 65555936Sbostic vap->va_atime = ip->i_atime; 65655936Sbostic vap->va_mtime = ip->i_mtime; 65755936Sbostic vap->va_ctime = ip->i_ctime; 65855936Sbostic vap->va_flags = ip->i_flags; 65955936Sbostic vap->va_gen = ip->i_gen; 66055936Sbostic /* this doesn't belong here */ 66155936Sbostic if (vp->v_type == VBLK) 66255936Sbostic vap->va_blocksize = BLKDEV_IOSIZE; 66355936Sbostic else if (vp->v_type == VCHR) 66455936Sbostic vap->va_blocksize = MAXBSIZE; 66555936Sbostic else 66655936Sbostic vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; 66755936Sbostic vap->va_bytes = dbtob(ip->i_blocks); 66855936Sbostic vap->va_type = vp->v_type; 66955936Sbostic vap->va_filerev = ip->i_modrev; 67055936Sbostic return (0); 67155936Sbostic } 67256053Sbostic /* 67356053Sbostic * Close called 67456053Sbostic * 67556053Sbostic * XXX -- we were using ufs_close, but since it updates the 67656053Sbostic * times on the inode, we might need to bump the uinodes 67756053Sbostic * count. 67856053Sbostic */ 67956053Sbostic /* ARGSUSED */ 68056053Sbostic int 68156053Sbostic lfs_close(ap) 68256053Sbostic struct vop_close_args /* { 68356053Sbostic struct vnode *a_vp; 68456053Sbostic int a_fflag; 68556053Sbostic struct ucred *a_cred; 68656053Sbostic struct proc *a_p; 68756053Sbostic } */ *ap; 68856053Sbostic { 68956053Sbostic register struct vnode *vp = ap->a_vp; 69056053Sbostic register struct inode *ip = VTOI(vp); 69156053Sbostic int mod; 69256053Sbostic 69356053Sbostic if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED)) { 69456053Sbostic mod = ip->i_flag & IMOD; 69556053Sbostic ITIMES(ip, &time, &time); 69656053Sbostic if (!mod && ip->i_flag & IMOD) 69756053Sbostic ip->i_lfs->lfs_uinodes++; 69856053Sbostic } 69956053Sbostic return (0); 70056053Sbostic } 70156053Sbostic 702