xref: /original-bsd/sys/ufs/ufs/ufs_vfsops.c (revision 6219b5e8)
1 /*	ufs_vfsops.c	6.9	84/09/28	*/
2 
3 #include "param.h"
4 #include "systm.h"
5 #include "dir.h"
6 #include "user.h"
7 #include "inode.h"
8 #include "proc.h"
9 #include "fs.h"
10 #include "buf.h"
11 #include "mount.h"
12 #include "file.h"
13 #include "conf.h"
14 
15 smount()
16 {
17 	register struct a {
18 		char	*fspec;
19 		char	*freg;
20 		int	ronly;
21 	} *uap = (struct a *)u.u_ap;
22 	dev_t dev;
23 	register struct inode *ip;
24 	register struct fs *fs;
25 	register char *cp;
26 	register struct nameidata *ndp = &u.u_nd;
27 	u_int len;
28 
29 	u.u_error = getmdev(&dev, uap->fspec);
30 	if (u.u_error)
31 		return;
32 	ndp->ni_nameiop = LOOKUP | NOCACHE | FOLLOW;
33 	ndp->ni_segflg = UIO_USERSPACE;
34 	ndp->ni_dirp = (caddr_t)uap->freg;
35 	ip = namei(ndp);
36 	if (ip == NULL)
37 		return;
38 	if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR) {
39 		iput(ip);
40 		u.u_error = EBUSY;
41 		return;
42 	}
43 	fs = mountfs(dev, uap->ronly, ip);
44 	if (fs == 0)
45 		return;
46 	(void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
47 	bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
48 }
49 
50 /* this routine has races if running twice */
51 struct fs *
52 mountfs(dev, ronly, ip)
53 	dev_t dev;
54 	int ronly;
55 	struct inode *ip;
56 {
57 	register struct mount *mp = 0;
58 	struct buf *tp = 0;
59 	register struct buf *bp = 0;
60 	register struct fs *fs;
61 	int blks;
62 	caddr_t space;
63 	int i, size;
64 	register error;
65 
66 	error =
67 	    (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE);
68 	if (error)
69 		goto out;
70 	tp = bread(dev, SBLOCK, SBSIZE);
71 	if (tp->b_flags & B_ERROR)
72 		goto out;
73 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
74 		if (mp->m_bufp != 0 && dev == mp->m_dev) {
75 			mp = 0;
76 			error = EBUSY;
77 			goto out;
78 		}
79 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
80 		if (mp->m_bufp == 0)
81 			goto found;
82 	mp = 0;
83 	error = EMFILE;		/* needs translation */
84 	goto out;
85 found:
86 	mp->m_bufp = tp;	/* just to reserve this slot */
87 	mp->m_dev = NODEV;
88 	fs = tp->b_un.b_fs;
89 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE
90 	    || fs->fs_bsize < sizeof(struct fs)) {
91 		error = EINVAL;		/* also needs translation */
92 		goto out;
93 	}
94 	bp = geteblk((int)fs->fs_sbsize);
95 	mp->m_bufp = bp;
96 	bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
97 	   (u_int)fs->fs_sbsize);
98 	brelse(tp);
99 	tp = 0;
100 	fs = bp->b_un.b_fs;
101 	fs->fs_ronly = (ronly != 0);
102 	if (ronly == 0)
103 		fs->fs_fmod = 1;
104 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
105 	space = wmemall(vmemall, (int)fs->fs_cssize);
106 	if (space == 0) {
107 		error = ENOMEM;
108 		goto out;
109 	}
110 	for (i = 0; i < blks; i += fs->fs_frag) {
111 		size = fs->fs_bsize;
112 		if (i + fs->fs_frag > blks)
113 			size = (blks - i) * fs->fs_fsize;
114 		tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
115 		if (tp->b_flags&B_ERROR) {
116 			wmemfree(space, (int)fs->fs_cssize);
117 			goto out;
118 		}
119 		bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
120 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
121 		space += size;
122 		brelse(tp);
123 		tp = 0;
124 	}
125 	mp->m_inodp = ip;
126 	mp->m_dev = dev;
127 	if (ip) {
128 		ip->i_flag |= IMOUNT;
129 		iunlock(ip);
130 	}
131 	return (fs);
132 out:
133 	if (error == 0)
134 		error = EIO;
135 	if (ip)
136 		iput(ip);
137 	if (mp)
138 		mp->m_bufp = 0;
139 	if (bp)
140 		brelse(bp);
141 	if (tp)
142 		brelse(tp);
143 	u.u_error = error;
144 	return (0);
145 }
146 
147 umount()
148 {
149 	struct a {
150 		char	*fspec;
151 	} *uap = (struct a *)u.u_ap;
152 
153 	u.u_error = unmount1(uap->fspec, 0);
154 }
155 
156 unmount1(fname, forcibly)
157 	caddr_t fname;
158 	int forcibly;
159 {
160 	dev_t dev;
161 	register struct mount *mp;
162 	int stillopen, flag, error;
163 	register struct inode *ip;
164 	register struct fs *fs;
165 
166 	error = getmdev(&dev, fname);
167 	if (error)
168 		return (error);
169 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
170 		if (mp->m_bufp != NULL && dev == mp->m_dev)
171 			goto found;
172 	return (EINVAL);
173 found:
174 	xumount(dev);	/* remove unused sticky files from text table */
175 	nchinval(dev);	/* flush the name cache */
176 	update();
177 #ifdef QUOTA
178 	if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly)
179 #else
180 	if ((stillopen = iflush(dev)) < 0 && !forcibly)
181 #endif
182 		return (EBUSY);
183 	if (stillopen < 0)
184 		return (EBUSY);			/* XXX */
185 #ifdef QUOTA
186 	closedq(mp);
187 	/*
188 	 * Here we have to iflush again to get rid of the quota inode.
189 	 * A drag, but it would be ugly to cheat, & this doesn't happen often
190 	 */
191 	(void)iflush(dev, (struct inode *)NULL);
192 #endif
193 	ip = mp->m_inodp;
194 	ip->i_flag &= ~IMOUNT;
195 	irele(ip);
196 	fs = mp->m_bufp->b_un.b_fs;
197 	wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize);
198 	flag = !fs->fs_ronly;
199 	brelse(mp->m_bufp);
200 	mp->m_bufp = 0;
201 	mp->m_dev = 0;
202 	mpurge(mp - &mount[0]);
203 	if (!stillopen) {
204 		(*bdevsw[major(dev)].d_close)(dev, flag);
205 		binval(dev);
206 	}
207 	return (0);
208 }
209 
210 sbupdate(mp)
211 	struct mount *mp;
212 {
213 	register struct fs *fs = mp->m_bufp->b_un.b_fs;
214 	register struct buf *bp;
215 	int blks;
216 	caddr_t space;
217 	int i, size;
218 
219 	bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
220 	bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
221 	bwrite(bp);
222 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
223 	space = (caddr_t)fs->fs_csp[0];
224 	for (i = 0; i < blks; i += fs->fs_frag) {
225 		size = fs->fs_bsize;
226 		if (i + fs->fs_frag > blks)
227 			size = (blks - i) * fs->fs_fsize;
228 		bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
229 		bcopy(space, bp->b_un.b_addr, (u_int)size);
230 		space += size;
231 		bwrite(bp);
232 	}
233 }
234 
235 /*
236  * Common code for mount and umount.
237  * Check that the user's argument is a reasonable
238  * thing on which to mount, and return the device number if so.
239  */
240 getmdev(pdev, fname)
241 	caddr_t fname;
242 	dev_t *pdev;
243 {
244 	dev_t dev;
245 	register struct inode *ip;
246 	register struct nameidata *ndp = &u.u_nd;
247 
248 	if (!suser())
249 		return (u.u_error);
250 	ndp->ni_nameiop = LOOKUP | FOLLOW;
251 	ndp->ni_segflg = UIO_USERSPACE;
252 	ndp->ni_dirp = fname;
253 	ip = namei(ndp);
254 	if (ip == NULL)
255 		return (u.u_error);
256 	if ((ip->i_mode&IFMT) != IFBLK) {
257 		iput(ip);
258 		return (ENOTBLK);
259 	}
260 	dev = (dev_t)ip->i_rdev;
261 	iput(ip);
262 	if (major(dev) >= nblkdev)
263 		return (ENXIO);
264 	*pdev = dev;
265 	return (0);
266 }
267