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