Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
ad787160 C |
2 | * Copyright (c) 1989, 1991, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
da7c5cc6 | 4 | * |
ad787160 C |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
7188ac27 | 20 | * |
ad787160 C |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
33 | * @(#)ffs_vfsops.c 8.1 (Berkeley) 6/11/93 | |
da7c5cc6 | 34 | */ |
71e4e98b | 35 | |
ab9f4fb0 KB |
36 | #include <sys/param.h> |
37 | #include <sys/systm.h> | |
38 | #include <sys/namei.h> | |
39 | #include <sys/proc.h> | |
40 | #include <sys/kernel.h> | |
41 | #include <sys/vnode.h> | |
9e4a3a4a | 42 | #include <sys/socket.h> |
ab9f4fb0 KB |
43 | #include <sys/mount.h> |
44 | #include <sys/buf.h> | |
03f3a6e4 | 45 | #include <sys/mbuf.h> |
ab9f4fb0 KB |
46 | #include <sys/file.h> |
47 | #include <sys/disklabel.h> | |
48 | #include <sys/ioctl.h> | |
49 | #include <sys/errno.h> | |
50 | #include <sys/malloc.h> | |
41fc9770 KM |
51 | |
52 | #include <miscfs/specfs/specdev.h> | |
71e4e98b | 53 | |
ab9f4fb0 KB |
54 | #include <ufs/ufs/quota.h> |
55 | #include <ufs/ufs/ufsmount.h> | |
56 | #include <ufs/ufs/inode.h> | |
57 | #include <ufs/ufs/ufs_extern.h> | |
58 | ||
59 | #include <ufs/ffs/fs.h> | |
60 | #include <ufs/ffs/ffs_extern.h> | |
61 | ||
06445aba | 62 | int ffs_sbupdate __P((struct ufsmount *, int)); |
c6f5111d | 63 | |
7188ac27 | 64 | struct vfsops ufs_vfsops = { |
ab9f4fb0 | 65 | ffs_mount, |
5bf9d21f | 66 | ufs_start, |
ab9f4fb0 | 67 | ffs_unmount, |
a9013e03 | 68 | ffs_root, |
8dc876c1 | 69 | ufs_quotactl, |
ab9f4fb0 KB |
70 | ffs_statfs, |
71 | ffs_sync, | |
067ae075 | 72 | ffs_vget, |
a9013e03 KM |
73 | ffs_fhtovp, |
74 | ffs_vptofh, | |
ab9f4fb0 | 75 | ffs_init, |
7188ac27 KM |
76 | }; |
77 | ||
067ae075 KM |
78 | extern u_long nextgennumber; |
79 | ||
7188ac27 | 80 | /* |
4ac55ebc | 81 | * Called by main() when ufs is going to be mounted as root. |
7188ac27 | 82 | * |
d48157d5 | 83 | * Name is updated by mount(8) after booting. |
7188ac27 | 84 | */ |
8a4911ca | 85 | #define ROOTNAME "root_device" |
7188ac27 | 86 | |
ab9f4fb0 | 87 | ffs_mountroot() |
71e4e98b | 88 | { |
7188ac27 | 89 | extern struct vnode *rootvp; |
ab9f4fb0 KB |
90 | register struct fs *fs; |
91 | register struct mount *mp; | |
0eb6f54a | 92 | struct proc *p = curproc; /* XXX */ |
7188ac27 | 93 | struct ufsmount *ump; |
7188ac27 KM |
94 | u_int size; |
95 | int error; | |
751df505 KM |
96 | |
97 | /* | |
98 | * Get vnodes for swapdev and rootdev. | |
99 | */ | |
100 | if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) | |
101 | panic("ffs_mountroot: can't setup bdevvp's"); | |
71e4e98b | 102 | |
4ac55ebc | 103 | mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); |
ea301039 | 104 | bzero((char *)mp, (u_long)sizeof(struct mount)); |
82161bc8 KM |
105 | mp->mnt_op = &ufs_vfsops; |
106 | mp->mnt_flag = MNT_RDONLY; | |
ab9f4fb0 KB |
107 | if (error = ffs_mountfs(rootvp, mp, p)) { |
108 | free(mp, M_MOUNT); | |
7188ac27 | 109 | return (error); |
71e4e98b | 110 | } |
d48157d5 | 111 | if (error = vfs_lock(mp)) { |
ab9f4fb0 KB |
112 | (void)ffs_unmount(mp, 0, p); |
113 | free(mp, M_MOUNT); | |
7188ac27 | 114 | return (error); |
6d07f4cd | 115 | } |
d48157d5 | 116 | rootfs = mp; |
82161bc8 KM |
117 | mp->mnt_next = mp; |
118 | mp->mnt_prev = mp; | |
119 | mp->mnt_vnodecovered = NULLVP; | |
7188ac27 KM |
120 | ump = VFSTOUFS(mp); |
121 | fs = ump->um_fs; | |
d45de50d | 122 | bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); |
7188ac27 | 123 | fs->fs_fsmnt[0] = '/'; |
82161bc8 KM |
124 | bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, |
125 | MNAMELEN); | |
126 | (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, | |
127 | &size); | |
128 | bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); | |
ab9f4fb0 | 129 | (void)ffs_statfs(mp, &mp->mnt_stat, p); |
7188ac27 KM |
130 | vfs_unlock(mp); |
131 | inittodr(fs->fs_time); | |
132 | return (0); | |
133 | } | |
134 | ||
135 | /* | |
136 | * VFS Operations. | |
137 | * | |
138 | * mount system call | |
139 | */ | |
06445aba | 140 | int |
ab9f4fb0 | 141 | ffs_mount(mp, path, data, ndp, p) |
d45de50d | 142 | register struct mount *mp; |
7188ac27 KM |
143 | char *path; |
144 | caddr_t data; | |
145 | struct nameidata *ndp; | |
0eb6f54a | 146 | struct proc *p; |
7188ac27 KM |
147 | { |
148 | struct vnode *devvp; | |
149 | struct ufs_args args; | |
150 | struct ufsmount *ump; | |
151 | register struct fs *fs; | |
152 | u_int size; | |
a79eb26d | 153 | int error, flags; |
7188ac27 KM |
154 | |
155 | if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) | |
156 | return (error); | |
190244fb MK |
157 | /* |
158 | * If updating, check whether changing from read-only to | |
159 | * read/write; if there is no device name, that's all we do. | |
160 | */ | |
161 | if (mp->mnt_flag & MNT_UPDATE) { | |
d48157d5 KM |
162 | ump = VFSTOUFS(mp); |
163 | fs = ump->um_fs; | |
a79eb26d KM |
164 | error = 0; |
165 | if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { | |
166 | flags = WRITECLOSE; | |
167 | if (mp->mnt_flag & MNT_FORCE) | |
168 | flags |= FORCECLOSE; | |
169 | if (vfs_busy(mp)) | |
170 | return (EBUSY); | |
171 | error = ffs_flushfiles(mp, flags, p); | |
172 | vfs_unbusy(mp); | |
173 | } | |
174 | if (!error && (mp->mnt_flag & MNT_RELOAD)) | |
175 | error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); | |
176 | if (error) | |
177 | return (error); | |
178 | if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) | |
d48157d5 | 179 | fs->fs_ronly = 0; |
c906fba1 KM |
180 | if (args.fspec == 0) { |
181 | /* | |
182 | * Process export requests. | |
183 | */ | |
184 | if (args.exflags & MNT_EXPORTED) { | |
cb09ceb4 | 185 | if (error = ufs_hang_addrlist(mp, &args)) |
c906fba1 KM |
186 | return (error); |
187 | mp->mnt_flag |= MNT_EXPORTED; | |
188 | } | |
189 | if (args.exflags & MNT_DELEXPORT) { | |
cb09ceb4 | 190 | ufs_free_addrlist(ump); |
c906fba1 KM |
191 | mp->mnt_flag &= |
192 | ~(MNT_EXPORTED | MNT_DEFEXPORTED); | |
193 | } | |
3b931949 | 194 | return (0); |
c906fba1 | 195 | } |
190244fb MK |
196 | } |
197 | /* | |
198 | * Not an update, or updating the name: look up the name | |
199 | * and verify that it refers to a sensible block device. | |
200 | */ | |
995e59df KM |
201 | NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); |
202 | if (error = namei(ndp)) | |
190244fb MK |
203 | return (error); |
204 | devvp = ndp->ni_vp; | |
ab9f4fb0 | 205 | |
190244fb MK |
206 | if (devvp->v_type != VBLK) { |
207 | vrele(devvp); | |
208 | return (ENOTBLK); | |
209 | } | |
210 | if (major(devvp->v_rdev) >= nblkdev) { | |
211 | vrele(devvp); | |
212 | return (ENXIO); | |
213 | } | |
214 | if ((mp->mnt_flag & MNT_UPDATE) == 0) | |
ab9f4fb0 | 215 | error = ffs_mountfs(devvp, mp, p); |
190244fb | 216 | else { |
d48157d5 KM |
217 | if (devvp != ump->um_devvp) |
218 | error = EINVAL; /* needs translation */ | |
2a7dbb09 KM |
219 | else |
220 | vrele(devvp); | |
d48157d5 | 221 | } |
7188ac27 KM |
222 | if (error) { |
223 | vrele(devvp); | |
224 | return (error); | |
27d00e76 | 225 | } |
7188ac27 KM |
226 | ump = VFSTOUFS(mp); |
227 | fs = ump->um_fs; | |
228 | (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); | |
229 | bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); | |
82161bc8 KM |
230 | bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, |
231 | MNAMELEN); | |
232 | (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, | |
233 | &size); | |
234 | bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); | |
ab9f4fb0 | 235 | (void)ffs_statfs(mp, &mp->mnt_stat, p); |
7188ac27 | 236 | return (0); |
71e4e98b SL |
237 | } |
238 | ||
a79eb26d KM |
239 | /* |
240 | * Reload all incore data for a filesystem (used after running fsck on | |
241 | * the root filesystem and finding things to fix). The filesystem must | |
242 | * be mounted read-only. | |
243 | * | |
244 | * Things to do to update the mount: | |
245 | * 1) invalidate all cached meta-data. | |
246 | * 2) re-read superblock from disk. | |
247 | * 3) re-read summary information from disk. | |
248 | * 4) invalidate all inactive vnodes. | |
249 | * 5) invalidate all cached file data. | |
250 | * 6) re-read inode data for all active vnodes. | |
251 | */ | |
252 | ffs_reload(mountp, cred, p) | |
253 | register struct mount *mountp; | |
254 | struct ucred *cred; | |
255 | struct proc *p; | |
256 | { | |
257 | register struct vnode *vp, *nvp, *devvp; | |
258 | struct inode *ip; | |
259 | struct dinode *dp; | |
260 | struct csum *space; | |
261 | struct buf *bp; | |
262 | struct fs *fs; | |
263 | int i, blks, size, error; | |
264 | ||
265 | if ((mountp->mnt_flag & MNT_RDONLY) == 0) | |
266 | return (EINVAL); | |
267 | /* | |
268 | * Step 1: invalidate all cached meta-data. | |
269 | */ | |
270 | devvp = VFSTOUFS(mountp)->um_devvp; | |
646464db | 271 | if (vinvalbuf(devvp, 0, cred, p, 0, 0)) |
a79eb26d KM |
272 | panic("ffs_reload: dirty1"); |
273 | /* | |
274 | * Step 2: re-read superblock from disk. | |
275 | */ | |
276 | if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) | |
277 | return (error); | |
278 | fs = bp->b_un.b_fs; | |
279 | if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || | |
280 | fs->fs_bsize < sizeof(struct fs)) { | |
281 | brelse(bp); | |
282 | return (EIO); /* XXX needs translation */ | |
283 | } | |
284 | fs = VFSTOUFS(mountp)->um_fs; | |
285 | bcopy((caddr_t)&fs->fs_csp[0], (caddr_t)&bp->b_un.b_fs->fs_csp[0], | |
286 | sizeof(fs->fs_csp)); | |
287 | bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)fs, (u_int)fs->fs_sbsize); | |
288 | if (fs->fs_sbsize < SBSIZE) | |
289 | bp->b_flags |= B_INVAL; | |
290 | brelse(bp); | |
291 | ffs_oldfscompat(fs); | |
292 | /* | |
293 | * Step 3: re-read summary information from disk. | |
294 | */ | |
295 | blks = howmany(fs->fs_cssize, fs->fs_fsize); | |
296 | space = fs->fs_csp[0]; | |
297 | for (i = 0; i < blks; i += fs->fs_frag) { | |
298 | size = fs->fs_bsize; | |
299 | if (i + fs->fs_frag > blks) | |
300 | size = (blks - i) * fs->fs_fsize; | |
301 | if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, | |
302 | NOCRED, &bp)) | |
303 | return (error); | |
304 | bcopy((caddr_t)bp->b_un.b_addr, fs->fs_csp[fragstoblks(fs, i)], | |
305 | (u_int)size); | |
306 | brelse(bp); | |
307 | } | |
308 | loop: | |
309 | for (vp = mountp->mnt_mounth; vp; vp = nvp) { | |
310 | nvp = vp->v_mountf; | |
311 | /* | |
312 | * Step 4: invalidate all inactive vnodes. | |
313 | */ | |
314 | if (vp->v_usecount == 0) { | |
315 | vgone(vp); | |
316 | continue; | |
317 | } | |
318 | /* | |
319 | * Step 5: invalidate all cached file data. | |
320 | */ | |
321 | if (vget(vp)) | |
322 | goto loop; | |
646464db | 323 | if (vinvalbuf(vp, 0, cred, p, 0, 0)) |
a79eb26d KM |
324 | panic("ffs_reload: dirty2"); |
325 | /* | |
326 | * Step 6: re-read inode data for all active vnodes. | |
327 | */ | |
328 | ip = VTOI(vp); | |
329 | if (error = bread(devvp, fsbtodb(fs, itod(fs, ip->i_number)), | |
330 | (int)fs->fs_bsize, NOCRED, &bp)) { | |
331 | vput(vp); | |
332 | return (error); | |
333 | } | |
334 | dp = bp->b_un.b_dino; | |
335 | dp += itoo(fs, ip->i_number); | |
336 | ip->i_din = *dp; | |
337 | brelse(bp); | |
338 | vput(vp); | |
339 | if (vp->v_mount != mountp) | |
340 | goto loop; | |
341 | } | |
342 | return (0); | |
343 | } | |
344 | ||
7188ac27 KM |
345 | /* |
346 | * Common code for mount and mountroot | |
347 | */ | |
ab9f4fb0 KB |
348 | int |
349 | ffs_mountfs(devvp, mp, p) | |
1182ae61 | 350 | register struct vnode *devvp; |
7188ac27 | 351 | struct mount *mp; |
0eb6f54a | 352 | struct proc *p; |
71e4e98b | 353 | { |
6b50a7c5 KM |
354 | register struct ufsmount *ump; |
355 | struct buf *bp; | |
71e4e98b | 356 | register struct fs *fs; |
7188ac27 | 357 | dev_t dev = devvp->v_rdev; |
ec67a3ce | 358 | struct partinfo dpart; |
27d00e76 | 359 | caddr_t base, space; |
7188ac27 KM |
360 | int havepart = 0, blks; |
361 | int error, i, size; | |
6b50a7c5 | 362 | int ronly; |
1c26e003 | 363 | extern struct vnode *rootvp; |
71e4e98b | 364 | |
ad787160 C |
365 | /* |
366 | * Disallow multiple mounts of the same device. | |
367 | * Disallow mounting of a device that is currently in use | |
368 | * (except for root, which might share swap device for miniroot). | |
369 | * Flush out any old buffers remaining from a previous use. | |
370 | */ | |
371 | if (error = ufs_mountedon(devvp)) | |
372 | return (error); | |
373 | if (vcount(devvp) > 1 && devvp != rootvp) | |
374 | return (EBUSY); | |
375 | if (error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)) | |
376 | return (error); | |
377 | ||
378 | ronly = (mp->mnt_flag & MNT_RDONLY) != 0; | |
1feabdab | 379 | if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)) |
7188ac27 | 380 | return (error); |
0eb6f54a | 381 | if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) |
609e7cfa | 382 | size = DEV_BSIZE; |
0eb6f54a | 383 | else { |
ec67a3ce MK |
384 | havepart = 1; |
385 | size = dpart.disklab->d_secsize; | |
7188ac27 | 386 | } |
6b50a7c5 KM |
387 | |
388 | bp = NULL; | |
389 | ump = NULL; | |
8dc876c1 | 390 | if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) |
71e4e98b | 391 | goto out; |
e018935f | 392 | fs = bp->b_un.b_fs; |
ad787160 C |
393 | if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || |
394 | fs->fs_bsize < sizeof(struct fs)) { | |
8dc876c1 | 395 | error = EINVAL; /* XXX needs translation */ |
1c281610 MK |
396 | goto out; |
397 | } | |
ab9f4fb0 | 398 | ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); |
7bff53ea | 399 | bzero((caddr_t)ump, sizeof *ump); |
b1ca3fbf | 400 | ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, |
5adcb337 | 401 | M_WAITOK); |
7188ac27 | 402 | bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, |
71e4e98b | 403 | (u_int)fs->fs_sbsize); |
5d96a9ad KM |
404 | if (fs->fs_sbsize < SBSIZE) |
405 | bp->b_flags |= B_INVAL; | |
e018935f MK |
406 | brelse(bp); |
407 | bp = NULL; | |
7188ac27 KM |
408 | fs = ump->um_fs; |
409 | fs->fs_ronly = ronly; | |
71e4e98b SL |
410 | if (ronly == 0) |
411 | fs->fs_fmod = 1; | |
609e7cfa MK |
412 | if (havepart) { |
413 | dpart.part->p_fstype = FS_BSDFFS; | |
414 | dpart.part->p_fsize = fs->fs_fsize; | |
415 | dpart.part->p_frag = fs->fs_frag; | |
42ff4c2e | 416 | dpart.part->p_cpg = fs->fs_cpg; |
609e7cfa | 417 | } |
71e4e98b | 418 | blks = howmany(fs->fs_cssize, fs->fs_fsize); |
b1ca3fbf | 419 | base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT, |
5adcb337 | 420 | M_WAITOK); |
71e4e98b SL |
421 | for (i = 0; i < blks; i += fs->fs_frag) { |
422 | size = fs->fs_bsize; | |
423 | if (i + fs->fs_frag > blks) | |
424 | size = (blks - i) * fs->fs_fsize; | |
a937f856 KM |
425 | error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, |
426 | NOCRED, &bp); | |
7188ac27 | 427 | if (error) { |
b1ca3fbf | 428 | free(base, M_UFSMNT); |
71e4e98b SL |
429 | goto out; |
430 | } | |
e018935f | 431 | bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); |
60f9c9e3 | 432 | fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; |
71e4e98b | 433 | space += size; |
e018935f MK |
434 | brelse(bp); |
435 | bp = NULL; | |
71e4e98b | 436 | } |
82161bc8 KM |
437 | mp->mnt_data = (qaddr_t)ump; |
438 | mp->mnt_stat.f_fsid.val[0] = (long)dev; | |
439 | mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; | |
ea301039 | 440 | mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; |
82161bc8 | 441 | mp->mnt_flag |= MNT_LOCAL; |
7188ac27 KM |
442 | ump->um_mountp = mp; |
443 | ump->um_dev = dev; | |
444 | ump->um_devvp = devvp; | |
3614593e MS |
445 | ump->um_nindir = fs->fs_nindir; |
446 | ump->um_bptrtodb = fs->fs_fsbtodb; | |
447 | ump->um_seqinc = fs->fs_frag; | |
8dc876c1 KM |
448 | for (i = 0; i < MAXQUOTAS; i++) |
449 | ump->um_quotas[i] = NULLVP; | |
0f93ba7b | 450 | devvp->v_specflags |= SI_MOUNTEDON; |
a79eb26d KM |
451 | ffs_oldfscompat(fs); |
452 | return (0); | |
453 | out: | |
454 | if (bp) | |
455 | brelse(bp); | |
456 | (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); | |
457 | if (ump) { | |
458 | free(ump->um_fs, M_UFSMNT); | |
459 | free(ump, M_UFSMNT); | |
460 | mp->mnt_data = (qaddr_t)0; | |
461 | } | |
462 | return (error); | |
463 | } | |
464 | ||
465 | /* | |
466 | * Sanity checks for old file systems. | |
467 | * | |
468 | * XXX - goes away some day. | |
469 | */ | |
470 | ffs_oldfscompat(fs) | |
471 | struct fs *fs; | |
472 | { | |
473 | int i; | |
7188ac27 | 474 | |
2a4eff84 JSP |
475 | fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ |
476 | fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ | |
2af59000 KM |
477 | if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ |
478 | fs->fs_nrpos = 8; /* XXX */ | |
4605fb61 KM |
479 | if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ |
480 | quad_t sizepb = fs->fs_bsize; /* XXX */ | |
481 | /* XXX */ | |
482 | fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ | |
483 | for (i = 0; i < NIADDR; i++) { /* XXX */ | |
484 | sizepb *= NINDIR(fs); /* XXX */ | |
485 | fs->fs_maxfilesize += sizepb; /* XXX */ | |
486 | } /* XXX */ | |
487 | fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ | |
488 | fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ | |
489 | } /* XXX */ | |
7188ac27 | 490 | return (0); |
71e4e98b SL |
491 | } |
492 | ||
7188ac27 KM |
493 | /* |
494 | * unmount system call | |
495 | */ | |
ab9f4fb0 KB |
496 | int |
497 | ffs_unmount(mp, mntflags, p) | |
7188ac27 | 498 | struct mount *mp; |
8dc876c1 | 499 | int mntflags; |
0eb6f54a | 500 | struct proc *p; |
71e4e98b | 501 | { |
7188ac27 | 502 | register struct ufsmount *ump; |
71e4e98b | 503 | register struct fs *fs; |
a79eb26d | 504 | int error, flags, ronly; |
71e4e98b | 505 | |
6b50a7c5 | 506 | flags = 0; |
87be6db2 | 507 | if (mntflags & MNT_FORCE) { |
a79eb26d | 508 | if (mp == rootfs) |
87be6db2 | 509 | return (EINVAL); |
8dc876c1 | 510 | flags |= FORCECLOSE; |
87be6db2 | 511 | } |
a79eb26d KM |
512 | if (error = ffs_flushfiles(mp, flags, p)) |
513 | return (error); | |
514 | ump = VFSTOUFS(mp); | |
515 | fs = ump->um_fs; | |
516 | ronly = !fs->fs_ronly; | |
517 | ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; | |
518 | error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, | |
519 | NOCRED, p); | |
520 | vrele(ump->um_devvp); | |
521 | free(fs->fs_csp[0], M_UFSMNT); | |
522 | free(fs, M_UFSMNT); | |
523 | free(ump, M_UFSMNT); | |
524 | mp->mnt_data = (qaddr_t)0; | |
525 | mp->mnt_flag &= ~MNT_LOCAL; | |
526 | return (error); | |
527 | } | |
528 | ||
529 | /* | |
530 | * Flush out all the files in a filesystem. | |
531 | */ | |
532 | ffs_flushfiles(mp, flags, p) | |
533 | register struct mount *mp; | |
534 | int flags; | |
535 | struct proc *p; | |
536 | { | |
537 | extern int doforce; | |
538 | register struct ufsmount *ump; | |
539 | int i, error; | |
540 | ||
541 | if (!doforce) | |
542 | flags &= ~FORCECLOSE; | |
7188ac27 | 543 | ump = VFSTOUFS(mp); |
71e4e98b | 544 | #ifdef QUOTA |
82161bc8 | 545 | if (mp->mnt_flag & MNT_QUOTA) { |
8dc876c1 | 546 | if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) |
6d943995 | 547 | return (error); |
8dc876c1 KM |
548 | for (i = 0; i < MAXQUOTAS; i++) { |
549 | if (ump->um_quotas[i] == NULLVP) | |
550 | continue; | |
70a360ba | 551 | quotaoff(p, mp, i); |
8dc876c1 | 552 | } |
6d943995 | 553 | /* |
8dc876c1 KM |
554 | * Here we fall through to vflush again to ensure |
555 | * that we have gotten rid of all the system vnodes. | |
6d943995 | 556 | */ |
8dc876c1 | 557 | } |
71e4e98b | 558 | #endif |
ad787160 C |
559 | error = vflush(mp, NULLVP, flags); |
560 | return (error); | |
561 | } | |
562 | ||
563 | /* | |
564 | * Return root of a filesystem | |
565 | */ | |
566 | int | |
567 | ffs_root(mp, vpp) | |
568 | struct mount *mp; | |
569 | struct vnode **vpp; | |
570 | { | |
571 | struct vnode *nvp; | |
572 | int error; | |
573 | ||
574 | if (error = VFS_VGET(mp, (ino_t)ROOTINO, &nvp)) | |
575 | return (error); | |
576 | *vpp = nvp; | |
577 | return (0); | |
578 | } | |
579 | ||
580 | /* | |
7188ac27 KM |
581 | * Get file system statistics. |
582 | */ | |
ab9f4fb0 KB |
583 | int |
584 | ffs_statfs(mp, sbp, p) | |
7188ac27 KM |
585 | struct mount *mp; |
586 | register struct statfs *sbp; | |
0eb6f54a | 587 | struct proc *p; |
7188ac27 KM |
588 | { |
589 | register struct ufsmount *ump; | |
590 | register struct fs *fs; | |
591 | ||
592 | ump = VFSTOUFS(mp); | |
593 | fs = ump->um_fs; | |
594 | if (fs->fs_magic != FS_MAGIC) | |
ab9f4fb0 | 595 | panic("ffs_statfs"); |
7188ac27 | 596 | sbp->f_type = MOUNT_UFS; |
06445aba KM |
597 | sbp->f_bsize = fs->fs_fsize; |
598 | sbp->f_iosize = fs->fs_bsize; | |
7188ac27 KM |
599 | sbp->f_blocks = fs->fs_dsize; |
600 | sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + | |
601 | fs->fs_cstotal.cs_nffree; | |
602 | sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - | |
603 | (fs->fs_dsize - sbp->f_bfree); | |
5c41c19e | 604 | sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; |
7188ac27 | 605 | sbp->f_ffree = fs->fs_cstotal.cs_nifree; |
82161bc8 KM |
606 | if (sbp != &mp->mnt_stat) { |
607 | bcopy((caddr_t)mp->mnt_stat.f_mntonname, | |
d45de50d | 608 | (caddr_t)&sbp->f_mntonname[0], MNAMELEN); |
82161bc8 | 609 | bcopy((caddr_t)mp->mnt_stat.f_mntfromname, |
d45de50d KM |
610 | (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); |
611 | } | |
7188ac27 KM |
612 | return (0); |
613 | } | |
614 | ||
7188ac27 KM |
615 | /* |
616 | * Go through the disk queues to initiate sandbagged IO; | |
617 | * go through the inodes to write those that have been modified; | |
618 | * initiate the writing of the super block if it has been modified. | |
8dc876c1 KM |
619 | * |
620 | * Note: we are always called with the filesystem marked `MPBUSY'. | |
7188ac27 | 621 | */ |
ab9f4fb0 | 622 | int |
6b50a7c5 | 623 | ffs_sync(mp, waitfor, cred, p) |
71e4e98b | 624 | struct mount *mp; |
7188ac27 | 625 | int waitfor; |
6b50a7c5 KM |
626 | struct ucred *cred; |
627 | struct proc *p; | |
71e4e98b | 628 | { |
31593ba7 | 629 | register struct vnode *vp; |
7188ac27 KM |
630 | register struct inode *ip; |
631 | register struct ufsmount *ump = VFSTOUFS(mp); | |
632 | register struct fs *fs; | |
812b91f3 | 633 | int error, allerror = 0; |
7188ac27 | 634 | |
7188ac27 | 635 | fs = ump->um_fs; |
7188ac27 KM |
636 | /* |
637 | * Write back modified superblock. | |
638 | * Consistency check that the superblock | |
639 | * is still in the buffer cache. | |
640 | */ | |
641 | if (fs->fs_fmod != 0) { | |
642 | if (fs->fs_ronly != 0) { /* XXX */ | |
643 | printf("fs = %s\n", fs->fs_fsmnt); | |
644 | panic("update: rofs mod"); | |
645 | } | |
646 | fs->fs_fmod = 0; | |
647 | fs->fs_time = time.tv_sec; | |
ab9f4fb0 | 648 | allerror = ffs_sbupdate(ump, waitfor); |
7188ac27 KM |
649 | } |
650 | /* | |
651 | * Write back each (modified) inode. | |
652 | */ | |
25b5cf58 | 653 | loop: |
a242f429 KM |
654 | for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { |
655 | /* | |
656 | * If the vnode that we are about to sync is no longer | |
657 | * associated with this mount point, start over. | |
658 | */ | |
659 | if (vp->v_mount != mp) | |
660 | goto loop; | |
d85a9d1b KM |
661 | if (VOP_ISLOCKED(vp)) |
662 | continue; | |
31593ba7 | 663 | ip = VTOI(vp); |
25b5cf58 | 664 | if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && |
bd60d0f0 | 665 | vp->v_dirtyblkhd.le_next == NULL) |
7188ac27 | 666 | continue; |
25b5cf58 KM |
667 | if (vget(vp)) |
668 | goto loop; | |
6b50a7c5 | 669 | if (error = VOP_FSYNC(vp, cred, waitfor, p)) |
812b91f3 KM |
670 | allerror = error; |
671 | vput(vp); | |
7188ac27 | 672 | } |
7188ac27 | 673 | /* |
5d96a9ad | 674 | * Force stale file system control information to be flushed. |
7188ac27 | 675 | */ |
6b50a7c5 KM |
676 | if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) |
677 | allerror = error; | |
8dc876c1 KM |
678 | #ifdef QUOTA |
679 | qsync(mp); | |
680 | #endif | |
812b91f3 | 681 | return (allerror); |
7188ac27 KM |
682 | } |
683 | ||
067ae075 KM |
684 | /* |
685 | * Look up a FFS dinode number to find its incore vnode. | |
686 | * If it is not in core, read it in from the specified device. | |
687 | * If it is in core, wait for the lock bit to clear, then | |
688 | * return the inode locked. Detection and handling of mount | |
689 | * points must be done by the calling routine. | |
690 | */ | |
691 | int | |
692 | ffs_vget(mp, ino, vpp) | |
693 | struct mount *mp; | |
694 | ino_t ino; | |
695 | struct vnode **vpp; | |
696 | { | |
697 | register struct fs *fs; | |
698 | register struct inode *ip; | |
699 | struct ufsmount *ump; | |
700 | struct buf *bp; | |
701 | struct dinode *dp; | |
702 | struct vnode *vp; | |
703 | union ihead *ih; | |
704 | dev_t dev; | |
705 | int i, type, error; | |
706 | ||
707 | ump = VFSTOUFS(mp); | |
708 | dev = ump->um_dev; | |
709 | if ((*vpp = ufs_ihashget(dev, ino)) != NULL) | |
710 | return (0); | |
711 | ||
712 | /* Allocate a new vnode/inode. */ | |
713 | if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) { | |
714 | *vpp = NULL; | |
715 | return (error); | |
716 | } | |
717 | type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ | |
718 | MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); | |
bd620aaa | 719 | bzero((caddr_t)ip, sizeof(struct inode)); |
067ae075 KM |
720 | vp->v_data = ip; |
721 | ip->i_vnode = vp; | |
067ae075 KM |
722 | ip->i_fs = fs = ump->um_fs; |
723 | ip->i_dev = dev; | |
724 | ip->i_number = ino; | |
725 | #ifdef QUOTA | |
726 | for (i = 0; i < MAXQUOTAS; i++) | |
727 | ip->i_dquot[i] = NODQUOT; | |
728 | #endif | |
729 | /* | |
730 | * Put it onto its hash chain and lock it so that other requests for | |
731 | * this inode will block if they arrive while we are sleeping waiting | |
732 | * for old data structures to be purged or for the contents of the | |
733 | * disk portion of this inode to be read. | |
734 | */ | |
735 | ufs_ihashins(ip); | |
736 | ||
737 | /* Read in the disk contents for the inode, copy into the inode. */ | |
738 | if (error = bread(ump->um_devvp, fsbtodb(fs, itod(fs, ino)), | |
739 | (int)fs->fs_bsize, NOCRED, &bp)) { | |
740 | /* | |
741 | * The inode does not contain anything useful, so it would | |
bd620aaa KM |
742 | * be misleading to leave it on its hash chain. With mode |
743 | * still zero, it will be unlinked and returned to the free | |
744 | * list by vput(). | |
067ae075 | 745 | */ |
e51f387e | 746 | vput(vp); |
067ae075 KM |
747 | brelse(bp); |
748 | *vpp = NULL; | |
749 | return (error); | |
750 | } | |
751 | dp = bp->b_un.b_dino; | |
752 | dp += itoo(fs, ino); | |
753 | ip->i_din = *dp; | |
754 | brelse(bp); | |
755 | ||
756 | /* | |
757 | * Initialize the vnode from the inode, check for aliases. | |
758 | * Note that the underlying vnode may have changed. | |
759 | */ | |
760 | if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) { | |
e51f387e | 761 | vput(vp); |
067ae075 KM |
762 | *vpp = NULL; |
763 | return (error); | |
764 | } | |
765 | /* | |
766 | * Finish inode initialization now that aliasing has been resolved. | |
767 | */ | |
768 | ip->i_devvp = ump->um_devvp; | |
769 | VREF(ip->i_devvp); | |
770 | /* | |
771 | * Set up a generation number for this inode if it does not | |
772 | * already have one. This should only happen on old filesystems. | |
773 | */ | |
774 | if (ip->i_gen == 0) { | |
775 | if (++nextgennumber < (u_long)time.tv_sec) | |
776 | nextgennumber = time.tv_sec; | |
777 | ip->i_gen = nextgennumber; | |
778 | if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) | |
779 | ip->i_flag |= IMOD; | |
780 | } | |
781 | /* | |
782 | * Ensure that uid and gid are correct. This is a temporary | |
783 | * fix until fsck has been changed to do the update. | |
784 | */ | |
785 | if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ | |
786 | ip->i_uid = ip->i_din.di_ouid; /* XXX */ | |
787 | ip->i_gid = ip->i_din.di_ogid; /* XXX */ | |
788 | } /* XXX */ | |
789 | ||
790 | *vpp = vp; | |
791 | return (0); | |
792 | } | |
793 | ||
a9013e03 KM |
794 | /* |
795 | * File handle to vnode | |
796 | * | |
797 | * Have to be really careful about stale file handles: | |
798 | * - check that the inode number is valid | |
799 | * - call ffs_vget() to get the locked inode | |
800 | * - check for an unallocated inode (i_mode == 0) | |
03f3a6e4 KM |
801 | * - check that the given client host has export rights and return |
802 | * those rights via. exflagsp and credanonp | |
a9013e03 KM |
803 | */ |
804 | int | |
03f3a6e4 | 805 | ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) |
a9013e03 KM |
806 | register struct mount *mp; |
807 | struct fid *fhp; | |
03f3a6e4 | 808 | struct mbuf *nam; |
a9013e03 | 809 | struct vnode **vpp; |
03f3a6e4 KM |
810 | int *exflagsp; |
811 | struct ucred **credanonp; | |
a9013e03 | 812 | { |
a9013e03 KM |
813 | register struct ufid *ufhp; |
814 | struct fs *fs; | |
a9013e03 KM |
815 | |
816 | ufhp = (struct ufid *)fhp; | |
9e4a3a4a | 817 | fs = VFSTOUFS(mp)->um_fs; |
a9013e03 KM |
818 | if (ufhp->ufid_ino < ROOTINO || |
819 | ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) | |
03f3a6e4 | 820 | return (ESTALE); |
485cf2ee | 821 | return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); |
a9013e03 KM |
822 | } |
823 | ||
824 | /* | |
825 | * Vnode pointer to File handle | |
826 | */ | |
827 | /* ARGSUSED */ | |
828 | ffs_vptofh(vp, fhp) | |
829 | struct vnode *vp; | |
830 | struct fid *fhp; | |
831 | { | |
832 | register struct inode *ip; | |
833 | register struct ufid *ufhp; | |
834 | ||
835 | ip = VTOI(vp); | |
836 | ufhp = (struct ufid *)fhp; | |
837 | ufhp->ufid_len = sizeof(struct ufid); | |
838 | ufhp->ufid_ino = ip->i_number; | |
839 | ufhp->ufid_gen = ip->i_gen; | |
840 | return (0); | |
841 | } | |
842 | ||
7188ac27 KM |
843 | /* |
844 | * Write a superblock and associated information back to disk. | |
845 | */ | |
06445aba | 846 | int |
ab9f4fb0 | 847 | ffs_sbupdate(mp, waitfor) |
7188ac27 KM |
848 | struct ufsmount *mp; |
849 | int waitfor; | |
850 | { | |
851 | register struct fs *fs = mp->um_fs; | |
71e4e98b SL |
852 | register struct buf *bp; |
853 | int blks; | |
854 | caddr_t space; | |
7188ac27 | 855 | int i, size, error = 0; |
71e4e98b | 856 | |
646464db | 857 | bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); |
71e4e98b | 858 | bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); |
2af59000 KM |
859 | /* Restore compatibility to old file systems. XXX */ |
860 | if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ | |
861 | bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ | |
7188ac27 KM |
862 | if (waitfor == MNT_WAIT) |
863 | error = bwrite(bp); | |
864 | else | |
865 | bawrite(bp); | |
71e4e98b SL |
866 | blks = howmany(fs->fs_cssize, fs->fs_fsize); |
867 | space = (caddr_t)fs->fs_csp[0]; | |
868 | for (i = 0; i < blks; i += fs->fs_frag) { | |
869 | size = fs->fs_bsize; | |
870 | if (i + fs->fs_frag > blks) | |
871 | size = (blks - i) * fs->fs_fsize; | |
646464db KM |
872 | bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), |
873 | size, 0, 0); | |
71e4e98b SL |
874 | bcopy(space, bp->b_un.b_addr, (u_int)size); |
875 | space += size; | |
7188ac27 KM |
876 | if (waitfor == MNT_WAIT) |
877 | error = bwrite(bp); | |
878 | else | |
879 | bawrite(bp); | |
71e4e98b | 880 | } |
7188ac27 | 881 | return (error); |
71e4e98b | 882 | } |