xref: /original-bsd/sys/ufs/ffs/ffs_vfsops.c (revision 8a1064d0)
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.4 (Berkeley) 05/03/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 	if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
88 	    (caddr_t)&dpart, FREAD) == 0) {
89 		havepart = 1;
90 		size = dpart.disklab->d_secsize;
91 	} else
92 		size = DEV_BSIZE;
93 	tp = bread(dev, SBLOCK, SBSIZE);
94 	if (tp->b_flags & B_ERROR)
95 		goto out;
96 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
97 		if (mp->m_bufp != 0 && dev == mp->m_dev) {
98 			mp = 0;
99 			error = EBUSY;
100 			goto out;
101 		}
102 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
103 		if (mp->m_bufp == 0)
104 			goto found;
105 	mp = 0;
106 	error = EMFILE;		/* needs translation */
107 	goto out;
108 found:
109 	mp->m_bufp = tp;	/* just to reserve this slot */
110 	mp->m_dev = NODEV;
111 	fs = tp->b_un.b_fs;
112 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
113 	    fs->fs_bsize < sizeof(struct fs)) {
114 		error = EINVAL;		/* also needs translation */
115 		goto out;
116 	}
117 	bp = geteblk((int)fs->fs_sbsize);
118 	mp->m_bufp = bp;
119 	bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
120 	   (u_int)fs->fs_sbsize);
121 	brelse(tp);
122 	tp = 0;
123 	fs = bp->b_un.b_fs;
124 	fs->fs_ronly = (ronly != 0);
125 	if (ronly == 0)
126 		fs->fs_fmod = 1;
127 	if (havepart) {
128 		dpart.part->p_fstype = FS_BSDFFS;
129 		dpart.part->p_fsize = fs->fs_fsize;
130 		dpart.part->p_frag = fs->fs_frag;
131 		fs->fs_dbsize = size;
132 	}
133 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
134 	space = wmemall(vmemall, (int)fs->fs_cssize);
135 	if (space == 0) {
136 		error = ENOMEM;
137 		goto out;
138 	}
139 	for (i = 0; i < blks; i += fs->fs_frag) {
140 		size = fs->fs_bsize;
141 		if (i + fs->fs_frag > blks)
142 			size = (blks - i) * fs->fs_fsize;
143 		tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
144 		if (tp->b_flags&B_ERROR) {
145 			wmemfree(space, (int)fs->fs_cssize);
146 			goto out;
147 		}
148 		bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
149 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
150 		space += size;
151 		brelse(tp);
152 		tp = 0;
153 	}
154 	mp->m_inodp = ip;
155 	mp->m_dev = dev;
156 	if (ip) {
157 		ip->i_flag |= IMOUNT;
158 		cacheinval(ip);
159 		iunlock(ip);
160 	}
161 	/* Sanity checks for old file systems.			   XXX */
162 	fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);	/* XXX */
163 	fs->fs_interleave = MAX(fs->fs_interleave, 1);		/* XXX */
164 
165 	return (fs);
166 out:
167 	if (error == 0)
168 		error = EIO;
169 	if (needclose && ip)
170 		(void) closei((dev_t)ip->i_rdev, IFBLK,
171 		    ronly? FREAD : FREAD|FWRITE);
172 	if (ip)
173 		iput(ip);
174 	if (mp)
175 		mp->m_bufp = 0;
176 	if (bp)
177 		brelse(bp);
178 	if (tp)
179 		brelse(tp);
180 	u.u_error = error;
181 	return (0);
182 }
183 
184 umount()
185 {
186 	struct a {
187 		char	*fspec;
188 	} *uap = (struct a *)u.u_ap;
189 
190 	u.u_error = unmount1(uap->fspec, 0);
191 }
192 
193 unmount1(fname, forcibly)
194 	caddr_t fname;
195 	int forcibly;
196 {
197 	dev_t dev;
198 	register struct mount *mp;
199 	int error;
200 	register struct inode *ip;
201 	register struct fs *fs;
202 
203 	forcibly = 0;					/* XXX */
204 	error = getmdev(&dev, fname);
205 	if (error)
206 		return (error);
207 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
208 		if (mp->m_bufp != NULL && dev == mp->m_dev)
209 			goto found;
210 	return (EINVAL);
211 found:
212 	xumount(dev);	/* remove unused sticky files from text table */
213 	nchinval(dev);	/* flush the name cache */
214 	update();
215 #ifdef QUOTA
216 	if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
217 #else
218 	if ((error = iflush(dev)) && !forcibly)
219 #endif
220 		return (error);
221 #ifdef QUOTA
222 	closedq(mp);
223 	/*
224 	 * Here we have to iflush again to get rid of the quota inode.
225 	 * A drag, but it would be ugly to cheat, & this doesn't happen often.
226 	 */
227 	(void)iflush(dev, (struct inode *)NULL);
228 #endif
229 	ip = mp->m_inodp;
230 	ip->i_flag &= ~IMOUNT;
231 	fs = mp->m_bufp->b_un.b_fs;
232 	wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize);
233 	brelse(mp->m_bufp);
234 	mp->m_bufp = 0;
235 	mp->m_dev = 0;
236 	mpurge(mp - &mount[0]);
237 	error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
238 	irele(ip);
239 	return (error);
240 }
241 
242 sbupdate(mp)
243 	struct mount *mp;
244 {
245 	register struct fs *fs = mp->m_bufp->b_un.b_fs;
246 	register struct buf *bp;
247 	int blks;
248 	caddr_t space;
249 	int i, size;
250 
251 	bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
252 	bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
253 	bwrite(bp);
254 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
255 	space = (caddr_t)fs->fs_csp[0];
256 	for (i = 0; i < blks; i += fs->fs_frag) {
257 		size = fs->fs_bsize;
258 		if (i + fs->fs_frag > blks)
259 			size = (blks - i) * fs->fs_fsize;
260 		bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
261 		bcopy(space, bp->b_un.b_addr, (u_int)size);
262 		space += size;
263 		bwrite(bp);
264 	}
265 }
266 
267 /*
268  * Common code for mount and umount.
269  * Check that the user's argument is a reasonable
270  * thing on which to mount, and return the device number if so.
271  */
272 getmdev(pdev, fname)
273 	caddr_t fname;
274 	dev_t *pdev;
275 {
276 	dev_t dev;
277 	register struct inode *ip;
278 	register struct nameidata *ndp = &u.u_nd;
279 
280 	if (!suser())
281 		return (u.u_error);
282 	ndp->ni_nameiop = LOOKUP | FOLLOW;
283 	ndp->ni_segflg = UIO_USERSPACE;
284 	ndp->ni_dirp = fname;
285 	ip = namei(ndp);
286 	if (ip == NULL) {
287 		if (u.u_error == ENOENT)
288 			return (ENODEV); /* needs translation */
289 		return (u.u_error);
290 	}
291 	if ((ip->i_mode&IFMT) != IFBLK) {
292 		iput(ip);
293 		return (ENOTBLK);
294 	}
295 	dev = (dev_t)ip->i_rdev;
296 	iput(ip);
297 	if (major(dev) >= nblkdev)
298 		return (ENXIO);
299 	*pdev = dev;
300 	return (0);
301 }
302