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