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*51558Smckusick * @(#)lfs_vnops.c 7.71 (Berkeley) 11/05/91 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 2651502Sbostic #include <ufs/ufs/quota.h> 2751502Sbostic #include <ufs/ufs/inode.h> 2851502Sbostic #include <ufs/ufs/dir.h> 2951502Sbostic #include <ufs/ufs/ufs_extern.h> 3047571Skarels 3151502Sbostic #include <ufs/lfs/lfs.h> 3251502Sbostic #include <ufs/lfs/lfs_extern.h> 3351134Sbostic 3451482Sbostic /* Global vfs data structures for lfs. */ 3551482Sbostic struct vnodeops lfs_vnodeops = { 3651482Sbostic ufs_lookup, /* lookup */ 3751482Sbostic ufs_create, /* create */ 3851482Sbostic ufs_mknod, /* mknod */ 3951482Sbostic ufs_open, /* open */ 4051482Sbostic ufs_close, /* close */ 4151482Sbostic ufs_access, /* access */ 4251482Sbostic ufs_getattr, /* getattr */ 4351482Sbostic ufs_setattr, /* setattr */ 4451482Sbostic lfs_read, /* read */ 4551482Sbostic lfs_write, /* write */ 4651482Sbostic ufs_ioctl, /* ioctl */ 4751482Sbostic ufs_select, /* select */ 4851482Sbostic ufs_mmap, /* mmap */ 4951482Sbostic lfs_fsync, /* fsync */ 5051482Sbostic ufs_seek, /* seek */ 5151482Sbostic ufs_remove, /* remove */ 5251482Sbostic ufs_link, /* link */ 5351482Sbostic ufs_rename, /* rename */ 5451482Sbostic ufs_mkdir, /* mkdir */ 5551482Sbostic ufs_rmdir, /* rmdir */ 5651482Sbostic ufs_symlink, /* symlink */ 5751482Sbostic ufs_readdir, /* readdir */ 5851482Sbostic ufs_readlink, /* readlink */ 5951482Sbostic ufs_abortop, /* abortop */ 60*51558Smckusick lfs_inactive, /* inactive */ 6151482Sbostic ufs_reclaim, /* reclaim */ 6251482Sbostic ufs_lock, /* lock */ 6351482Sbostic ufs_unlock, /* unlock */ 64*51558Smckusick lfs_bmap, /* bmap */ 6551482Sbostic ufs_strategy, /* strategy */ 6651482Sbostic ufs_print, /* print */ 6751482Sbostic ufs_islocked, /* islocked */ 6851482Sbostic ufs_advlock, /* advlock */ 69*51558Smckusick lfs_blkatoff, /* blkatoff */ 70*51558Smckusick lfs_vget, /* vget */ 71*51558Smckusick lfs_valloc, /* valloc */ 72*51558Smckusick lfs_vfree, /* vfree */ 73*51558Smckusick lfs_truncate, /* truncate */ 74*51558Smckusick lfs_update, /* update */ 75*51558Smckusick lfs_bwrite, /* bwrite */ 7651482Sbostic }; 776254Sroot 78*51558Smckusick struct vnodeops lfs_specops = { 79*51558Smckusick spec_lookup, /* lookup */ 80*51558Smckusick spec_create, /* create */ 81*51558Smckusick spec_mknod, /* mknod */ 82*51558Smckusick spec_open, /* open */ 83*51558Smckusick ufsspec_close, /* close */ 84*51558Smckusick ufs_access, /* access */ 85*51558Smckusick ufs_getattr, /* getattr */ 86*51558Smckusick ufs_setattr, /* setattr */ 87*51558Smckusick ufsspec_read, /* read */ 88*51558Smckusick ufsspec_write, /* write */ 89*51558Smckusick spec_ioctl, /* ioctl */ 90*51558Smckusick spec_select, /* select */ 91*51558Smckusick spec_mmap, /* mmap */ 92*51558Smckusick spec_fsync, /* fsync */ 93*51558Smckusick spec_seek, /* seek */ 94*51558Smckusick spec_remove, /* remove */ 95*51558Smckusick spec_link, /* link */ 96*51558Smckusick spec_rename, /* rename */ 97*51558Smckusick spec_mkdir, /* mkdir */ 98*51558Smckusick spec_rmdir, /* rmdir */ 99*51558Smckusick spec_symlink, /* symlink */ 100*51558Smckusick spec_readdir, /* readdir */ 101*51558Smckusick spec_readlink, /* readlink */ 102*51558Smckusick spec_abortop, /* abortop */ 103*51558Smckusick lfs_inactive, /* inactive */ 104*51558Smckusick ufs_reclaim, /* reclaim */ 105*51558Smckusick ufs_lock, /* lock */ 106*51558Smckusick ufs_unlock, /* unlock */ 107*51558Smckusick spec_bmap, /* bmap */ 108*51558Smckusick spec_strategy, /* strategy */ 109*51558Smckusick ufs_print, /* print */ 110*51558Smckusick ufs_islocked, /* islocked */ 111*51558Smckusick spec_advlock, /* advlock */ 112*51558Smckusick spec_blkatoff, /* blkatoff */ 113*51558Smckusick spec_vget, /* vget */ 114*51558Smckusick spec_valloc, /* valloc */ 115*51558Smckusick spec_vfree, /* vfree */ 116*51558Smckusick spec_truncate, /* truncate */ 117*51558Smckusick lfs_update, /* update */ 118*51558Smckusick lfs_bwrite, /* bwrite */ 119*51558Smckusick }; 120*51558Smckusick 121*51558Smckusick #ifdef FIFO 122*51558Smckusick struct vnodeops lfs_fifoops = { 123*51558Smckusick fifo_lookup, /* lookup */ 124*51558Smckusick fifo_create, /* create */ 125*51558Smckusick fifo_mknod, /* mknod */ 126*51558Smckusick fifo_open, /* open */ 127*51558Smckusick ufsfifo_close, /* close */ 128*51558Smckusick ufs_access, /* access */ 129*51558Smckusick ufs_getattr, /* getattr */ 130*51558Smckusick ufs_setattr, /* setattr */ 131*51558Smckusick ufsfifo_read, /* read */ 132*51558Smckusick ufsfifo_write, /* write */ 133*51558Smckusick fifo_ioctl, /* ioctl */ 134*51558Smckusick fifo_select, /* select */ 135*51558Smckusick fifo_mmap, /* mmap */ 136*51558Smckusick fifo_fsync, /* fsync */ 137*51558Smckusick fifo_seek, /* seek */ 138*51558Smckusick fifo_remove, /* remove */ 139*51558Smckusick fifo_link, /* link */ 140*51558Smckusick fifo_rename, /* rename */ 141*51558Smckusick fifo_mkdir, /* mkdir */ 142*51558Smckusick fifo_rmdir, /* rmdir */ 143*51558Smckusick fifo_symlink, /* symlink */ 144*51558Smckusick fifo_readdir, /* readdir */ 145*51558Smckusick fifo_readlink, /* readlink */ 146*51558Smckusick fifo_abortop, /* abortop */ 147*51558Smckusick lfs_inactive, /* inactive */ 148*51558Smckusick ufs_reclaim, /* reclaim */ 149*51558Smckusick ufs_lock, /* lock */ 150*51558Smckusick ufs_unlock, /* unlock */ 151*51558Smckusick fifo_bmap, /* bmap */ 152*51558Smckusick fifo_strategy, /* strategy */ 153*51558Smckusick ufs_print, /* print */ 154*51558Smckusick ufs_islocked, /* islocked */ 155*51558Smckusick fifo_advlock, /* advlock */ 156*51558Smckusick fifo_blkatoff, /* blkatoff */ 157*51558Smckusick fifo_vget, /* vget */ 158*51558Smckusick fifo_valloc, /* valloc */ 159*51558Smckusick fifo_vfree, /* vfree */ 160*51558Smckusick fifo_truncate, /* truncate */ 161*51558Smckusick lfs_update, /* update */ 162*51558Smckusick lfs_bwrite, /* bwrite */ 163*51558Smckusick }; 164*51558Smckusick #endif /* FIFO */ 165*51558Smckusick 16637Sbill /* 16739608Smckusick * Vnode op for reading. 16839608Smckusick */ 16937737Smckusick /* ARGSUSED */ 17051134Sbostic lfs_read(vp, uio, ioflag, cred) 17139608Smckusick struct vnode *vp; 17239608Smckusick register struct uio *uio; 17339608Smckusick int ioflag; 17439608Smckusick struct ucred *cred; 17539608Smckusick { 17639608Smckusick register struct inode *ip = VTOI(vp); 17751502Sbostic register struct lfs *fs; /* LFS */ 17839608Smckusick struct buf *bp; 17939608Smckusick daddr_t lbn, bn, rablock; 18039896Smckusick int size, diff, error = 0; 18139608Smckusick long n, on, type; 18239608Smckusick 18351155Sbostic printf("lfs_read: ino %d\n", ip->i_number); 18448039Smckusick #ifdef DIAGNOSTIC 18539608Smckusick if (uio->uio_rw != UIO_READ) 18639608Smckusick panic("ufs_read mode"); 18739608Smckusick type = ip->i_mode & IFMT; 18839608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 18939608Smckusick panic("ufs_read type"); 19048039Smckusick #endif 19139608Smckusick if (uio->uio_resid == 0) 19239608Smckusick return (0); 19339608Smckusick if (uio->uio_offset < 0) 19439608Smckusick return (EINVAL); 19539608Smckusick ip->i_flag |= IACC; 19651155Sbostic 19751155Sbostic fs = ip->i_lfs; /* LFS */ 19839608Smckusick do { 19939608Smckusick lbn = lblkno(fs, uio->uio_offset); 20039608Smckusick on = blkoff(fs, uio->uio_offset); 20151155Sbostic n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 20239608Smckusick diff = ip->i_size - uio->uio_offset; 20339608Smckusick if (diff <= 0) 20439608Smckusick return (0); 20539608Smckusick if (diff < n) 20639608Smckusick n = diff; 20751155Sbostic size = blksize(fs); /* LFS */ 20839674Smckusick rablock = lbn + 1; 20939896Smckusick if (vp->v_lastr + 1 == lbn && 21039896Smckusick lblktosize(fs, rablock) < ip->i_size) 21139896Smckusick error = breada(ITOV(ip), lbn, size, rablock, 21251155Sbostic blksize(fs), NOCRED, &bp); 21339608Smckusick else 21439674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 21539815Smckusick vp->v_lastr = lbn; 21639608Smckusick n = MIN(n, size - bp->b_resid); 21739608Smckusick if (error) { 21839608Smckusick brelse(bp); 21939608Smckusick return (error); 22039608Smckusick } 22139608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 22251155Sbostic if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size) 22339608Smckusick bp->b_flags |= B_AGE; 22439608Smckusick brelse(bp); 22539608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 22639608Smckusick return (error); 22739608Smckusick } 22839608Smckusick 22939608Smckusick /* 23039608Smckusick * Vnode op for writing. 23139608Smckusick */ 23251134Sbostic lfs_write(vp, uio, ioflag, cred) 23339608Smckusick register struct vnode *vp; 23439608Smckusick struct uio *uio; 23539608Smckusick int ioflag; 23639608Smckusick struct ucred *cred; 23739608Smckusick { 23848039Smckusick struct proc *p = uio->uio_procp; 23939608Smckusick register struct inode *ip = VTOI(vp); 24051502Sbostic register struct lfs *fs; /* LFS */ 24139608Smckusick struct buf *bp; 24239608Smckusick daddr_t lbn, bn; 24339608Smckusick u_long osize; 24445722Smckusick int n, on, flags; 24545722Smckusick int size, resid, error = 0; 24639608Smckusick 24751155Sbostic printf("lfs_write ino %d\n", ip->i_number); 24848039Smckusick #ifdef DIAGNOSTIC 24939608Smckusick if (uio->uio_rw != UIO_WRITE) 25039608Smckusick panic("ufs_write mode"); 25148039Smckusick #endif 25239608Smckusick switch (vp->v_type) { 25339608Smckusick case VREG: 25439608Smckusick if (ioflag & IO_APPEND) 25539608Smckusick uio->uio_offset = ip->i_size; 25639608Smckusick /* fall through */ 25739608Smckusick case VLNK: 25839608Smckusick break; 25939608Smckusick 26039608Smckusick case VDIR: 26139608Smckusick if ((ioflag & IO_SYNC) == 0) 26239608Smckusick panic("ufs_write nonsync dir write"); 26339608Smckusick break; 26439608Smckusick 26539608Smckusick default: 26639608Smckusick panic("ufs_write type"); 26739608Smckusick } 26839608Smckusick if (uio->uio_offset < 0) 26939608Smckusick return (EINVAL); 27039608Smckusick if (uio->uio_resid == 0) 27139608Smckusick return (0); 27239608Smckusick /* 27339608Smckusick * Maybe this should be above the vnode op call, but so long as 27439608Smckusick * file servers have no limits, i don't think it matters 27539608Smckusick */ 27649679Smckusick if (vp->v_type == VREG && p && 27739608Smckusick uio->uio_offset + uio->uio_resid > 27847571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 27947571Skarels psignal(p, SIGXFSZ); 28039608Smckusick return (EFBIG); 28139608Smckusick } 28239608Smckusick resid = uio->uio_resid; 28339608Smckusick osize = ip->i_size; 28451183Sbostic fs = ip->i_lfs; /* LFS */ 28539674Smckusick flags = 0; 28651183Sbostic #ifdef NOTLFS 28739674Smckusick if (ioflag & IO_SYNC) 28839674Smckusick flags = B_SYNC; 28951183Sbostic #endif 29039608Smckusick do { 29139608Smckusick lbn = lblkno(fs, uio->uio_offset); 29251183Sbostic on = blkoff(fs, uio->uio_offset); /* LFS */ 29351183Sbostic n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 29451183Sbostic if (n < fs->lfs_bsize) /* LFS */ 29539674Smckusick flags |= B_CLRBUF; 29639608Smckusick else 29751183Sbostic flags &= ~B_CLRBUF; /* LFS */ 29851183Sbostic if (error = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp)) 29939608Smckusick break; 30039674Smckusick bn = bp->b_blkno; 30145722Smckusick if (uio->uio_offset + n > ip->i_size) { 30239608Smckusick ip->i_size = uio->uio_offset + n; 30345722Smckusick vnode_pager_setsize(vp, ip->i_size); 30445722Smckusick } 30551183Sbostic size = blksize(fs); 30645722Smckusick (void) vnode_pager_uncache(vp); 30739608Smckusick n = MIN(n, size - bp->b_resid); 30839608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 30951183Sbostic #ifdef NOTLFS /* LFS */ 31039608Smckusick if (ioflag & IO_SYNC) 31139608Smckusick (void) bwrite(bp); 31239608Smckusick else if (n + on == fs->fs_bsize) { 31339608Smckusick bp->b_flags |= B_AGE; 31439608Smckusick bawrite(bp); 31539608Smckusick } else 31639608Smckusick bdwrite(bp); 31751183Sbostic #else 31851183Sbostic /* 31951183Sbostic * Update segment usage information; call segment 32051183Sbostic * writer if necessary. 32151183Sbostic */ 32251183Sbostic lfs_bwrite(bp); 32351183Sbostic #endif 32439608Smckusick ip->i_flag |= IUPD|ICHG; 32539608Smckusick if (cred->cr_uid != 0) 32639608Smckusick ip->i_mode &= ~(ISUID|ISGID); 32739608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 32839608Smckusick if (error && (ioflag & IO_UNIT)) { 32951183Sbostic #ifdef NOTLFS 33051183Sbostic /* This just doesn't work... */ 331*51558Smckusick (void) lfs_itrunc(vp, osize, ioflag & IO_SYNC); 33251183Sbostic #endif 33339608Smckusick uio->uio_offset -= resid - uio->uio_resid; 33439608Smckusick uio->uio_resid = resid; 33539608Smckusick } 33642493Smckusick if (!error && (ioflag & IO_SYNC)) 33751183Sbostic ITIMES(ip, &time, &time); /* LFS */ 33839608Smckusick return (error); 33939608Smckusick } 34039608Smckusick 3419167Ssam /* 34237737Smckusick * Synch an open file. 3439167Ssam */ 34437737Smckusick /* ARGSUSED */ 34551134Sbostic lfs_fsync(vp, fflags, cred, waitfor, p) 34637737Smckusick struct vnode *vp; 34737737Smckusick int fflags; 34837737Smckusick struct ucred *cred; 34939597Smckusick int waitfor; 35048039Smckusick struct proc *p; 3517701Ssam { 35239597Smckusick struct inode *ip = VTOI(vp); 3537701Ssam 35448039Smckusick if (fflags & FWRITE) 35537737Smckusick ip->i_flag |= ICHG; 35649737Smckusick /* 35751482Sbostic * XXX 35851482Sbostic * Sync the mounted file system associated with the file 35951482Sbostic * descriptor. 36049737Smckusick */ 36151183Sbostic ITIMES(ip, &time, &time); /* LFS */ 36237737Smckusick return (0); 36337737Smckusick } 364*51558Smckusick 365*51558Smckusick /* 366*51558Smckusick * Last reference to an inode, write the inode out and if necessary, 367*51558Smckusick * truncate and deallocate the file. 368*51558Smckusick */ 369*51558Smckusick int 370*51558Smckusick lfs_inactive(vp, p) 371*51558Smckusick struct vnode *vp; 372*51558Smckusick struct proc *p; 373*51558Smckusick { 374*51558Smckusick register struct inode *ip; 375*51558Smckusick int mode, error; 376*51558Smckusick extern int prtactive; 377*51558Smckusick 378*51558Smckusick if (prtactive && vp->v_usecount != 0) 379*51558Smckusick vprint("lfs_inactive: pushing active", vp); 380*51558Smckusick 381*51558Smckusick /* Get rid of inodes related to stale file handles. */ 382*51558Smckusick ip = VTOI(vp); 383*51558Smckusick if (ip->i_mode == 0) { 384*51558Smckusick if ((vp->v_flag & VXLOCK) == 0) 385*51558Smckusick vgone(vp); 386*51558Smckusick return (0); 387*51558Smckusick } 388*51558Smckusick 389*51558Smckusick error = 0; 390*51558Smckusick ILOCK(ip); 391*51558Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 392*51558Smckusick #ifdef QUOTA 393*51558Smckusick if (!getinoquota(ip)) 394*51558Smckusick (void)chkiq(ip, -1, NOCRED, 0); 395*51558Smckusick #endif 396*51558Smckusick error = lfs_truncate(vp, (u_long)0, 0); 397*51558Smckusick mode = ip->i_mode; 398*51558Smckusick ip->i_mode = 0; 399*51558Smckusick ip->i_rdev = 0; 400*51558Smckusick ip->i_flag |= IUPD|ICHG; 401*51558Smckusick lfs_vfree(vp, ip->i_number, mode); 402*51558Smckusick } 403*51558Smckusick if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) 404*51558Smckusick lfs_update(vp, &time, &time, 0); 405*51558Smckusick IUNLOCK(ip); 406*51558Smckusick ip->i_flag = 0; 407*51558Smckusick /* 408*51558Smckusick * If we are done with the inode, reclaim it 409*51558Smckusick * so that it can be reused immediately. 410*51558Smckusick */ 411*51558Smckusick if (vp->v_usecount == 0 && ip->i_mode == 0) 412*51558Smckusick vgone(vp); 413*51558Smckusick return (error); 414*51558Smckusick } 415