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