xref: /csrg-svn/sys/ufs/lfs/lfs_syscalls.c (revision 56029)
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