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