123400Smckusick /* 266804Sbostic * Copyright (c) 1989, 1991, 1993, 1994 363371Sbostic * The Regents of the University of California. All rights reserved. 423400Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*69318Smckusick * @(#)ffs_vfsops.c 8.24 (Berkeley) 05/09/95 823400Smckusick */ 912795Ssam 1051473Sbostic #include <sys/param.h> 1151473Sbostic #include <sys/systm.h> 1251473Sbostic #include <sys/namei.h> 1351473Sbostic #include <sys/proc.h> 1451473Sbostic #include <sys/kernel.h> 1551473Sbostic #include <sys/vnode.h> 1655890Smckusick #include <sys/socket.h> 1751473Sbostic #include <sys/mount.h> 1851473Sbostic #include <sys/buf.h> 1954733Smckusick #include <sys/mbuf.h> 2051473Sbostic #include <sys/file.h> 2151473Sbostic #include <sys/disklabel.h> 2251473Sbostic #include <sys/ioctl.h> 2351473Sbostic #include <sys/errno.h> 2451473Sbostic #include <sys/malloc.h> 2512795Ssam 2655045Smckusick #include <miscfs/specfs/specdev.h> 2755045Smckusick 2851473Sbostic #include <ufs/ufs/quota.h> 2951473Sbostic #include <ufs/ufs/ufsmount.h> 3051473Sbostic #include <ufs/ufs/inode.h> 3151473Sbostic #include <ufs/ufs/ufs_extern.h> 3247571Skarels 3351473Sbostic #include <ufs/ffs/fs.h> 3451473Sbostic #include <ufs/ffs/ffs_extern.h> 3551473Sbostic 3651942Smckusick int ffs_sbupdate __P((struct ufsmount *, int)); 3751473Sbostic 3837737Smckusick struct vfsops ufs_vfsops = { 3951473Sbostic ffs_mount, 4039043Smckusick ufs_start, 4151473Sbostic ffs_unmount, 4266804Sbostic ufs_root, 4341314Smckusick ufs_quotactl, 4451473Sbostic ffs_statfs, 4551473Sbostic ffs_sync, 4654657Smckusick ffs_vget, 4751545Smckusick ffs_fhtovp, 4851545Smckusick ffs_vptofh, 4951473Sbostic ffs_init, 5068668Smckusick ffs_sysctl, 5137737Smckusick }; 5237737Smckusick 5354657Smckusick extern u_long nextgennumber; 5454657Smckusick 5537737Smckusick /* 5653045Sralph * Called by main() when ufs is going to be mounted as root. 5737737Smckusick * 5839336Smckusick * Name is updated by mount(8) after booting. 5937737Smckusick */ 6039297Smckusick #define ROOTNAME "root_device" 6137737Smckusick 6251473Sbostic ffs_mountroot() 6312795Ssam { 6451473Sbostic extern struct vnode *rootvp; 6551473Sbostic register struct fs *fs; 6637737Smckusick register struct mount *mp; 6748036Smckusick struct proc *p = curproc; /* XXX */ 6837737Smckusick struct ufsmount *ump; 6968668Smckusick struct vfsconf *vfsp; 7037737Smckusick u_int size; 7137737Smckusick int error; 7256332Smckusick 7356332Smckusick /* 7456332Smckusick * Get vnodes for swapdev and rootdev. 7556332Smckusick */ 7656332Smckusick if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) 7756332Smckusick panic("ffs_mountroot: can't setup bdevvp's"); 7812795Ssam 7968668Smckusick for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 8068668Smckusick if (!strcmp(vfsp->vfc_name, "ufs")) 8168668Smckusick break; 8268668Smckusick if (vfsp == NULL) 8368668Smckusick return (ENODEV); 8453045Sralph mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); 8554305Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 8668788Smckusick mp->mnt_vfc = vfsp; 8768668Smckusick mp->mnt_op = vfsp->vfc_vfsops; 8841397Smckusick mp->mnt_flag = MNT_RDONLY; 8951473Sbostic if (error = ffs_mountfs(rootvp, mp, p)) { 9051473Sbostic free(mp, M_MOUNT); 9137737Smckusick return (error); 9212795Ssam } 9339336Smckusick if (error = vfs_lock(mp)) { 9451473Sbostic (void)ffs_unmount(mp, 0, p); 9551473Sbostic free(mp, M_MOUNT); 9637737Smckusick return (error); 9721013Smckusick } 98*69318Smckusick CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 9941397Smckusick mp->mnt_vnodecovered = NULLVP; 10068668Smckusick vfsp->vfc_refcount++; 10168668Smckusick mp->mnt_stat.f_type = vfsp->vfc_typenum; 10268668Smckusick mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK) | MNT_ROOTFS; 10368668Smckusick strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 10437737Smckusick ump = VFSTOUFS(mp); 10537737Smckusick fs = ump->um_fs; 10640346Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 10737737Smckusick fs->fs_fsmnt[0] = '/'; 10841397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 10941397Smckusick MNAMELEN); 11041397Smckusick (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 11141397Smckusick &size); 11241397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 11351473Sbostic (void)ffs_statfs(mp, &mp->mnt_stat, p); 11437737Smckusick vfs_unlock(mp); 11537737Smckusick inittodr(fs->fs_time); 11637737Smckusick return (0); 11737737Smckusick } 11837737Smckusick 11937737Smckusick /* 12037737Smckusick * VFS Operations. 12137737Smckusick * 12237737Smckusick * mount system call 12337737Smckusick */ 12451942Smckusick int 12551473Sbostic ffs_mount(mp, path, data, ndp, p) 12640346Smckusick register struct mount *mp; 12737737Smckusick char *path; 12837737Smckusick caddr_t data; 12937737Smckusick struct nameidata *ndp; 13048036Smckusick struct proc *p; 13137737Smckusick { 13237737Smckusick struct vnode *devvp; 13337737Smckusick struct ufs_args args; 13437737Smckusick struct ufsmount *ump; 13537737Smckusick register struct fs *fs; 13637737Smckusick u_int size; 13757051Smckusick int error, flags; 13867534Smckusick mode_t accessmode; 13937737Smckusick 14037737Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 14137737Smckusick return (error); 14240371Smckusick /* 14350264Skarels * If updating, check whether changing from read-only to 14450264Skarels * read/write; if there is no device name, that's all we do. 14550264Skarels */ 14650264Skarels if (mp->mnt_flag & MNT_UPDATE) { 14739336Smckusick ump = VFSTOUFS(mp); 14839336Smckusick fs = ump->um_fs; 14957051Smckusick if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 15057051Smckusick flags = WRITECLOSE; 15157051Smckusick if (mp->mnt_flag & MNT_FORCE) 15257051Smckusick flags |= FORCECLOSE; 15357051Smckusick if (vfs_busy(mp)) 15457051Smckusick return (EBUSY); 155*69318Smckusick if (error = ffs_flushfiles(mp, flags, p)) { 156*69318Smckusick vfs_unbusy(mp); 157*69318Smckusick return (error); 158*69318Smckusick } 159*69318Smckusick fs->fs_clean = 1; 160*69318Smckusick fs->fs_ronly = 1; 161*69318Smckusick if (error = ffs_sbupdate(ump, MNT_WAIT)) { 162*69318Smckusick fs->fs_clean = 0; 163*69318Smckusick fs->fs_ronly = 0; 164*69318Smckusick vfs_unbusy(mp); 165*69318Smckusick return (error); 166*69318Smckusick } 16757051Smckusick vfs_unbusy(mp); 16857051Smckusick } 169*69318Smckusick if ((mp->mnt_flag & MNT_RELOAD) && 170*69318Smckusick (error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p))) 17157051Smckusick return (error); 17267534Smckusick if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { 17367534Smckusick /* 17467534Smckusick * If upgrade to read-write by non-root, then verify 17567534Smckusick * that user has necessary permissions on the device. 17667534Smckusick */ 17767534Smckusick if (p->p_ucred->cr_uid != 0) { 17867534Smckusick devvp = ump->um_devvp; 17967534Smckusick VOP_LOCK(devvp); 18067534Smckusick if (error = VOP_ACCESS(devvp, VREAD | VWRITE, 18167534Smckusick p->p_ucred, p)) { 18267534Smckusick VOP_UNLOCK(devvp); 18367534Smckusick return (error); 18467534Smckusick } 18567534Smckusick VOP_UNLOCK(devvp); 18667534Smckusick } 18739336Smckusick fs->fs_ronly = 0; 188*69318Smckusick fs->fs_clean = 0; 189*69318Smckusick (void) ffs_sbupdate(ump, MNT_WAIT); 19067534Smckusick } 19152177Smckusick if (args.fspec == 0) { 19252177Smckusick /* 19352177Smckusick * Process export requests. 19452177Smckusick */ 19565672Shibler return (vfs_export(mp, &ump->um_export, &args.export)); 19652177Smckusick } 19750264Skarels } 19850264Skarels /* 19950264Skarels * Not an update, or updating the name: look up the name 20050264Skarels * and verify that it refers to a sensible block device. 20150264Skarels */ 20252332Smckusick NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 20352332Smckusick if (error = namei(ndp)) 20450264Skarels return (error); 20550264Skarels devvp = ndp->ni_vp; 20651473Sbostic 20750264Skarels if (devvp->v_type != VBLK) { 20850264Skarels vrele(devvp); 20950264Skarels return (ENOTBLK); 21050264Skarels } 21150264Skarels if (major(devvp->v_rdev) >= nblkdev) { 21250264Skarels vrele(devvp); 21350264Skarels return (ENXIO); 21450264Skarels } 21567534Smckusick /* 21667534Smckusick * If mount by non-root, then verify that user has necessary 21767534Smckusick * permissions on the device. 21867534Smckusick */ 21967534Smckusick if (p->p_ucred->cr_uid != 0) { 22067534Smckusick accessmode = VREAD; 22167534Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0) 22267534Smckusick accessmode |= VWRITE; 22367534Smckusick VOP_LOCK(devvp); 22467534Smckusick if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) { 22567534Smckusick vput(devvp); 22667534Smckusick return (error); 22767534Smckusick } 22867534Smckusick VOP_UNLOCK(devvp); 22967534Smckusick } 23050264Skarels if ((mp->mnt_flag & MNT_UPDATE) == 0) 23151473Sbostic error = ffs_mountfs(devvp, mp, p); 23250264Skarels else { 23339336Smckusick if (devvp != ump->um_devvp) 23439336Smckusick error = EINVAL; /* needs translation */ 23542858Smckusick else 23642858Smckusick vrele(devvp); 23739336Smckusick } 23837737Smckusick if (error) { 23937737Smckusick vrele(devvp); 24037737Smckusick return (error); 24132721Smckusick } 24237737Smckusick ump = VFSTOUFS(mp); 24337737Smckusick fs = ump->um_fs; 24437737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 24537737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 24641397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 24741397Smckusick MNAMELEN); 24841397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 24941397Smckusick &size); 25041397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 25151473Sbostic (void)ffs_statfs(mp, &mp->mnt_stat, p); 25237737Smckusick return (0); 25312795Ssam } 25412795Ssam 25537737Smckusick /* 25657051Smckusick * Reload all incore data for a filesystem (used after running fsck on 25757051Smckusick * the root filesystem and finding things to fix). The filesystem must 25857051Smckusick * be mounted read-only. 25957051Smckusick * 26057051Smckusick * Things to do to update the mount: 26157051Smckusick * 1) invalidate all cached meta-data. 26257051Smckusick * 2) re-read superblock from disk. 26357051Smckusick * 3) re-read summary information from disk. 26457051Smckusick * 4) invalidate all inactive vnodes. 26557051Smckusick * 5) invalidate all cached file data. 26657051Smckusick * 6) re-read inode data for all active vnodes. 26757051Smckusick */ 26857051Smckusick ffs_reload(mountp, cred, p) 26957051Smckusick register struct mount *mountp; 27057051Smckusick struct ucred *cred; 27157051Smckusick struct proc *p; 27257051Smckusick { 27357051Smckusick register struct vnode *vp, *nvp, *devvp; 27457051Smckusick struct inode *ip; 27557051Smckusick struct csum *space; 27657051Smckusick struct buf *bp; 27768545Smckusick struct fs *fs, *newfs; 27868115Smckusick struct partinfo dpart; 27957051Smckusick int i, blks, size, error; 28069245Smckusick int32_t *lp; 28157051Smckusick 28257051Smckusick if ((mountp->mnt_flag & MNT_RDONLY) == 0) 28357051Smckusick return (EINVAL); 28457051Smckusick /* 28557051Smckusick * Step 1: invalidate all cached meta-data. 28657051Smckusick */ 28757051Smckusick devvp = VFSTOUFS(mountp)->um_devvp; 28857801Smckusick if (vinvalbuf(devvp, 0, cred, p, 0, 0)) 28957051Smckusick panic("ffs_reload: dirty1"); 29057051Smckusick /* 29157051Smckusick * Step 2: re-read superblock from disk. 29257051Smckusick */ 29368115Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 29468115Smckusick size = DEV_BSIZE; 29568115Smckusick else 29668115Smckusick size = dpart.disklab->d_secsize; 29768554Smckusick if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) 29857051Smckusick return (error); 29968545Smckusick newfs = (struct fs *)bp->b_data; 30068545Smckusick if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || 30168545Smckusick newfs->fs_bsize < sizeof(struct fs)) { 30257051Smckusick brelse(bp); 30357051Smckusick return (EIO); /* XXX needs translation */ 30457051Smckusick } 30557051Smckusick fs = VFSTOUFS(mountp)->um_fs; 30668580Smckusick /* 30768580Smckusick * Copy pointer fields back into superblock before copying in XXX 30868580Smckusick * new superblock. These should really be in the ufsmount. XXX 30968580Smckusick * Note that important parameters (eg fs_ncg) are unchanged. 31068580Smckusick */ 31168545Smckusick bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp)); 31268545Smckusick newfs->fs_maxcluster = fs->fs_maxcluster; 31368545Smckusick bcopy(newfs, fs, (u_int)fs->fs_sbsize); 31457051Smckusick if (fs->fs_sbsize < SBSIZE) 31557051Smckusick bp->b_flags |= B_INVAL; 31657051Smckusick brelse(bp); 31767460Smckusick mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 31857051Smckusick ffs_oldfscompat(fs); 31957051Smckusick /* 32057051Smckusick * Step 3: re-read summary information from disk. 32157051Smckusick */ 32257051Smckusick blks = howmany(fs->fs_cssize, fs->fs_fsize); 32357051Smckusick space = fs->fs_csp[0]; 32457051Smckusick for (i = 0; i < blks; i += fs->fs_frag) { 32557051Smckusick size = fs->fs_bsize; 32657051Smckusick if (i + fs->fs_frag > blks) 32757051Smckusick size = (blks - i) * fs->fs_fsize; 32857051Smckusick if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 32957051Smckusick NOCRED, &bp)) 33057051Smckusick return (error); 33164511Sbostic bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); 33257051Smckusick brelse(bp); 33357051Smckusick } 33468580Smckusick /* 33568580Smckusick * We no longer know anything about clusters per cylinder group. 33668580Smckusick */ 33768580Smckusick if (fs->fs_contigsumsize > 0) { 33868580Smckusick lp = fs->fs_maxcluster; 33968580Smckusick for (i = 0; i < fs->fs_ncg; i++) 34068580Smckusick *lp++ = fs->fs_contigsumsize; 34168580Smckusick } 34257051Smckusick loop: 34365236Smckusick for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 34465236Smckusick nvp = vp->v_mntvnodes.le_next; 34557051Smckusick /* 34657051Smckusick * Step 4: invalidate all inactive vnodes. 34757051Smckusick */ 34857051Smckusick if (vp->v_usecount == 0) { 34957051Smckusick vgone(vp); 35057051Smckusick continue; 35157051Smckusick } 35257051Smckusick /* 35357051Smckusick * Step 5: invalidate all cached file data. 35457051Smckusick */ 35565236Smckusick if (vget(vp, 1)) 35657051Smckusick goto loop; 35757801Smckusick if (vinvalbuf(vp, 0, cred, p, 0, 0)) 35857051Smckusick panic("ffs_reload: dirty2"); 35957051Smckusick /* 36057051Smckusick * Step 6: re-read inode data for all active vnodes. 36157051Smckusick */ 36257051Smckusick ip = VTOI(vp); 36364605Sbostic if (error = 36464605Sbostic bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 36557051Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 36657051Smckusick vput(vp); 36757051Smckusick return (error); 36857051Smckusick } 36964605Sbostic ip->i_din = *((struct dinode *)bp->b_data + 37064605Sbostic ino_to_fsbo(fs, ip->i_number)); 37157051Smckusick brelse(bp); 37257051Smckusick vput(vp); 37357051Smckusick if (vp->v_mount != mountp) 37457051Smckusick goto loop; 37557051Smckusick } 37657051Smckusick return (0); 37757051Smckusick } 37857051Smckusick 37957051Smckusick /* 38037737Smckusick * Common code for mount and mountroot 38137737Smckusick */ 38251473Sbostic int 38351473Sbostic ffs_mountfs(devvp, mp, p) 38440376Smckusick register struct vnode *devvp; 38537737Smckusick struct mount *mp; 38648036Smckusick struct proc *p; 38712795Ssam { 38854461Smckusick register struct ufsmount *ump; 38954461Smckusick struct buf *bp; 39012795Ssam register struct fs *fs; 39168004Smckusick dev_t dev; 39230749Skarels struct partinfo dpart; 39337737Smckusick caddr_t base, space; 39468115Smckusick int error, i, blks, size, ronly; 39567868Smckusick int32_t *lp; 39668004Smckusick struct ucred *cred; 39745652Smckusick extern struct vnode *rootvp; 39868115Smckusick u_int64_t maxfilesize; /* XXX */ 39912795Ssam 40068004Smckusick dev = devvp->v_rdev; 40168004Smckusick cred = p ? p->p_ucred : NOCRED; 40240376Smckusick /* 40340376Smckusick * Disallow multiple mounts of the same device. 40445652Smckusick * Disallow mounting of a device that is currently in use 40545652Smckusick * (except for root, which might share swap device for miniroot). 40640376Smckusick * Flush out any old buffers remaining from a previous use. 40740376Smckusick */ 40865672Shibler if (error = vfs_mountedon(devvp)) 40940376Smckusick return (error); 41045652Smckusick if (vcount(devvp) > 1 && devvp != rootvp) 41140376Smckusick return (EBUSY); 41268004Smckusick if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) 41354461Smckusick return (error); 41454461Smckusick 41554461Smckusick ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 41659472Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)) 41737737Smckusick return (error); 41868004Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) 41937737Smckusick size = DEV_BSIZE; 42068115Smckusick else 42130749Skarels size = dpart.disklab->d_secsize; 42254461Smckusick 42354461Smckusick bp = NULL; 42454461Smckusick ump = NULL; 42568554Smckusick if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, cred, &bp)) 42612795Ssam goto out; 42764511Sbostic fs = (struct fs *)bp->b_data; 42830749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 42930749Skarels fs->fs_bsize < sizeof(struct fs)) { 43041314Smckusick error = EINVAL; /* XXX needs translation */ 43116639Skarels goto out; 43216639Skarels } 43368116Smckusick /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ 43468116Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { 43568116Smckusick error = EROFS; /* needs translation */ 43668116Smckusick goto out; 43768116Smckusick } 43851473Sbostic ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 43952538Smckusick bzero((caddr_t)ump, sizeof *ump); 44051982Smckusick ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, 44134473Smckusick M_WAITOK); 44264511Sbostic bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); 44339675Smckusick if (fs->fs_sbsize < SBSIZE) 44439675Smckusick bp->b_flags |= B_INVAL; 44534421Skarels brelse(bp); 44634421Skarels bp = NULL; 44737737Smckusick fs = ump->um_fs; 44837737Smckusick fs->fs_ronly = ronly; 44967868Smckusick size = fs->fs_cssize; 45068116Smckusick blks = howmany(size, fs->fs_fsize); 45167868Smckusick if (fs->fs_contigsumsize > 0) 45267868Smckusick size += fs->fs_ncg * sizeof(int32_t); 45367868Smckusick base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK); 45412795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 45512795Ssam size = fs->fs_bsize; 45612795Ssam if (i + fs->fs_frag > blks) 45712795Ssam size = (blks - i) * fs->fs_fsize; 45868004Smckusick if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 45968004Smckusick cred, &bp)) { 46051982Smckusick free(base, M_UFSMNT); 46112795Ssam goto out; 46212795Ssam } 46364511Sbostic bcopy(bp->b_data, space, (u_int)size); 46417225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 46512795Ssam space += size; 46634421Skarels brelse(bp); 46734421Skarels bp = NULL; 46812795Ssam } 46967868Smckusick if (fs->fs_contigsumsize > 0) { 47067868Smckusick fs->fs_maxcluster = lp = (int32_t *)space; 47167868Smckusick for (i = 0; i < fs->fs_ncg; i++) 47267868Smckusick *lp++ = fs->fs_contigsumsize; 47367868Smckusick } 47441397Smckusick mp->mnt_data = (qaddr_t)ump; 47541397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 47668668Smckusick mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 47754305Smckusick mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 47837737Smckusick ump->um_mountp = mp; 47937737Smckusick ump->um_dev = dev; 48037737Smckusick ump->um_devvp = devvp; 48156446Smargo ump->um_nindir = fs->fs_nindir; 48256446Smargo ump->um_bptrtodb = fs->fs_fsbtodb; 48356446Smargo ump->um_seqinc = fs->fs_frag; 48441314Smckusick for (i = 0; i < MAXQUOTAS; i++) 48541314Smckusick ump->um_quotas[i] = NULLVP; 48640653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 48757051Smckusick ffs_oldfscompat(fs); 48867868Smckusick ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ 48968115Smckusick maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; /* XXX */ 49068115Smckusick if (fs->fs_maxfilesize > maxfilesize) /* XXX */ 49168115Smckusick fs->fs_maxfilesize = maxfilesize; /* XXX */ 492*69318Smckusick if (ronly == 0) { 493*69318Smckusick fs->fs_clean = 0; 494*69318Smckusick (void) ffs_sbupdate(ump, MNT_WAIT); 495*69318Smckusick } 49657051Smckusick return (0); 49757051Smckusick out: 49857051Smckusick if (bp) 49957051Smckusick brelse(bp); 50068004Smckusick (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); 50157051Smckusick if (ump) { 50257051Smckusick free(ump->um_fs, M_UFSMNT); 50357051Smckusick free(ump, M_UFSMNT); 50457051Smckusick mp->mnt_data = (qaddr_t)0; 50557051Smckusick } 50657051Smckusick return (error); 50757051Smckusick } 50837737Smckusick 50957051Smckusick /* 51057051Smckusick * Sanity checks for old file systems. 51157051Smckusick * 51257051Smckusick * XXX - goes away some day. 51357051Smckusick */ 51457051Smckusick ffs_oldfscompat(fs) 51557051Smckusick struct fs *fs; 51657051Smckusick { 51757051Smckusick int i; 51857051Smckusick 51955056Spendry fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 52055056Spendry fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 52134145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 52234145Smckusick fs->fs_nrpos = 8; /* XXX */ 52353913Smckusick if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 52468122Smckusick u_int64_t sizepb = fs->fs_bsize; /* XXX */ 52553913Smckusick /* XXX */ 52653913Smckusick fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 52753913Smckusick for (i = 0; i < NIADDR; i++) { /* XXX */ 52853913Smckusick sizepb *= NINDIR(fs); /* XXX */ 52953913Smckusick fs->fs_maxfilesize += sizepb; /* XXX */ 53053913Smckusick } /* XXX */ 53153913Smckusick fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 53253913Smckusick fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 53353913Smckusick } /* XXX */ 53437737Smckusick return (0); 53512795Ssam } 53612795Ssam 53739043Smckusick /* 53837737Smckusick * unmount system call 53937737Smckusick */ 54051473Sbostic int 54151473Sbostic ffs_unmount(mp, mntflags, p) 54237737Smckusick struct mount *mp; 54341314Smckusick int mntflags; 54448036Smckusick struct proc *p; 54512795Ssam { 54637737Smckusick register struct ufsmount *ump; 54737737Smckusick register struct fs *fs; 54867861Smckusick int error, flags; 54912795Ssam 55054461Smckusick flags = 0; 55148065Smckusick if (mntflags & MNT_FORCE) { 55265236Smckusick if (mp->mnt_flag & MNT_ROOTFS) 55348065Smckusick return (EINVAL); 55441314Smckusick flags |= FORCECLOSE; 55548065Smckusick } 55657051Smckusick if (error = ffs_flushfiles(mp, flags, p)) 55757051Smckusick return (error); 55837737Smckusick ump = VFSTOUFS(mp); 55957051Smckusick fs = ump->um_fs; 560*69318Smckusick if (fs->fs_ronly == 0) { 561*69318Smckusick fs->fs_clean = 1; 562*69318Smckusick if (error = ffs_sbupdate(ump, MNT_WAIT)) { 563*69318Smckusick fs->fs_clean = 0; 564*69318Smckusick return (error); 565*69318Smckusick } 566*69318Smckusick } 56757051Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 56867861Smckusick error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, 56957051Smckusick NOCRED, p); 57057051Smckusick vrele(ump->um_devvp); 57157051Smckusick free(fs->fs_csp[0], M_UFSMNT); 57257051Smckusick free(fs, M_UFSMNT); 57357051Smckusick free(ump, M_UFSMNT); 57457051Smckusick mp->mnt_data = (qaddr_t)0; 57557051Smckusick return (error); 57657051Smckusick } 57757051Smckusick 57857051Smckusick /* 57957051Smckusick * Flush out all the files in a filesystem. 58057051Smckusick */ 58157051Smckusick ffs_flushfiles(mp, flags, p) 58257051Smckusick register struct mount *mp; 58357051Smckusick int flags; 58457051Smckusick struct proc *p; 58557051Smckusick { 58657051Smckusick extern int doforce; 58757051Smckusick register struct ufsmount *ump; 58857051Smckusick int i, error; 58957051Smckusick 59057051Smckusick if (!doforce) 59157051Smckusick flags &= ~FORCECLOSE; 59257051Smckusick ump = VFSTOUFS(mp); 59312795Ssam #ifdef QUOTA 59441397Smckusick if (mp->mnt_flag & MNT_QUOTA) { 59541314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 59639898Smckusick return (error); 59741314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 59841314Smckusick if (ump->um_quotas[i] == NULLVP) 59941314Smckusick continue; 60050114Smckusick quotaoff(p, mp, i); 60141314Smckusick } 60239898Smckusick /* 60341314Smckusick * Here we fall through to vflush again to ensure 60441314Smckusick * that we have gotten rid of all the system vnodes. 60539898Smckusick */ 60641314Smckusick } 60712795Ssam #endif 60857051Smckusick error = vflush(mp, NULLVP, flags); 60930749Skarels return (error); 61012795Ssam } 61112795Ssam 61237737Smckusick /* 61337737Smckusick * Get file system statistics. 61437737Smckusick */ 61551473Sbostic int 61651473Sbostic ffs_statfs(mp, sbp, p) 61737737Smckusick struct mount *mp; 61837737Smckusick register struct statfs *sbp; 61948036Smckusick struct proc *p; 62037737Smckusick { 62137737Smckusick register struct ufsmount *ump; 62237737Smckusick register struct fs *fs; 62337737Smckusick 62437737Smckusick ump = VFSTOUFS(mp); 62537737Smckusick fs = ump->um_fs; 62637737Smckusick if (fs->fs_magic != FS_MAGIC) 62751473Sbostic panic("ffs_statfs"); 62851942Smckusick sbp->f_bsize = fs->fs_fsize; 62951942Smckusick sbp->f_iosize = fs->fs_bsize; 63037737Smckusick sbp->f_blocks = fs->fs_dsize; 63137737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 63237737Smckusick fs->fs_cstotal.cs_nffree; 63337737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 63437737Smckusick (fs->fs_dsize - sbp->f_bfree); 63539350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 63637737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 63741397Smckusick if (sbp != &mp->mnt_stat) { 63868668Smckusick sbp->f_type = mp->mnt_vfc->vfc_typenum; 63941397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 64040346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 64141397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 64240346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 64340346Smckusick } 64437737Smckusick return (0); 64537737Smckusick } 64637737Smckusick 64737737Smckusick /* 64837737Smckusick * Go through the disk queues to initiate sandbagged IO; 64937737Smckusick * go through the inodes to write those that have been modified; 65037737Smckusick * initiate the writing of the super block if it has been modified. 65141314Smckusick * 65241314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 65337737Smckusick */ 65451473Sbostic int 65554461Smckusick ffs_sync(mp, waitfor, cred, p) 65637737Smckusick struct mount *mp; 65737737Smckusick int waitfor; 65854461Smckusick struct ucred *cred; 65954461Smckusick struct proc *p; 66037737Smckusick { 66139390Smckusick register struct vnode *vp; 66237737Smckusick register struct inode *ip; 66337737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 66437737Smckusick register struct fs *fs; 66539596Smckusick int error, allerror = 0; 66637737Smckusick 66737737Smckusick fs = ump->um_fs; 668*69318Smckusick if (fs->fs_ronly != 0) { /* XXX */ 669*69318Smckusick printf("fs = %s\n", fs->fs_fsmnt); 670*69318Smckusick panic("update: rofs mod"); 67137737Smckusick } 67237737Smckusick /* 67337737Smckusick * Write back each (modified) inode. 67437737Smckusick */ 67539877Smckusick loop: 67665236Smckusick for (vp = mp->mnt_vnodelist.lh_first; 67765236Smckusick vp != NULL; 67865236Smckusick vp = vp->v_mntvnodes.le_next) { 67941462Smckusick /* 68041462Smckusick * If the vnode that we are about to sync is no longer 68141462Smckusick * associated with this mount point, start over. 68241462Smckusick */ 68341462Smckusick if (vp->v_mount != mp) 68441462Smckusick goto loop; 68548359Smckusick if (VOP_ISLOCKED(vp)) 68648359Smckusick continue; 68739390Smckusick ip = VTOI(vp); 68864511Sbostic if ((ip->i_flag & 68964605Sbostic (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && 69065236Smckusick vp->v_dirtyblkhd.lh_first == NULL) 69137737Smckusick continue; 69265236Smckusick if (vget(vp, 1)) 69339877Smckusick goto loop; 69454461Smckusick if (error = VOP_FSYNC(vp, cred, waitfor, p)) 69539596Smckusick allerror = error; 69639596Smckusick vput(vp); 69737737Smckusick } 69837737Smckusick /* 69939675Smckusick * Force stale file system control information to be flushed. 70037737Smckusick */ 70154461Smckusick if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) 70254461Smckusick allerror = error; 70341314Smckusick #ifdef QUOTA 70441314Smckusick qsync(mp); 70541314Smckusick #endif 706*69318Smckusick /* 707*69318Smckusick * Write back modified superblock. 708*69318Smckusick */ 709*69318Smckusick if (fs->fs_fmod != 0) { 710*69318Smckusick fs->fs_fmod = 0; 711*69318Smckusick fs->fs_time = time.tv_sec; 712*69318Smckusick if (error = ffs_sbupdate(ump, waitfor)) 713*69318Smckusick allerror = error; 714*69318Smckusick } 71539596Smckusick return (allerror); 71637737Smckusick } 71737737Smckusick 71837737Smckusick /* 71964605Sbostic * Look up a FFS dinode number to find its incore vnode, otherwise read it 72064605Sbostic * in from disk. If it is in core, wait for the lock bit to clear, then 72164605Sbostic * return the inode locked. Detection and handling of mount points must be 72264605Sbostic * done by the calling routine. 72354657Smckusick */ 72454657Smckusick int 72554657Smckusick ffs_vget(mp, ino, vpp) 72654657Smckusick struct mount *mp; 72754657Smckusick ino_t ino; 72854657Smckusick struct vnode **vpp; 72954657Smckusick { 73054657Smckusick register struct fs *fs; 73154657Smckusick register struct inode *ip; 73254657Smckusick struct ufsmount *ump; 73354657Smckusick struct buf *bp; 73454657Smckusick struct vnode *vp; 73554657Smckusick dev_t dev; 73654657Smckusick int i, type, error; 73754657Smckusick 73854657Smckusick ump = VFSTOUFS(mp); 73954657Smckusick dev = ump->um_dev; 74054657Smckusick if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 74154657Smckusick return (0); 74254657Smckusick 74354657Smckusick /* Allocate a new vnode/inode. */ 74454657Smckusick if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) { 74554657Smckusick *vpp = NULL; 74654657Smckusick return (error); 74754657Smckusick } 74854657Smckusick type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ 74954657Smckusick MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); 75059819Smckusick bzero((caddr_t)ip, sizeof(struct inode)); 75154657Smckusick vp->v_data = ip; 75254657Smckusick ip->i_vnode = vp; 75354657Smckusick ip->i_fs = fs = ump->um_fs; 75454657Smckusick ip->i_dev = dev; 75554657Smckusick ip->i_number = ino; 75654657Smckusick #ifdef QUOTA 75754657Smckusick for (i = 0; i < MAXQUOTAS; i++) 75854657Smckusick ip->i_dquot[i] = NODQUOT; 75954657Smckusick #endif 76054657Smckusick /* 76154657Smckusick * Put it onto its hash chain and lock it so that other requests for 76254657Smckusick * this inode will block if they arrive while we are sleeping waiting 76354657Smckusick * for old data structures to be purged or for the contents of the 76454657Smckusick * disk portion of this inode to be read. 76554657Smckusick */ 76654657Smckusick ufs_ihashins(ip); 76754657Smckusick 76854657Smckusick /* Read in the disk contents for the inode, copy into the inode. */ 76964605Sbostic if (error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 77054657Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 77154657Smckusick /* 77254657Smckusick * The inode does not contain anything useful, so it would 77359819Smckusick * be misleading to leave it on its hash chain. With mode 77459819Smckusick * still zero, it will be unlinked and returned to the free 77559819Smckusick * list by vput(). 77654657Smckusick */ 77756797Smckusick vput(vp); 77854657Smckusick brelse(bp); 77954657Smckusick *vpp = NULL; 78054657Smckusick return (error); 78154657Smckusick } 78264605Sbostic ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 78354657Smckusick brelse(bp); 78454657Smckusick 78554657Smckusick /* 78654657Smckusick * Initialize the vnode from the inode, check for aliases. 78754657Smckusick * Note that the underlying vnode may have changed. 78854657Smckusick */ 78954657Smckusick if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) { 79056797Smckusick vput(vp); 79154657Smckusick *vpp = NULL; 79254657Smckusick return (error); 79354657Smckusick } 79454657Smckusick /* 79554657Smckusick * Finish inode initialization now that aliasing has been resolved. 79654657Smckusick */ 79754657Smckusick ip->i_devvp = ump->um_devvp; 79854657Smckusick VREF(ip->i_devvp); 79954657Smckusick /* 80054657Smckusick * Set up a generation number for this inode if it does not 80154657Smckusick * already have one. This should only happen on old filesystems. 80254657Smckusick */ 80354657Smckusick if (ip->i_gen == 0) { 80454657Smckusick if (++nextgennumber < (u_long)time.tv_sec) 80554657Smckusick nextgennumber = time.tv_sec; 80654657Smckusick ip->i_gen = nextgennumber; 80754657Smckusick if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 80864605Sbostic ip->i_flag |= IN_MODIFIED; 80954657Smckusick } 81054657Smckusick /* 81154657Smckusick * Ensure that uid and gid are correct. This is a temporary 81254657Smckusick * fix until fsck has been changed to do the update. 81354657Smckusick */ 81454657Smckusick if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 81554657Smckusick ip->i_uid = ip->i_din.di_ouid; /* XXX */ 81654657Smckusick ip->i_gid = ip->i_din.di_ogid; /* XXX */ 81754657Smckusick } /* XXX */ 81854657Smckusick 81954657Smckusick *vpp = vp; 82054657Smckusick return (0); 82154657Smckusick } 82254657Smckusick 82354657Smckusick /* 82451545Smckusick * File handle to vnode 82551545Smckusick * 82651545Smckusick * Have to be really careful about stale file handles: 82751545Smckusick * - check that the inode number is valid 82851545Smckusick * - call ffs_vget() to get the locked inode 82951545Smckusick * - check for an unallocated inode (i_mode == 0) 83054733Smckusick * - check that the given client host has export rights and return 83154733Smckusick * those rights via. exflagsp and credanonp 83251545Smckusick */ 83351545Smckusick int 83454733Smckusick ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 83551545Smckusick register struct mount *mp; 83651545Smckusick struct fid *fhp; 83754733Smckusick struct mbuf *nam; 83851545Smckusick struct vnode **vpp; 83954733Smckusick int *exflagsp; 84054733Smckusick struct ucred **credanonp; 84151545Smckusick { 84251545Smckusick register struct ufid *ufhp; 84351545Smckusick struct fs *fs; 84451545Smckusick 84551545Smckusick ufhp = (struct ufid *)fhp; 84655890Smckusick fs = VFSTOUFS(mp)->um_fs; 84751545Smckusick if (ufhp->ufid_ino < ROOTINO || 84851545Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) 84954733Smckusick return (ESTALE); 85056245Smckusick return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); 85151545Smckusick } 85251545Smckusick 85351545Smckusick /* 85451545Smckusick * Vnode pointer to File handle 85551545Smckusick */ 85651545Smckusick /* ARGSUSED */ 85751545Smckusick ffs_vptofh(vp, fhp) 85851545Smckusick struct vnode *vp; 85951545Smckusick struct fid *fhp; 86051545Smckusick { 86151545Smckusick register struct inode *ip; 86251545Smckusick register struct ufid *ufhp; 86351545Smckusick 86451545Smckusick ip = VTOI(vp); 86551545Smckusick ufhp = (struct ufid *)fhp; 86651545Smckusick ufhp->ufid_len = sizeof(struct ufid); 86751545Smckusick ufhp->ufid_ino = ip->i_number; 86851545Smckusick ufhp->ufid_gen = ip->i_gen; 86951545Smckusick return (0); 87051545Smckusick } 87151545Smckusick 87251545Smckusick /* 87368668Smckusick * Initialize the filesystem; just use ufs_init. 87468668Smckusick */ 87568668Smckusick int 87668668Smckusick ffs_init(vfsp) 87768668Smckusick struct vfsconf *vfsp; 87868668Smckusick { 87968668Smckusick 88068668Smckusick return (ufs_init(vfsp)); 88168668Smckusick } 88268668Smckusick 88368668Smckusick /* 88468668Smckusick * fast filesystem related variables. 88568668Smckusick */ 88668668Smckusick ffs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 88768668Smckusick int *name; 88868668Smckusick u_int namelen; 88968668Smckusick void *oldp; 89068668Smckusick size_t *oldlenp; 89168668Smckusick void *newp; 89268668Smckusick size_t newlen; 89368668Smckusick struct proc *p; 89468668Smckusick { 89568668Smckusick extern int doclusterread, doclusterwrite, doreallocblks, doasyncfree; 89668668Smckusick 89768668Smckusick /* all sysctl names at this level are terminal */ 89868668Smckusick if (namelen != 1) 89968668Smckusick return (ENOTDIR); /* overloaded */ 90068668Smckusick 90168668Smckusick switch (name[0]) { 90268668Smckusick case FFS_CLUSTERREAD: 90368668Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, 90468668Smckusick &doclusterread)); 90568668Smckusick case FFS_CLUSTERWRITE: 90668668Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, 90768668Smckusick &doclusterwrite)); 90868668Smckusick case FFS_REALLOCBLKS: 90968668Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, 91068668Smckusick &doreallocblks)); 91168668Smckusick case FFS_ASYNCFREE: 91268668Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, &doasyncfree)); 91368668Smckusick default: 91468668Smckusick return (EOPNOTSUPP); 91568668Smckusick } 91668668Smckusick /* NOTREACHED */ 91768668Smckusick } 91868668Smckusick 91968668Smckusick /* 92037737Smckusick * Write a superblock and associated information back to disk. 92137737Smckusick */ 92251942Smckusick int 92351473Sbostic ffs_sbupdate(mp, waitfor) 92437737Smckusick struct ufsmount *mp; 92537737Smckusick int waitfor; 92637737Smckusick { 92767868Smckusick register struct fs *dfs, *fs = mp->um_fs; 92812795Ssam register struct buf *bp; 92912795Ssam int blks; 93012795Ssam caddr_t space; 931*69318Smckusick int i, size, error, allerror = 0; 93212795Ssam 933*69318Smckusick /* 934*69318Smckusick * First write back the summary information. 935*69318Smckusick */ 936*69318Smckusick blks = howmany(fs->fs_cssize, fs->fs_fsize); 937*69318Smckusick space = (caddr_t)fs->fs_csp[0]; 938*69318Smckusick for (i = 0; i < blks; i += fs->fs_frag) { 939*69318Smckusick size = fs->fs_bsize; 940*69318Smckusick if (i + fs->fs_frag > blks) 941*69318Smckusick size = (blks - i) * fs->fs_fsize; 942*69318Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), 943*69318Smckusick size, 0, 0); 944*69318Smckusick bcopy(space, bp->b_data, (u_int)size); 945*69318Smckusick space += size; 946*69318Smckusick if (waitfor != MNT_WAIT) 947*69318Smckusick bawrite(bp); 948*69318Smckusick else if (error = bwrite(bp)) 949*69318Smckusick allerror = error; 950*69318Smckusick } 951*69318Smckusick /* 952*69318Smckusick * Now write back the superblock itself. If any errors occurred 953*69318Smckusick * up to this point, then fail so that the superblock avoids 954*69318Smckusick * being written out as clean. 955*69318Smckusick */ 956*69318Smckusick if (allerror) 957*69318Smckusick return (allerror); 95857801Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); 95964511Sbostic bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); 96034145Smckusick /* Restore compatibility to old file systems. XXX */ 96167868Smckusick dfs = (struct fs *)bp->b_data; /* XXX */ 96234145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 96367868Smckusick dfs->fs_nrpos = -1; /* XXX */ 96467397Smkm if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 96568122Smckusick int32_t *lp, tmp; /* XXX */ 96667397Smkm /* XXX */ 96768122Smckusick lp = (int32_t *)&dfs->fs_qbmask; /* XXX */ 96867397Smkm tmp = lp[4]; /* XXX */ 96967397Smkm for (i = 4; i > 0; i--) /* XXX */ 97067397Smkm lp[i] = lp[i-1]; /* XXX */ 97167397Smkm lp[0] = tmp; /* XXX */ 97267397Smkm } /* XXX */ 97367868Smckusick dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ 974*69318Smckusick if (waitfor != MNT_WAIT) 97537737Smckusick bawrite(bp); 976*69318Smckusick else if (error = bwrite(bp)) 977*69318Smckusick allerror = error; 978*69318Smckusick return (allerror); 97912795Ssam } 980