xref: /csrg-svn/sys/ufs/lfs/lfs_vfsops.c (revision 29118)
123400Smckusick /*
2*29118Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323400Smckusick  * All rights reserved.  The Berkeley software License Agreement
423400Smckusick  * specifies the terms and conditions for redistribution.
523400Smckusick  *
6*29118Smckusick  *	@(#)lfs_vfsops.c	7.1 (Berkeley) 06/05/86
723400Smckusick  */
812795Ssam 
917100Sbloom #include "param.h"
1017100Sbloom #include "systm.h"
1117100Sbloom #include "dir.h"
1217100Sbloom #include "user.h"
1317100Sbloom #include "inode.h"
1417100Sbloom #include "proc.h"
1517100Sbloom #include "fs.h"
1617100Sbloom #include "buf.h"
1717100Sbloom #include "mount.h"
1817100Sbloom #include "file.h"
1917100Sbloom #include "conf.h"
2012795Ssam 
2112795Ssam smount()
2212795Ssam {
2312795Ssam 	register struct a {
2412795Ssam 		char	*fspec;
2512795Ssam 		char	*freg;
2612795Ssam 		int	ronly;
2716697Smckusick 	} *uap = (struct a *)u.u_ap;
2812795Ssam 	dev_t dev;
2912795Ssam 	register struct inode *ip;
3012795Ssam 	register struct fs *fs;
3116697Smckusick 	register struct nameidata *ndp = &u.u_nd;
3216705Smckusick 	u_int len;
3312795Ssam 
3416697Smckusick 	u.u_error = getmdev(&dev, uap->fspec);
3512795Ssam 	if (u.u_error)
3612795Ssam 		return;
3727267Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
3816697Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
3916697Smckusick 	ndp->ni_dirp = (caddr_t)uap->freg;
4016697Smckusick 	ip = namei(ndp);
4112795Ssam 	if (ip == NULL)
4212795Ssam 		return;
4321013Smckusick 	if (ip->i_count != 1) {
4412795Ssam 		iput(ip);
4512795Ssam 		u.u_error = EBUSY;
4612795Ssam 		return;
4712795Ssam 	}
4821013Smckusick 	if ((ip->i_mode&IFMT) != IFDIR) {
4921013Smckusick 		iput(ip);
5021013Smckusick 		u.u_error = ENOTDIR;
5121013Smckusick 		return;
5221013Smckusick 	}
5312795Ssam 	fs = mountfs(dev, uap->ronly, ip);
5412795Ssam 	if (fs == 0)
5512795Ssam 		return;
5616705Smckusick 	(void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
5716728Skarels 	bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
5812795Ssam }
5912795Ssam 
6012795Ssam /* this routine has races if running twice */
6112795Ssam struct fs *
6212795Ssam mountfs(dev, ronly, ip)
6312795Ssam 	dev_t dev;
6412795Ssam 	int ronly;
6512795Ssam 	struct inode *ip;
6612795Ssam {
6712795Ssam 	register struct mount *mp = 0;
6812795Ssam 	struct buf *tp = 0;
6912795Ssam 	register struct buf *bp = 0;
7012795Ssam 	register struct fs *fs;
7112795Ssam 	int blks;
7212795Ssam 	caddr_t space;
7312795Ssam 	int i, size;
7416639Skarels 	register error;
7521013Smckusick 	int needclose = 0;
7612795Ssam 
7716639Skarels 	error =
7812795Ssam 	    (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE);
7916639Skarels 	if (error)
8012795Ssam 		goto out;
8121013Smckusick 	needclose = 1;
8212795Ssam 	tp = bread(dev, SBLOCK, SBSIZE);
8312795Ssam 	if (tp->b_flags & B_ERROR)
8412795Ssam 		goto out;
8512795Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
8612795Ssam 		if (mp->m_bufp != 0 && dev == mp->m_dev) {
8712795Ssam 			mp = 0;
8816639Skarels 			error = EBUSY;
8926224Skarels 			needclose = 0;
9012795Ssam 			goto out;
9112795Ssam 		}
9212795Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
9312795Ssam 		if (mp->m_bufp == 0)
9412795Ssam 			goto found;
9512795Ssam 	mp = 0;
9616639Skarels 	error = EMFILE;		/* needs translation */
9712795Ssam 	goto out;
9812795Ssam found:
9912795Ssam 	mp->m_bufp = tp;	/* just to reserve this slot */
10012795Ssam 	mp->m_dev = NODEV;
10112795Ssam 	fs = tp->b_un.b_fs;
10216639Skarels 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE
10316639Skarels 	    || fs->fs_bsize < sizeof(struct fs)) {
10416639Skarels 		error = EINVAL;		/* also needs translation */
10516639Skarels 		goto out;
10616639Skarels 	}
10712795Ssam 	bp = geteblk((int)fs->fs_sbsize);
10812795Ssam 	mp->m_bufp = bp;
10912795Ssam 	bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
11012795Ssam 	   (u_int)fs->fs_sbsize);
11112795Ssam 	brelse(tp);
11212795Ssam 	tp = 0;
11312795Ssam 	fs = bp->b_un.b_fs;
11412795Ssam 	fs->fs_ronly = (ronly != 0);
11512795Ssam 	if (ronly == 0)
11612795Ssam 		fs->fs_fmod = 1;
11712795Ssam 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
11812795Ssam 	space = wmemall(vmemall, (int)fs->fs_cssize);
11916639Skarels 	if (space == 0) {
12016639Skarels 		error = ENOMEM;
12112795Ssam 		goto out;
12216639Skarels 	}
12312795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
12412795Ssam 		size = fs->fs_bsize;
12512795Ssam 		if (i + fs->fs_frag > blks)
12612795Ssam 			size = (blks - i) * fs->fs_fsize;
12712795Ssam 		tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
12812795Ssam 		if (tp->b_flags&B_ERROR) {
12912795Ssam 			wmemfree(space, (int)fs->fs_cssize);
13012795Ssam 			goto out;
13112795Ssam 		}
13212795Ssam 		bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
13317225Smckusick 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
13412795Ssam 		space += size;
13512795Ssam 		brelse(tp);
13612795Ssam 		tp = 0;
13712795Ssam 	}
13812795Ssam 	mp->m_inodp = ip;
13912795Ssam 	mp->m_dev = dev;
14012795Ssam 	if (ip) {
14112795Ssam 		ip->i_flag |= IMOUNT;
14227267Smckusick 		cacheinval(ip);
14312795Ssam 		iunlock(ip);
14412795Ssam 	}
14512795Ssam 	return (fs);
14612795Ssam out:
14716639Skarels 	if (error == 0)
14816639Skarels 		error = EIO;
14912795Ssam 	if (ip)
15012795Ssam 		iput(ip);
15112795Ssam 	if (mp)
15212795Ssam 		mp->m_bufp = 0;
15312795Ssam 	if (bp)
15412795Ssam 		brelse(bp);
15512795Ssam 	if (tp)
15612795Ssam 		brelse(tp);
15726224Skarels 	if (needclose) {
15826224Skarels 		(*bdevsw[major(dev)].d_close)(dev, ronly? FREAD : FREAD|FWRITE);
15926224Skarels 		binval(dev);
16026224Skarels 	}
16116639Skarels 	u.u_error = error;
16212795Ssam 	return (0);
16312795Ssam }
16412795Ssam 
16512795Ssam umount()
16612795Ssam {
16712795Ssam 	struct a {
16812795Ssam 		char	*fspec;
16916697Smckusick 	} *uap = (struct a *)u.u_ap;
17012795Ssam 
17116697Smckusick 	u.u_error = unmount1(uap->fspec, 0);
17212795Ssam }
17312795Ssam 
17416697Smckusick unmount1(fname, forcibly)
17516697Smckusick 	caddr_t fname;
17612795Ssam 	int forcibly;
17712795Ssam {
17812795Ssam 	dev_t dev;
17912795Ssam 	register struct mount *mp;
18012795Ssam 	int stillopen, flag, error;
18112795Ssam 	register struct inode *ip;
18212795Ssam 	register struct fs *fs;
18312795Ssam 
18416697Smckusick 	error = getmdev(&dev, fname);
18512795Ssam 	if (error)
18612795Ssam 		return (error);
18712795Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
18812795Ssam 		if (mp->m_bufp != NULL && dev == mp->m_dev)
18912795Ssam 			goto found;
19012795Ssam 	return (EINVAL);
19112795Ssam found:
19212795Ssam 	xumount(dev);	/* remove unused sticky files from text table */
19315800Smckusick 	nchinval(dev);	/* flush the name cache */
19412795Ssam 	update();
19512795Ssam #ifdef QUOTA
19612795Ssam 	if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly)
19712795Ssam #else
19812795Ssam 	if ((stillopen = iflush(dev)) < 0 && !forcibly)
19912795Ssam #endif
20012795Ssam 		return (EBUSY);
20112795Ssam 	if (stillopen < 0)
20212795Ssam 		return (EBUSY);			/* XXX */
20312795Ssam #ifdef QUOTA
20412795Ssam 	closedq(mp);
20512795Ssam 	/*
20612795Ssam 	 * Here we have to iflush again to get rid of the quota inode.
20712795Ssam 	 * A drag, but it would be ugly to cheat, & this doesn't happen often
20812795Ssam 	 */
20912795Ssam 	(void)iflush(dev, (struct inode *)NULL);
21012795Ssam #endif
21112795Ssam 	ip = mp->m_inodp;
21212795Ssam 	ip->i_flag &= ~IMOUNT;
21312795Ssam 	irele(ip);
21412795Ssam 	fs = mp->m_bufp->b_un.b_fs;
21512795Ssam 	wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize);
21612795Ssam 	flag = !fs->fs_ronly;
21712795Ssam 	brelse(mp->m_bufp);
21812795Ssam 	mp->m_bufp = 0;
21912795Ssam 	mp->m_dev = 0;
22012795Ssam 	mpurge(mp - &mount[0]);
22112795Ssam 	if (!stillopen) {
22212795Ssam 		(*bdevsw[major(dev)].d_close)(dev, flag);
22312795Ssam 		binval(dev);
22412795Ssam 	}
22512795Ssam 	return (0);
22612795Ssam }
22712795Ssam 
22812795Ssam sbupdate(mp)
22912795Ssam 	struct mount *mp;
23012795Ssam {
23112795Ssam 	register struct fs *fs = mp->m_bufp->b_un.b_fs;
23212795Ssam 	register struct buf *bp;
23312795Ssam 	int blks;
23412795Ssam 	caddr_t space;
23512795Ssam 	int i, size;
23612795Ssam 
23712795Ssam 	bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
23812795Ssam 	bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
23912795Ssam 	bwrite(bp);
24012795Ssam 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
24112795Ssam 	space = (caddr_t)fs->fs_csp[0];
24212795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
24312795Ssam 		size = fs->fs_bsize;
24412795Ssam 		if (i + fs->fs_frag > blks)
24512795Ssam 			size = (blks - i) * fs->fs_fsize;
24612795Ssam 		bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
24712795Ssam 		bcopy(space, bp->b_un.b_addr, (u_int)size);
24812795Ssam 		space += size;
24912795Ssam 		bwrite(bp);
25012795Ssam 	}
25112795Ssam }
25212795Ssam 
25312795Ssam /*
25412795Ssam  * Common code for mount and umount.
25512795Ssam  * Check that the user's argument is a reasonable
25612795Ssam  * thing on which to mount, and return the device number if so.
25712795Ssam  */
25816697Smckusick getmdev(pdev, fname)
25916697Smckusick 	caddr_t fname;
26012795Ssam 	dev_t *pdev;
26112795Ssam {
26212795Ssam 	dev_t dev;
26312795Ssam 	register struct inode *ip;
26416697Smckusick 	register struct nameidata *ndp = &u.u_nd;
26512795Ssam 
26612795Ssam 	if (!suser())
26712795Ssam 		return (u.u_error);
26816697Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
26916697Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
27016697Smckusick 	ndp->ni_dirp = fname;
27116697Smckusick 	ip = namei(ndp);
27221013Smckusick 	if (ip == NULL) {
27321013Smckusick 		if (u.u_error == ENOENT)
27421013Smckusick 			return (ENODEV); /* needs translation */
27512795Ssam 		return (u.u_error);
27621013Smckusick 	}
27715956Skarels 	if ((ip->i_mode&IFMT) != IFBLK) {
27815956Skarels 		iput(ip);
27912795Ssam 		return (ENOTBLK);
28015956Skarels 	}
28112795Ssam 	dev = (dev_t)ip->i_rdev;
28215956Skarels 	iput(ip);
28312795Ssam 	if (major(dev) >= nblkdev)
28412795Ssam 		return (ENXIO);
28512795Ssam 	*pdev = dev;
28612795Ssam 	return (0);
28712795Ssam }
288