xref: /csrg-svn/sys/ufs/lfs/lfs_syscalls.c (revision 55804)
151882Sbostic /*-
251882Sbostic  * Copyright (c) 1991 The Regents of the University of California.
351882Sbostic  * All rights reserved.
451882Sbostic  *
551882Sbostic  * %sccs.include.redist.c%
651882Sbostic  *
7*55804Sbostic  *	@(#)lfs_syscalls.c	7.17 (Berkeley) 08/01/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) {
142*55804Sbostic 		if (inop->ii_inode == LFS_IFILE_INUM)
143*55804Sbostic 			daddr = fs->lfs_idaddr;
144*55804Sbostic 		else {
145*55804Sbostic 			LFS_IENTRY(ifp, fs, inop->ii_inode, bp);
146*55804Sbostic 			daddr = ifp->if_daddr;
147*55804Sbostic 			brelse(bp);
148*55804Sbostic 		}
149*55804Sbostic 
15051882Sbostic 		if (daddr != inop->ii_daddr)
15151882Sbostic 			continue;
15251882Sbostic 		/*
15351882Sbostic 		 * XXX
15451882Sbostic 		 * This is grossly inefficient since the cleaner just handed
15551882Sbostic 		 * us a copy of the inode and we're going to have to seek
15651882Sbostic 		 * to get our own.  The fix requires creating a version of
15751882Sbostic 		 * lfs_vget that takes the copy and uses it instead of reading
15851882Sbostic 		 * from disk, if it's not already in the cache.
15951882Sbostic 		 */
16054662Smckusick 		if (!VFS_VGET(mntp, inop->ii_inode, &vp)) {
16151882Sbostic 			VTOI(vp)->i_flag |= IMOD;
16252173Sbostic 			vput(vp);
16352173Sbostic 		}
16451882Sbostic 	}
16552173Sbostic 	free(start, M_SEGMENT);
16651882Sbostic 	return (lfs_segwrite(mntp, 1));
16751882Sbostic }
16851882Sbostic 
16951882Sbostic /*
17051882Sbostic  * lfs_bmapv:
17151882Sbostic  *
17252087Sbostic  * This will fill in the current disk address for arrays of blocks.
17351882Sbostic  *
17451882Sbostic  *  0 on success
17551882Sbostic  * -1/errno is return on error.
17651882Sbostic  */
17751882Sbostic int
17851882Sbostic lfs_bmapv(p, uap, retval)
17951882Sbostic 	struct proc *p;
18051882Sbostic 	struct args {
18151882Sbostic 		fsid_t fsid;		/* file system */
18251882Sbostic 		BLOCK_INFO *blkiov;	/* block array */
18351882Sbostic 		int blkcnt;		/* count of block array entries */
18451882Sbostic 	} *uap;
18551882Sbostic 	int *retval;
18651882Sbostic {
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) {
21154662Smckusick 		if (VFS_VGET(mntp, blkp->bi_inode, &vp))
21252173Sbostic 			daddr = LFS_UNUSED_DADDR;
21352173Sbostic 		else {
21453531Sheideman 			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);
26155593Sbostic 	fs->lfs_bfree += (sup->su_nsums * LFS_SUMMARY_SIZE / DEV_BSIZE) +
26255593Sbostic 	    sup->su_ninos * btodb(fs->lfs_bsize);
26351882Sbostic 	sup->su_flags &= ~SEGUSE_DIRTY;
264*55804Sbostic 	sup->su_nbytes -= sup->su_nsums * LFS_SUMMARY_SIZE;
26555593Sbostic 	sup->su_ninos = 0;
26655593Sbostic 	sup->su_nsums = 0;
26752087Sbostic 	LFS_UBWRITE(bp);
26851928Sbostic 
26951928Sbostic 	LFS_CLEANERINFO(cip, fs, bp);
27051928Sbostic 	++cip->clean;
27151928Sbostic 	--cip->dirty;
27252087Sbostic 	LFS_UBWRITE(bp);
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