xref: /csrg-svn/sys/ufs/lfs/lfs_vfsops.c (revision 30749)
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*30749Skarels  *	@(#)lfs_vfsops.c	7.2.1.1 (Berkeley) 04/02/87
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"
20*30749Skarels #include "ioctl.h"
21*30749Skarels #include "disklabel.h"
22*30749Skarels #include "stat.h"
2312795Ssam 
2412795Ssam smount()
2512795Ssam {
2612795Ssam 	register struct a {
2712795Ssam 		char	*fspec;
2812795Ssam 		char	*freg;
2912795Ssam 		int	ronly;
3016697Smckusick 	} *uap = (struct a *)u.u_ap;
3112795Ssam 	dev_t dev;
3212795Ssam 	register struct inode *ip;
3312795Ssam 	register struct fs *fs;
3416697Smckusick 	register struct nameidata *ndp = &u.u_nd;
3516705Smckusick 	u_int len;
3612795Ssam 
3716697Smckusick 	u.u_error = getmdev(&dev, uap->fspec);
3812795Ssam 	if (u.u_error)
3912795Ssam 		return;
4027267Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
4116697Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
4216697Smckusick 	ndp->ni_dirp = (caddr_t)uap->freg;
4316697Smckusick 	ip = namei(ndp);
4412795Ssam 	if (ip == NULL)
4512795Ssam 		return;
4621013Smckusick 	if (ip->i_count != 1) {
4712795Ssam 		iput(ip);
4812795Ssam 		u.u_error = EBUSY;
4912795Ssam 		return;
5012795Ssam 	}
5121013Smckusick 	if ((ip->i_mode&IFMT) != IFDIR) {
5221013Smckusick 		iput(ip);
5321013Smckusick 		u.u_error = ENOTDIR;
5421013Smckusick 		return;
5521013Smckusick 	}
5612795Ssam 	fs = mountfs(dev, uap->ronly, ip);
5712795Ssam 	if (fs == 0)
5812795Ssam 		return;
5916705Smckusick 	(void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
6016728Skarels 	bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
6112795Ssam }
6212795Ssam 
6312795Ssam /* this routine has races if running twice */
6412795Ssam struct fs *
6512795Ssam mountfs(dev, ronly, ip)
6612795Ssam 	dev_t dev;
6712795Ssam 	int ronly;
6812795Ssam 	struct inode *ip;
6912795Ssam {
7012795Ssam 	register struct mount *mp = 0;
7112795Ssam 	struct buf *tp = 0;
7212795Ssam 	register struct buf *bp = 0;
7312795Ssam 	register struct fs *fs;
74*30749Skarels 	struct partinfo dpart;
75*30749Skarels 	int havepart = 0, blks;
7612795Ssam 	caddr_t space;
7712795Ssam 	int i, size;
7816639Skarels 	register error;
7921013Smckusick 	int needclose = 0;
8012795Ssam 
8116639Skarels 	error =
82*30749Skarels 	    (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
83*30749Skarels 	        S_IFBLK);
8416639Skarels 	if (error)
8512795Ssam 		goto out;
8621013Smckusick 	needclose = 1;
87*30749Skarels #ifdef SECSIZE
88*30749Skarels 	/*
89*30749Skarels 	 * If possible, determine hardware sector size
90*30749Skarels 	 * and adjust fsbtodb to correspond.
91*30749Skarels 	 */
92*30749Skarels #endif SECSIZE
93*30749Skarels 	if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
94*30749Skarels 	    (caddr_t)&dpart, FREAD) == 0) {
95*30749Skarels 		havepart = 1;
96*30749Skarels 		size = dpart.disklab->d_secsize;
97*30749Skarels #ifdef SECSIZE
98*30749Skarels 		if (size < MINSECSIZE) {
99*30749Skarels 			error = EINVAL;
100*30749Skarels 			goto out;
101*30749Skarels 		}
102*30749Skarels #endif SECSIZE
103*30749Skarels 	} else
104*30749Skarels 		size = DEV_BSIZE;
105*30749Skarels #ifdef SECSIZE
106*30749Skarels 	tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size);
107*30749Skarels #else SECSIZE
10812795Ssam 	tp = bread(dev, SBLOCK, SBSIZE);
109*30749Skarels #endif SECSIZE
11012795Ssam 	if (tp->b_flags & B_ERROR)
11112795Ssam 		goto out;
11212795Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
11312795Ssam 		if (mp->m_bufp != 0 && dev == mp->m_dev) {
11412795Ssam 			mp = 0;
11516639Skarels 			error = EBUSY;
11612795Ssam 			goto out;
11712795Ssam 		}
11812795Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
11912795Ssam 		if (mp->m_bufp == 0)
12012795Ssam 			goto found;
12112795Ssam 	mp = 0;
12216639Skarels 	error = EMFILE;		/* needs translation */
12312795Ssam 	goto out;
12412795Ssam found:
12512795Ssam 	mp->m_bufp = tp;	/* just to reserve this slot */
12612795Ssam 	mp->m_dev = NODEV;
12712795Ssam 	fs = tp->b_un.b_fs;
128*30749Skarels 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
129*30749Skarels 	    fs->fs_bsize < sizeof(struct fs)) {
13016639Skarels 		error = EINVAL;		/* also needs translation */
13116639Skarels 		goto out;
13216639Skarels 	}
13312795Ssam 	bp = geteblk((int)fs->fs_sbsize);
13412795Ssam 	mp->m_bufp = bp;
13512795Ssam 	bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
13612795Ssam 	   (u_int)fs->fs_sbsize);
13712795Ssam 	brelse(tp);
13812795Ssam 	tp = 0;
13912795Ssam 	fs = bp->b_un.b_fs;
14012795Ssam 	fs->fs_ronly = (ronly != 0);
14112795Ssam 	if (ronly == 0)
14212795Ssam 		fs->fs_fmod = 1;
143*30749Skarels #ifdef SECSIZE
144*30749Skarels 	/*
145*30749Skarels 	 * If we have a disk label, force per-partition
146*30749Skarels 	 * filesystem information to be correct
147*30749Skarels 	 * and set correct current fsbtodb shift.
148*30749Skarels 	 */
149*30749Skarels #endif SECSIZE
150*30749Skarels 	if (havepart) {
151*30749Skarels 		dpart.part->p_fstype = FS_BSDFFS;
152*30749Skarels 		dpart.part->p_fsize = fs->fs_fsize;
153*30749Skarels 		dpart.part->p_frag = fs->fs_frag;
154*30749Skarels #ifdef SECSIZE
155*30749Skarels #ifdef tahoe
156*30749Skarels 		/*
157*30749Skarels 		 * Save the original fsbtodb shift to restore on updates.
158*30749Skarels 		 * (Console doesn't understand fsbtodb changes.)
159*30749Skarels 		 */
160*30749Skarels 		fs->fs_sparecon[0] = fs->fs_fsbtodb;
161*30749Skarels #endif
162*30749Skarels 		i = fs->fs_fsize / size;
163*30749Skarels 		for (fs->fs_fsbtodb = 0; i > 1; i >>= 1)
164*30749Skarels 			fs->fs_fsbtodb++;
165*30749Skarels #endif SECSIZE
166*30749Skarels 		fs->fs_dbsize = size;
167*30749Skarels 	}
16812795Ssam 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
16912795Ssam 	space = wmemall(vmemall, (int)fs->fs_cssize);
17016639Skarels 	if (space == 0) {
17116639Skarels 		error = ENOMEM;
17212795Ssam 		goto out;
17316639Skarels 	}
17412795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
17512795Ssam 		size = fs->fs_bsize;
17612795Ssam 		if (i + fs->fs_frag > blks)
17712795Ssam 			size = (blks - i) * fs->fs_fsize;
178*30749Skarels #ifdef SECSIZE
179*30749Skarels 		tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
180*30749Skarels 		    fs->fs_dbsize);
181*30749Skarels #else SECSIZE
18212795Ssam 		tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
183*30749Skarels #endif SECSIZE
18412795Ssam 		if (tp->b_flags&B_ERROR) {
18512795Ssam 			wmemfree(space, (int)fs->fs_cssize);
18612795Ssam 			goto out;
18712795Ssam 		}
18812795Ssam 		bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
18917225Smckusick 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
19012795Ssam 		space += size;
19112795Ssam 		brelse(tp);
19212795Ssam 		tp = 0;
19312795Ssam 	}
19412795Ssam 	mp->m_inodp = ip;
19512795Ssam 	mp->m_dev = dev;
19612795Ssam 	if (ip) {
19712795Ssam 		ip->i_flag |= IMOUNT;
19827267Smckusick 		cacheinval(ip);
19912795Ssam 		iunlock(ip);
20012795Ssam 	}
20130383Smckusick 	/* Sanity checks for old file systems.			   XXX */
20230383Smckusick 	fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);	/* XXX */
20330383Smckusick 	fs->fs_interleave = MAX(fs->fs_interleave, 1);		/* XXX */
204*30749Skarels 
20512795Ssam 	return (fs);
20612795Ssam out:
20716639Skarels 	if (error == 0)
20816639Skarels 		error = EIO;
209*30749Skarels 	if (needclose)
210*30749Skarels 		(void) closei((dev_t)ip->i_rdev, IFBLK,
211*30749Skarels 		    ronly? FREAD : FREAD|FWRITE);
21212795Ssam 	if (ip)
21312795Ssam 		iput(ip);
21412795Ssam 	if (mp)
21512795Ssam 		mp->m_bufp = 0;
21612795Ssam 	if (bp)
21712795Ssam 		brelse(bp);
21812795Ssam 	if (tp)
21912795Ssam 		brelse(tp);
22016639Skarels 	u.u_error = error;
22112795Ssam 	return (0);
22212795Ssam }
22312795Ssam 
22412795Ssam umount()
22512795Ssam {
22612795Ssam 	struct a {
22712795Ssam 		char	*fspec;
22816697Smckusick 	} *uap = (struct a *)u.u_ap;
22912795Ssam 
23016697Smckusick 	u.u_error = unmount1(uap->fspec, 0);
23112795Ssam }
23212795Ssam 
23316697Smckusick unmount1(fname, forcibly)
23416697Smckusick 	caddr_t fname;
23512795Ssam 	int forcibly;
23612795Ssam {
23712795Ssam 	dev_t dev;
23812795Ssam 	register struct mount *mp;
239*30749Skarels 	int error;
24012795Ssam 	register struct inode *ip;
24112795Ssam 	register struct fs *fs;
24212795Ssam 
243*30749Skarels 	forcibly = 0;					/* XXX */
24416697Smckusick 	error = getmdev(&dev, fname);
24512795Ssam 	if (error)
24612795Ssam 		return (error);
24712795Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
24812795Ssam 		if (mp->m_bufp != NULL && dev == mp->m_dev)
24912795Ssam 			goto found;
25012795Ssam 	return (EINVAL);
25112795Ssam found:
25212795Ssam 	xumount(dev);	/* remove unused sticky files from text table */
25315800Smckusick 	nchinval(dev);	/* flush the name cache */
25412795Ssam 	update();
25512795Ssam #ifdef QUOTA
256*30749Skarels 	if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
25712795Ssam #else
258*30749Skarels 	if ((error = iflush(dev)) && !forcibly)
25912795Ssam #endif
260*30749Skarels 		return (error);
26112795Ssam #ifdef QUOTA
26212795Ssam 	closedq(mp);
26312795Ssam 	/*
26412795Ssam 	 * Here we have to iflush again to get rid of the quota inode.
265*30749Skarels 	 * A drag, but it would be ugly to cheat, & this doesn't happen often.
26612795Ssam 	 */
26712795Ssam 	(void)iflush(dev, (struct inode *)NULL);
26812795Ssam #endif
26912795Ssam 	ip = mp->m_inodp;
27012795Ssam 	ip->i_flag &= ~IMOUNT;
27112795Ssam 	fs = mp->m_bufp->b_un.b_fs;
27212795Ssam 	wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize);
27312795Ssam 	brelse(mp->m_bufp);
27412795Ssam 	mp->m_bufp = 0;
27512795Ssam 	mp->m_dev = 0;
27612795Ssam 	mpurge(mp - &mount[0]);
277*30749Skarels 	error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
278*30749Skarels 	irele(ip);
279*30749Skarels 	return (error);
28012795Ssam }
28112795Ssam 
28212795Ssam sbupdate(mp)
28312795Ssam 	struct mount *mp;
28412795Ssam {
28512795Ssam 	register struct fs *fs = mp->m_bufp->b_un.b_fs;
28612795Ssam 	register struct buf *bp;
28712795Ssam 	int blks;
28812795Ssam 	caddr_t space;
28912795Ssam 	int i, size;
29012795Ssam 
291*30749Skarels #ifdef SECSIZE
292*30749Skarels 	bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
293*30749Skarels 	    (int)fs->fs_sbsize, fs->fs_dbsize);
294*30749Skarels #else SECSIZE
29512795Ssam 	bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
296*30749Skarels #endif SECSIZE
29712795Ssam 	bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
298*30749Skarels #ifdef SECSIZE
299*30749Skarels #ifdef tahoe
300*30749Skarels 	/* restore standard fsbtodb shift */
301*30749Skarels 	bp->b_un.b_fs->fs_fsbtodb = fs->fs_sparecon[0];
302*30749Skarels 	bp->b_un.b_fs->fs_sparecon[0] = 0;
303*30749Skarels #endif
304*30749Skarels #endif SECSIZE
30512795Ssam 	bwrite(bp);
30612795Ssam 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
30712795Ssam 	space = (caddr_t)fs->fs_csp[0];
30812795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
30912795Ssam 		size = fs->fs_bsize;
31012795Ssam 		if (i + fs->fs_frag > blks)
31112795Ssam 			size = (blks - i) * fs->fs_fsize;
312*30749Skarels #ifdef SECSIZE
313*30749Skarels 		bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
314*30749Skarels 		    fs->fs_dbsize);
315*30749Skarels #else SECSIZE
31612795Ssam 		bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
317*30749Skarels #endif SECSIZE
31812795Ssam 		bcopy(space, bp->b_un.b_addr, (u_int)size);
31912795Ssam 		space += size;
32012795Ssam 		bwrite(bp);
32112795Ssam 	}
32212795Ssam }
32312795Ssam 
32412795Ssam /*
32512795Ssam  * Common code for mount and umount.
32612795Ssam  * Check that the user's argument is a reasonable
32712795Ssam  * thing on which to mount, and return the device number if so.
32812795Ssam  */
32916697Smckusick getmdev(pdev, fname)
33016697Smckusick 	caddr_t fname;
33112795Ssam 	dev_t *pdev;
33212795Ssam {
33312795Ssam 	dev_t dev;
33412795Ssam 	register struct inode *ip;
33516697Smckusick 	register struct nameidata *ndp = &u.u_nd;
33612795Ssam 
33712795Ssam 	if (!suser())
33812795Ssam 		return (u.u_error);
33916697Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
34016697Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
34116697Smckusick 	ndp->ni_dirp = fname;
34216697Smckusick 	ip = namei(ndp);
34321013Smckusick 	if (ip == NULL) {
34421013Smckusick 		if (u.u_error == ENOENT)
34521013Smckusick 			return (ENODEV); /* needs translation */
34612795Ssam 		return (u.u_error);
34721013Smckusick 	}
34815956Skarels 	if ((ip->i_mode&IFMT) != IFBLK) {
34915956Skarels 		iput(ip);
35012795Ssam 		return (ENOTBLK);
35115956Skarels 	}
35212795Ssam 	dev = (dev_t)ip->i_rdev;
35315956Skarels 	iput(ip);
35412795Ssam 	if (major(dev) >= nblkdev)
35512795Ssam 		return (ENXIO);
35612795Ssam 	*pdev = dev;
35712795Ssam 	return (0);
35812795Ssam }
359