diff options
Diffstat (limited to 'sys/ufs/ffs/ffs_vfsops.c')
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 404 |
1 files changed, 276 insertions, 128 deletions
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 505dd5d..1fd5951 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94 + * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 */ #include <sys/param.h> @@ -73,22 +73,19 @@ struct vfsops ufs_vfsops = { ffs_fhtovp, ffs_vptofh, ffs_init, + ffs_sysctl, }; extern u_long nextgennumber; /* * Called by main() when ufs is going to be mounted as root. - * - * Name is updated by mount(8) after booting. */ -#define ROOTNAME "root_device" - ffs_mountroot() { extern struct vnode *rootvp; - register struct fs *fs; - register struct mount *mp; + struct fs *fs; + struct mount *mp; struct proc *p = curproc; /* XXX */ struct ufsmount *ump; u_int size; @@ -97,36 +94,27 @@ ffs_mountroot() /* * Get vnodes for swapdev and rootdev. */ - if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) - panic("ffs_mountroot: can't setup bdevvp's"); - - mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); - bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = &ufs_vfsops; - mp->mnt_flag = MNT_RDONLY; - if (error = ffs_mountfs(rootvp, mp, p)) { - free(mp, M_MOUNT); + if ((error = bdevvp(swapdev, &swapdev_vp)) || + (error = bdevvp(rootdev, &rootvp))) { + printf("ffs_mountroot: can't setup bdevvp's"); return (error); } - if (error = vfs_lock(mp)) { - (void)ffs_unmount(mp, 0, p); + if (error = vfs_rootmountalloc("ufs", "root_device", &mp)) + return (error); + if (error = ffs_mountfs(rootvp, mp, p)) { + mp->mnt_vfc->vfc_refcount--; + vfs_unbusy(mp, p); free(mp, M_MOUNT); return (error); } - TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); - mp->mnt_flag |= MNT_ROOTFS; - mp->mnt_vnodecovered = NULLVP; + simple_lock(&mountlist_slock); + CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); + simple_unlock(&mountlist_slock); ump = VFSTOUFS(mp); fs = ump->um_fs; - bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); - fs->fs_fsmnt[0] = '/'; - bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, - MNAMELEN); - (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, - &size); - bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); + (void) copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0); (void)ffs_statfs(mp, &mp->mnt_stat, p); - vfs_unlock(mp); + vfs_unbusy(mp, p); inittodr(fs->fs_time); return (0); } @@ -150,6 +138,7 @@ ffs_mount(mp, path, data, ndp, p) register struct fs *fs; u_int size; int error, flags; + mode_t accessmode; if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) return (error); @@ -160,22 +149,42 @@ ffs_mount(mp, path, data, ndp, p) if (mp->mnt_flag & MNT_UPDATE) { ump = VFSTOUFS(mp); fs = ump->um_fs; - error = 0; if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; - if (vfs_busy(mp)) - return (EBUSY); - error = ffs_flushfiles(mp, flags, p); - vfs_unbusy(mp); + if (error = ffs_flushfiles(mp, flags, p)) + return (error); + fs->fs_clean = 1; + fs->fs_ronly = 1; + if (error = ffs_sbupdate(ump, MNT_WAIT)) { + fs->fs_clean = 0; + fs->fs_ronly = 0; + return (error); + } } - if (!error && (mp->mnt_flag & MNT_RELOAD)) - error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); - if (error) + if ((mp->mnt_flag & MNT_RELOAD) && + (error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p))) return (error); - if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) + if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { + /* + * If upgrade to read-write by non-root, then verify + * that user has necessary permissions on the device. + */ + if (p->p_ucred->cr_uid != 0) { + devvp = ump->um_devvp; + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); + if (error = VOP_ACCESS(devvp, VREAD | VWRITE, + p->p_ucred, p)) { + VOP_UNLOCK(devvp, 0, p); + return (error); + } + VOP_UNLOCK(devvp, 0, p); + } fs->fs_ronly = 0; + fs->fs_clean = 0; + (void) ffs_sbupdate(ump, MNT_WAIT); + } if (args.fspec == 0) { /* * Process export requests. @@ -200,6 +209,21 @@ ffs_mount(mp, path, data, ndp, p) vrele(devvp); return (ENXIO); } + /* + * If mount by non-root, then verify that user has necessary + * permissions on the device. + */ + if (p->p_ucred->cr_uid != 0) { + accessmode = VREAD; + if ((mp->mnt_flag & MNT_RDONLY) == 0) + accessmode |= VWRITE; + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); + if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) { + vput(devvp); + return (error); + } + VOP_UNLOCK(devvp, 0, p); + } if ((mp->mnt_flag & MNT_UPDATE) == 0) error = ffs_mountfs(devvp, mp, p); else { @@ -247,8 +271,10 @@ ffs_reload(mountp, cred, p) struct inode *ip; struct csum *space; struct buf *bp; - struct fs *fs; + struct fs *fs, *newfs; + struct partinfo dpart; int i, blks, size, error; + int32_t *lp; if ((mountp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); @@ -261,21 +287,31 @@ ffs_reload(mountp, cred, p) /* * Step 2: re-read superblock from disk. */ - if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) + if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) + size = DEV_BSIZE; + else + size = dpart.disklab->d_secsize; + if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) return (error); - fs = (struct fs *)bp->b_data; - if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || - fs->fs_bsize < sizeof(struct fs)) { + newfs = (struct fs *)bp->b_data; + if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || + newfs->fs_bsize < sizeof(struct fs)) { brelse(bp); return (EIO); /* XXX needs translation */ } fs = VFSTOUFS(mountp)->um_fs; - bcopy(&fs->fs_csp[0], &((struct fs *)bp->b_data)->fs_csp[0], - sizeof(fs->fs_csp)); - bcopy(bp->b_data, fs, (u_int)fs->fs_sbsize); + /* + * Copy pointer fields back into superblock before copying in XXX + * new superblock. These should really be in the ufsmount. XXX + * Note that important parameters (eg fs_ncg) are unchanged. + */ + bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp)); + newfs->fs_maxcluster = fs->fs_maxcluster; + bcopy(newfs, fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; brelse(bp); + mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; ffs_oldfscompat(fs); /* * Step 3: re-read summary information from disk. @@ -292,21 +328,36 @@ ffs_reload(mountp, cred, p) bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); brelse(bp); } + /* + * We no longer know anything about clusters per cylinder group. + */ + if (fs->fs_contigsumsize > 0) { + lp = fs->fs_maxcluster; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + } + loop: + simple_lock(&mntvnode_slock); for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { + if (vp->v_mount != mountp) { + simple_unlock(&mntvnode_slock); + goto loop; + } nvp = vp->v_mntvnodes.le_next; /* * Step 4: invalidate all inactive vnodes. */ - if (vp->v_usecount == 0) { - vgone(vp); - continue; - } + if (vrecycle(vp, &mntvnode_slock, p)) + goto loop; /* * Step 5: invalidate all cached file data. */ - if (vget(vp, 1)) + simple_lock(&vp->v_interlock); + simple_unlock(&mntvnode_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { goto loop; + } if (vinvalbuf(vp, 0, cred, p, 0, 0)) panic("ffs_reload: dirty2"); /* @@ -323,9 +374,9 @@ loop: ino_to_fsbo(fs, ip->i_number)); brelse(bp); vput(vp); - if (vp->v_mount != mountp) - goto loop; + simple_lock(&mntvnode_slock); } + simple_unlock(&mntvnode_slock); return (0); } @@ -341,14 +392,17 @@ ffs_mountfs(devvp, mp, p) register struct ufsmount *ump; struct buf *bp; register struct fs *fs; - dev_t dev = devvp->v_rdev; + dev_t dev; struct partinfo dpart; caddr_t base, space; - int havepart = 0, blks; - int error, i, size; - int ronly; + int error, i, blks, size, ronly; + int32_t *lp; + struct ucred *cred; extern struct vnode *rootvp; + u_int64_t maxfilesize; /* XXX */ + dev = devvp->v_rdev; + cred = p ? p->p_ucred : NOCRED; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use @@ -359,22 +413,20 @@ ffs_mountfs(devvp, mp, p) return (error); if (vcount(devvp) > 1 && devvp != rootvp) return (EBUSY); - if (error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)) + if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)) return (error); - if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) + if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) size = DEV_BSIZE; - else { - havepart = 1; + else size = dpart.disklab->d_secsize; - } bp = NULL; ump = NULL; - if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) + if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, cred, &bp)) goto out; fs = (struct fs *)bp->b_data; if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || @@ -382,6 +434,11 @@ ffs_mountfs(devvp, mp, p) error = EINVAL; /* XXX needs translation */ goto out; } + /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ + if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { + error = EROFS; /* needs translation */ + goto out; + } ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); bzero((caddr_t)ump, sizeof *ump); ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, @@ -393,18 +450,17 @@ ffs_mountfs(devvp, mp, p) bp = NULL; fs = ump->um_fs; fs->fs_ronly = ronly; - if (ronly == 0) - fs->fs_fmod = 1; - blks = howmany(fs->fs_cssize, fs->fs_fsize); - base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT, - M_WAITOK); + size = fs->fs_cssize; + blks = howmany(size, fs->fs_fsize); + if (fs->fs_contigsumsize > 0) + size += fs->fs_ncg * sizeof(int32_t); + base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK); for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; - error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, - NOCRED, &bp); - if (error) { + if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, + cred, &bp)) { free(base, M_UFSMNT); goto out; } @@ -414,11 +470,15 @@ ffs_mountfs(devvp, mp, p) brelse(bp); bp = NULL; } + if (fs->fs_contigsumsize > 0) { + fs->fs_maxcluster = lp = (int32_t *)space; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + } mp->mnt_data = (qaddr_t)ump; mp->mnt_stat.f_fsid.val[0] = (long)dev; - mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; + mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; - mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; @@ -429,11 +489,19 @@ ffs_mountfs(devvp, mp, p) ump->um_quotas[i] = NULLVP; devvp->v_specflags |= SI_MOUNTEDON; ffs_oldfscompat(fs); + ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ + maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; /* XXX */ + if (fs->fs_maxfilesize > maxfilesize) /* XXX */ + fs->fs_maxfilesize = maxfilesize; /* XXX */ + if (ronly == 0) { + fs->fs_clean = 0; + (void) ffs_sbupdate(ump, MNT_WAIT); + } return (0); out: if (bp) brelse(bp); - (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); + (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); if (ump) { free(ump->um_fs, M_UFSMNT); free(ump, M_UFSMNT); @@ -457,7 +525,7 @@ ffs_oldfscompat(fs) if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ fs->fs_nrpos = 8; /* XXX */ if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ - quad_t sizepb = fs->fs_bsize; /* XXX */ + u_int64_t sizepb = fs->fs_bsize; /* XXX */ /* XXX */ fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ for (i = 0; i < NIADDR; i++) { /* XXX */ @@ -481,28 +549,30 @@ ffs_unmount(mp, mntflags, p) { register struct ufsmount *ump; register struct fs *fs; - int error, flags, ronly; + int error, flags; flags = 0; - if (mntflags & MNT_FORCE) { - if (mp->mnt_flag & MNT_ROOTFS) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } if (error = ffs_flushfiles(mp, flags, p)) return (error); ump = VFSTOUFS(mp); fs = ump->um_fs; - ronly = !fs->fs_ronly; + if (fs->fs_ronly == 0) { + fs->fs_clean = 1; + if (error = ffs_sbupdate(ump, MNT_WAIT)) { + fs->fs_clean = 0; + return (error); + } + } ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; - error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, + error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, NOCRED, p); vrele(ump->um_devvp); free(fs->fs_csp[0], M_UFSMNT); free(fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; - mp->mnt_flag &= ~MNT_LOCAL; return (error); } @@ -514,12 +584,9 @@ ffs_flushfiles(mp, flags, p) int flags; struct proc *p; { - extern int doforce; register struct ufsmount *ump; int i, error; - if (!doforce) - flags &= ~FORCECLOSE; ump = VFSTOUFS(mp); #ifdef QUOTA if (mp->mnt_flag & MNT_QUOTA) { @@ -556,7 +623,6 @@ ffs_statfs(mp, sbp, p) fs = ump->um_fs; if (fs->fs_magic != FS_MAGIC) panic("ffs_statfs"); - sbp->f_type = MOUNT_UFS; sbp->f_bsize = fs->fs_fsize; sbp->f_iosize = fs->fs_bsize; sbp->f_blocks = fs->fs_dsize; @@ -567,6 +633,7 @@ ffs_statfs(mp, sbp, p) sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; sbp->f_ffree = fs->fs_cstotal.cs_nifree; if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy((caddr_t)mp->mnt_stat.f_mntonname, (caddr_t)&sbp->f_mntonname[0], MNAMELEN); bcopy((caddr_t)mp->mnt_stat.f_mntfromname, @@ -589,53 +656,55 @@ ffs_sync(mp, waitfor, cred, p) struct ucred *cred; struct proc *p; { - register struct vnode *vp; - register struct inode *ip; - register struct ufsmount *ump = VFSTOUFS(mp); - register struct fs *fs; + struct vnode *nvp, *vp; + struct inode *ip; + struct ufsmount *ump = VFSTOUFS(mp); + struct fs *fs; int error, allerror = 0; fs = ump->um_fs; - /* - * Write back modified superblock. - * Consistency check that the superblock - * is still in the buffer cache. - */ - if (fs->fs_fmod != 0) { - if (fs->fs_ronly != 0) { /* XXX */ - printf("fs = %s\n", fs->fs_fsmnt); - panic("update: rofs mod"); - } - fs->fs_fmod = 0; - fs->fs_time = time.tv_sec; - allerror = ffs_sbupdate(ump, waitfor); + if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ + printf("fs = %s\n", fs->fs_fsmnt); + panic("update: rofs mod"); } /* * Write back each (modified) inode. */ + simple_lock(&mntvnode_slock); loop: for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; - vp = vp->v_mntvnodes.le_next) { + vp = nvp) { /* * If the vnode that we are about to sync is no longer * associated with this mount point, start over. */ if (vp->v_mount != mp) goto loop; - if (VOP_ISLOCKED(vp)) - continue; + simple_lock(&vp->v_interlock); + nvp = vp->v_mntvnodes.le_next; ip = VTOI(vp); if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && - vp->v_dirtyblkhd.lh_first == NULL) + vp->v_dirtyblkhd.lh_first == NULL) { + simple_unlock(&vp->v_interlock); continue; - if (vget(vp, 1)) - goto loop; + } + simple_unlock(&mntvnode_slock); + error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); + if (error) { + simple_lock(&mntvnode_slock); + if (error == ENOENT) + goto loop; + continue; + } if (error = VOP_FSYNC(vp, cred, waitfor, p)) allerror = error; - vput(vp); + VOP_UNLOCK(vp, 0, p); + vrele(vp); + simple_lock(&mntvnode_slock); } + simple_unlock(&mntvnode_slock); /* * Force stale file system control information to be flushed. */ @@ -644,6 +713,15 @@ loop: #ifdef QUOTA qsync(mp); #endif + /* + * Write back modified superblock. + */ + if (fs->fs_fmod != 0) { + fs->fs_fmod = 0; + fs->fs_time = time.tv_sec; + if (error = ffs_sbupdate(ump, waitfor)) + allerror = error; + } return (allerror); } @@ -659,8 +737,9 @@ ffs_vget(mp, ino, vpp) ino_t ino; struct vnode **vpp; { - register struct fs *fs; - register struct inode *ip; + struct proc *p = curproc; /* XXX */ + struct fs *fs; + struct inode *ip; struct ufsmount *ump; struct buf *bp; struct vnode *vp; @@ -680,6 +759,7 @@ ffs_vget(mp, ino, vpp) type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); bzero((caddr_t)ip, sizeof(struct inode)); + lockinit(&ip->i_lock, PINOD, "inode", 0, 0); vp->v_data = ip; ip->i_vnode = vp; ip->i_fs = fs = ump->um_fs; @@ -802,6 +882,53 @@ ffs_vptofh(vp, fhp) } /* + * Initialize the filesystem; just use ufs_init. + */ +int +ffs_init(vfsp) + struct vfsconf *vfsp; +{ + + return (ufs_init(vfsp)); +} + +/* + * fast filesystem related variables. + */ +ffs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + struct proc *p; +{ + extern int doclusterread, doclusterwrite, doreallocblks, doasyncfree; + + /* all sysctl names at this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { + case FFS_CLUSTERREAD: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &doclusterread)); + case FFS_CLUSTERWRITE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &doclusterwrite)); + case FFS_REALLOCBLKS: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &doreallocblks)); + case FFS_ASYNCFREE: + return (sysctl_int(oldp, oldlenp, newp, newlen, &doasyncfree)); + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ +} + +/* * Write a superblock and associated information back to disk. */ int @@ -809,21 +936,15 @@ ffs_sbupdate(mp, waitfor) struct ufsmount *mp; int waitfor; { - register struct fs *fs = mp->um_fs; + register struct fs *dfs, *fs = mp->um_fs; register struct buf *bp; int blks; caddr_t space; - int i, size, error = 0; + int i, size, error, allerror = 0; - bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); - bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); - /* Restore compatibility to old file systems. XXX */ - if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ - ((struct fs *)bp->b_data)->fs_nrpos = -1; /* XXX */ - if (waitfor == MNT_WAIT) - error = bwrite(bp); - else - bawrite(bp); + /* + * First write back the summary information. + */ blks = howmany(fs->fs_cssize, fs->fs_fsize); space = (caddr_t)fs->fs_csp[0]; for (i = 0; i < blks; i += fs->fs_frag) { @@ -834,10 +955,37 @@ ffs_sbupdate(mp, waitfor) size, 0, 0); bcopy(space, bp->b_data, (u_int)size); space += size; - if (waitfor == MNT_WAIT) - error = bwrite(bp); - else + if (waitfor != MNT_WAIT) bawrite(bp); + else if (error = bwrite(bp)) + allerror = error; } - return (error); + /* + * Now write back the superblock itself. If any errors occurred + * up to this point, then fail so that the superblock avoids + * being written out as clean. + */ + if (allerror) + return (allerror); + bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); + bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); + /* Restore compatibility to old file systems. XXX */ + dfs = (struct fs *)bp->b_data; /* XXX */ + if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ + dfs->fs_nrpos = -1; /* XXX */ + if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ + int32_t *lp, tmp; /* XXX */ + /* XXX */ + lp = (int32_t *)&dfs->fs_qbmask; /* XXX */ + tmp = lp[4]; /* XXX */ + for (i = 4; i > 0; i--) /* XXX */ + lp[i] = lp[i-1]; /* XXX */ + lp[0] = tmp; /* XXX */ + } /* XXX */ + dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ + if (waitfor != MNT_WAIT) + bawrite(bp); + else if (error = bwrite(bp)) + allerror = error; + return (allerror); } |