151882Sbostic /*- 251882Sbostic * Copyright (c) 1991 The Regents of the University of California. 351882Sbostic * All rights reserved. 451882Sbostic * 551882Sbostic * %sccs.include.redist.c% 651882Sbostic * 7*52087Sbostic * @(#)lfs_syscalls.c 7.5 (Berkeley) 12/31/91 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> 2151882Sbostic 2251882Sbostic #include <ufs/lfs/lfs.h> 2351882Sbostic #include <ufs/lfs/lfs_extern.h> 2451882Sbostic 2551882Sbostic /* 2651882Sbostic * lfs_markv: 2751882Sbostic * 2851882Sbostic * This will mark inodes and blocks dirty, so they are written into the log. 2951882Sbostic * It will block until all the blocks have been written. The segment create 3051882Sbostic * time passed in the block_info and inode_info structures is used to decide 3151882Sbostic * if the data is valid for each block (in case some process dirtied a block 3251882Sbostic * or inode that is being cleaned between the determination that a block is 3351882Sbostic * live and the lfs_markv call). 3451882Sbostic * 3551882Sbostic * 0 on success 3651882Sbostic * -1/errno is return on error. 3751882Sbostic */ 3851882Sbostic int 3951882Sbostic lfs_markv(p, uap, retval) 4051882Sbostic struct proc *p; 4151882Sbostic struct args { 4251882Sbostic fsid_t fsid; /* file system */ 4351882Sbostic BLOCK_INFO *blkiov; /* block array */ 4451882Sbostic int blkcnt; /* count of block array entries */ 4551882Sbostic INODE_INFO *inoiov; /* inode array */ 4651882Sbostic int inocnt; /* count of inode array entries */ 4751882Sbostic } *uap; 4851882Sbostic int *retval; 4951882Sbostic { 5051882Sbostic BLOCK_INFO *blkp; 5151882Sbostic IFILE *ifp; 5251882Sbostic INODE_INFO *inop; 5351882Sbostic struct buf *bp; 54*52087Sbostic struct inode *ip; 5551882Sbostic struct lfs *fs; 5651882Sbostic struct mount *mntp; 5751882Sbostic struct vnode *vp; 58*52087Sbostic ino_t lastino; 5951882Sbostic daddr_t daddr; 6051882Sbostic u_long bsize; 6151882Sbostic int cnt, error; 6251882Sbostic 6351882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 6451882Sbostic return (error); 6551882Sbostic 6651882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 6751882Sbostic return (EINVAL); 6851882Sbostic 6951882Sbostic cnt = uap->blkcnt; 7051882Sbostic blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 7151882Sbostic if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) { 7251882Sbostic free(blkp, M_SEGMENT); 7351882Sbostic return (error); 7451882Sbostic } 7551882Sbostic 7651882Sbostic /* 77*52087Sbostic * Mark blocks/inodes dirty. Note that errors are mostly ignored. If 78*52087Sbostic * we can't get the info, the block is probably not all that useful, 79*52087Sbostic * and hopefully subsequent calls from the cleaner will fix everything. 8051882Sbostic */ 81*52087Sbostic fs = VFSTOUFS(mntp)->um_lfs; 8251882Sbostic bsize = VFSTOUFS(mntp)->um_lfs->lfs_bsize; 83*52087Sbostic for (lastino = LFS_UNUSED_INUM; cnt--; ++blkp) { 84*52087Sbostic /* 85*52087Sbostic * Get the IFILE entry (only once) and see if the file still 86*52087Sbostic * exists. 87*52087Sbostic */ 88*52087Sbostic if (lastino != blkp->bi_inode) { 89*52087Sbostic lastino = blkp->bi_inode; 90*52087Sbostic LFS_IENTRY(ifp, fs, blkp->bi_inode, bp); 91*52087Sbostic daddr = ifp->if_daddr; 92*52087Sbostic brelse(bp); 93*52087Sbostic if (daddr == LFS_UNUSED_DADDR) 94*52087Sbostic continue; 95*52087Sbostic } 96*52087Sbostic 97*52087Sbostic /* 98*52087Sbostic * Get the vnode/inode. If the inode modification time is 99*52087Sbostic * earlier than the segment in which the block was found then 100*52087Sbostic * they have to be valid, skip other checks. 101*52087Sbostic */ 102*52087Sbostic if (lfs_vget(mntp, blkp->bi_inode, &vp)) 10351882Sbostic continue; 104*52087Sbostic ip = VTOI(vp); 105*52087Sbostic if (ip->i_mtime > blkp->bi_segcreate) { 106*52087Sbostic /* Check to see if the block has been replaced. */ 107*52087Sbostic if (lfs_bmap(vp, blkp->bi_lbn, NULL, &daddr)) 108*52087Sbostic continue; 109*52087Sbostic if (daddr != blkp->bi_daddr) 110*52087Sbostic continue; 111*52087Sbostic } 112*52087Sbostic 113*52087Sbostic /* Get the block (from core or the cleaner) and write it. */ 11451882Sbostic bp = getblk(vp, blkp->bi_lbn, bsize); 11551882Sbostic if (!(bp->b_flags & B_CACHE) && 11651882Sbostic (error = copyin(blkp->bi_bp, bp->b_un.b_daddr, bsize))) { 11751882Sbostic brelse(bp); 11851882Sbostic free(blkp, M_SEGMENT); 11951882Sbostic return (error); 12051882Sbostic } 12151882Sbostic lfs_bwrite(bp); 12251882Sbostic } 12351882Sbostic free(blkp, M_SEGMENT); 12451882Sbostic 12551882Sbostic cnt = uap->inocnt; 12651882Sbostic inop = malloc(cnt * sizeof(INODE_INFO), M_SEGMENT, M_WAITOK); 12751882Sbostic if (error = copyin(uap->inoiov, inop, cnt * sizeof(INODE_INFO))) { 12851882Sbostic free(inop, M_SEGMENT); 12951882Sbostic return (error); 13051882Sbostic } 13151882Sbostic 13251882Sbostic for (; cnt--; ++inop) { 13351882Sbostic LFS_IENTRY(ifp, fs, inop->ii_inode, bp); 13451882Sbostic daddr = ifp->if_daddr; 135*52087Sbostic brelse(bp); 13651882Sbostic if (daddr != inop->ii_daddr) 13751882Sbostic continue; 13851882Sbostic /* 13951882Sbostic * XXX 14051882Sbostic * This is grossly inefficient since the cleaner just handed 14151882Sbostic * us a copy of the inode and we're going to have to seek 14251882Sbostic * to get our own. The fix requires creating a version of 14351882Sbostic * lfs_vget that takes the copy and uses it instead of reading 14451882Sbostic * from disk, if it's not already in the cache. 14551882Sbostic */ 14651882Sbostic if (!lfs_vget(mntp, inop->ii_inode, &vp)) 14751882Sbostic VTOI(vp)->i_flag |= IMOD; 14851882Sbostic } 14951882Sbostic free(inop, M_SEGMENT); 15051882Sbostic return (lfs_segwrite(mntp, 1)); 15151882Sbostic } 15251882Sbostic 15351882Sbostic /* 15451882Sbostic * lfs_bmapv: 15551882Sbostic * 156*52087Sbostic * This will fill in the current disk address for arrays of blocks. 15751882Sbostic * 15851882Sbostic * 0 on success 15951882Sbostic * -1/errno is return on error. 16051882Sbostic */ 16151882Sbostic int 16251882Sbostic lfs_bmapv(p, uap, retval) 16351882Sbostic struct proc *p; 16451882Sbostic struct args { 16551882Sbostic fsid_t fsid; /* file system */ 16651882Sbostic BLOCK_INFO *blkiov; /* block array */ 16751882Sbostic int blkcnt; /* count of block array entries */ 16851882Sbostic } *uap; 16951882Sbostic int *retval; 17051882Sbostic { 17151882Sbostic BLOCK_INFO *blkp; 17251882Sbostic struct mount *mntp; 17351882Sbostic struct vnode *vp; 17451882Sbostic daddr_t daddr; 17551882Sbostic int cnt, error; 17651882Sbostic 17751882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 17851882Sbostic return (error); 17951882Sbostic 18051882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 18151882Sbostic return (EINVAL); 18251882Sbostic 18351882Sbostic cnt = uap->blkcnt; 18451882Sbostic blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 18551882Sbostic if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) { 18651882Sbostic free(blkp, M_SEGMENT); 18751882Sbostic return (error); 18851882Sbostic } 18951882Sbostic 19051882Sbostic for (; cnt--; ++blkp) 19151882Sbostic blkp->bi_daddr = 19251882Sbostic lfs_vget(mntp, blkp->bi_inode, &vp) || 19351882Sbostic lfs_bmap(vp, blkp->bi_lbn, NULL, &daddr) ? 19451882Sbostic LFS_UNUSED_DADDR : daddr; 19551882Sbostic free(blkp, M_SEGMENT); 19651882Sbostic return (0); 19751882Sbostic } 19851882Sbostic 19951882Sbostic /* 20051882Sbostic * lfs_segclean: 20151882Sbostic * 20251882Sbostic * Mark the segment clean. 20351882Sbostic * 20451882Sbostic * 0 on success 20551882Sbostic * -1/errno is return on error. 20651882Sbostic */ 20751882Sbostic int 20851882Sbostic lfs_segclean(p, uap, retval) 20951882Sbostic struct proc *p; 21051882Sbostic struct args { 21151882Sbostic fsid_t fsid; /* file system */ 21251882Sbostic u_long segment; /* segment number */ 21351882Sbostic } *uap; 21451882Sbostic int *retval; 21551882Sbostic { 21651928Sbostic CLEANERINFO *cip; 21751882Sbostic SEGUSE *sup; 21851882Sbostic struct buf *bp; 21951882Sbostic struct mount *mntp; 22051882Sbostic struct lfs *fs; 22151882Sbostic int error; 22251882Sbostic 22351882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 22451882Sbostic return (error); 22551882Sbostic 22651882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 22751882Sbostic return (EINVAL); 22851882Sbostic 22951882Sbostic fs = VFSTOUFS(mntp)->um_lfs; 23051928Sbostic 23151882Sbostic LFS_SEGENTRY(sup, fs, uap->segment, bp); 23251882Sbostic sup->su_flags &= ~SEGUSE_DIRTY; 23351966Sbostic sup->su_nbytes = sup->su_flags & SEGUSE_SUPERBLOCK ? LFS_SBPAD : 0; 234*52087Sbostic LFS_UBWRITE(bp); 23551928Sbostic 23651928Sbostic LFS_CLEANERINFO(cip, fs, bp); 23751928Sbostic ++cip->clean; 23851928Sbostic --cip->dirty; 239*52087Sbostic LFS_UBWRITE(bp); 24051928Sbostic 24151882Sbostic return (0); 24251882Sbostic } 24351882Sbostic 24451882Sbostic /* 24551882Sbostic * lfs_segwait: 24651882Sbostic * 24751882Sbostic * This will block until a segment in file system fsid is written. A timeout 24851882Sbostic * in milliseconds may be specified which will awake the cleaner automatically. 24951882Sbostic * An fsid of -1 means any file system, and a timeout of 0 means forever. 25051882Sbostic * 25151882Sbostic * 0 on success 25251882Sbostic * 1 on timeout 25351882Sbostic * -1/errno is return on error. 25451882Sbostic */ 25551882Sbostic int 25651882Sbostic lfs_segwait(p, uap, retval) 25751882Sbostic struct proc *p; 25851882Sbostic struct args { 25951882Sbostic fsid_t fsid; /* file system */ 26051882Sbostic struct timeval *tv; /* timeout */ 26151882Sbostic } *uap; 26251882Sbostic int *retval; 26351882Sbostic { 26451882Sbostic extern int lfs_allclean_wakeup; 26551882Sbostic struct mount *mntp; 26651882Sbostic struct timeval atv; 26751882Sbostic void *addr; 26851882Sbostic u_long timeout; 26951882Sbostic int error, s; 27051882Sbostic 27151882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 27251882Sbostic return (error); 27351882Sbostic 27451882Sbostic #ifdef WHEN_QUADS_WORK 27551882Sbostic if (uap->fsid == (fsid_t)-1) 27651882Sbostic addr = &lfs_allclean_wakeup; 27751882Sbostic else { 27851882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 27951882Sbostic return (EINVAL); 28051882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 28151882Sbostic } 28251882Sbostic #else 28351882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 28451882Sbostic addr = &lfs_allclean_wakeup; 28551882Sbostic else 28651882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 28751882Sbostic #endif 28851882Sbostic 28951882Sbostic if (uap->tv) { 29051882Sbostic if (error = copyin(uap->tv, &atv, sizeof(struct timeval))) 29151882Sbostic return (error); 29251882Sbostic if (itimerfix(&atv)) 29351882Sbostic return (EINVAL); 29451882Sbostic s = splhigh(); timevaladd(&atv, &time); splx(s); 29551882Sbostic timeout = hzto(&atv); 29651882Sbostic } else 29751882Sbostic timeout = 0; 29851882Sbostic 29951882Sbostic error = tsleep(addr, PCATCH | PUSER, "segment", timeout); 30051882Sbostic return (error == ERESTART ? EINTR : 0); 30151882Sbostic } 302