151882Sbostic /*- 251882Sbostic * Copyright (c) 1991 The Regents of the University of California. 351882Sbostic * All rights reserved. 451882Sbostic * 551882Sbostic * %sccs.include.redist.c% 651882Sbostic * 7*53531Sheideman * @(#)lfs_syscalls.c 7.11 (Berkeley) 05/14/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> 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 { 50*53531Sheideman USES_VOP_BMAP; 51*53531Sheideman USES_VOP_BWRITE; 52*53531Sheideman USES_VOP_VGET; 5351882Sbostic BLOCK_INFO *blkp; 5451882Sbostic IFILE *ifp; 5551882Sbostic INODE_INFO *inop; 5651882Sbostic struct buf *bp; 5752087Sbostic struct inode *ip; 5851882Sbostic struct lfs *fs; 5951882Sbostic struct mount *mntp; 6051882Sbostic struct vnode *vp; 6152173Sbostic void *start; 6252087Sbostic ino_t lastino; 6351882Sbostic daddr_t daddr; 6451882Sbostic u_long bsize; 6551882Sbostic int cnt, error; 6651882Sbostic 6752173Sbostic #ifdef VERBOSE 6852173Sbostic printf("lfs_markv\n"); 6952173Sbostic #endif 7051882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 7151882Sbostic return (error); 7251882Sbostic 7351882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 7451882Sbostic return (EINVAL); 7551882Sbostic 7651882Sbostic cnt = uap->blkcnt; 7752996Sbostic start = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 7852996Sbostic if (error = copyin(uap->blkiov, start, cnt * sizeof(BLOCK_INFO))) { 7952820Sbostic free(start, M_SEGMENT); 8051882Sbostic return (error); 8151882Sbostic } 8251882Sbostic 8351882Sbostic /* 8452087Sbostic * Mark blocks/inodes dirty. Note that errors are mostly ignored. If 8552087Sbostic * we can't get the info, the block is probably not all that useful, 8652087Sbostic * and hopefully subsequent calls from the cleaner will fix everything. 8751882Sbostic */ 8852087Sbostic fs = VFSTOUFS(mntp)->um_lfs; 8952820Sbostic bsize = fs->lfs_bsize; 9052996Sbostic for (lastino = LFS_UNUSED_INUM, 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) { 9652087Sbostic lastino = blkp->bi_inode; 9752087Sbostic LFS_IENTRY(ifp, fs, blkp->bi_inode, bp); 9852087Sbostic daddr = ifp->if_daddr; 9952087Sbostic brelse(bp); 10052087Sbostic if (daddr == LFS_UNUSED_DADDR) 10152087Sbostic continue; 10252087Sbostic } 10352087Sbostic 10452087Sbostic /* 10552087Sbostic * Get the vnode/inode. If the inode modification time is 10652087Sbostic * earlier than the segment in which the block was found then 10752087Sbostic * they have to be valid, skip other checks. 10852087Sbostic */ 109*53531Sheideman if (LFS_VGET(mntp, blkp->bi_inode, &vp)) 11051882Sbostic continue; 11152087Sbostic ip = VTOI(vp); 11252173Sbostic 11352173Sbostic /* 11452173Sbostic * If modify time later than segment create time, see if the 11552173Sbostic * block has been replaced. 11652173Sbostic */ 11753478Smckusick if (ip->i_mtime.tv_sec > blkp->bi_segcreate && 118*53531Sheideman (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr) || 11952173Sbostic daddr != blkp->bi_daddr)) { 12052173Sbostic vput(vp); 12152173Sbostic continue; 12252087Sbostic } 12352087Sbostic 12452087Sbostic /* Get the block (from core or the cleaner) and write it. */ 12551882Sbostic bp = getblk(vp, blkp->bi_lbn, bsize); 12652173Sbostic vput(vp); 12751882Sbostic if (!(bp->b_flags & B_CACHE) && 12852820Sbostic (error = copyin(blkp->bi_bp, bp->b_un.b_addr, bsize))) { 12951882Sbostic brelse(bp); 13052820Sbostic free(start, M_SEGMENT); 13151882Sbostic return (error); 13251882Sbostic } 133*53531Sheideman VOP_BWRITE(bp); 13451882Sbostic } 13552173Sbostic free(start, M_SEGMENT); 13651882Sbostic 13751882Sbostic cnt = uap->inocnt; 13852996Sbostic start = malloc(cnt * sizeof(INODE_INFO), M_SEGMENT, M_WAITOK); 13952996Sbostic if (error = copyin(uap->inoiov, start, cnt * sizeof(INODE_INFO))) { 14052820Sbostic free(start, M_SEGMENT); 14151882Sbostic return (error); 14251882Sbostic } 14351882Sbostic 14452996Sbostic for (inop = start; cnt--; ++inop) { 14551882Sbostic LFS_IENTRY(ifp, fs, inop->ii_inode, bp); 14651882Sbostic daddr = ifp->if_daddr; 14752087Sbostic brelse(bp); 14851882Sbostic if (daddr != inop->ii_daddr) 14951882Sbostic continue; 15051882Sbostic /* 15151882Sbostic * XXX 15251882Sbostic * This is grossly inefficient since the cleaner just handed 15351882Sbostic * us a copy of the inode and we're going to have to seek 15451882Sbostic * to get our own. The fix requires creating a version of 15551882Sbostic * lfs_vget that takes the copy and uses it instead of reading 15651882Sbostic * from disk, if it's not already in the cache. 15751882Sbostic */ 158*53531Sheideman if (!LFS_VGET(mntp, inop->ii_inode, &vp)) { 15951882Sbostic VTOI(vp)->i_flag |= IMOD; 16052173Sbostic vput(vp); 16152173Sbostic } 16251882Sbostic } 16352173Sbostic free(start, M_SEGMENT); 16451882Sbostic return (lfs_segwrite(mntp, 1)); 16551882Sbostic } 16651882Sbostic 16751882Sbostic /* 16851882Sbostic * lfs_bmapv: 16951882Sbostic * 17052087Sbostic * This will fill in the current disk address for arrays of blocks. 17151882Sbostic * 17251882Sbostic * 0 on success 17351882Sbostic * -1/errno is return on error. 17451882Sbostic */ 17551882Sbostic int 17651882Sbostic lfs_bmapv(p, uap, retval) 17751882Sbostic struct proc *p; 17851882Sbostic struct args { 17951882Sbostic fsid_t fsid; /* file system */ 18051882Sbostic BLOCK_INFO *blkiov; /* block array */ 18151882Sbostic int blkcnt; /* count of block array entries */ 18251882Sbostic } *uap; 18351882Sbostic int *retval; 18451882Sbostic { 185*53531Sheideman USES_VOP_BMAP; 186*53531Sheideman USES_VOP_VGET; 18751882Sbostic BLOCK_INFO *blkp; 18851882Sbostic struct mount *mntp; 18951882Sbostic struct vnode *vp; 19052173Sbostic void *start; 19151882Sbostic daddr_t daddr; 19252173Sbostic int cnt, error, step; 19351882Sbostic 19452173Sbostic #ifdef VERBOSE 19552173Sbostic printf("lfs_bmapv\n"); 19652173Sbostic #endif 19751882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 19851882Sbostic return (error); 19951882Sbostic 20051882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 20151882Sbostic return (EINVAL); 20251882Sbostic 20351882Sbostic cnt = uap->blkcnt; 20452173Sbostic start = blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 20551882Sbostic if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) { 20651882Sbostic free(blkp, M_SEGMENT); 20751882Sbostic return (error); 20851882Sbostic } 20951882Sbostic 21052173Sbostic for (step = cnt; step--; ++blkp) { 211*53531Sheideman if (LFS_VGET(mntp, blkp->bi_inode, &vp)) 21252173Sbostic daddr = LFS_UNUSED_DADDR; 21352173Sbostic else { 214*53531Sheideman if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr)) 21552173Sbostic daddr = LFS_UNUSED_DADDR; 21652173Sbostic vput(vp); 21752173Sbostic } 21852173Sbostic blkp->bi_daddr = daddr; 21952173Sbostic } 22052173Sbostic copyout(start, uap->blkiov, cnt * sizeof(BLOCK_INFO)); 22152173Sbostic free(start, M_SEGMENT); 22251882Sbostic return (0); 22351882Sbostic } 22451882Sbostic 22551882Sbostic /* 22651882Sbostic * lfs_segclean: 22751882Sbostic * 22851882Sbostic * Mark the segment clean. 22951882Sbostic * 23051882Sbostic * 0 on success 23151882Sbostic * -1/errno is return on error. 23251882Sbostic */ 23351882Sbostic int 23451882Sbostic lfs_segclean(p, uap, retval) 23551882Sbostic struct proc *p; 23651882Sbostic struct args { 23751882Sbostic fsid_t fsid; /* file system */ 23851882Sbostic u_long segment; /* segment number */ 23951882Sbostic } *uap; 24051882Sbostic int *retval; 24151882Sbostic { 24251928Sbostic CLEANERINFO *cip; 24351882Sbostic SEGUSE *sup; 24451882Sbostic struct buf *bp; 24551882Sbostic struct mount *mntp; 24651882Sbostic struct lfs *fs; 24751882Sbostic int error; 24851882Sbostic 24952173Sbostic #ifdef VERBOSE 25052173Sbostic printf("lfs_segclean\n"); 25152173Sbostic #endif 25251882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 25351882Sbostic return (error); 25451882Sbostic 25551882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 25651882Sbostic return (EINVAL); 25751882Sbostic 25851882Sbostic fs = VFSTOUFS(mntp)->um_lfs; 25951928Sbostic 26051882Sbostic LFS_SEGENTRY(sup, fs, uap->segment, bp); 26151882Sbostic sup->su_flags &= ~SEGUSE_DIRTY; 26252089Sbostic sup->su_nbytes = 0; 26352087Sbostic LFS_UBWRITE(bp); 26451928Sbostic 26551928Sbostic LFS_CLEANERINFO(cip, fs, bp); 26651928Sbostic ++cip->clean; 26751928Sbostic --cip->dirty; 26852087Sbostic LFS_UBWRITE(bp); 26951928Sbostic 27051882Sbostic return (0); 27151882Sbostic } 27251882Sbostic 27351882Sbostic /* 27451882Sbostic * lfs_segwait: 27551882Sbostic * 27651882Sbostic * This will block until a segment in file system fsid is written. A timeout 27751882Sbostic * in milliseconds may be specified which will awake the cleaner automatically. 27851882Sbostic * An fsid of -1 means any file system, and a timeout of 0 means forever. 27951882Sbostic * 28051882Sbostic * 0 on success 28151882Sbostic * 1 on timeout 28251882Sbostic * -1/errno is return on error. 28351882Sbostic */ 28451882Sbostic int 28551882Sbostic lfs_segwait(p, uap, retval) 28651882Sbostic struct proc *p; 28751882Sbostic struct args { 28851882Sbostic fsid_t fsid; /* file system */ 28951882Sbostic struct timeval *tv; /* timeout */ 29051882Sbostic } *uap; 29151882Sbostic int *retval; 29251882Sbostic { 29351882Sbostic extern int lfs_allclean_wakeup; 29451882Sbostic struct mount *mntp; 29551882Sbostic struct timeval atv; 29651882Sbostic void *addr; 29751882Sbostic u_long timeout; 29851882Sbostic int error, s; 29951882Sbostic 30052173Sbostic #ifdef VERBOSE 30152173Sbostic printf("lfs_segwait\n"); 30252173Sbostic #endif 30351882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 30451882Sbostic return (error); 30551882Sbostic 30651882Sbostic #ifdef WHEN_QUADS_WORK 30751882Sbostic if (uap->fsid == (fsid_t)-1) 30851882Sbostic addr = &lfs_allclean_wakeup; 30951882Sbostic else { 31051882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 31151882Sbostic return (EINVAL); 31251882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 31351882Sbostic } 31451882Sbostic #else 31551882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 31651882Sbostic addr = &lfs_allclean_wakeup; 31751882Sbostic else 31851882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 31951882Sbostic #endif 32051882Sbostic 32151882Sbostic if (uap->tv) { 32251882Sbostic if (error = copyin(uap->tv, &atv, sizeof(struct timeval))) 32351882Sbostic return (error); 32451882Sbostic if (itimerfix(&atv)) 32551882Sbostic return (EINVAL); 32651882Sbostic s = splhigh(); timevaladd(&atv, &time); splx(s); 32751882Sbostic timeout = hzto(&atv); 32851882Sbostic } else 32951882Sbostic timeout = 0; 33051882Sbostic 33151882Sbostic error = tsleep(addr, PCATCH | PUSER, "segment", timeout); 33251882Sbostic return (error == ERESTART ? EINTR : 0); 33351882Sbostic } 334