151882Sbostic /*- 251882Sbostic * Copyright (c) 1991 The Regents of the University of California. 351882Sbostic * All rights reserved. 451882Sbostic * 551882Sbostic * %sccs.include.redist.c% 651882Sbostic * 7*55593Sbostic * @(#)lfs_syscalls.c 7.16 (Berkeley) 07/23/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 { 5051882Sbostic BLOCK_INFO *blkp; 5151882Sbostic IFILE *ifp; 5251882Sbostic INODE_INFO *inop; 5351882Sbostic struct buf *bp; 5452087Sbostic struct inode *ip; 5551882Sbostic struct lfs *fs; 5651882Sbostic struct mount *mntp; 5751882Sbostic struct vnode *vp; 5852173Sbostic void *start; 5952087Sbostic ino_t lastino; 6051882Sbostic daddr_t daddr; 6151882Sbostic u_long bsize; 6251882Sbostic int cnt, error; 6351882Sbostic 6452173Sbostic #ifdef VERBOSE 6552173Sbostic printf("lfs_markv\n"); 6652173Sbostic #endif 6751882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 6851882Sbostic return (error); 6951882Sbostic 7051882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 7151882Sbostic return (EINVAL); 7251882Sbostic 7351882Sbostic cnt = uap->blkcnt; 7452996Sbostic start = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 7552996Sbostic if (error = copyin(uap->blkiov, start, cnt * sizeof(BLOCK_INFO))) { 7652820Sbostic free(start, M_SEGMENT); 7751882Sbostic return (error); 7851882Sbostic } 7951882Sbostic 8051882Sbostic /* 8152087Sbostic * Mark blocks/inodes dirty. Note that errors are mostly ignored. If 8252087Sbostic * we can't get the info, the block is probably not all that useful, 8352087Sbostic * and hopefully subsequent calls from the cleaner will fix everything. 8451882Sbostic */ 8552087Sbostic fs = VFSTOUFS(mntp)->um_lfs; 8652820Sbostic bsize = fs->lfs_bsize; 8752996Sbostic for (lastino = LFS_UNUSED_INUM, blkp = start; cnt--; ++blkp) { 8852087Sbostic /* 8952087Sbostic * Get the IFILE entry (only once) and see if the file still 9052087Sbostic * exists. 9152087Sbostic */ 9252087Sbostic if (lastino != blkp->bi_inode) { 9352087Sbostic lastino = blkp->bi_inode; 9452087Sbostic LFS_IENTRY(ifp, fs, blkp->bi_inode, bp); 9552087Sbostic daddr = ifp->if_daddr; 9652087Sbostic brelse(bp); 9752087Sbostic if (daddr == LFS_UNUSED_DADDR) 9852087Sbostic continue; 9952087Sbostic } 10052087Sbostic 10152087Sbostic /* 10252087Sbostic * Get the vnode/inode. If the inode modification time is 10352087Sbostic * earlier than the segment in which the block was found then 10452087Sbostic * they have to be valid, skip other checks. 10552087Sbostic */ 10654662Smckusick if (VFS_VGET(mntp, blkp->bi_inode, &vp)) 10751882Sbostic continue; 10852087Sbostic ip = VTOI(vp); 10952173Sbostic 11052173Sbostic /* 11152173Sbostic * If modify time later than segment create time, see if the 11252173Sbostic * block has been replaced. 11352173Sbostic */ 11454103Smckusick if (ip->i_mtime.ts_sec > blkp->bi_segcreate && 11553531Sheideman (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr) || 11652173Sbostic daddr != blkp->bi_daddr)) { 11752173Sbostic vput(vp); 11852173Sbostic continue; 11952087Sbostic } 12052087Sbostic 12152087Sbostic /* Get the block (from core or the cleaner) and write it. */ 12251882Sbostic bp = getblk(vp, blkp->bi_lbn, bsize); 12352173Sbostic vput(vp); 12451882Sbostic if (!(bp->b_flags & B_CACHE) && 12552820Sbostic (error = copyin(blkp->bi_bp, bp->b_un.b_addr, bsize))) { 12651882Sbostic brelse(bp); 12752820Sbostic free(start, M_SEGMENT); 12851882Sbostic return (error); 12951882Sbostic } 13053531Sheideman VOP_BWRITE(bp); 13151882Sbostic } 13252173Sbostic free(start, M_SEGMENT); 13351882Sbostic 13451882Sbostic cnt = uap->inocnt; 13552996Sbostic start = malloc(cnt * sizeof(INODE_INFO), M_SEGMENT, M_WAITOK); 13652996Sbostic if (error = copyin(uap->inoiov, start, cnt * sizeof(INODE_INFO))) { 13752820Sbostic free(start, M_SEGMENT); 13851882Sbostic return (error); 13951882Sbostic } 14051882Sbostic 14152996Sbostic for (inop = start; cnt--; ++inop) { 14251882Sbostic LFS_IENTRY(ifp, fs, inop->ii_inode, bp); 14351882Sbostic daddr = ifp->if_daddr; 14452087Sbostic brelse(bp); 14551882Sbostic if (daddr != inop->ii_daddr) 14651882Sbostic continue; 14751882Sbostic /* 14851882Sbostic * XXX 14951882Sbostic * This is grossly inefficient since the cleaner just handed 15051882Sbostic * us a copy of the inode and we're going to have to seek 15151882Sbostic * to get our own. The fix requires creating a version of 15251882Sbostic * lfs_vget that takes the copy and uses it instead of reading 15351882Sbostic * from disk, if it's not already in the cache. 15451882Sbostic */ 15554662Smckusick if (!VFS_VGET(mntp, inop->ii_inode, &vp)) { 15651882Sbostic VTOI(vp)->i_flag |= IMOD; 15752173Sbostic vput(vp); 15852173Sbostic } 15951882Sbostic } 16052173Sbostic free(start, M_SEGMENT); 16151882Sbostic return (lfs_segwrite(mntp, 1)); 16251882Sbostic } 16351882Sbostic 16451882Sbostic /* 16551882Sbostic * lfs_bmapv: 16651882Sbostic * 16752087Sbostic * This will fill in the current disk address for arrays of blocks. 16851882Sbostic * 16951882Sbostic * 0 on success 17051882Sbostic * -1/errno is return on error. 17151882Sbostic */ 17251882Sbostic int 17351882Sbostic lfs_bmapv(p, uap, retval) 17451882Sbostic struct proc *p; 17551882Sbostic struct args { 17651882Sbostic fsid_t fsid; /* file system */ 17751882Sbostic BLOCK_INFO *blkiov; /* block array */ 17851882Sbostic int blkcnt; /* count of block array entries */ 17951882Sbostic } *uap; 18051882Sbostic int *retval; 18151882Sbostic { 18251882Sbostic BLOCK_INFO *blkp; 18351882Sbostic struct mount *mntp; 18451882Sbostic struct vnode *vp; 18552173Sbostic void *start; 18651882Sbostic daddr_t daddr; 18752173Sbostic int cnt, error, step; 18851882Sbostic 18952173Sbostic #ifdef VERBOSE 19052173Sbostic printf("lfs_bmapv\n"); 19152173Sbostic #endif 19251882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 19351882Sbostic return (error); 19451882Sbostic 19551882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 19651882Sbostic return (EINVAL); 19751882Sbostic 19851882Sbostic cnt = uap->blkcnt; 19952173Sbostic start = blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 20051882Sbostic if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) { 20151882Sbostic free(blkp, M_SEGMENT); 20251882Sbostic return (error); 20351882Sbostic } 20451882Sbostic 20552173Sbostic for (step = cnt; step--; ++blkp) { 20654662Smckusick if (VFS_VGET(mntp, blkp->bi_inode, &vp)) 20752173Sbostic daddr = LFS_UNUSED_DADDR; 20852173Sbostic else { 20953531Sheideman if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr)) 21052173Sbostic daddr = LFS_UNUSED_DADDR; 21152173Sbostic vput(vp); 21252173Sbostic } 21352173Sbostic blkp->bi_daddr = daddr; 21452173Sbostic } 21552173Sbostic copyout(start, uap->blkiov, cnt * sizeof(BLOCK_INFO)); 21652173Sbostic free(start, M_SEGMENT); 21751882Sbostic return (0); 21851882Sbostic } 21951882Sbostic 22051882Sbostic /* 22151882Sbostic * lfs_segclean: 22251882Sbostic * 22351882Sbostic * Mark the segment clean. 22451882Sbostic * 22551882Sbostic * 0 on success 22651882Sbostic * -1/errno is return on error. 22751882Sbostic */ 22851882Sbostic int 22951882Sbostic lfs_segclean(p, uap, retval) 23051882Sbostic struct proc *p; 23151882Sbostic struct args { 23251882Sbostic fsid_t fsid; /* file system */ 23351882Sbostic u_long segment; /* segment number */ 23451882Sbostic } *uap; 23551882Sbostic int *retval; 23651882Sbostic { 23751928Sbostic CLEANERINFO *cip; 23851882Sbostic SEGUSE *sup; 23951882Sbostic struct buf *bp; 24051882Sbostic struct mount *mntp; 24151882Sbostic struct lfs *fs; 24251882Sbostic int error; 24351882Sbostic 24452173Sbostic #ifdef VERBOSE 24552173Sbostic printf("lfs_segclean\n"); 24652173Sbostic #endif 24751882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 24851882Sbostic return (error); 24951882Sbostic 25051882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 25151882Sbostic return (EINVAL); 25251882Sbostic 25351882Sbostic fs = VFSTOUFS(mntp)->um_lfs; 25451928Sbostic 25551882Sbostic LFS_SEGENTRY(sup, fs, uap->segment, bp); 256*55593Sbostic fs->lfs_bfree += (sup->su_nsums * LFS_SUMMARY_SIZE / DEV_BSIZE) + 257*55593Sbostic sup->su_ninos * btodb(fs->lfs_bsize); 25851882Sbostic sup->su_flags &= ~SEGUSE_DIRTY; 25952089Sbostic sup->su_nbytes = 0; 260*55593Sbostic sup->su_ninos = 0; 261*55593Sbostic sup->su_nsums = 0; 26252087Sbostic LFS_UBWRITE(bp); 26351928Sbostic 26451928Sbostic LFS_CLEANERINFO(cip, fs, bp); 26551928Sbostic ++cip->clean; 26651928Sbostic --cip->dirty; 26752087Sbostic LFS_UBWRITE(bp); 268*55593Sbostic /* 269*55593Sbostic * Count all the blocks in the segment as being free again. 270*55593Sbostic */ 271*55593Sbostic fs->lfs_bfree += fs->lfs_ssize; 27251928Sbostic 27351882Sbostic return (0); 27451882Sbostic } 27551882Sbostic 27651882Sbostic /* 27751882Sbostic * lfs_segwait: 27851882Sbostic * 27951882Sbostic * This will block until a segment in file system fsid is written. A timeout 28051882Sbostic * in milliseconds may be specified which will awake the cleaner automatically. 28151882Sbostic * An fsid of -1 means any file system, and a timeout of 0 means forever. 28251882Sbostic * 28351882Sbostic * 0 on success 28451882Sbostic * 1 on timeout 28551882Sbostic * -1/errno is return on error. 28651882Sbostic */ 28751882Sbostic int 28851882Sbostic lfs_segwait(p, uap, retval) 28951882Sbostic struct proc *p; 29051882Sbostic struct args { 29151882Sbostic fsid_t fsid; /* file system */ 29251882Sbostic struct timeval *tv; /* timeout */ 29351882Sbostic } *uap; 29451882Sbostic int *retval; 29551882Sbostic { 29651882Sbostic extern int lfs_allclean_wakeup; 29751882Sbostic struct mount *mntp; 29851882Sbostic struct timeval atv; 29951882Sbostic void *addr; 30051882Sbostic u_long timeout; 30151882Sbostic int error, s; 30251882Sbostic 30352173Sbostic #ifdef VERBOSE 30452173Sbostic printf("lfs_segwait\n"); 30552173Sbostic #endif 30651882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 30751882Sbostic return (error); 30851882Sbostic 30951882Sbostic #ifdef WHEN_QUADS_WORK 31051882Sbostic if (uap->fsid == (fsid_t)-1) 31151882Sbostic addr = &lfs_allclean_wakeup; 31251882Sbostic else { 31351882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 31451882Sbostic return (EINVAL); 31551882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 31651882Sbostic } 31751882Sbostic #else 31851882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 31951882Sbostic addr = &lfs_allclean_wakeup; 32051882Sbostic else 32151882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 32251882Sbostic #endif 32351882Sbostic 32451882Sbostic if (uap->tv) { 32551882Sbostic if (error = copyin(uap->tv, &atv, sizeof(struct timeval))) 32651882Sbostic return (error); 32751882Sbostic if (itimerfix(&atv)) 32851882Sbostic return (EINVAL); 32954764Smckusick s = splclock(); 33054764Smckusick timevaladd(&atv, (struct timeval *)&time); 33151882Sbostic timeout = hzto(&atv); 33254277Sbostic splx(s); 33351882Sbostic } else 33451882Sbostic timeout = 0; 33551882Sbostic 33651882Sbostic error = tsleep(addr, PCATCH | PUSER, "segment", timeout); 33751882Sbostic return (error == ERESTART ? EINTR : 0); 33851882Sbostic } 339