xref: /csrg-svn/sys/ufs/ffs/ffs_vfsops.c (revision 30749)
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  *	@(#)ffs_vfsops.c	7.2.1.1 (Berkeley) 04/02/87
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 
24 smount()
25 {
26 	register struct a {
27 		char	*fspec;
28 		char	*freg;
29 		int	ronly;
30 	} *uap = (struct a *)u.u_ap;
31 	dev_t dev;
32 	register struct inode *ip;
33 	register struct fs *fs;
34 	register struct nameidata *ndp = &u.u_nd;
35 	u_int len;
36 
37 	u.u_error = getmdev(&dev, uap->fspec);
38 	if (u.u_error)
39 		return;
40 	ndp->ni_nameiop = LOOKUP | FOLLOW;
41 	ndp->ni_segflg = UIO_USERSPACE;
42 	ndp->ni_dirp = (caddr_t)uap->freg;
43 	ip = namei(ndp);
44 	if (ip == NULL)
45 		return;
46 	if (ip->i_count != 1) {
47 		iput(ip);
48 		u.u_error = EBUSY;
49 		return;
50 	}
51 	if ((ip->i_mode&IFMT) != IFDIR) {
52 		iput(ip);
53 		u.u_error = ENOTDIR;
54 		return;
55 	}
56 	fs = mountfs(dev, uap->ronly, ip);
57 	if (fs == 0)
58 		return;
59 	(void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
60 	bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
61 }
62 
63 /* this routine has races if running twice */
64 struct fs *
65 mountfs(dev, ronly, ip)
66 	dev_t dev;
67 	int ronly;
68 	struct inode *ip;
69 {
70 	register struct mount *mp = 0;
71 	struct buf *tp = 0;
72 	register struct buf *bp = 0;
73 	register struct fs *fs;
74 	struct partinfo dpart;
75 	int havepart = 0, blks;
76 	caddr_t space;
77 	int i, size;
78 	register error;
79 	int needclose = 0;
80 
81 	error =
82 	    (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
83 	        S_IFBLK);
84 	if (error)
85 		goto out;
86 	needclose = 1;
87 #ifdef SECSIZE
88 	/*
89 	 * If possible, determine hardware sector size
90 	 * and adjust fsbtodb to correspond.
91 	 */
92 #endif SECSIZE
93 	if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
94 	    (caddr_t)&dpart, FREAD) == 0) {
95 		havepart = 1;
96 		size = dpart.disklab->d_secsize;
97 #ifdef SECSIZE
98 		if (size < MINSECSIZE) {
99 			error = EINVAL;
100 			goto out;
101 		}
102 #endif SECSIZE
103 	} else
104 		size = DEV_BSIZE;
105 #ifdef SECSIZE
106 	tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size);
107 #else SECSIZE
108 	tp = bread(dev, SBLOCK, SBSIZE);
109 #endif SECSIZE
110 	if (tp->b_flags & B_ERROR)
111 		goto out;
112 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
113 		if (mp->m_bufp != 0 && dev == mp->m_dev) {
114 			mp = 0;
115 			error = EBUSY;
116 			goto out;
117 		}
118 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
119 		if (mp->m_bufp == 0)
120 			goto found;
121 	mp = 0;
122 	error = EMFILE;		/* needs translation */
123 	goto out;
124 found:
125 	mp->m_bufp = tp;	/* just to reserve this slot */
126 	mp->m_dev = NODEV;
127 	fs = tp->b_un.b_fs;
128 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
129 	    fs->fs_bsize < sizeof(struct fs)) {
130 		error = EINVAL;		/* also needs translation */
131 		goto out;
132 	}
133 	bp = geteblk((int)fs->fs_sbsize);
134 	mp->m_bufp = bp;
135 	bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
136 	   (u_int)fs->fs_sbsize);
137 	brelse(tp);
138 	tp = 0;
139 	fs = bp->b_un.b_fs;
140 	fs->fs_ronly = (ronly != 0);
141 	if (ronly == 0)
142 		fs->fs_fmod = 1;
143 #ifdef SECSIZE
144 	/*
145 	 * If we have a disk label, force per-partition
146 	 * filesystem information to be correct
147 	 * and set correct current fsbtodb shift.
148 	 */
149 #endif SECSIZE
150 	if (havepart) {
151 		dpart.part->p_fstype = FS_BSDFFS;
152 		dpart.part->p_fsize = fs->fs_fsize;
153 		dpart.part->p_frag = fs->fs_frag;
154 #ifdef SECSIZE
155 #ifdef tahoe
156 		/*
157 		 * Save the original fsbtodb shift to restore on updates.
158 		 * (Console doesn't understand fsbtodb changes.)
159 		 */
160 		fs->fs_sparecon[0] = fs->fs_fsbtodb;
161 #endif
162 		i = fs->fs_fsize / size;
163 		for (fs->fs_fsbtodb = 0; i > 1; i >>= 1)
164 			fs->fs_fsbtodb++;
165 #endif SECSIZE
166 		fs->fs_dbsize = size;
167 	}
168 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
169 	space = wmemall(vmemall, (int)fs->fs_cssize);
170 	if (space == 0) {
171 		error = ENOMEM;
172 		goto out;
173 	}
174 	for (i = 0; i < blks; i += fs->fs_frag) {
175 		size = fs->fs_bsize;
176 		if (i + fs->fs_frag > blks)
177 			size = (blks - i) * fs->fs_fsize;
178 #ifdef SECSIZE
179 		tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
180 		    fs->fs_dbsize);
181 #else SECSIZE
182 		tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
183 #endif SECSIZE
184 		if (tp->b_flags&B_ERROR) {
185 			wmemfree(space, (int)fs->fs_cssize);
186 			goto out;
187 		}
188 		bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
189 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
190 		space += size;
191 		brelse(tp);
192 		tp = 0;
193 	}
194 	mp->m_inodp = ip;
195 	mp->m_dev = dev;
196 	if (ip) {
197 		ip->i_flag |= IMOUNT;
198 		cacheinval(ip);
199 		iunlock(ip);
200 	}
201 	/* Sanity checks for old file systems.			   XXX */
202 	fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);	/* XXX */
203 	fs->fs_interleave = MAX(fs->fs_interleave, 1);		/* XXX */
204 
205 	return (fs);
206 out:
207 	if (error == 0)
208 		error = EIO;
209 	if (needclose)
210 		(void) closei((dev_t)ip->i_rdev, IFBLK,
211 		    ronly? FREAD : FREAD|FWRITE);
212 	if (ip)
213 		iput(ip);
214 	if (mp)
215 		mp->m_bufp = 0;
216 	if (bp)
217 		brelse(bp);
218 	if (tp)
219 		brelse(tp);
220 	u.u_error = error;
221 	return (0);
222 }
223 
224 umount()
225 {
226 	struct a {
227 		char	*fspec;
228 	} *uap = (struct a *)u.u_ap;
229 
230 	u.u_error = unmount1(uap->fspec, 0);
231 }
232 
233 unmount1(fname, forcibly)
234 	caddr_t fname;
235 	int forcibly;
236 {
237 	dev_t dev;
238 	register struct mount *mp;
239 	int error;
240 	register struct inode *ip;
241 	register struct fs *fs;
242 
243 	forcibly = 0;					/* XXX */
244 	error = getmdev(&dev, fname);
245 	if (error)
246 		return (error);
247 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
248 		if (mp->m_bufp != NULL && dev == mp->m_dev)
249 			goto found;
250 	return (EINVAL);
251 found:
252 	xumount(dev);	/* remove unused sticky files from text table */
253 	nchinval(dev);	/* flush the name cache */
254 	update();
255 #ifdef QUOTA
256 	if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
257 #else
258 	if ((error = iflush(dev)) && !forcibly)
259 #endif
260 		return (error);
261 #ifdef QUOTA
262 	closedq(mp);
263 	/*
264 	 * Here we have to iflush again to get rid of the quota inode.
265 	 * A drag, but it would be ugly to cheat, & this doesn't happen often.
266 	 */
267 	(void)iflush(dev, (struct inode *)NULL);
268 #endif
269 	ip = mp->m_inodp;
270 	ip->i_flag &= ~IMOUNT;
271 	fs = mp->m_bufp->b_un.b_fs;
272 	wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize);
273 	brelse(mp->m_bufp);
274 	mp->m_bufp = 0;
275 	mp->m_dev = 0;
276 	mpurge(mp - &mount[0]);
277 	error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
278 	irele(ip);
279 	return (error);
280 }
281 
282 sbupdate(mp)
283 	struct mount *mp;
284 {
285 	register struct fs *fs = mp->m_bufp->b_un.b_fs;
286 	register struct buf *bp;
287 	int blks;
288 	caddr_t space;
289 	int i, size;
290 
291 #ifdef SECSIZE
292 	bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
293 	    (int)fs->fs_sbsize, fs->fs_dbsize);
294 #else SECSIZE
295 	bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
296 #endif SECSIZE
297 	bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
298 #ifdef SECSIZE
299 #ifdef tahoe
300 	/* restore standard fsbtodb shift */
301 	bp->b_un.b_fs->fs_fsbtodb = fs->fs_sparecon[0];
302 	bp->b_un.b_fs->fs_sparecon[0] = 0;
303 #endif
304 #endif SECSIZE
305 	bwrite(bp);
306 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
307 	space = (caddr_t)fs->fs_csp[0];
308 	for (i = 0; i < blks; i += fs->fs_frag) {
309 		size = fs->fs_bsize;
310 		if (i + fs->fs_frag > blks)
311 			size = (blks - i) * fs->fs_fsize;
312 #ifdef SECSIZE
313 		bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
314 		    fs->fs_dbsize);
315 #else SECSIZE
316 		bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
317 #endif SECSIZE
318 		bcopy(space, bp->b_un.b_addr, (u_int)size);
319 		space += size;
320 		bwrite(bp);
321 	}
322 }
323 
324 /*
325  * Common code for mount and umount.
326  * Check that the user's argument is a reasonable
327  * thing on which to mount, and return the device number if so.
328  */
329 getmdev(pdev, fname)
330 	caddr_t fname;
331 	dev_t *pdev;
332 {
333 	dev_t dev;
334 	register struct inode *ip;
335 	register struct nameidata *ndp = &u.u_nd;
336 
337 	if (!suser())
338 		return (u.u_error);
339 	ndp->ni_nameiop = LOOKUP | FOLLOW;
340 	ndp->ni_segflg = UIO_USERSPACE;
341 	ndp->ni_dirp = fname;
342 	ip = namei(ndp);
343 	if (ip == NULL) {
344 		if (u.u_error == ENOENT)
345 			return (ENODEV); /* needs translation */
346 		return (u.u_error);
347 	}
348 	if ((ip->i_mode&IFMT) != IFBLK) {
349 		iput(ip);
350 		return (ENOTBLK);
351 	}
352 	dev = (dev_t)ip->i_rdev;
353 	iput(ip);
354 	if (major(dev) >= nblkdev)
355 		return (ENXIO);
356 	*pdev = dev;
357 	return (0);
358 }
359