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*53321Smckusick * @(#)lfs_vnops.c 7.80 (Berkeley) 05/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 26*53321Smckusick #include <vm/vm.h> 27*53321Smckusick 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. */ 3751482Sbostic struct vnodeops lfs_vnodeops = { 3851482Sbostic ufs_lookup, /* lookup */ 3951482Sbostic ufs_create, /* create */ 4051482Sbostic ufs_mknod, /* mknod */ 4151482Sbostic ufs_open, /* open */ 4251482Sbostic ufs_close, /* close */ 4351482Sbostic ufs_access, /* access */ 4451482Sbostic ufs_getattr, /* getattr */ 4551482Sbostic ufs_setattr, /* setattr */ 4651482Sbostic lfs_read, /* read */ 4751482Sbostic lfs_write, /* write */ 4851482Sbostic ufs_ioctl, /* ioctl */ 4951482Sbostic ufs_select, /* select */ 5051482Sbostic ufs_mmap, /* mmap */ 5151482Sbostic lfs_fsync, /* fsync */ 5251482Sbostic ufs_seek, /* seek */ 5351482Sbostic ufs_remove, /* remove */ 5451482Sbostic ufs_link, /* link */ 5551482Sbostic ufs_rename, /* rename */ 5651482Sbostic ufs_mkdir, /* mkdir */ 5751482Sbostic ufs_rmdir, /* rmdir */ 5851482Sbostic ufs_symlink, /* symlink */ 5951482Sbostic ufs_readdir, /* readdir */ 6051482Sbostic ufs_readlink, /* readlink */ 6151482Sbostic ufs_abortop, /* abortop */ 6251558Smckusick lfs_inactive, /* inactive */ 6351482Sbostic ufs_reclaim, /* reclaim */ 6451482Sbostic ufs_lock, /* lock */ 6551482Sbostic ufs_unlock, /* unlock */ 6651558Smckusick lfs_bmap, /* bmap */ 6751482Sbostic ufs_strategy, /* strategy */ 6851482Sbostic ufs_print, /* print */ 6951482Sbostic ufs_islocked, /* islocked */ 7051482Sbostic ufs_advlock, /* advlock */ 7151558Smckusick lfs_blkatoff, /* blkatoff */ 7251558Smckusick lfs_vget, /* vget */ 7351558Smckusick lfs_valloc, /* valloc */ 7451558Smckusick lfs_vfree, /* vfree */ 7551558Smckusick lfs_truncate, /* truncate */ 7651558Smckusick lfs_update, /* update */ 7751558Smckusick lfs_bwrite, /* bwrite */ 7851482Sbostic }; 796254Sroot 8051558Smckusick struct vnodeops lfs_specops = { 8151558Smckusick spec_lookup, /* lookup */ 8251558Smckusick spec_create, /* create */ 8351558Smckusick spec_mknod, /* mknod */ 8451558Smckusick spec_open, /* open */ 8551558Smckusick ufsspec_close, /* close */ 8651558Smckusick ufs_access, /* access */ 8751558Smckusick ufs_getattr, /* getattr */ 8851558Smckusick ufs_setattr, /* setattr */ 8951558Smckusick ufsspec_read, /* read */ 9051558Smckusick ufsspec_write, /* write */ 9151558Smckusick spec_ioctl, /* ioctl */ 9251558Smckusick spec_select, /* select */ 9351558Smckusick spec_mmap, /* mmap */ 9451558Smckusick spec_fsync, /* fsync */ 9551558Smckusick spec_seek, /* seek */ 9651558Smckusick spec_remove, /* remove */ 9751558Smckusick spec_link, /* link */ 9851558Smckusick spec_rename, /* rename */ 9951558Smckusick spec_mkdir, /* mkdir */ 10051558Smckusick spec_rmdir, /* rmdir */ 10151558Smckusick spec_symlink, /* symlink */ 10251558Smckusick spec_readdir, /* readdir */ 10351558Smckusick spec_readlink, /* readlink */ 10451558Smckusick spec_abortop, /* abortop */ 10551558Smckusick lfs_inactive, /* inactive */ 10651558Smckusick ufs_reclaim, /* reclaim */ 10751558Smckusick ufs_lock, /* lock */ 10851558Smckusick ufs_unlock, /* unlock */ 10951558Smckusick spec_bmap, /* bmap */ 11051558Smckusick spec_strategy, /* strategy */ 11151558Smckusick ufs_print, /* print */ 11251558Smckusick ufs_islocked, /* islocked */ 11351558Smckusick spec_advlock, /* advlock */ 11451558Smckusick spec_blkatoff, /* blkatoff */ 11551558Smckusick spec_vget, /* vget */ 11651558Smckusick spec_valloc, /* valloc */ 11751558Smckusick spec_vfree, /* vfree */ 11851558Smckusick spec_truncate, /* truncate */ 11951558Smckusick lfs_update, /* update */ 12051558Smckusick lfs_bwrite, /* bwrite */ 12151558Smckusick }; 12251558Smckusick 12351558Smckusick #ifdef FIFO 12451558Smckusick struct vnodeops lfs_fifoops = { 12551558Smckusick fifo_lookup, /* lookup */ 12651558Smckusick fifo_create, /* create */ 12751558Smckusick fifo_mknod, /* mknod */ 12851558Smckusick fifo_open, /* open */ 12951558Smckusick ufsfifo_close, /* close */ 13051558Smckusick ufs_access, /* access */ 13151558Smckusick ufs_getattr, /* getattr */ 13251558Smckusick ufs_setattr, /* setattr */ 13351558Smckusick ufsfifo_read, /* read */ 13451558Smckusick ufsfifo_write, /* write */ 13551558Smckusick fifo_ioctl, /* ioctl */ 13651558Smckusick fifo_select, /* select */ 13751558Smckusick fifo_mmap, /* mmap */ 13851558Smckusick fifo_fsync, /* fsync */ 13951558Smckusick fifo_seek, /* seek */ 14051558Smckusick fifo_remove, /* remove */ 14151558Smckusick fifo_link, /* link */ 14251558Smckusick fifo_rename, /* rename */ 14351558Smckusick fifo_mkdir, /* mkdir */ 14451558Smckusick fifo_rmdir, /* rmdir */ 14551558Smckusick fifo_symlink, /* symlink */ 14651558Smckusick fifo_readdir, /* readdir */ 14751558Smckusick fifo_readlink, /* readlink */ 14851558Smckusick fifo_abortop, /* abortop */ 14951558Smckusick lfs_inactive, /* inactive */ 15051558Smckusick ufs_reclaim, /* reclaim */ 15151558Smckusick ufs_lock, /* lock */ 15251558Smckusick ufs_unlock, /* unlock */ 15351558Smckusick fifo_bmap, /* bmap */ 15451558Smckusick fifo_strategy, /* strategy */ 15551558Smckusick ufs_print, /* print */ 15651558Smckusick ufs_islocked, /* islocked */ 15751558Smckusick fifo_advlock, /* advlock */ 15851558Smckusick fifo_blkatoff, /* blkatoff */ 15951558Smckusick fifo_vget, /* vget */ 16051558Smckusick fifo_valloc, /* valloc */ 16151558Smckusick fifo_vfree, /* vfree */ 16251558Smckusick fifo_truncate, /* truncate */ 16351558Smckusick lfs_update, /* update */ 16451558Smckusick lfs_bwrite, /* bwrite */ 16551558Smckusick }; 16651558Smckusick #endif /* FIFO */ 16751558Smckusick 16837Sbill /* 16939608Smckusick * Vnode op for reading. 17039608Smckusick */ 17137737Smckusick /* ARGSUSED */ 17251134Sbostic lfs_read(vp, uio, ioflag, cred) 17339608Smckusick struct vnode *vp; 17439608Smckusick register struct uio *uio; 17539608Smckusick int ioflag; 17639608Smckusick struct ucred *cred; 17739608Smckusick { 17839608Smckusick register struct inode *ip = VTOI(vp); 17951502Sbostic register struct lfs *fs; /* LFS */ 18039608Smckusick struct buf *bp; 18139608Smckusick daddr_t lbn, bn, rablock; 18253233Smckusick int size, error = 0; 18339608Smckusick long n, on, type; 18453233Smckusick off_t diff; 18539608Smckusick 18651852Sbostic #ifdef VERBOSE 18751852Sbostic printf("lfs_read: ino %d\n", ip->i_number); 18851852Sbostic #endif 18948039Smckusick #ifdef DIAGNOSTIC 19039608Smckusick if (uio->uio_rw != UIO_READ) 19139608Smckusick panic("ufs_read mode"); 19239608Smckusick type = ip->i_mode & IFMT; 19339608Smckusick if (type != IFDIR && type != IFREG && type != IFLNK) 19439608Smckusick panic("ufs_read type"); 19548039Smckusick #endif 19639608Smckusick if (uio->uio_resid == 0) 19739608Smckusick return (0); 19839608Smckusick if (uio->uio_offset < 0) 19939608Smckusick return (EINVAL); 20039608Smckusick ip->i_flag |= IACC; 20151155Sbostic 20251155Sbostic fs = ip->i_lfs; /* LFS */ 20339608Smckusick do { 20439608Smckusick lbn = lblkno(fs, uio->uio_offset); 20539608Smckusick on = blkoff(fs, uio->uio_offset); 20651155Sbostic n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 20739608Smckusick diff = ip->i_size - uio->uio_offset; 20839608Smckusick if (diff <= 0) 20939608Smckusick return (0); 21039608Smckusick if (diff < n) 21139608Smckusick n = diff; 21251155Sbostic size = blksize(fs); /* LFS */ 21339674Smckusick rablock = lbn + 1; 21439896Smckusick if (vp->v_lastr + 1 == lbn && 21539896Smckusick lblktosize(fs, rablock) < ip->i_size) 21652195Smckusick error = breadn(ITOV(ip), lbn, size, &rablock, 21752195Smckusick &size, 1, NOCRED, &bp); 21839608Smckusick else 21939674Smckusick error = bread(ITOV(ip), lbn, size, NOCRED, &bp); 22039815Smckusick vp->v_lastr = lbn; 22139608Smckusick n = MIN(n, size - bp->b_resid); 22239608Smckusick if (error) { 22339608Smckusick brelse(bp); 22439608Smckusick return (error); 22539608Smckusick } 22639608Smckusick error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 22751155Sbostic if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size) 22839608Smckusick bp->b_flags |= B_AGE; 22939608Smckusick brelse(bp); 23039608Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 23139608Smckusick return (error); 23239608Smckusick } 23339608Smckusick 23439608Smckusick /* 23539608Smckusick * Vnode op for writing. 23639608Smckusick */ 23751134Sbostic lfs_write(vp, uio, ioflag, cred) 23839608Smckusick register struct vnode *vp; 23939608Smckusick struct uio *uio; 24039608Smckusick int ioflag; 24139608Smckusick struct ucred *cred; 24239608Smckusick { 24348039Smckusick struct proc *p = uio->uio_procp; 24439608Smckusick register struct inode *ip = VTOI(vp); 24552091Sbostic register struct lfs *fs; 24639608Smckusick struct buf *bp; 24752091Sbostic daddr_t lbn; 24853233Smckusick off_t osize; 24952091Sbostic int n, on, flags, newblock; 25045722Smckusick int size, resid, error = 0; 25139608Smckusick 25251852Sbostic #ifdef VERBOSE 25351852Sbostic printf("lfs_write ino %d\n", ip->i_number); 25451852Sbostic #endif 25548039Smckusick #ifdef DIAGNOSTIC 25639608Smckusick if (uio->uio_rw != UIO_WRITE) 25752091Sbostic panic("lfs_write mode"); 25848039Smckusick #endif 25939608Smckusick switch (vp->v_type) { 26039608Smckusick case VREG: 26139608Smckusick if (ioflag & IO_APPEND) 26239608Smckusick uio->uio_offset = ip->i_size; 26339608Smckusick /* fall through */ 26439608Smckusick case VLNK: 26539608Smckusick break; 26639608Smckusick 26739608Smckusick case VDIR: 26852091Sbostic /* XXX This may not be correct for LFS. */ 26939608Smckusick if ((ioflag & IO_SYNC) == 0) 27052091Sbostic panic("lfs_write nonsync dir write"); 27139608Smckusick break; 27239608Smckusick 27339608Smckusick default: 27452091Sbostic panic("lfs_write type"); 27539608Smckusick } 27639608Smckusick if (uio->uio_offset < 0) 27739608Smckusick return (EINVAL); 27839608Smckusick if (uio->uio_resid == 0) 27939608Smckusick return (0); 28039608Smckusick /* 28139608Smckusick * Maybe this should be above the vnode op call, but so long as 28239608Smckusick * file servers have no limits, i don't think it matters 28339608Smckusick */ 28449679Smckusick if (vp->v_type == VREG && p && 28539608Smckusick uio->uio_offset + uio->uio_resid > 28647571Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { 28747571Skarels psignal(p, SIGXFSZ); 28839608Smckusick return (EFBIG); 28939608Smckusick } 29039608Smckusick resid = uio->uio_resid; 29139608Smckusick osize = ip->i_size; 29251183Sbostic fs = ip->i_lfs; /* LFS */ 29339674Smckusick flags = 0; 29451183Sbostic #ifdef NOTLFS 29539674Smckusick if (ioflag & IO_SYNC) 29639674Smckusick flags = B_SYNC; 29751183Sbostic #endif 29839608Smckusick do { 29939608Smckusick lbn = lblkno(fs, uio->uio_offset); 30051932Sbostic on = blkoff(fs, uio->uio_offset); 30151183Sbostic n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid); 30252091Sbostic if (error = lfs_balloc(vp, n, lbn, &bp)) 30339608Smckusick break; 30445722Smckusick if (uio->uio_offset + n > ip->i_size) { 30539608Smckusick ip->i_size = uio->uio_offset + n; 30652019Smckusick vnode_pager_setsize(vp, (u_long)ip->i_size); 30745722Smckusick } 30851183Sbostic size = blksize(fs); 30945722Smckusick (void) vnode_pager_uncache(vp); 31039608Smckusick n = MIN(n, size - bp->b_resid); 31139608Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 31251183Sbostic #ifdef NOTLFS /* LFS */ 31339608Smckusick if (ioflag & IO_SYNC) 31439608Smckusick (void) bwrite(bp); 31539608Smckusick else if (n + on == fs->fs_bsize) { 31639608Smckusick bp->b_flags |= B_AGE; 31739608Smckusick bawrite(bp); 31839608Smckusick } else 31939608Smckusick bdwrite(bp); 32052091Sbostic ip->i_flag |= IUPD|ICHG; 32151183Sbostic #else 32252091Sbostic /* XXX This doesn't handle IO_SYNC. */ 32352091Sbostic LFS_UBWRITE(bp); 32451183Sbostic #endif 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)) { 32953242Smckusick (void)lfs_truncate(vp, osize, ioflag & IO_SYNC, cred); 33039608Smckusick uio->uio_offset -= resid - uio->uio_resid; 33139608Smckusick uio->uio_resid = resid; 33239608Smckusick } 33342493Smckusick if (!error && (ioflag & IO_SYNC)) 33451932Sbostic error = lfs_update(vp, &time, &time, 1); 33539608Smckusick return (error); 33639608Smckusick } 33739608Smckusick 3389167Ssam /* 33937737Smckusick * Synch an open file. 3409167Ssam */ 34137737Smckusick /* ARGSUSED */ 34251134Sbostic lfs_fsync(vp, fflags, cred, waitfor, p) 34337737Smckusick struct vnode *vp; 34437737Smckusick int fflags; 34537737Smckusick struct ucred *cred; 34639597Smckusick int waitfor; 34748039Smckusick struct proc *p; 3487701Ssam { 34951852Sbostic struct inode *ip; 3507701Ssam 35151852Sbostic #ifdef VERBOSE 35251852Sbostic printf("lfs_fsync\n"); 35351852Sbostic #endif 35451852Sbostic ip = VTOI(vp); 35548039Smckusick if (fflags & FWRITE) 35637737Smckusick ip->i_flag |= ICHG; 35752329Sbostic return (lfs_update(vp, &time, &time, waitfor == MNT_WAIT)); 35837737Smckusick } 35951558Smckusick 36051558Smckusick /* 36151558Smckusick * Last reference to an inode, write the inode out and if necessary, 36251558Smckusick * truncate and deallocate the file. 36351558Smckusick */ 36451558Smckusick int 36551558Smckusick lfs_inactive(vp, p) 36651558Smckusick struct vnode *vp; 36751558Smckusick struct proc *p; 36851558Smckusick { 36951852Sbostic extern int prtactive; 37051558Smckusick register struct inode *ip; 37151558Smckusick int mode, error; 37251558Smckusick 37351852Sbostic #ifdef VERBOSE 37451852Sbostic printf("lfs_inactive\n"); 37551852Sbostic #endif 37651558Smckusick if (prtactive && vp->v_usecount != 0) 37751558Smckusick vprint("lfs_inactive: pushing active", vp); 37851558Smckusick 37951558Smckusick /* Get rid of inodes related to stale file handles. */ 38051558Smckusick ip = VTOI(vp); 38151558Smckusick if (ip->i_mode == 0) { 38251558Smckusick if ((vp->v_flag & VXLOCK) == 0) 38351558Smckusick vgone(vp); 38451558Smckusick return (0); 38551558Smckusick } 38651558Smckusick 38751558Smckusick error = 0; 38851558Smckusick ILOCK(ip); 38951558Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 39051558Smckusick #ifdef QUOTA 39151558Smckusick if (!getinoquota(ip)) 39251558Smckusick (void)chkiq(ip, -1, NOCRED, 0); 39351558Smckusick #endif 39453242Smckusick error = lfs_truncate(vp, (off_t)0, 0, NOCRED); 39551558Smckusick mode = ip->i_mode; 39651558Smckusick ip->i_mode = 0; 39751558Smckusick ip->i_rdev = 0; 39851558Smckusick ip->i_flag |= IUPD|ICHG; 39951558Smckusick lfs_vfree(vp, ip->i_number, mode); 40051558Smckusick } 40151558Smckusick if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) 40251558Smckusick lfs_update(vp, &time, &time, 0); 40351558Smckusick IUNLOCK(ip); 40451558Smckusick ip->i_flag = 0; 40551558Smckusick /* 40651558Smckusick * If we are done with the inode, reclaim it 40751558Smckusick * so that it can be reused immediately. 40851558Smckusick */ 40951558Smckusick if (vp->v_usecount == 0 && ip->i_mode == 0) 41051558Smckusick vgone(vp); 41151558Smckusick return (error); 41251558Smckusick } 413