ffs_vfsops.c revision 1.88 1 /* $NetBSD: ffs_vfsops.c,v 1.88 2001/10/30 01:11:54 lukem Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.88 2001/10/30 01:11:54 lukem Exp $");
40
41 #if defined(_KERNEL_OPT)
42 #include "opt_ffs.h"
43 #include "opt_quota.h"
44 #include "opt_compat_netbsd.h"
45 #include "opt_softdep.h"
46 #endif
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/namei.h>
51 #include <sys/proc.h>
52 #include <sys/kernel.h>
53 #include <sys/vnode.h>
54 #include <sys/socket.h>
55 #include <sys/mount.h>
56 #include <sys/buf.h>
57 #include <sys/device.h>
58 #include <sys/mbuf.h>
59 #include <sys/file.h>
60 #include <sys/disklabel.h>
61 #include <sys/ioctl.h>
62 #include <sys/errno.h>
63 #include <sys/malloc.h>
64 #include <sys/pool.h>
65 #include <sys/lock.h>
66 #include <sys/sysctl.h>
67
68 #include <miscfs/specfs/specdev.h>
69
70 #include <ufs/ufs/quota.h>
71 #include <ufs/ufs/ufsmount.h>
72 #include <ufs/ufs/inode.h>
73 #include <ufs/ufs/dir.h>
74 #include <ufs/ufs/ufs_extern.h>
75 #include <ufs/ufs/ufs_bswap.h>
76
77 #include <ufs/ffs/fs.h>
78 #include <ufs/ffs/ffs_extern.h>
79
80 /* how many times ffs_init() was called */
81 int ffs_initcount = 0;
82
83 extern struct lock ufs_hashlock;
84
85 extern struct vnodeopv_desc ffs_vnodeop_opv_desc;
86 extern struct vnodeopv_desc ffs_specop_opv_desc;
87 extern struct vnodeopv_desc ffs_fifoop_opv_desc;
88
89 const struct vnodeopv_desc * const ffs_vnodeopv_descs[] = {
90 &ffs_vnodeop_opv_desc,
91 &ffs_specop_opv_desc,
92 &ffs_fifoop_opv_desc,
93 NULL,
94 };
95
96 struct vfsops ffs_vfsops = {
97 MOUNT_FFS,
98 ffs_mount,
99 ufs_start,
100 ffs_unmount,
101 ufs_root,
102 ufs_quotactl,
103 ffs_statfs,
104 ffs_sync,
105 ffs_vget,
106 ffs_fhtovp,
107 ffs_vptofh,
108 ffs_init,
109 ffs_reinit,
110 ffs_done,
111 ffs_sysctl,
112 ffs_mountroot,
113 ufs_check_export,
114 ffs_vnodeopv_descs,
115 };
116
117 struct genfs_ops ffs_genfsops = {
118 ffs_gop_size,
119 ffs_gop_alloc,
120 genfs_gop_write,
121 };
122
123 struct pool ffs_inode_pool;
124
125 /*
126 * Called by main() when ffs is going to be mounted as root.
127 */
128
129 int
130 ffs_mountroot()
131 {
132 struct fs *fs;
133 struct mount *mp;
134 struct proc *p = curproc; /* XXX */
135 struct ufsmount *ump;
136 int error;
137
138 if (root_device->dv_class != DV_DISK)
139 return (ENODEV);
140
141 /*
142 * Get vnodes for rootdev.
143 */
144 if (bdevvp(rootdev, &rootvp))
145 panic("ffs_mountroot: can't setup bdevvp's");
146
147 if ((error = vfs_rootmountalloc(MOUNT_FFS, "root_device", &mp))) {
148 vrele(rootvp);
149 return (error);
150 }
151 if ((error = ffs_mountfs(rootvp, mp, p)) != 0) {
152 mp->mnt_op->vfs_refcount--;
153 vfs_unbusy(mp);
154 free(mp, M_MOUNT);
155 vrele(rootvp);
156 return (error);
157 }
158 simple_lock(&mountlist_slock);
159 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
160 simple_unlock(&mountlist_slock);
161 ump = VFSTOUFS(mp);
162 fs = ump->um_fs;
163 memset(fs->fs_fsmnt, 0, sizeof(fs->fs_fsmnt));
164 (void)copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0);
165 (void)ffs_statfs(mp, &mp->mnt_stat, p);
166 vfs_unbusy(mp);
167 inittodr(fs->fs_time);
168 return (0);
169 }
170
171 /*
172 * VFS Operations.
173 *
174 * mount system call
175 */
176 int
177 ffs_mount(mp, path, data, ndp, p)
178 struct mount *mp;
179 const char *path;
180 void *data;
181 struct nameidata *ndp;
182 struct proc *p;
183 {
184 struct vnode *devvp;
185 struct ufs_args args;
186 struct ufsmount *ump = NULL;
187 struct fs *fs;
188 size_t size;
189 int error, flags;
190 mode_t accessmode;
191
192 error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
193 if (error)
194 return (error);
195
196 #if !defined(SOFTDEP)
197 mp->mnt_flag &= ~MNT_SOFTDEP;
198 #endif
199
200 /*
201 * If updating, check whether changing from read-only to
202 * read/write; if there is no device name, that's all we do.
203 */
204 if (mp->mnt_flag & MNT_UPDATE) {
205 ump = VFSTOUFS(mp);
206 fs = ump->um_fs;
207 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
208 flags = WRITECLOSE;
209 if (mp->mnt_flag & MNT_FORCE)
210 flags |= FORCECLOSE;
211 if (mp->mnt_flag & MNT_SOFTDEP)
212 error = softdep_flushfiles(mp, flags, p);
213 else
214 error = ffs_flushfiles(mp, flags, p);
215 if (error == 0 &&
216 ffs_cgupdate(ump, MNT_WAIT) == 0 &&
217 fs->fs_clean & FS_WASCLEAN) {
218 if (mp->mnt_flag & MNT_SOFTDEP)
219 fs->fs_flags &= ~FS_DOSOFTDEP;
220 fs->fs_clean = FS_ISCLEAN;
221 (void) ffs_sbupdate(ump, MNT_WAIT);
222 }
223 if (error)
224 return (error);
225 fs->fs_ronly = 1;
226 fs->fs_fmod = 0;
227 }
228
229 /*
230 * Flush soft dependencies if disabling it via an update
231 * mount. This may leave some items to be processed,
232 * so don't do this yet XXX.
233 */
234 if ((fs->fs_flags & FS_DOSOFTDEP) &&
235 !(mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) {
236 #ifdef notyet
237 flags = WRITECLOSE;
238 if (mp->mnt_flag & MNT_FORCE)
239 flags |= FORCECLOSE;
240 error = softdep_flushfiles(mp, flags, p);
241 if (error == 0 && ffs_cgupdate(ump, MNT_WAIT) == 0)
242 fs->fs_flags &= ~FS_DOSOFTDEP;
243 (void) ffs_sbupdate(ump, MNT_WAIT);
244 #elif defined(SOFTDEP)
245 mp->mnt_flag |= MNT_SOFTDEP;
246 #endif
247 }
248
249 /*
250 * When upgrading to a softdep mount, we must first flush
251 * all vnodes. (not done yet -- see above)
252 */
253 if (!(fs->fs_flags & FS_DOSOFTDEP) &&
254 (mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) {
255 #ifdef notyet
256 flags = WRITECLOSE;
257 if (mp->mnt_flag & MNT_FORCE)
258 flags |= FORCECLOSE;
259 error = ffs_flushfiles(mp, flags, p);
260 #else
261 mp->mnt_flag &= ~MNT_SOFTDEP;
262 #endif
263 }
264
265 if (mp->mnt_flag & MNT_RELOAD) {
266 error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
267 if (error)
268 return (error);
269 }
270 if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
271 /*
272 * If upgrade to read-write by non-root, then verify
273 * that user has necessary permissions on the device.
274 */
275 devvp = ump->um_devvp;
276 if (p->p_ucred->cr_uid != 0) {
277 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
278 error = VOP_ACCESS(devvp, VREAD | VWRITE,
279 p->p_ucred, p);
280 VOP_UNLOCK(devvp, 0);
281 if (error)
282 return (error);
283 }
284 fs->fs_ronly = 0;
285 fs->fs_clean <<= 1;
286 fs->fs_fmod = 1;
287 if ((fs->fs_flags & FS_DOSOFTDEP)) {
288 error = softdep_mount(devvp, mp, fs,
289 p->p_ucred);
290 if (error)
291 return (error);
292 }
293 }
294 if (args.fspec == 0) {
295 /*
296 * Process export requests.
297 */
298 return (vfs_export(mp, &ump->um_export, &args.export));
299 }
300 if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) ==
301 (MNT_SOFTDEP | MNT_ASYNC)) {
302 printf("%s fs uses soft updates, ignoring async mode\n",
303 fs->fs_fsmnt);
304 mp->mnt_flag &= ~MNT_ASYNC;
305 }
306 }
307 /*
308 * Not an update, or updating the name: look up the name
309 * and verify that it refers to a sensible block device.
310 */
311 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
312 if ((error = namei(ndp)) != 0)
313 return (error);
314 devvp = ndp->ni_vp;
315
316 if (devvp->v_type != VBLK) {
317 vrele(devvp);
318 return (ENOTBLK);
319 }
320 if (major(devvp->v_rdev) >= nblkdev) {
321 vrele(devvp);
322 return (ENXIO);
323 }
324 /*
325 * If mount by non-root, then verify that user has necessary
326 * permissions on the device.
327 */
328 if (p->p_ucred->cr_uid != 0) {
329 accessmode = VREAD;
330 if ((mp->mnt_flag & MNT_RDONLY) == 0)
331 accessmode |= VWRITE;
332 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
333 error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
334 VOP_UNLOCK(devvp, 0);
335 if (error) {
336 vrele(devvp);
337 return (error);
338 }
339 }
340 if ((mp->mnt_flag & MNT_UPDATE) == 0) {
341 error = ffs_mountfs(devvp, mp, p);
342 if (!error) {
343 ump = VFSTOUFS(mp);
344 fs = ump->um_fs;
345 if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) ==
346 (MNT_SOFTDEP | MNT_ASYNC)) {
347 printf("%s fs uses soft updates, "
348 "ignoring async mode\n",
349 fs->fs_fsmnt);
350 mp->mnt_flag &= ~MNT_ASYNC;
351 }
352 }
353 }
354 else {
355 if (devvp != ump->um_devvp)
356 error = EINVAL; /* needs translation */
357 else
358 vrele(devvp);
359 }
360 if (error) {
361 vrele(devvp);
362 return (error);
363 }
364 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
365 memset(fs->fs_fsmnt + size, 0, sizeof(fs->fs_fsmnt) - size);
366 memcpy(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN);
367 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
368 &size);
369 memset(mp->mnt_stat.f_mntfromname + size, 0, MNAMELEN - size);
370 if (mp->mnt_flag & MNT_SOFTDEP)
371 fs->fs_flags |= FS_DOSOFTDEP;
372 else
373 fs->fs_flags &= ~FS_DOSOFTDEP;
374 if (fs->fs_fmod != 0) { /* XXX */
375 fs->fs_fmod = 0;
376 if (fs->fs_clean & FS_WASCLEAN)
377 fs->fs_time = time.tv_sec;
378 else
379 printf("%s: file system not clean (fs_clean=%x); please fsck(8)\n",
380 mp->mnt_stat.f_mntfromname, fs->fs_clean);
381 (void) ffs_cgupdate(ump, MNT_WAIT);
382 }
383 return (0);
384 }
385
386 /*
387 * Reload all incore data for a filesystem (used after running fsck on
388 * the root filesystem and finding things to fix). The filesystem must
389 * be mounted read-only.
390 *
391 * Things to do to update the mount:
392 * 1) invalidate all cached meta-data.
393 * 2) re-read superblock from disk.
394 * 3) re-read summary information from disk.
395 * 4) invalidate all inactive vnodes.
396 * 5) invalidate all cached file data.
397 * 6) re-read inode data for all active vnodes.
398 */
399 int
400 ffs_reload(mountp, cred, p)
401 struct mount *mountp;
402 struct ucred *cred;
403 struct proc *p;
404 {
405 struct vnode *vp, *nvp, *devvp;
406 struct inode *ip;
407 void *space;
408 struct buf *bp;
409 struct fs *fs, *newfs;
410 struct partinfo dpart;
411 int i, blks, size, error;
412 int32_t *lp;
413 caddr_t cp;
414
415 if ((mountp->mnt_flag & MNT_RDONLY) == 0)
416 return (EINVAL);
417 /*
418 * Step 1: invalidate all cached meta-data.
419 */
420 devvp = VFSTOUFS(mountp)->um_devvp;
421 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
422 error = vinvalbuf(devvp, 0, cred, p, 0, 0);
423 VOP_UNLOCK(devvp, 0);
424 if (error)
425 panic("ffs_reload: dirty1");
426 /*
427 * Step 2: re-read superblock from disk.
428 */
429 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
430 size = DEV_BSIZE;
431 else
432 size = dpart.disklab->d_secsize;
433 error = bread(devvp, (ufs_daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp);
434 if (error) {
435 brelse(bp);
436 return (error);
437 }
438 fs = VFSTOUFS(mountp)->um_fs;
439 newfs = malloc(fs->fs_sbsize, M_UFSMNT, M_WAITOK);
440 memcpy(newfs, bp->b_data, fs->fs_sbsize);
441 #ifdef FFS_EI
442 if (VFSTOUFS(mountp)->um_flags & UFS_NEEDSWAP) {
443 ffs_sb_swap((struct fs*)bp->b_data, newfs);
444 fs->fs_flags |= FS_SWAPPED;
445 }
446 #endif
447 if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE ||
448 newfs->fs_bsize < sizeof(struct fs)) {
449 brelse(bp);
450 free(newfs, M_UFSMNT);
451 return (EIO); /* XXX needs translation */
452 }
453 /*
454 * Copy pointer fields back into superblock before copying in XXX
455 * new superblock. These should really be in the ufsmount. XXX
456 * Note that important parameters (eg fs_ncg) are unchanged.
457 */
458 newfs->fs_csp = fs->fs_csp;
459 newfs->fs_maxcluster = fs->fs_maxcluster;
460 newfs->fs_contigdirs = fs->fs_contigdirs;
461 newfs->fs_ronly = fs->fs_ronly;
462 memcpy(fs, newfs, (u_int)fs->fs_sbsize);
463 if (fs->fs_sbsize < SBSIZE)
464 bp->b_flags |= B_INVAL;
465 brelse(bp);
466 free(newfs, M_UFSMNT);
467 mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
468 ffs_oldfscompat(fs);
469 /* An old fsck may have zeroed these fields, so recheck them. */
470 if (fs->fs_avgfilesize <= 0)
471 fs->fs_avgfilesize = AVFILESIZ;
472 if (fs->fs_avgfpdir <= 0)
473 fs->fs_avgfpdir = AFPDIR;
474
475 ffs_statfs(mountp, &mountp->mnt_stat, p);
476 /*
477 * Step 3: re-read summary information from disk.
478 */
479 blks = howmany(fs->fs_cssize, fs->fs_fsize);
480 space = fs->fs_csp;
481 for (i = 0; i < blks; i += fs->fs_frag) {
482 size = fs->fs_bsize;
483 if (i + fs->fs_frag > blks)
484 size = (blks - i) * fs->fs_fsize;
485 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
486 NOCRED, &bp);
487 if (error) {
488 brelse(bp);
489 return (error);
490 }
491 #ifdef FFS_EI
492 if (UFS_FSNEEDSWAP(fs))
493 ffs_csum_swap((struct csum *)bp->b_data,
494 (struct csum *)space, size);
495 else
496 #endif
497 memcpy(space, bp->b_data, (size_t)size);
498 space = (char *)space + size;
499 brelse(bp);
500 }
501 if ((fs->fs_flags & FS_DOSOFTDEP))
502 softdep_mount(devvp, mountp, fs, cred);
503 /*
504 * We no longer know anything about clusters per cylinder group.
505 */
506 if (fs->fs_contigsumsize > 0) {
507 lp = fs->fs_maxcluster;
508 for (i = 0; i < fs->fs_ncg; i++)
509 *lp++ = fs->fs_contigsumsize;
510 }
511
512 loop:
513 simple_lock(&mntvnode_slock);
514 for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
515 if (vp->v_mount != mountp) {
516 simple_unlock(&mntvnode_slock);
517 goto loop;
518 }
519 nvp = vp->v_mntvnodes.le_next;
520 /*
521 * Step 4: invalidate all inactive vnodes.
522 */
523 if (vrecycle(vp, &mntvnode_slock, p))
524 goto loop;
525 /*
526 * Step 5: invalidate all cached file data.
527 */
528 simple_lock(&vp->v_interlock);
529 simple_unlock(&mntvnode_slock);
530 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
531 goto loop;
532 if (vinvalbuf(vp, 0, cred, p, 0, 0))
533 panic("ffs_reload: dirty2");
534 /*
535 * Step 6: re-read inode data for all active vnodes.
536 */
537 ip = VTOI(vp);
538 error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
539 (int)fs->fs_bsize, NOCRED, &bp);
540 if (error) {
541 brelse(bp);
542 vput(vp);
543 return (error);
544 }
545 cp = (caddr_t)bp->b_data +
546 (ino_to_fsbo(fs, ip->i_number) * DINODE_SIZE);
547 #ifdef FFS_EI
548 if (UFS_FSNEEDSWAP(fs))
549 ffs_dinode_swap((struct dinode *)cp,
550 &ip->i_din.ffs_din);
551 else
552 #endif
553 memcpy(&ip->i_din.ffs_din, cp, DINODE_SIZE);
554 ip->i_ffs_effnlink = ip->i_ffs_nlink;
555 brelse(bp);
556 vput(vp);
557 simple_lock(&mntvnode_slock);
558 }
559 simple_unlock(&mntvnode_slock);
560 return (0);
561 }
562
563 /*
564 * Common code for mount and mountroot
565 */
566 int
567 ffs_mountfs(devvp, mp, p)
568 struct vnode *devvp;
569 struct mount *mp;
570 struct proc *p;
571 {
572 struct ufsmount *ump;
573 struct buf *bp;
574 struct fs *fs;
575 dev_t dev;
576 struct partinfo dpart;
577 void *space;
578 int blks;
579 int error, i, size, ronly;
580 #ifdef FFS_EI
581 int needswap;
582 #endif
583 int32_t *lp;
584 struct ucred *cred;
585 u_int64_t maxfilesize; /* XXX */
586 u_int32_t sbsize;
587
588 dev = devvp->v_rdev;
589 cred = p ? p->p_ucred : NOCRED;
590 /*
591 * Disallow multiple mounts of the same device.
592 * Disallow mounting of a device that is currently in use
593 * (except for root, which might share swap device for miniroot).
594 * Flush out any old buffers remaining from a previous use.
595 */
596 if ((error = vfs_mountedon(devvp)) != 0)
597 return (error);
598 if (vcount(devvp) > 1 && devvp != rootvp)
599 return (EBUSY);
600 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
601 error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
602 VOP_UNLOCK(devvp, 0);
603 if (error)
604 return (error);
605
606 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
607 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
608 if (error)
609 return (error);
610 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
611 size = DEV_BSIZE;
612 else
613 size = dpart.disklab->d_secsize;
614
615 bp = NULL;
616 ump = NULL;
617 error = bread(devvp, (ufs_daddr_t)(SBOFF / size), SBSIZE, cred, &bp);
618 if (error)
619 goto out;
620
621 fs = (struct fs*)bp->b_data;
622 if (fs->fs_magic == FS_MAGIC) {
623 sbsize = fs->fs_sbsize;
624 #ifdef FFS_EI
625 needswap = 0;
626 } else if (fs->fs_magic == bswap32(FS_MAGIC)) {
627 sbsize = bswap32(fs->fs_sbsize);
628 needswap = 1;
629 #endif
630 } else {
631 error = EINVAL;
632 goto out;
633 }
634 if (sbsize > MAXBSIZE || sbsize < sizeof(struct fs)) {
635 error = EINVAL;
636 goto out;
637 }
638
639 fs = malloc((u_long)sbsize, M_UFSMNT, M_WAITOK);
640 memcpy(fs, bp->b_data, sbsize);
641 #ifdef FFS_EI
642 if (needswap) {
643 ffs_sb_swap((struct fs*)bp->b_data, fs);
644 fs->fs_flags |= FS_SWAPPED;
645 }
646 #endif
647 ffs_oldfscompat(fs);
648
649 if (fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
650 error = EINVAL;
651 goto out;
652 }
653 /* make sure cylinder group summary area is a reasonable size. */
654 if (fs->fs_cgsize == 0 || fs->fs_cpg == 0 ||
655 fs->fs_ncg > fs->fs_ncyl / fs->fs_cpg + 1 ||
656 fs->fs_cssize >
657 fragroundup(fs, fs->fs_ncg * sizeof(struct csum))) {
658 error = EINVAL; /* XXX needs translation */
659 goto out2;
660 }
661 /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
662 if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
663 error = EROFS; /* XXX what should be returned? */
664 goto out2;
665 }
666
667 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
668 memset((caddr_t)ump, 0, sizeof *ump);
669 ump->um_fs = fs;
670 if (fs->fs_sbsize < SBSIZE)
671 bp->b_flags |= B_INVAL;
672 brelse(bp);
673 bp = NULL;
674 fs->fs_ronly = ronly;
675 if (ronly == 0) {
676 fs->fs_clean <<= 1;
677 fs->fs_fmod = 1;
678 }
679 size = fs->fs_cssize;
680 blks = howmany(size, fs->fs_fsize);
681 if (fs->fs_contigsumsize > 0)
682 size += fs->fs_ncg * sizeof(int32_t);
683 size += fs->fs_ncg * sizeof(*fs->fs_contigdirs);
684 space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
685 fs->fs_csp = space;
686 for (i = 0; i < blks; i += fs->fs_frag) {
687 size = fs->fs_bsize;
688 if (i + fs->fs_frag > blks)
689 size = (blks - i) * fs->fs_fsize;
690 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
691 cred, &bp);
692 if (error) {
693 free(fs->fs_csp, M_UFSMNT);
694 goto out2;
695 }
696 #ifdef FFS_EI
697 if (needswap)
698 ffs_csum_swap((struct csum *)bp->b_data,
699 (struct csum *)space, size);
700 else
701 #endif
702 memcpy(space, bp->b_data, (u_int)size);
703
704 space = (char *)space + size;
705 brelse(bp);
706 bp = NULL;
707 }
708 if (fs->fs_contigsumsize > 0) {
709 fs->fs_maxcluster = lp = space;
710 for (i = 0; i < fs->fs_ncg; i++)
711 *lp++ = fs->fs_contigsumsize;
712 space = lp;
713 }
714 size = fs->fs_ncg * sizeof(*fs->fs_contigdirs);
715 fs->fs_contigdirs = space;
716 space = (char *)space + size;
717 memset(fs->fs_contigdirs, 0, size);
718 /* Compatibility for old filesystems - XXX */
719 if (fs->fs_avgfilesize <= 0)
720 fs->fs_avgfilesize = AVFILESIZ;
721 if (fs->fs_avgfpdir <= 0)
722 fs->fs_avgfpdir = AFPDIR;
723 mp->mnt_data = (qaddr_t)ump;
724 mp->mnt_stat.f_fsid.val[0] = (long)dev;
725 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_FFS);
726 mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
727 mp->mnt_fs_bshift = fs->fs_bshift;
728 mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */
729 mp->mnt_flag |= MNT_LOCAL;
730 #ifdef FFS_EI
731 if (needswap)
732 ump->um_flags |= UFS_NEEDSWAP;
733 #endif
734 ump->um_mountp = mp;
735 ump->um_dev = dev;
736 ump->um_devvp = devvp;
737 ump->um_nindir = fs->fs_nindir;
738 ump->um_lognindir = ffs(fs->fs_nindir) - 1;
739 ump->um_bptrtodb = fs->fs_fsbtodb;
740 ump->um_seqinc = fs->fs_frag;
741 for (i = 0; i < MAXQUOTAS; i++)
742 ump->um_quotas[i] = NULLVP;
743 devvp->v_specmountpoint = mp;
744 ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */
745 maxfilesize = (u_int64_t)0x80000000 * fs->fs_bsize - 1; /* XXX */
746 if (fs->fs_maxfilesize > maxfilesize) /* XXX */
747 fs->fs_maxfilesize = maxfilesize; /* XXX */
748 if (ronly == 0 && (fs->fs_flags & FS_DOSOFTDEP)) {
749 error = softdep_mount(devvp, mp, fs, cred);
750 if (error) {
751 free(fs->fs_csp, M_UFSMNT);
752 goto out;
753 }
754 }
755 return (0);
756 out2:
757 free(fs, M_UFSMNT);
758 out:
759 devvp->v_specmountpoint = NULL;
760 if (bp)
761 brelse(bp);
762 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
763 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
764 VOP_UNLOCK(devvp, 0);
765 if (ump) {
766 free(ump, M_UFSMNT);
767 mp->mnt_data = (qaddr_t)0;
768 }
769 return (error);
770 }
771
772 /*
773 * Sanity checks for old file systems.
774 *
775 * XXX - goes away some day.
776 */
777 int
778 ffs_oldfscompat(fs)
779 struct fs *fs;
780 {
781 int i;
782
783 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */
784 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */
785 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
786 fs->fs_nrpos = 8; /* XXX */
787 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
788 u_int64_t sizepb = fs->fs_bsize; /* XXX */
789 /* XXX */
790 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
791 for (i = 0; i < NIADDR; i++) { /* XXX */
792 sizepb *= NINDIR(fs); /* XXX */
793 fs->fs_maxfilesize += sizepb; /* XXX */
794 } /* XXX */
795 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
796 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
797 } /* XXX */
798 return (0);
799 }
800
801 /*
802 * unmount system call
803 */
804 int
805 ffs_unmount(mp, mntflags, p)
806 struct mount *mp;
807 int mntflags;
808 struct proc *p;
809 {
810 struct ufsmount *ump;
811 struct fs *fs;
812 int error, flags;
813
814 flags = 0;
815 if (mntflags & MNT_FORCE)
816 flags |= FORCECLOSE;
817 if (mp->mnt_flag & MNT_SOFTDEP) {
818 if ((error = softdep_flushfiles(mp, flags, p)) != 0)
819 return (error);
820 } else {
821 if ((error = ffs_flushfiles(mp, flags, p)) != 0)
822 return (error);
823 }
824 ump = VFSTOUFS(mp);
825 fs = ump->um_fs;
826 if (fs->fs_ronly == 0 &&
827 ffs_cgupdate(ump, MNT_WAIT) == 0 &&
828 fs->fs_clean & FS_WASCLEAN) {
829 if (mp->mnt_flag & MNT_SOFTDEP)
830 fs->fs_flags &= ~FS_DOSOFTDEP;
831 fs->fs_clean = FS_ISCLEAN;
832 (void) ffs_sbupdate(ump, MNT_WAIT);
833 }
834 if (ump->um_devvp->v_type != VBAD)
835 ump->um_devvp->v_specmountpoint = NULL;
836 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
837 error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
838 NOCRED, p);
839 vput(ump->um_devvp);
840 free(fs->fs_csp, M_UFSMNT);
841 free(fs, M_UFSMNT);
842 free(ump, M_UFSMNT);
843 mp->mnt_data = (qaddr_t)0;
844 mp->mnt_flag &= ~MNT_LOCAL;
845 return (error);
846 }
847
848 /*
849 * Flush out all the files in a filesystem.
850 */
851 int
852 ffs_flushfiles(mp, flags, p)
853 struct mount *mp;
854 int flags;
855 struct proc *p;
856 {
857 extern int doforce;
858 struct ufsmount *ump;
859 int error;
860
861 if (!doforce)
862 flags &= ~FORCECLOSE;
863 ump = VFSTOUFS(mp);
864 #ifdef QUOTA
865 if (mp->mnt_flag & MNT_QUOTA) {
866 int i;
867 if ((error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) != 0)
868 return (error);
869 for (i = 0; i < MAXQUOTAS; i++) {
870 if (ump->um_quotas[i] == NULLVP)
871 continue;
872 quotaoff(p, mp, i);
873 }
874 /*
875 * Here we fall through to vflush again to ensure
876 * that we have gotten rid of all the system vnodes.
877 */
878 }
879 #endif
880 /*
881 * Flush all the files.
882 */
883 error = vflush(mp, NULLVP, flags);
884 if (error)
885 return (error);
886 /*
887 * Flush filesystem metadata.
888 */
889 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
890 error = VOP_FSYNC(ump->um_devvp, p->p_ucred, FSYNC_WAIT, 0, 0, p);
891 VOP_UNLOCK(ump->um_devvp, 0);
892 return (error);
893 }
894
895 /*
896 * Get file system statistics.
897 */
898 int
899 ffs_statfs(mp, sbp, p)
900 struct mount *mp;
901 struct statfs *sbp;
902 struct proc *p;
903 {
904 struct ufsmount *ump;
905 struct fs *fs;
906
907 ump = VFSTOUFS(mp);
908 fs = ump->um_fs;
909 if (fs->fs_magic != FS_MAGIC)
910 panic("ffs_statfs");
911 #ifdef COMPAT_09
912 sbp->f_type = 1;
913 #else
914 sbp->f_type = 0;
915 #endif
916 sbp->f_bsize = fs->fs_fsize;
917 sbp->f_iosize = fs->fs_bsize;
918 sbp->f_blocks = fs->fs_dsize;
919 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
920 fs->fs_cstotal.cs_nffree;
921 sbp->f_bavail = (long) (((u_int64_t) fs->fs_dsize * (u_int64_t)
922 (100 - fs->fs_minfree) / (u_int64_t) 100) -
923 (u_int64_t) (fs->fs_dsize - sbp->f_bfree));
924 sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
925 sbp->f_ffree = fs->fs_cstotal.cs_nifree;
926 if (sbp != &mp->mnt_stat) {
927 memcpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, MNAMELEN);
928 memcpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname, MNAMELEN);
929 }
930 strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
931 return (0);
932 }
933
934 /*
935 * Go through the disk queues to initiate sandbagged IO;
936 * go through the inodes to write those that have been modified;
937 * initiate the writing of the super block if it has been modified.
938 *
939 * Note: we are always called with the filesystem marked `MPBUSY'.
940 */
941 int
942 ffs_sync(mp, waitfor, cred, p)
943 struct mount *mp;
944 int waitfor;
945 struct ucred *cred;
946 struct proc *p;
947 {
948 struct vnode *vp, *nvp;
949 struct inode *ip;
950 struct ufsmount *ump = VFSTOUFS(mp);
951 struct fs *fs;
952 int error, allerror = 0;
953
954 fs = ump->um_fs;
955 if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */
956 printf("fs = %s\n", fs->fs_fsmnt);
957 panic("update: rofs mod");
958 }
959 /*
960 * Write back each (modified) inode.
961 */
962 simple_lock(&mntvnode_slock);
963 loop:
964 for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) {
965 /*
966 * If the vnode that we are about to sync is no longer
967 * associated with this mount point, start over.
968 */
969 if (vp->v_mount != mp)
970 goto loop;
971 simple_lock(&vp->v_interlock);
972 nvp = LIST_NEXT(vp, v_mntvnodes);
973 ip = VTOI(vp);
974 if (vp->v_type == VNON ||
975 ((ip->i_flag &
976 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFIED | IN_ACCESSED)) == 0 &&
977 LIST_EMPTY(&vp->v_dirtyblkhd) &&
978 vp->v_uobj.uo_npages == 0))
979 {
980 simple_unlock(&vp->v_interlock);
981 continue;
982 }
983 simple_unlock(&mntvnode_slock);
984 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
985 if (error) {
986 simple_lock(&mntvnode_slock);
987 if (error == ENOENT)
988 goto loop;
989 continue;
990 }
991 if ((error = VOP_FSYNC(vp, cred,
992 waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0, p)) != 0)
993 allerror = error;
994 vput(vp);
995 simple_lock(&mntvnode_slock);
996 }
997 simple_unlock(&mntvnode_slock);
998 /*
999 * Force stale file system control information to be flushed.
1000 */
1001 if (waitfor != MNT_LAZY) {
1002 if (ump->um_mountp->mnt_flag & MNT_SOFTDEP)
1003 waitfor = MNT_NOWAIT;
1004 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1005 if ((error = VOP_FSYNC(ump->um_devvp, cred,
1006 waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0, p)) != 0)
1007 allerror = error;
1008 VOP_UNLOCK(ump->um_devvp, 0);
1009 }
1010 #ifdef QUOTA
1011 qsync(mp);
1012 #endif
1013 /*
1014 * Write back modified superblock.
1015 */
1016 if (fs->fs_fmod != 0) {
1017 fs->fs_fmod = 0;
1018 fs->fs_time = time.tv_sec;
1019 if ((error = ffs_cgupdate(ump, waitfor)))
1020 allerror = error;
1021 }
1022 return (allerror);
1023 }
1024
1025 /*
1026 * Look up a FFS dinode number to find its incore vnode, otherwise read it
1027 * in from disk. If it is in core, wait for the lock bit to clear, then
1028 * return the inode locked. Detection and handling of mount points must be
1029 * done by the calling routine.
1030 */
1031 int
1032 ffs_vget(mp, ino, vpp)
1033 struct mount *mp;
1034 ino_t ino;
1035 struct vnode **vpp;
1036 {
1037 struct fs *fs;
1038 struct inode *ip;
1039 struct ufsmount *ump;
1040 struct buf *bp;
1041 struct vnode *vp;
1042 dev_t dev;
1043 int error;
1044 caddr_t cp;
1045
1046 ump = VFSTOUFS(mp);
1047 dev = ump->um_dev;
1048
1049 if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL)
1050 return (0);
1051
1052 /* Allocate a new vnode/inode. */
1053 if ((error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) != 0) {
1054 *vpp = NULL;
1055 return (error);
1056 }
1057
1058 /*
1059 * If someone beat us to it while sleeping in getnewvnode(),
1060 * push back the freshly allocated vnode we don't need, and return.
1061 */
1062
1063 do {
1064 if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) {
1065 ungetnewvnode(vp);
1066 return (0);
1067 }
1068 } while (lockmgr(&ufs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0));
1069
1070 /*
1071 * XXX MFS ends up here, too, to allocate an inode. Should we
1072 * XXX create another pool for MFS inodes?
1073 */
1074
1075 ip = pool_get(&ffs_inode_pool, PR_WAITOK);
1076 memset(ip, 0, sizeof(struct inode));
1077 vp->v_data = ip;
1078 ip->i_vnode = vp;
1079 ip->i_fs = fs = ump->um_fs;
1080 ip->i_dev = dev;
1081 ip->i_number = ino;
1082 LIST_INIT(&ip->i_pcbufhd);
1083 #ifdef QUOTA
1084 {
1085 int i;
1086
1087 for (i = 0; i < MAXQUOTAS; i++)
1088 ip->i_dquot[i] = NODQUOT;
1089 }
1090 #endif
1091
1092 /*
1093 * Put it onto its hash chain and lock it so that other requests for
1094 * this inode will block if they arrive while we are sleeping waiting
1095 * for old data structures to be purged or for the contents of the
1096 * disk portion of this inode to be read.
1097 */
1098
1099 ufs_ihashins(ip);
1100 lockmgr(&ufs_hashlock, LK_RELEASE, 0);
1101
1102 /* Read in the disk contents for the inode, copy into the inode. */
1103 error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1104 (int)fs->fs_bsize, NOCRED, &bp);
1105 if (error) {
1106
1107 /*
1108 * The inode does not contain anything useful, so it would
1109 * be misleading to leave it on its hash chain. With mode
1110 * still zero, it will be unlinked and returned to the free
1111 * list by vput().
1112 */
1113
1114 vput(vp);
1115 brelse(bp);
1116 *vpp = NULL;
1117 return (error);
1118 }
1119 cp = (caddr_t)bp->b_data + (ino_to_fsbo(fs, ino) * DINODE_SIZE);
1120 #ifdef FFS_EI
1121 if (UFS_FSNEEDSWAP(fs))
1122 ffs_dinode_swap((struct dinode *)cp, &ip->i_din.ffs_din);
1123 else
1124 #endif
1125 memcpy(&ip->i_din.ffs_din, cp, DINODE_SIZE);
1126 if (DOINGSOFTDEP(vp))
1127 softdep_load_inodeblock(ip);
1128 else
1129 ip->i_ffs_effnlink = ip->i_ffs_nlink;
1130 brelse(bp);
1131
1132 /*
1133 * Initialize the vnode from the inode, check for aliases.
1134 * Note that the underlying vnode may have changed.
1135 */
1136
1137 ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
1138
1139 /*
1140 * Finish inode initialization now that aliasing has been resolved.
1141 */
1142
1143 genfs_node_init(vp, &ffs_genfsops);
1144 ip->i_devvp = ump->um_devvp;
1145 VREF(ip->i_devvp);
1146
1147 /*
1148 * Ensure that uid and gid are correct. This is a temporary
1149 * fix until fsck has been changed to do the update.
1150 */
1151
1152 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
1153 ip->i_ffs_uid = ip->i_din.ffs_din.di_ouid; /* XXX */
1154 ip->i_ffs_gid = ip->i_din.ffs_din.di_ogid; /* XXX */
1155 } /* XXX */
1156 uvm_vnp_setsize(vp, ip->i_ffs_size);
1157 *vpp = vp;
1158 return (0);
1159 }
1160
1161 /*
1162 * File handle to vnode
1163 *
1164 * Have to be really careful about stale file handles:
1165 * - check that the inode number is valid
1166 * - call ffs_vget() to get the locked inode
1167 * - check for an unallocated inode (i_mode == 0)
1168 * - check that the given client host has export rights and return
1169 * those rights via. exflagsp and credanonp
1170 */
1171 int
1172 ffs_fhtovp(mp, fhp, vpp)
1173 struct mount *mp;
1174 struct fid *fhp;
1175 struct vnode **vpp;
1176 {
1177 struct ufid *ufhp;
1178 struct fs *fs;
1179
1180 ufhp = (struct ufid *)fhp;
1181 fs = VFSTOUFS(mp)->um_fs;
1182 if (ufhp->ufid_ino < ROOTINO ||
1183 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1184 return (ESTALE);
1185 return (ufs_fhtovp(mp, ufhp, vpp));
1186 }
1187
1188 /*
1189 * Vnode pointer to File handle
1190 */
1191 /* ARGSUSED */
1192 int
1193 ffs_vptofh(vp, fhp)
1194 struct vnode *vp;
1195 struct fid *fhp;
1196 {
1197 struct inode *ip;
1198 struct ufid *ufhp;
1199
1200 ip = VTOI(vp);
1201 ufhp = (struct ufid *)fhp;
1202 ufhp->ufid_len = sizeof(struct ufid);
1203 ufhp->ufid_ino = ip->i_number;
1204 ufhp->ufid_gen = ip->i_ffs_gen;
1205 return (0);
1206 }
1207
1208 void
1209 ffs_init()
1210 {
1211 if (ffs_initcount++ > 0)
1212 return;
1213
1214 softdep_initialize();
1215 ufs_init();
1216
1217 pool_init(&ffs_inode_pool, sizeof(struct inode), 0, 0, 0, "ffsinopl",
1218 0, pool_page_alloc_nointr, pool_page_free_nointr, M_FFSNODE);
1219 }
1220
1221 void
1222 ffs_reinit()
1223 {
1224 softdep_reinitialize();
1225 ufs_reinit();
1226 }
1227
1228 void
1229 ffs_done()
1230 {
1231 if (--ffs_initcount > 0)
1232 return;
1233
1234 /* XXX softdep cleanup ? */
1235 ufs_done();
1236 pool_destroy(&ffs_inode_pool);
1237 }
1238
1239 int
1240 ffs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1241 int *name;
1242 u_int namelen;
1243 void *oldp;
1244 size_t *oldlenp;
1245 void *newp;
1246 size_t newlen;
1247 struct proc *p;
1248 {
1249 extern int doasyncfree;
1250 extern int ffs_log_changeopt;
1251
1252 /* all sysctl names at this level are terminal */
1253 if (namelen != 1)
1254 return (ENOTDIR); /* overloaded */
1255
1256 switch (name[0]) {
1257 case FFS_ASYNCFREE:
1258 return (sysctl_int(oldp, oldlenp, newp, newlen, &doasyncfree));
1259 case FFS_LOG_CHANGEOPT:
1260 return (sysctl_int(oldp, oldlenp, newp, newlen,
1261 &ffs_log_changeopt));
1262 default:
1263 return (EOPNOTSUPP);
1264 }
1265 /* NOTREACHED */
1266 }
1267
1268 /*
1269 * Write a superblock and associated information back to disk.
1270 */
1271 int
1272 ffs_sbupdate(mp, waitfor)
1273 struct ufsmount *mp;
1274 int waitfor;
1275 {
1276 struct fs *fs = mp->um_fs;
1277 struct buf *bp;
1278 int i, error = 0;
1279 int32_t saved_nrpos = fs->fs_nrpos;
1280 int64_t saved_qbmask = fs->fs_qbmask;
1281 int64_t saved_qfmask = fs->fs_qfmask;
1282 u_int64_t saved_maxfilesize = fs->fs_maxfilesize;
1283 u_int8_t saveflag;
1284
1285 /* Restore compatibility to old file systems. XXX */
1286 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
1287 fs->fs_nrpos = -1; /* XXX */
1288 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
1289 int32_t *lp, tmp; /* XXX */
1290 /* XXX */
1291 lp = (int32_t *)&fs->fs_qbmask; /* XXX nuke qfmask too */
1292 tmp = lp[4]; /* XXX */
1293 for (i = 4; i > 0; i--) /* XXX */
1294 lp[i] = lp[i-1]; /* XXX */
1295 lp[0] = tmp; /* XXX */
1296 } /* XXX */
1297 fs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */
1298
1299 bp = getblk(mp->um_devvp, SBOFF >> (fs->fs_fshift - fs->fs_fsbtodb),
1300 (int)fs->fs_sbsize, 0, 0);
1301 saveflag = fs->fs_flags & FS_INTERNAL;
1302 fs->fs_flags &= ~FS_INTERNAL;
1303 memcpy(bp->b_data, fs, fs->fs_sbsize);
1304 #ifdef FFS_EI
1305 if (mp->um_flags & UFS_NEEDSWAP)
1306 ffs_sb_swap(fs, (struct fs*)bp->b_data);
1307 #endif
1308
1309 fs->fs_flags |= saveflag;
1310 fs->fs_nrpos = saved_nrpos; /* XXX */
1311 fs->fs_qbmask = saved_qbmask; /* XXX */
1312 fs->fs_qfmask = saved_qfmask; /* XXX */
1313 fs->fs_maxfilesize = saved_maxfilesize; /* XXX */
1314
1315 if (waitfor == MNT_WAIT)
1316 error = bwrite(bp);
1317 else
1318 bawrite(bp);
1319 return (error);
1320 }
1321
1322 int
1323 ffs_cgupdate(mp, waitfor)
1324 struct ufsmount *mp;
1325 int waitfor;
1326 {
1327 struct fs *fs = mp->um_fs;
1328 struct buf *bp;
1329 int blks;
1330 void *space;
1331 int i, size, error = 0, allerror = 0;
1332
1333 allerror = ffs_sbupdate(mp, waitfor);
1334 blks = howmany(fs->fs_cssize, fs->fs_fsize);
1335 space = fs->fs_csp;
1336 for (i = 0; i < blks; i += fs->fs_frag) {
1337 size = fs->fs_bsize;
1338 if (i + fs->fs_frag > blks)
1339 size = (blks - i) * fs->fs_fsize;
1340 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
1341 size, 0, 0);
1342 #ifdef FFS_EI
1343 if (mp->um_flags & UFS_NEEDSWAP)
1344 ffs_csum_swap((struct csum*)space,
1345 (struct csum*)bp->b_data, size);
1346 else
1347 #endif
1348 memcpy(bp->b_data, space, (u_int)size);
1349 space = (char *)space + size;
1350 if (waitfor == MNT_WAIT)
1351 error = bwrite(bp);
1352 else
1353 bawrite(bp);
1354 }
1355 if (!allerror && error)
1356 allerror = error;
1357 return (allerror);
1358 }
1359