151882Sbostic /*- 251882Sbostic * Copyright (c) 1991 The Regents of the University of California. 351882Sbostic * All rights reserved. 451882Sbostic * 551882Sbostic * %sccs.include.redist.c% 651882Sbostic * 7*56029Sbostic * @(#)lfs_syscalls.c 7.20 (Berkeley) 08/25/92 851882Sbostic */ 951882Sbostic 1051882Sbostic #include <sys/param.h> 1151882Sbostic #include <sys/proc.h> 1251882Sbostic #include <sys/buf.h> 1351882Sbostic #include <sys/mount.h> 1451882Sbostic #include <sys/vnode.h> 1551882Sbostic #include <sys/malloc.h> 1651882Sbostic #include <sys/kernel.h> 1751882Sbostic 1851882Sbostic #include <ufs/ufs/quota.h> 1951882Sbostic #include <ufs/ufs/inode.h> 2051882Sbostic #include <ufs/ufs/ufsmount.h> 2155941Sbostic #include <ufs/ufs/ufs_extern.h> 2251882Sbostic 2351882Sbostic #include <ufs/lfs/lfs.h> 2451882Sbostic #include <ufs/lfs/lfs_extern.h> 2551882Sbostic 2655941Sbostic struct buf *lfs_fakebuf __P((struct vnode *, int, size_t, caddr_t)); 2755941Sbostic 2851882Sbostic /* 2951882Sbostic * lfs_markv: 3051882Sbostic * 3151882Sbostic * This will mark inodes and blocks dirty, so they are written into the log. 3251882Sbostic * It will block until all the blocks have been written. The segment create 3351882Sbostic * time passed in the block_info and inode_info structures is used to decide 3451882Sbostic * if the data is valid for each block (in case some process dirtied a block 3551882Sbostic * or inode that is being cleaned between the determination that a block is 3651882Sbostic * live and the lfs_markv call). 3751882Sbostic * 3851882Sbostic * 0 on success 3951882Sbostic * -1/errno is return on error. 4051882Sbostic */ 4151882Sbostic int 4251882Sbostic lfs_markv(p, uap, retval) 4351882Sbostic struct proc *p; 4451882Sbostic struct args { 4551882Sbostic fsid_t fsid; /* file system */ 4651882Sbostic BLOCK_INFO *blkiov; /* block array */ 4751882Sbostic int blkcnt; /* count of block array entries */ 4851882Sbostic } *uap; 4951882Sbostic int *retval; 5051882Sbostic { 5155941Sbostic struct segment *sp; 5251882Sbostic BLOCK_INFO *blkp; 5351882Sbostic IFILE *ifp; 5455941Sbostic struct buf *bp, **bpp; 5552087Sbostic struct inode *ip; 5651882Sbostic struct lfs *fs; 5751882Sbostic struct mount *mntp; 5851882Sbostic struct vnode *vp; 5952173Sbostic void *start; 6052087Sbostic ino_t lastino; 6155941Sbostic daddr_t b_daddr, v_daddr; 6251882Sbostic u_long bsize; 6351882Sbostic int cnt, error; 6451882Sbostic 6551882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 6651882Sbostic return (error); 6751882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 6851882Sbostic return (EINVAL); 6955941Sbostic /* Initialize a segment. */ 7055941Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 7155941Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 7255941Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 7355941Sbostic sp->seg_flags = SEGM_CKP; 74*56029Sbostic sp->vp = NULL; 7551882Sbostic 7651882Sbostic cnt = uap->blkcnt; 7752996Sbostic start = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 7855941Sbostic if (error = copyin(uap->blkiov, start, cnt * sizeof(BLOCK_INFO))) 7955941Sbostic goto err1; 8051882Sbostic 8155941Sbostic /* Mark blocks/inodes dirty. */ 8252087Sbostic fs = VFSTOUFS(mntp)->um_lfs; 8352820Sbostic bsize = fs->lfs_bsize; 8455941Sbostic error = 0; 8555941Sbostic 8655941Sbostic lfs_seglock(fs); 8755941Sbostic lfs_initseg(fs, sp); 8855941Sbostic sp->seg_flags |= SEGM_CLEAN; 8955941Sbostic for (v_daddr = LFS_UNUSED_DADDR, lastino = LFS_UNUSED_INUM, 9055941Sbostic blkp = start; cnt--; ++blkp) { 9152087Sbostic /* 9252087Sbostic * Get the IFILE entry (only once) and see if the file still 9352087Sbostic * exists. 9452087Sbostic */ 9552087Sbostic if (lastino != blkp->bi_inode) { 9655941Sbostic if (lastino != LFS_UNUSED_INUM) { 97*56029Sbostic lfs_updatemeta(sp); 9855941Sbostic lfs_writeinode(fs, sp, ip); 9955941Sbostic vput(vp); 10055941Sbostic } 10152087Sbostic lastino = blkp->bi_inode; 10252087Sbostic LFS_IENTRY(ifp, fs, blkp->bi_inode, bp); 10355941Sbostic v_daddr = ifp->if_daddr; 10452087Sbostic brelse(bp); 10555941Sbostic if (v_daddr == LFS_UNUSED_DADDR) 10652087Sbostic continue; 10755941Sbostic /* Get the vnode/inode. */ 10855941Sbostic if (lfs_fastvget(mntp, blkp->bi_inode, v_daddr, &vp, 10955941Sbostic blkp->bi_lbn == LFS_UNUSED_LBN ? NULL : 11055941Sbostic blkp->bi_bp)) { 11155941Sbostic #ifdef DIAGNOSTIC 11255941Sbostic printf("lfs_markv: VFS_VGET failed (%d)\n", 11355941Sbostic blkp->bi_inode); 11455941Sbostic #endif 115*56029Sbostic lastino = LFS_UNUSED_INUM; 11655941Sbostic v_daddr == LFS_UNUSED_DADDR; 11755941Sbostic continue; 11855941Sbostic } 119*56029Sbostic sp->vp = vp; 12055941Sbostic ip = VTOI(vp); 12155941Sbostic } else if (v_daddr == LFS_UNUSED_DADDR) 12255941Sbostic continue; 12352087Sbostic 12455941Sbostic /* If this BLOCK_INFO didn't contain a block, keep going. */ 12555941Sbostic if (blkp->bi_lbn == LFS_UNUSED_LBN) 12651882Sbostic continue; 12752173Sbostic /* 12852173Sbostic * If modify time later than segment create time, see if the 12952173Sbostic * block has been replaced. 13052173Sbostic */ 13154103Smckusick if (ip->i_mtime.ts_sec > blkp->bi_segcreate && 13255941Sbostic (VOP_BMAP(vp, blkp->bi_lbn, NULL, &b_daddr) || 13355941Sbostic b_daddr != blkp->bi_daddr)) 13452173Sbostic continue; 13555941Sbostic /* 13655941Sbostic * If we got to here, then we are keeping the block. If it 13755941Sbostic * is an indirect block, we want to actually put it in the 13855941Sbostic * buffer cache so that it can be updated in the finish_meta 13955941Sbostic * section. If it's not, we need to allocate a fake buffer 14055941Sbostic * so that writeseg can perform the copyin and write the buffer. 14155941Sbostic */ 14255941Sbostic if (blkp->bi_lbn >= 0) /* Data Block */ 14355941Sbostic bp = lfs_fakebuf(vp, blkp->bi_lbn, bsize, 14455941Sbostic blkp->bi_bp); 14555941Sbostic else { 14655941Sbostic bp = getblk(vp, blkp->bi_lbn, bsize); 14755941Sbostic if (!(bp->b_flags & B_CACHE) && 14855941Sbostic (error = copyin(blkp->bi_bp, bp->b_un.b_addr, 14955941Sbostic bsize))) 15055941Sbostic goto err2; 15155941Sbostic if (error = VOP_BWRITE(bp)) 15255941Sbostic goto err2; 15352087Sbostic } 154*56029Sbostic while (lfs_gatherblock(sp, bp, NULL)); 15551882Sbostic } 156*56029Sbostic if (sp->vp) { 157*56029Sbostic lfs_updatemeta(sp); 158*56029Sbostic lfs_writeinode(fs, sp, ip); 159*56029Sbostic vput(vp); 160*56029Sbostic } 16155941Sbostic (void) lfs_writeseg(fs, sp); 16255941Sbostic lfs_segunlock(fs); 16352173Sbostic free(start, M_SEGMENT); 16455941Sbostic free(sp->bpp, M_SEGMENT); 16555941Sbostic free(sp, M_SEGMENT); 16655941Sbostic return (error); 16755941Sbostic /* 16855941Sbostic * XXX If we come in to error 2, we might have indirect blocks that were 16955941Sbostic * updated and now have bad block pointers. I don't know what to do 17055941Sbostic * about this. 17155941Sbostic */ 17251882Sbostic 17355941Sbostic err2: vput(vp); 17455941Sbostic /* Free up fakebuffers */ 17555941Sbostic for (bpp = --sp->cbpp; bpp >= sp->bpp; --bpp) 17655941Sbostic if ((*bpp)->b_flags & B_CALL) { 17755941Sbostic brelvp(*bpp); 17855941Sbostic free(*bpp, M_SEGMENT); 17955941Sbostic } else 18055941Sbostic brelse(*bpp); 18155941Sbostic lfs_segunlock(fs); 18255941Sbostic err1: 18355941Sbostic free(sp->bpp, M_SEGMENT); 18455941Sbostic free(sp, M_SEGMENT); 18552173Sbostic free(start, M_SEGMENT); 18655941Sbostic return(error); 18751882Sbostic } 18851882Sbostic 18951882Sbostic /* 19051882Sbostic * lfs_bmapv: 19151882Sbostic * 19252087Sbostic * This will fill in the current disk address for arrays of blocks. 19351882Sbostic * 19451882Sbostic * 0 on success 19551882Sbostic * -1/errno is return on error. 19651882Sbostic */ 19751882Sbostic int 19851882Sbostic lfs_bmapv(p, uap, retval) 19951882Sbostic struct proc *p; 20051882Sbostic struct args { 20151882Sbostic fsid_t fsid; /* file system */ 20251882Sbostic BLOCK_INFO *blkiov; /* block array */ 20351882Sbostic int blkcnt; /* count of block array entries */ 20451882Sbostic } *uap; 20551882Sbostic int *retval; 20651882Sbostic { 20751882Sbostic BLOCK_INFO *blkp; 20851882Sbostic struct mount *mntp; 20951882Sbostic struct vnode *vp; 21052173Sbostic void *start; 21151882Sbostic daddr_t daddr; 21252173Sbostic int cnt, error, step; 21351882Sbostic 21451882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 21551882Sbostic return (error); 21651882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 21751882Sbostic return (EINVAL); 21851882Sbostic 21951882Sbostic cnt = uap->blkcnt; 22052173Sbostic start = blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 22151882Sbostic if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) { 22251882Sbostic free(blkp, M_SEGMENT); 22351882Sbostic return (error); 22451882Sbostic } 22551882Sbostic 22652173Sbostic for (step = cnt; step--; ++blkp) { 22754662Smckusick if (VFS_VGET(mntp, blkp->bi_inode, &vp)) 22852173Sbostic daddr = LFS_UNUSED_DADDR; 22952173Sbostic else { 23053531Sheideman if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr)) 23152173Sbostic daddr = LFS_UNUSED_DADDR; 23252173Sbostic vput(vp); 23352173Sbostic } 23452173Sbostic blkp->bi_daddr = daddr; 23552173Sbostic } 23652173Sbostic copyout(start, uap->blkiov, cnt * sizeof(BLOCK_INFO)); 23752173Sbostic free(start, M_SEGMENT); 23851882Sbostic return (0); 23951882Sbostic } 24051882Sbostic 24151882Sbostic /* 24251882Sbostic * lfs_segclean: 24351882Sbostic * 24451882Sbostic * Mark the segment clean. 24551882Sbostic * 24651882Sbostic * 0 on success 24751882Sbostic * -1/errno is return on error. 24851882Sbostic */ 24951882Sbostic int 25051882Sbostic lfs_segclean(p, uap, retval) 25151882Sbostic struct proc *p; 25251882Sbostic struct args { 25351882Sbostic fsid_t fsid; /* file system */ 25451882Sbostic u_long segment; /* segment number */ 25551882Sbostic } *uap; 25651882Sbostic int *retval; 25751882Sbostic { 25851928Sbostic CLEANERINFO *cip; 25951882Sbostic SEGUSE *sup; 26051882Sbostic struct buf *bp; 26151882Sbostic struct mount *mntp; 26251882Sbostic struct lfs *fs; 26351882Sbostic int error; 26451882Sbostic 26551882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 26651882Sbostic return (error); 26751882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 26851882Sbostic return (EINVAL); 26951882Sbostic 27051882Sbostic fs = VFSTOUFS(mntp)->um_lfs; 27151928Sbostic 27251882Sbostic LFS_SEGENTRY(sup, fs, uap->segment, bp); 27355941Sbostic fs->lfs_avail += fsbtodb(fs, fs->lfs_ssize) - 1; 27455593Sbostic fs->lfs_bfree += (sup->su_nsums * LFS_SUMMARY_SIZE / DEV_BSIZE) + 27555593Sbostic sup->su_ninos * btodb(fs->lfs_bsize); 27651882Sbostic sup->su_flags &= ~SEGUSE_DIRTY; 27755804Sbostic sup->su_nbytes -= sup->su_nsums * LFS_SUMMARY_SIZE; 27855593Sbostic sup->su_ninos = 0; 27955593Sbostic sup->su_nsums = 0; 28055941Sbostic (void) VOP_BWRITE(bp); 28151928Sbostic 28251928Sbostic LFS_CLEANERINFO(cip, fs, bp); 28351928Sbostic ++cip->clean; 28451928Sbostic --cip->dirty; 28555941Sbostic (void) VOP_BWRITE(bp); 28655941Sbostic wakeup(&fs->lfs_avail); 28751882Sbostic return (0); 28851882Sbostic } 28951882Sbostic 29051882Sbostic /* 29151882Sbostic * lfs_segwait: 29251882Sbostic * 29351882Sbostic * This will block until a segment in file system fsid is written. A timeout 29451882Sbostic * in milliseconds may be specified which will awake the cleaner automatically. 29551882Sbostic * An fsid of -1 means any file system, and a timeout of 0 means forever. 29651882Sbostic * 29751882Sbostic * 0 on success 29851882Sbostic * 1 on timeout 29951882Sbostic * -1/errno is return on error. 30051882Sbostic */ 30151882Sbostic int 30251882Sbostic lfs_segwait(p, uap, retval) 30351882Sbostic struct proc *p; 30451882Sbostic struct args { 30551882Sbostic fsid_t fsid; /* file system */ 30651882Sbostic struct timeval *tv; /* timeout */ 30751882Sbostic } *uap; 30851882Sbostic int *retval; 30951882Sbostic { 31051882Sbostic extern int lfs_allclean_wakeup; 31151882Sbostic struct mount *mntp; 31251882Sbostic struct timeval atv; 31351882Sbostic void *addr; 31451882Sbostic u_long timeout; 31551882Sbostic int error, s; 31651882Sbostic 31755941Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) { 31851882Sbostic return (error); 31955941Sbostic } 32051882Sbostic #ifdef WHEN_QUADS_WORK 32151882Sbostic if (uap->fsid == (fsid_t)-1) 32251882Sbostic addr = &lfs_allclean_wakeup; 32351882Sbostic else { 32451882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 32551882Sbostic return (EINVAL); 32651882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 32751882Sbostic } 32851882Sbostic #else 32951882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 33051882Sbostic addr = &lfs_allclean_wakeup; 33151882Sbostic else 33251882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 33351882Sbostic #endif 33451882Sbostic 33551882Sbostic if (uap->tv) { 33651882Sbostic if (error = copyin(uap->tv, &atv, sizeof(struct timeval))) 33751882Sbostic return (error); 33851882Sbostic if (itimerfix(&atv)) 33951882Sbostic return (EINVAL); 34054764Smckusick s = splclock(); 34154764Smckusick timevaladd(&atv, (struct timeval *)&time); 34251882Sbostic timeout = hzto(&atv); 34354277Sbostic splx(s); 34451882Sbostic } else 34551882Sbostic timeout = 0; 34651882Sbostic 34751882Sbostic error = tsleep(addr, PCATCH | PUSER, "segment", timeout); 34851882Sbostic return (error == ERESTART ? EINTR : 0); 34951882Sbostic } 35055941Sbostic 35155941Sbostic /* 35255941Sbostic * VFS_VGET call specialized for the cleaner. The cleaner already knows the 35355941Sbostic * daddr from the ifile, so don't look it up again. If the cleaner is 35455941Sbostic * processing IINFO structures, it may have the ondisk inode already, so 35555941Sbostic * don't go retrieving it again. 35655941Sbostic */ 35755941Sbostic int 35855941Sbostic lfs_fastvget(mp, ino, daddr, vpp, dinp) 35955941Sbostic struct mount *mp; 36055941Sbostic ino_t ino; 36155941Sbostic daddr_t daddr; 36255941Sbostic struct vnode **vpp; 36355941Sbostic struct dinode *dinp; 36455941Sbostic { 36555941Sbostic register struct inode *ip; 36655941Sbostic struct vnode *vp; 36755941Sbostic struct ufsmount *ump; 36855941Sbostic struct buf *bp; 36955941Sbostic dev_t dev; 37055941Sbostic int error; 37155941Sbostic 37255941Sbostic ump = VFSTOUFS(mp); 37355941Sbostic dev = ump->um_dev; 37455941Sbostic if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 37555941Sbostic return (0); 37655941Sbostic 37755941Sbostic /* Allocate new vnode/inode. */ 37855941Sbostic if (error = lfs_vcreate(mp, ino, &vp)) { 37955941Sbostic *vpp = NULL; 38055941Sbostic return (error); 38155941Sbostic } 38255941Sbostic 38355941Sbostic /* 38455941Sbostic * Put it onto its hash chain and lock it so that other requests for 38555941Sbostic * this inode will block if they arrive while we are sleeping waiting 38655941Sbostic * for old data structures to be purged or for the contents of the 38755941Sbostic * disk portion of this inode to be read. 38855941Sbostic */ 38955941Sbostic ip = VTOI(vp); 39055941Sbostic ufs_ihashins(ip); 39155941Sbostic 39255941Sbostic /* 39355941Sbostic * XXX 39455941Sbostic * This may not need to be here, logically it should go down with 39555941Sbostic * the i_devvp initialization. 39655941Sbostic * Ask Kirk. 39755941Sbostic */ 39855941Sbostic ip->i_lfs = ump->um_lfs; 39955941Sbostic 40055941Sbostic /* Read in the disk contents for the inode, copy into the inode. */ 40155941Sbostic if (dinp) 40255941Sbostic if (error = copyin(dinp, &ip->i_din, sizeof(struct dinode))) 40355941Sbostic return (error); 40455941Sbostic else { 40555941Sbostic if (error = bread(ump->um_devvp, daddr, 40655941Sbostic (int)ump->um_lfs->lfs_bsize, NOCRED, &bp)) { 40755941Sbostic /* 40855941Sbostic * The inode does not contain anything useful, so it 40955941Sbostic * would be misleading to leave it on its hash chain. 41055941Sbostic * Iput() will return it to the free list. 41155941Sbostic */ 41255941Sbostic ufs_ihashrem(ip); 41355941Sbostic 41455941Sbostic /* Unlock and discard unneeded inode. */ 41555941Sbostic ufs_iput(ip); 41655941Sbostic brelse(bp); 41755941Sbostic *vpp = NULL; 41855941Sbostic return (error); 41955941Sbostic } 42055941Sbostic ip->i_din = *lfs_ifind(ump->um_lfs, ino, bp->b_un.b_dino); 42155941Sbostic brelse(bp); 42255941Sbostic } 42355941Sbostic 42455941Sbostic /* 42555941Sbostic * Initialize the vnode from the inode, check for aliases. In all 42655941Sbostic * cases re-init ip, the underlying vnode/inode may have changed. 42755941Sbostic */ 42855941Sbostic if (error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp)) { 42955941Sbostic ufs_iput(ip); 43055941Sbostic *vpp = NULL; 43155941Sbostic return (error); 43255941Sbostic } 43355941Sbostic /* 43455941Sbostic * Finish inode initialization now that aliasing has been resolved. 43555941Sbostic */ 43655941Sbostic ip->i_devvp = ump->um_devvp; 43755941Sbostic ip->i_flag |= IMOD; 43855941Sbostic ++ump->um_lfs->lfs_uinodes; 43955941Sbostic VREF(ip->i_devvp); 44055941Sbostic *vpp = vp; 44155941Sbostic return (0); 44255941Sbostic } 44355941Sbostic struct buf * 44455941Sbostic lfs_fakebuf(vp, lbn, size, uaddr) 44555941Sbostic struct vnode *vp; 44655941Sbostic int lbn; 44755941Sbostic size_t size; 44855941Sbostic caddr_t uaddr; 44955941Sbostic { 45055941Sbostic struct buf *bp; 45155941Sbostic 45255941Sbostic bp = lfs_newbuf(vp, lbn, 0); 45355941Sbostic bp->b_saveaddr = uaddr; 45455941Sbostic bp->b_bufsize = size; 45555941Sbostic bp->b_bcount = size; 45655941Sbostic bp->b_flags |= B_INVAL; 45755941Sbostic return(bp); 45855941Sbostic } 459