xref: /csrg-svn/sys/ufs/lfs/lfs_vfsops.c (revision 34473)
123400Smckusick /*
229118Smckusick  * 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*34473Smckusick  *	@(#)lfs_vfsops.c	7.11 (Berkeley) 05/24/88
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"
2030749Skarels #include "ioctl.h"
2130749Skarels #include "disklabel.h"
2230749Skarels #include "stat.h"
2331660Smckusick #include "malloc.h"
2412795Ssam 
2512795Ssam smount()
2612795Ssam {
2712795Ssam 	register struct a {
2812795Ssam 		char	*fspec;
2912795Ssam 		char	*freg;
3012795Ssam 		int	ronly;
3116697Smckusick 	} *uap = (struct a *)u.u_ap;
3212795Ssam 	dev_t dev;
3312795Ssam 	register struct inode *ip;
3412795Ssam 	register struct fs *fs;
3516697Smckusick 	register struct nameidata *ndp = &u.u_nd;
3616705Smckusick 	u_int len;
3712795Ssam 
3816697Smckusick 	u.u_error = getmdev(&dev, uap->fspec);
3912795Ssam 	if (u.u_error)
4012795Ssam 		return;
4127267Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
4216697Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
4316697Smckusick 	ndp->ni_dirp = (caddr_t)uap->freg;
4416697Smckusick 	ip = namei(ndp);
4512795Ssam 	if (ip == NULL)
4612795Ssam 		return;
4721013Smckusick 	if (ip->i_count != 1) {
4812795Ssam 		iput(ip);
4912795Ssam 		u.u_error = EBUSY;
5012795Ssam 		return;
5112795Ssam 	}
5221013Smckusick 	if ((ip->i_mode&IFMT) != IFDIR) {
5321013Smckusick 		iput(ip);
5421013Smckusick 		u.u_error = ENOTDIR;
5521013Smckusick 		return;
5621013Smckusick 	}
5712795Ssam 	fs = mountfs(dev, uap->ronly, ip);
5832721Smckusick 	if (fs == 0) {
5932721Smckusick 		iput(ip);
6012795Ssam 		return;
6132721Smckusick 	}
6216705Smckusick 	(void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
6316728Skarels 	bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
6412795Ssam }
6512795Ssam 
6612795Ssam struct fs *
6712795Ssam mountfs(dev, ronly, ip)
6812795Ssam 	dev_t dev;
6912795Ssam 	int ronly;
7012795Ssam 	struct inode *ip;
7112795Ssam {
7232721Smckusick 	register struct mount *mp;
7332721Smckusick 	struct mount *fmp = NULL;
7432721Smckusick 	register struct buf *bp = NULL;
7512795Ssam 	register struct fs *fs;
7630749Skarels 	struct partinfo dpart;
7730749Skarels 	int havepart = 0, blks;
7832721Smckusick 	caddr_t base, space;
7912795Ssam 	int i, size;
8016639Skarels 	register error;
8121013Smckusick 	int needclose = 0;
8212795Ssam 
8332721Smckusick 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
8432721Smckusick 		if (mp->m_fs == NULL) {
8532721Smckusick 			if (fmp == NULL)
8632721Smckusick 				fmp = mp;
8732721Smckusick 		} else if (dev == mp->m_dev) {
8832721Smckusick 			u.u_error = EBUSY;		/* XXX */
8932721Smckusick 			return ((struct fs *) NULL);
9032721Smckusick 		}
9132721Smckusick 	}
9232721Smckusick 	if ((mp = fmp) == NULL) {
9332721Smckusick 		u.u_error = EMFILE;		/* needs translation      XXX */
9432721Smckusick 		return ((struct fs *) NULL);
9532721Smckusick 	}
9632721Smckusick 	mp->m_fs = (struct fs *)1;	/* just to reserve this slot */
9732721Smckusick 	mp->m_dev = dev;
9834356Skarels 	mp->m_inodp = NULL;
9916639Skarels 	error =
10030749Skarels 	    (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
10130749Skarels 	        S_IFBLK);
10232721Smckusick 	if (error) {
10332721Smckusick 		u.u_error = error;
10432721Smckusick 		mp->m_fs = NULL;
10532721Smckusick 		return ((struct fs *) NULL);
10632721Smckusick 	}
10721013Smckusick 	needclose = 1;
10830749Skarels 	if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
10930749Skarels 	    (caddr_t)&dpart, FREAD) == 0) {
11030749Skarels 		havepart = 1;
11130749Skarels 		size = dpart.disklab->d_secsize;
11230749Skarels 	} else
11330749Skarels 		size = DEV_BSIZE;
11434421Skarels 	bp = bread(dev, SBLOCK, SBSIZE);
11534421Skarels 	if (bp->b_flags & B_ERROR) {
11632721Smckusick 		mp->m_fs = NULL;
11712795Ssam 		goto out;
11832721Smckusick 	}
11934421Skarels 	fs = bp->b_un.b_fs;
12030749Skarels 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
12130749Skarels 	    fs->fs_bsize < sizeof(struct fs)) {
12231660Smckusick 		mp->m_fs = NULL;
12316639Skarels 		error = EINVAL;		/* also needs translation */
12416639Skarels 		goto out;
12516639Skarels 	}
126*34473Smckusick 	mp->m_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
127*34473Smckusick 	    M_WAITOK);
12834421Skarels 	bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)mp->m_fs,
12912795Ssam 	   (u_int)fs->fs_sbsize);
13034421Skarels 	brelse(bp);
13134421Skarels 	bp = NULL;
13231660Smckusick 	fs = mp->m_fs;
13312795Ssam 	fs->fs_ronly = (ronly != 0);
13412795Ssam 	if (ronly == 0)
13512795Ssam 		fs->fs_fmod = 1;
13630749Skarels 	if (havepart) {
13730749Skarels 		dpart.part->p_fstype = FS_BSDFFS;
13830749Skarels 		dpart.part->p_fsize = fs->fs_fsize;
13930749Skarels 		dpart.part->p_frag = fs->fs_frag;
14031385Skarels 		dpart.part->p_cpg = fs->fs_cpg;
14130749Skarels 	}
14212795Ssam 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
143*34473Smckusick 	base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
144*34473Smckusick 	    M_WAITOK);
14532721Smckusick 	if (space == NULL) {
14616639Skarels 		error = ENOMEM;
14712795Ssam 		goto out;
14816639Skarels 	}
14912795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
15012795Ssam 		size = fs->fs_bsize;
15112795Ssam 		if (i + fs->fs_frag > blks)
15212795Ssam 			size = (blks - i) * fs->fs_fsize;
15334421Skarels 		bp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
15434421Skarels 		if (bp->b_flags&B_ERROR) {
155*34473Smckusick 			free((caddr_t)base, M_SUPERBLK);
15612795Ssam 			goto out;
15712795Ssam 		}
15834421Skarels 		bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size);
15917225Smckusick 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
16012795Ssam 		space += size;
16134421Skarels 		brelse(bp);
16234421Skarels 		bp = NULL;
16312795Ssam 	}
16412795Ssam 	mp->m_inodp = ip;
16512795Ssam 	if (ip) {
16612795Ssam 		ip->i_flag |= IMOUNT;
16727267Smckusick 		cacheinval(ip);
16812795Ssam 		iunlock(ip);
16912795Ssam 	}
17030383Smckusick 	/* Sanity checks for old file systems.			   XXX */
17130383Smckusick 	fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);	/* XXX */
17230383Smckusick 	fs->fs_interleave = MAX(fs->fs_interleave, 1);		/* XXX */
17334145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
17434145Smckusick 		fs->fs_nrpos = 8;				/* XXX */
17512795Ssam 	return (fs);
17612795Ssam out:
17732721Smckusick 	if (needclose)
17832721Smckusick 		(void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE);
17932721Smckusick 	if (mp->m_fs) {
18031660Smckusick 		free((caddr_t)mp->m_fs, M_SUPERBLK);
18132721Smckusick 		mp->m_fs = NULL;
18232721Smckusick 	}
18334421Skarels 	if (bp)
18434421Skarels 		brelse(bp);
18532721Smckusick 	u.u_error = error ? error : EIO;			/* XXX */
18632721Smckusick 	return ((struct fs *) NULL);
18712795Ssam }
18812795Ssam 
18912795Ssam umount()
19012795Ssam {
19112795Ssam 	struct a {
19212795Ssam 		char	*fspec;
19316697Smckusick 	} *uap = (struct a *)u.u_ap;
19412795Ssam 
19516697Smckusick 	u.u_error = unmount1(uap->fspec, 0);
19612795Ssam }
19712795Ssam 
19816697Smckusick unmount1(fname, forcibly)
19916697Smckusick 	caddr_t fname;
20012795Ssam 	int forcibly;
20112795Ssam {
20212795Ssam 	dev_t dev;
20312795Ssam 	register struct mount *mp;
20430749Skarels 	int error;
20512795Ssam 	register struct inode *ip;
20612795Ssam 	register struct fs *fs;
20712795Ssam 
20830749Skarels 	forcibly = 0;					/* XXX */
20916697Smckusick 	error = getmdev(&dev, fname);
21012795Ssam 	if (error)
21112795Ssam 		return (error);
21212795Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
21331660Smckusick 		if (mp->m_fs != NULL && dev == mp->m_dev)
21412795Ssam 			goto found;
21512795Ssam 	return (EINVAL);
21612795Ssam found:
21712795Ssam 	xumount(dev);	/* remove unused sticky files from text table */
21815800Smckusick 	nchinval(dev);	/* flush the name cache */
21912795Ssam 	update();
22012795Ssam #ifdef QUOTA
22130749Skarels 	if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
22212795Ssam #else
22330749Skarels 	if ((error = iflush(dev)) && !forcibly)
22412795Ssam #endif
22530749Skarels 		return (error);
22612795Ssam #ifdef QUOTA
22712795Ssam 	closedq(mp);
22812795Ssam 	/*
22912795Ssam 	 * Here we have to iflush again to get rid of the quota inode.
23030749Skarels 	 * A drag, but it would be ugly to cheat, & this doesn't happen often.
23112795Ssam 	 */
23212795Ssam 	(void)iflush(dev, (struct inode *)NULL);
23312795Ssam #endif
23412795Ssam 	ip = mp->m_inodp;
23512795Ssam 	ip->i_flag &= ~IMOUNT;
23631660Smckusick 	fs = mp->m_fs;
23731660Smckusick 	free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
23831660Smckusick 	free((caddr_t)mp->m_fs, M_SUPERBLK);
23932721Smckusick 	mp->m_fs = NULL;
24032721Smckusick 	mp->m_dev = NODEV;
24112795Ssam 	mpurge(mp - &mount[0]);
24230749Skarels 	error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
24330749Skarels 	irele(ip);
24430749Skarels 	return (error);
24512795Ssam }
24612795Ssam 
24712795Ssam sbupdate(mp)
24812795Ssam 	struct mount *mp;
24912795Ssam {
25031660Smckusick 	register struct fs *fs = mp->m_fs;
25112795Ssam 	register struct buf *bp;
25212795Ssam 	int blks;
25312795Ssam 	caddr_t space;
25412795Ssam 	int i, size;
25512795Ssam 
25612795Ssam 	bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
25712795Ssam 	bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
25834145Smckusick 	/* Restore compatibility to old file systems.		   XXX */
25934145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
26034145Smckusick 		bp->b_un.b_fs->fs_nrpos = -1;			/* XXX */
26112795Ssam 	bwrite(bp);
26212795Ssam 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
26312795Ssam 	space = (caddr_t)fs->fs_csp[0];
26412795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
26512795Ssam 		size = fs->fs_bsize;
26612795Ssam 		if (i + fs->fs_frag > blks)
26712795Ssam 			size = (blks - i) * fs->fs_fsize;
26812795Ssam 		bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
26912795Ssam 		bcopy(space, bp->b_un.b_addr, (u_int)size);
27012795Ssam 		space += size;
27112795Ssam 		bwrite(bp);
27212795Ssam 	}
27312795Ssam }
27412795Ssam 
27512795Ssam /*
27612795Ssam  * Common code for mount and umount.
27712795Ssam  * Check that the user's argument is a reasonable
27812795Ssam  * thing on which to mount, and return the device number if so.
27912795Ssam  */
28016697Smckusick getmdev(pdev, fname)
28116697Smckusick 	caddr_t fname;
28212795Ssam 	dev_t *pdev;
28312795Ssam {
28412795Ssam 	dev_t dev;
28512795Ssam 	register struct inode *ip;
28616697Smckusick 	register struct nameidata *ndp = &u.u_nd;
28712795Ssam 
28812795Ssam 	if (!suser())
28912795Ssam 		return (u.u_error);
29016697Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
29116697Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
29216697Smckusick 	ndp->ni_dirp = fname;
29316697Smckusick 	ip = namei(ndp);
29421013Smckusick 	if (ip == NULL) {
29521013Smckusick 		if (u.u_error == ENOENT)
29621013Smckusick 			return (ENODEV); /* needs translation */
29712795Ssam 		return (u.u_error);
29821013Smckusick 	}
29915956Skarels 	if ((ip->i_mode&IFMT) != IFBLK) {
30015956Skarels 		iput(ip);
30112795Ssam 		return (ENOTBLK);
30215956Skarels 	}
30312795Ssam 	dev = (dev_t)ip->i_rdev;
30415956Skarels 	iput(ip);
30512795Ssam 	if (major(dev) >= nblkdev)
30612795Ssam 		return (ENXIO);
30712795Ssam 	*pdev = dev;
30812795Ssam 	return (0);
30912795Ssam }
310