151882Sbostic /*- 251882Sbostic * Copyright (c) 1991 The Regents of the University of California. 351882Sbostic * All rights reserved. 451882Sbostic * 551882Sbostic * %sccs.include.redist.c% 651882Sbostic * 7*51966Sbostic * @(#)lfs_syscalls.c 7.4 (Berkeley) 12/15/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; 5451882Sbostic struct lfs *fs; 5551882Sbostic struct mount *mntp; 5651882Sbostic struct vnode *vp; 5751882Sbostic daddr_t daddr; 5851882Sbostic u_long bsize; 5951882Sbostic int cnt, error; 6051882Sbostic 6151882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 6251882Sbostic return (error); 6351882Sbostic 6451882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 6551882Sbostic return (EINVAL); 6651882Sbostic 6751882Sbostic cnt = uap->blkcnt; 6851882Sbostic blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 6951882Sbostic if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) { 7051882Sbostic free(blkp, M_SEGMENT); 7151882Sbostic return (error); 7251882Sbostic } 7351882Sbostic 7451882Sbostic /* 7551882Sbostic * Mark blocks/inodes dirty. For blocks, we get the vnode, and check 7651882Sbostic * to see if the modified or disk address is newer than the cleaner 7751882Sbostic * thinks. If so, we're done. Otherwise, we get the block, from core 7851882Sbostic * if we have it, otherwise from the cleaner, and write it. Note that 7951882Sbostic * errors are mostly ignored. If we can't get the info, the block is 8051882Sbostic * probably not all that useful, and hopefully subsequent calls from 8151882Sbostic * the cleaner will fix everything. 8251882Sbostic */ 8351882Sbostic bsize = VFSTOUFS(mntp)->um_lfs->lfs_bsize; 8451882Sbostic for (; cnt--; ++blkp) { 8551882Sbostic if (lfs_vget(mntp, blkp->bi_inode, &vp) || 8651882Sbostic VTOI(vp)->i_mtime >= blkp->bi_segcreate || 8751882Sbostic lfs_bmap(vp, blkp->bi_lbn, NULL, &daddr) || 8851882Sbostic daddr != blkp->bi_daddr) 8951882Sbostic continue; 9051882Sbostic bp = getblk(vp, blkp->bi_lbn, bsize); 9151882Sbostic if (!(bp->b_flags & B_CACHE) && 9251882Sbostic (error = copyin(blkp->bi_bp, bp->b_un.b_daddr, bsize))) { 9351882Sbostic brelse(bp); 9451882Sbostic free(blkp, M_SEGMENT); 9551882Sbostic return (error); 9651882Sbostic } 9751882Sbostic lfs_bwrite(bp); 9851882Sbostic brelse(bp); 9951882Sbostic } 10051882Sbostic free(blkp, M_SEGMENT); 10151882Sbostic 10251882Sbostic cnt = uap->inocnt; 10351882Sbostic inop = malloc(cnt * sizeof(INODE_INFO), M_SEGMENT, M_WAITOK); 10451882Sbostic if (error = copyin(uap->inoiov, inop, cnt * sizeof(INODE_INFO))) { 10551882Sbostic free(inop, M_SEGMENT); 10651882Sbostic return (error); 10751882Sbostic } 10851882Sbostic 10951882Sbostic fs = VFSTOUFS(mntp)->um_lfs; 11051882Sbostic for (; cnt--; ++inop) { 11151882Sbostic LFS_IENTRY(ifp, fs, inop->ii_inode, bp); 11251882Sbostic daddr = ifp->if_daddr; 11351935Sbostic LFS_IRELEASE(fs, bp); 11451882Sbostic if (daddr != inop->ii_daddr) 11551882Sbostic continue; 11651882Sbostic /* 11751882Sbostic * XXX 11851882Sbostic * This is grossly inefficient since the cleaner just handed 11951882Sbostic * us a copy of the inode and we're going to have to seek 12051882Sbostic * to get our own. The fix requires creating a version of 12151882Sbostic * lfs_vget that takes the copy and uses it instead of reading 12251882Sbostic * from disk, if it's not already in the cache. 12351882Sbostic */ 12451882Sbostic if (!lfs_vget(mntp, inop->ii_inode, &vp)) 12551882Sbostic VTOI(vp)->i_flag |= IMOD; 12651882Sbostic } 12751882Sbostic free(inop, M_SEGMENT); 12851882Sbostic return (lfs_segwrite(mntp, 1)); 12951882Sbostic } 13051882Sbostic 13151882Sbostic /* 13251882Sbostic * lfs_bmapv: 13351882Sbostic * 13451882Sbostic * This will fill in the current disk address for arrays of inodes and blocks. 13551882Sbostic * 13651882Sbostic * 0 on success 13751882Sbostic * -1/errno is return on error. 13851882Sbostic */ 13951882Sbostic int 14051882Sbostic lfs_bmapv(p, uap, retval) 14151882Sbostic struct proc *p; 14251882Sbostic struct args { 14351882Sbostic fsid_t fsid; /* file system */ 14451882Sbostic BLOCK_INFO *blkiov; /* block array */ 14551882Sbostic int blkcnt; /* count of block array entries */ 14651882Sbostic } *uap; 14751882Sbostic int *retval; 14851882Sbostic { 14951882Sbostic BLOCK_INFO *blkp; 15051882Sbostic struct mount *mntp; 15151882Sbostic struct vnode *vp; 15251882Sbostic daddr_t daddr; 15351882Sbostic int cnt, error; 15451882Sbostic 15551882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 15651882Sbostic return (error); 15751882Sbostic 15851882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 15951882Sbostic return (EINVAL); 16051882Sbostic 16151882Sbostic cnt = uap->blkcnt; 16251882Sbostic blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK); 16351882Sbostic if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) { 16451882Sbostic free(blkp, M_SEGMENT); 16551882Sbostic return (error); 16651882Sbostic } 16751882Sbostic 16851882Sbostic for (; cnt--; ++blkp) 16951882Sbostic blkp->bi_daddr = 17051882Sbostic lfs_vget(mntp, blkp->bi_inode, &vp) || 17151882Sbostic lfs_bmap(vp, blkp->bi_lbn, NULL, &daddr) ? 17251882Sbostic LFS_UNUSED_DADDR : daddr; 17351882Sbostic free(blkp, M_SEGMENT); 17451882Sbostic return (0); 17551882Sbostic } 17651882Sbostic 17751882Sbostic /* 17851882Sbostic * lfs_segclean: 17951882Sbostic * 18051882Sbostic * Mark the segment clean. 18151882Sbostic * 18251882Sbostic * 0 on success 18351882Sbostic * -1/errno is return on error. 18451882Sbostic */ 18551882Sbostic int 18651882Sbostic lfs_segclean(p, uap, retval) 18751882Sbostic struct proc *p; 18851882Sbostic struct args { 18951882Sbostic fsid_t fsid; /* file system */ 19051882Sbostic u_long segment; /* segment number */ 19151882Sbostic } *uap; 19251882Sbostic int *retval; 19351882Sbostic { 19451928Sbostic CLEANERINFO *cip; 19551882Sbostic SEGUSE *sup; 19651882Sbostic struct buf *bp; 19751882Sbostic struct mount *mntp; 19851882Sbostic struct lfs *fs; 19951882Sbostic int error; 20051882Sbostic 20151882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 20251882Sbostic return (error); 20351882Sbostic 20451882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 20551882Sbostic return (EINVAL); 20651882Sbostic 20751882Sbostic fs = VFSTOUFS(mntp)->um_lfs; 20851928Sbostic 20951882Sbostic LFS_SEGENTRY(sup, fs, uap->segment, bp); 21051882Sbostic sup->su_flags &= ~SEGUSE_DIRTY; 211*51966Sbostic sup->su_nbytes = sup->su_flags & SEGUSE_SUPERBLOCK ? LFS_SBPAD : 0; 21251935Sbostic LFS_IWRITE(fs, bp); 21351928Sbostic 21451928Sbostic LFS_CLEANERINFO(cip, fs, bp); 21551928Sbostic ++cip->clean; 21651928Sbostic --cip->dirty; 21751935Sbostic LFS_IWRITE(fs, bp); 21851928Sbostic 21951882Sbostic return (0); 22051882Sbostic } 22151882Sbostic 22251882Sbostic /* 22351882Sbostic * lfs_segwait: 22451882Sbostic * 22551882Sbostic * This will block until a segment in file system fsid is written. A timeout 22651882Sbostic * in milliseconds may be specified which will awake the cleaner automatically. 22751882Sbostic * An fsid of -1 means any file system, and a timeout of 0 means forever. 22851882Sbostic * 22951882Sbostic * 0 on success 23051882Sbostic * 1 on timeout 23151882Sbostic * -1/errno is return on error. 23251882Sbostic */ 23351882Sbostic int 23451882Sbostic lfs_segwait(p, uap, retval) 23551882Sbostic struct proc *p; 23651882Sbostic struct args { 23751882Sbostic fsid_t fsid; /* file system */ 23851882Sbostic struct timeval *tv; /* timeout */ 23951882Sbostic } *uap; 24051882Sbostic int *retval; 24151882Sbostic { 24251882Sbostic extern int lfs_allclean_wakeup; 24351882Sbostic struct mount *mntp; 24451882Sbostic struct timeval atv; 24551882Sbostic void *addr; 24651882Sbostic u_long timeout; 24751882Sbostic int error, s; 24851882Sbostic 24951882Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 25051882Sbostic return (error); 25151882Sbostic 25251882Sbostic #ifdef WHEN_QUADS_WORK 25351882Sbostic if (uap->fsid == (fsid_t)-1) 25451882Sbostic addr = &lfs_allclean_wakeup; 25551882Sbostic else { 25651882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 25751882Sbostic return (EINVAL); 25851882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 25951882Sbostic } 26051882Sbostic #else 26151882Sbostic if ((mntp = getvfs(&uap->fsid)) == NULL) 26251882Sbostic addr = &lfs_allclean_wakeup; 26351882Sbostic else 26451882Sbostic addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 26551882Sbostic #endif 26651882Sbostic 26751882Sbostic if (uap->tv) { 26851882Sbostic if (error = copyin(uap->tv, &atv, sizeof(struct timeval))) 26951882Sbostic return (error); 27051882Sbostic if (itimerfix(&atv)) 27151882Sbostic return (EINVAL); 27251882Sbostic s = splhigh(); timevaladd(&atv, &time); splx(s); 27351882Sbostic timeout = hzto(&atv); 27451882Sbostic } else 27551882Sbostic timeout = 0; 27651882Sbostic 27751882Sbostic error = tsleep(addr, PCATCH | PUSER, "segment", timeout); 27851882Sbostic return (error == ERESTART ? EINTR : 0); 27951882Sbostic } 280