xref: /original-bsd/sys/ufs/ufs/ufs_vfsops.c (revision 241757c4)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)ufs_vfsops.c	7.11 (Berkeley) 05/24/88
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "dir.h"
12 #include "user.h"
13 #include "inode.h"
14 #include "proc.h"
15 #include "fs.h"
16 #include "buf.h"
17 #include "mount.h"
18 #include "file.h"
19 #include "conf.h"
20 #include "ioctl.h"
21 #include "disklabel.h"
22 #include "stat.h"
23 #include "malloc.h"
24 
25 smount()
26 {
27 	register struct a {
28 		char	*fspec;
29 		char	*freg;
30 		int	ronly;
31 	} *uap = (struct a *)u.u_ap;
32 	dev_t dev;
33 	register struct inode *ip;
34 	register struct fs *fs;
35 	register struct nameidata *ndp = &u.u_nd;
36 	u_int len;
37 
38 	u.u_error = getmdev(&dev, uap->fspec);
39 	if (u.u_error)
40 		return;
41 	ndp->ni_nameiop = LOOKUP | FOLLOW;
42 	ndp->ni_segflg = UIO_USERSPACE;
43 	ndp->ni_dirp = (caddr_t)uap->freg;
44 	ip = namei(ndp);
45 	if (ip == NULL)
46 		return;
47 	if (ip->i_count != 1) {
48 		iput(ip);
49 		u.u_error = EBUSY;
50 		return;
51 	}
52 	if ((ip->i_mode&IFMT) != IFDIR) {
53 		iput(ip);
54 		u.u_error = ENOTDIR;
55 		return;
56 	}
57 	fs = mountfs(dev, uap->ronly, ip);
58 	if (fs == 0) {
59 		iput(ip);
60 		return;
61 	}
62 	(void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
63 	bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
64 }
65 
66 struct fs *
67 mountfs(dev, ronly, ip)
68 	dev_t dev;
69 	int ronly;
70 	struct inode *ip;
71 {
72 	register struct mount *mp;
73 	struct mount *fmp = NULL;
74 	register struct buf *bp = NULL;
75 	register struct fs *fs;
76 	struct partinfo dpart;
77 	int havepart = 0, blks;
78 	caddr_t base, space;
79 	int i, size;
80 	register error;
81 	int needclose = 0;
82 
83 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
84 		if (mp->m_fs == NULL) {
85 			if (fmp == NULL)
86 				fmp = mp;
87 		} else if (dev == mp->m_dev) {
88 			u.u_error = EBUSY;		/* XXX */
89 			return ((struct fs *) NULL);
90 		}
91 	}
92 	if ((mp = fmp) == NULL) {
93 		u.u_error = EMFILE;		/* needs translation      XXX */
94 		return ((struct fs *) NULL);
95 	}
96 	mp->m_fs = (struct fs *)1;	/* just to reserve this slot */
97 	mp->m_dev = dev;
98 	mp->m_inodp = NULL;
99 	error =
100 	    (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
101 	        S_IFBLK);
102 	if (error) {
103 		u.u_error = error;
104 		mp->m_fs = NULL;
105 		return ((struct fs *) NULL);
106 	}
107 	needclose = 1;
108 	if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
109 	    (caddr_t)&dpart, FREAD) == 0) {
110 		havepart = 1;
111 		size = dpart.disklab->d_secsize;
112 	} else
113 		size = DEV_BSIZE;
114 	bp = bread(dev, SBLOCK, SBSIZE);
115 	if (bp->b_flags & B_ERROR) {
116 		mp->m_fs = NULL;
117 		goto out;
118 	}
119 	fs = bp->b_un.b_fs;
120 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
121 	    fs->fs_bsize < sizeof(struct fs)) {
122 		mp->m_fs = NULL;
123 		error = EINVAL;		/* also needs translation */
124 		goto out;
125 	}
126 	mp->m_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
127 	    M_WAITOK);
128 	bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)mp->m_fs,
129 	   (u_int)fs->fs_sbsize);
130 	brelse(bp);
131 	bp = NULL;
132 	fs = mp->m_fs;
133 	fs->fs_ronly = (ronly != 0);
134 	if (ronly == 0)
135 		fs->fs_fmod = 1;
136 	if (havepart) {
137 		dpart.part->p_fstype = FS_BSDFFS;
138 		dpart.part->p_fsize = fs->fs_fsize;
139 		dpart.part->p_frag = fs->fs_frag;
140 		dpart.part->p_cpg = fs->fs_cpg;
141 	}
142 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
143 	base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
144 	    M_WAITOK);
145 	if (space == NULL) {
146 		error = ENOMEM;
147 		goto out;
148 	}
149 	for (i = 0; i < blks; i += fs->fs_frag) {
150 		size = fs->fs_bsize;
151 		if (i + fs->fs_frag > blks)
152 			size = (blks - i) * fs->fs_fsize;
153 		bp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
154 		if (bp->b_flags&B_ERROR) {
155 			free((caddr_t)base, M_SUPERBLK);
156 			goto out;
157 		}
158 		bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size);
159 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
160 		space += size;
161 		brelse(bp);
162 		bp = NULL;
163 	}
164 	mp->m_inodp = ip;
165 	if (ip) {
166 		ip->i_flag |= IMOUNT;
167 		cacheinval(ip);
168 		iunlock(ip);
169 	}
170 	/* Sanity checks for old file systems.			   XXX */
171 	fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);	/* XXX */
172 	fs->fs_interleave = MAX(fs->fs_interleave, 1);		/* XXX */
173 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
174 		fs->fs_nrpos = 8;				/* XXX */
175 	return (fs);
176 out:
177 	if (needclose)
178 		(void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE);
179 	if (mp->m_fs) {
180 		free((caddr_t)mp->m_fs, M_SUPERBLK);
181 		mp->m_fs = NULL;
182 	}
183 	if (bp)
184 		brelse(bp);
185 	u.u_error = error ? error : EIO;			/* XXX */
186 	return ((struct fs *) NULL);
187 }
188 
189 umount()
190 {
191 	struct a {
192 		char	*fspec;
193 	} *uap = (struct a *)u.u_ap;
194 
195 	u.u_error = unmount1(uap->fspec, 0);
196 }
197 
198 unmount1(fname, forcibly)
199 	caddr_t fname;
200 	int forcibly;
201 {
202 	dev_t dev;
203 	register struct mount *mp;
204 	int error;
205 	register struct inode *ip;
206 	register struct fs *fs;
207 
208 	forcibly = 0;					/* XXX */
209 	error = getmdev(&dev, fname);
210 	if (error)
211 		return (error);
212 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
213 		if (mp->m_fs != NULL && dev == mp->m_dev)
214 			goto found;
215 	return (EINVAL);
216 found:
217 	xumount(dev);	/* remove unused sticky files from text table */
218 	nchinval(dev);	/* flush the name cache */
219 	update();
220 #ifdef QUOTA
221 	if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
222 #else
223 	if ((error = iflush(dev)) && !forcibly)
224 #endif
225 		return (error);
226 #ifdef QUOTA
227 	closedq(mp);
228 	/*
229 	 * Here we have to iflush again to get rid of the quota inode.
230 	 * A drag, but it would be ugly to cheat, & this doesn't happen often.
231 	 */
232 	(void)iflush(dev, (struct inode *)NULL);
233 #endif
234 	ip = mp->m_inodp;
235 	ip->i_flag &= ~IMOUNT;
236 	fs = mp->m_fs;
237 	free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
238 	free((caddr_t)mp->m_fs, M_SUPERBLK);
239 	mp->m_fs = NULL;
240 	mp->m_dev = NODEV;
241 	mpurge(mp - &mount[0]);
242 	error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
243 	irele(ip);
244 	return (error);
245 }
246 
247 sbupdate(mp)
248 	struct mount *mp;
249 {
250 	register struct fs *fs = mp->m_fs;
251 	register struct buf *bp;
252 	int blks;
253 	caddr_t space;
254 	int i, size;
255 
256 	bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
257 	bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
258 	/* Restore compatibility to old file systems.		   XXX */
259 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
260 		bp->b_un.b_fs->fs_nrpos = -1;			/* XXX */
261 	bwrite(bp);
262 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
263 	space = (caddr_t)fs->fs_csp[0];
264 	for (i = 0; i < blks; i += fs->fs_frag) {
265 		size = fs->fs_bsize;
266 		if (i + fs->fs_frag > blks)
267 			size = (blks - i) * fs->fs_fsize;
268 		bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
269 		bcopy(space, bp->b_un.b_addr, (u_int)size);
270 		space += size;
271 		bwrite(bp);
272 	}
273 }
274 
275 /*
276  * Common code for mount and umount.
277  * Check that the user's argument is a reasonable
278  * thing on which to mount, and return the device number if so.
279  */
280 getmdev(pdev, fname)
281 	caddr_t fname;
282 	dev_t *pdev;
283 {
284 	dev_t dev;
285 	register struct inode *ip;
286 	register struct nameidata *ndp = &u.u_nd;
287 
288 	if (!suser())
289 		return (u.u_error);
290 	ndp->ni_nameiop = LOOKUP | FOLLOW;
291 	ndp->ni_segflg = UIO_USERSPACE;
292 	ndp->ni_dirp = fname;
293 	ip = namei(ndp);
294 	if (ip == NULL) {
295 		if (u.u_error == ENOENT)
296 			return (ENODEV); /* needs translation */
297 		return (u.u_error);
298 	}
299 	if ((ip->i_mode&IFMT) != IFBLK) {
300 		iput(ip);
301 		return (ENOTBLK);
302 	}
303 	dev = (dev_t)ip->i_rdev;
304 	iput(ip);
305 	if (major(dev) >= nblkdev)
306 		return (ENXIO);
307 	*pdev = dev;
308 	return (0);
309 }
310