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*69245Smckusick * @(#)ffs_vfsops.c 8.23 (Berkeley) 05/04/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 } 9865236Smckusick TAILQ_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 error = 0; 15057051Smckusick if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 15157051Smckusick flags = WRITECLOSE; 15257051Smckusick if (mp->mnt_flag & MNT_FORCE) 15357051Smckusick flags |= FORCECLOSE; 15457051Smckusick if (vfs_busy(mp)) 15557051Smckusick return (EBUSY); 15657051Smckusick error = ffs_flushfiles(mp, flags, p); 15757051Smckusick vfs_unbusy(mp); 15857051Smckusick } 15957051Smckusick if (!error && (mp->mnt_flag & MNT_RELOAD)) 16057051Smckusick error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); 16157051Smckusick if (error) 16257051Smckusick return (error); 16367534Smckusick if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { 16467534Smckusick /* 16567534Smckusick * If upgrade to read-write by non-root, then verify 16667534Smckusick * that user has necessary permissions on the device. 16767534Smckusick */ 16867534Smckusick if (p->p_ucred->cr_uid != 0) { 16967534Smckusick devvp = ump->um_devvp; 17067534Smckusick VOP_LOCK(devvp); 17167534Smckusick if (error = VOP_ACCESS(devvp, VREAD | VWRITE, 17267534Smckusick p->p_ucred, p)) { 17367534Smckusick VOP_UNLOCK(devvp); 17467534Smckusick return (error); 17567534Smckusick } 17667534Smckusick VOP_UNLOCK(devvp); 17767534Smckusick } 17839336Smckusick fs->fs_ronly = 0; 17967534Smckusick } 18052177Smckusick if (args.fspec == 0) { 18152177Smckusick /* 18252177Smckusick * Process export requests. 18352177Smckusick */ 18465672Shibler return (vfs_export(mp, &ump->um_export, &args.export)); 18552177Smckusick } 18650264Skarels } 18750264Skarels /* 18850264Skarels * Not an update, or updating the name: look up the name 18950264Skarels * and verify that it refers to a sensible block device. 19050264Skarels */ 19152332Smckusick NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 19252332Smckusick if (error = namei(ndp)) 19350264Skarels return (error); 19450264Skarels devvp = ndp->ni_vp; 19551473Sbostic 19650264Skarels if (devvp->v_type != VBLK) { 19750264Skarels vrele(devvp); 19850264Skarels return (ENOTBLK); 19950264Skarels } 20050264Skarels if (major(devvp->v_rdev) >= nblkdev) { 20150264Skarels vrele(devvp); 20250264Skarels return (ENXIO); 20350264Skarels } 20467534Smckusick /* 20567534Smckusick * If mount by non-root, then verify that user has necessary 20667534Smckusick * permissions on the device. 20767534Smckusick */ 20867534Smckusick if (p->p_ucred->cr_uid != 0) { 20967534Smckusick accessmode = VREAD; 21067534Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0) 21167534Smckusick accessmode |= VWRITE; 21267534Smckusick VOP_LOCK(devvp); 21367534Smckusick if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) { 21467534Smckusick vput(devvp); 21567534Smckusick return (error); 21667534Smckusick } 21767534Smckusick VOP_UNLOCK(devvp); 21867534Smckusick } 21950264Skarels if ((mp->mnt_flag & MNT_UPDATE) == 0) 22051473Sbostic error = ffs_mountfs(devvp, mp, p); 22150264Skarels else { 22239336Smckusick if (devvp != ump->um_devvp) 22339336Smckusick error = EINVAL; /* needs translation */ 22442858Smckusick else 22542858Smckusick vrele(devvp); 22639336Smckusick } 22737737Smckusick if (error) { 22837737Smckusick vrele(devvp); 22937737Smckusick return (error); 23032721Smckusick } 23137737Smckusick ump = VFSTOUFS(mp); 23237737Smckusick fs = ump->um_fs; 23337737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 23437737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 23541397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 23641397Smckusick MNAMELEN); 23741397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 23841397Smckusick &size); 23941397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 24051473Sbostic (void)ffs_statfs(mp, &mp->mnt_stat, p); 24137737Smckusick return (0); 24212795Ssam } 24312795Ssam 24437737Smckusick /* 24557051Smckusick * Reload all incore data for a filesystem (used after running fsck on 24657051Smckusick * the root filesystem and finding things to fix). The filesystem must 24757051Smckusick * be mounted read-only. 24857051Smckusick * 24957051Smckusick * Things to do to update the mount: 25057051Smckusick * 1) invalidate all cached meta-data. 25157051Smckusick * 2) re-read superblock from disk. 25257051Smckusick * 3) re-read summary information from disk. 25357051Smckusick * 4) invalidate all inactive vnodes. 25457051Smckusick * 5) invalidate all cached file data. 25557051Smckusick * 6) re-read inode data for all active vnodes. 25657051Smckusick */ 25757051Smckusick ffs_reload(mountp, cred, p) 25857051Smckusick register struct mount *mountp; 25957051Smckusick struct ucred *cred; 26057051Smckusick struct proc *p; 26157051Smckusick { 26257051Smckusick register struct vnode *vp, *nvp, *devvp; 26357051Smckusick struct inode *ip; 26457051Smckusick struct csum *space; 26557051Smckusick struct buf *bp; 26668545Smckusick struct fs *fs, *newfs; 26768115Smckusick struct partinfo dpart; 26857051Smckusick int i, blks, size, error; 269*69245Smckusick int32_t *lp; 27057051Smckusick 27157051Smckusick if ((mountp->mnt_flag & MNT_RDONLY) == 0) 27257051Smckusick return (EINVAL); 27357051Smckusick /* 27457051Smckusick * Step 1: invalidate all cached meta-data. 27557051Smckusick */ 27657051Smckusick devvp = VFSTOUFS(mountp)->um_devvp; 27757801Smckusick if (vinvalbuf(devvp, 0, cred, p, 0, 0)) 27857051Smckusick panic("ffs_reload: dirty1"); 27957051Smckusick /* 28057051Smckusick * Step 2: re-read superblock from disk. 28157051Smckusick */ 28268115Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 28368115Smckusick size = DEV_BSIZE; 28468115Smckusick else 28568115Smckusick size = dpart.disklab->d_secsize; 28668554Smckusick if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) 28757051Smckusick return (error); 28868545Smckusick newfs = (struct fs *)bp->b_data; 28968545Smckusick if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || 29068545Smckusick newfs->fs_bsize < sizeof(struct fs)) { 29157051Smckusick brelse(bp); 29257051Smckusick return (EIO); /* XXX needs translation */ 29357051Smckusick } 29457051Smckusick fs = VFSTOUFS(mountp)->um_fs; 29568580Smckusick /* 29668580Smckusick * Copy pointer fields back into superblock before copying in XXX 29768580Smckusick * new superblock. These should really be in the ufsmount. XXX 29868580Smckusick * Note that important parameters (eg fs_ncg) are unchanged. 29968580Smckusick */ 30068545Smckusick bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp)); 30168545Smckusick newfs->fs_maxcluster = fs->fs_maxcluster; 30268545Smckusick bcopy(newfs, fs, (u_int)fs->fs_sbsize); 30357051Smckusick if (fs->fs_sbsize < SBSIZE) 30457051Smckusick bp->b_flags |= B_INVAL; 30557051Smckusick brelse(bp); 30667460Smckusick mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 30757051Smckusick ffs_oldfscompat(fs); 30857051Smckusick /* 30957051Smckusick * Step 3: re-read summary information from disk. 31057051Smckusick */ 31157051Smckusick blks = howmany(fs->fs_cssize, fs->fs_fsize); 31257051Smckusick space = fs->fs_csp[0]; 31357051Smckusick for (i = 0; i < blks; i += fs->fs_frag) { 31457051Smckusick size = fs->fs_bsize; 31557051Smckusick if (i + fs->fs_frag > blks) 31657051Smckusick size = (blks - i) * fs->fs_fsize; 31757051Smckusick if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 31857051Smckusick NOCRED, &bp)) 31957051Smckusick return (error); 32064511Sbostic bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); 32157051Smckusick brelse(bp); 32257051Smckusick } 32368580Smckusick /* 32468580Smckusick * We no longer know anything about clusters per cylinder group. 32568580Smckusick */ 32668580Smckusick if (fs->fs_contigsumsize > 0) { 32768580Smckusick lp = fs->fs_maxcluster; 32868580Smckusick for (i = 0; i < fs->fs_ncg; i++) 32968580Smckusick *lp++ = fs->fs_contigsumsize; 33068580Smckusick } 33157051Smckusick loop: 33265236Smckusick for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 33365236Smckusick nvp = vp->v_mntvnodes.le_next; 33457051Smckusick /* 33557051Smckusick * Step 4: invalidate all inactive vnodes. 33657051Smckusick */ 33757051Smckusick if (vp->v_usecount == 0) { 33857051Smckusick vgone(vp); 33957051Smckusick continue; 34057051Smckusick } 34157051Smckusick /* 34257051Smckusick * Step 5: invalidate all cached file data. 34357051Smckusick */ 34465236Smckusick if (vget(vp, 1)) 34557051Smckusick goto loop; 34657801Smckusick if (vinvalbuf(vp, 0, cred, p, 0, 0)) 34757051Smckusick panic("ffs_reload: dirty2"); 34857051Smckusick /* 34957051Smckusick * Step 6: re-read inode data for all active vnodes. 35057051Smckusick */ 35157051Smckusick ip = VTOI(vp); 35264605Sbostic if (error = 35364605Sbostic bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 35457051Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 35557051Smckusick vput(vp); 35657051Smckusick return (error); 35757051Smckusick } 35864605Sbostic ip->i_din = *((struct dinode *)bp->b_data + 35964605Sbostic ino_to_fsbo(fs, ip->i_number)); 36057051Smckusick brelse(bp); 36157051Smckusick vput(vp); 36257051Smckusick if (vp->v_mount != mountp) 36357051Smckusick goto loop; 36457051Smckusick } 36557051Smckusick return (0); 36657051Smckusick } 36757051Smckusick 36857051Smckusick /* 36937737Smckusick * Common code for mount and mountroot 37037737Smckusick */ 37151473Sbostic int 37251473Sbostic ffs_mountfs(devvp, mp, p) 37340376Smckusick register struct vnode *devvp; 37437737Smckusick struct mount *mp; 37548036Smckusick struct proc *p; 37612795Ssam { 37754461Smckusick register struct ufsmount *ump; 37854461Smckusick struct buf *bp; 37912795Ssam register struct fs *fs; 38068004Smckusick dev_t dev; 38130749Skarels struct partinfo dpart; 38237737Smckusick caddr_t base, space; 38368115Smckusick int error, i, blks, size, ronly; 38467868Smckusick int32_t *lp; 38568004Smckusick struct ucred *cred; 38645652Smckusick extern struct vnode *rootvp; 38768115Smckusick u_int64_t maxfilesize; /* XXX */ 38812795Ssam 38968004Smckusick dev = devvp->v_rdev; 39068004Smckusick cred = p ? p->p_ucred : NOCRED; 39140376Smckusick /* 39240376Smckusick * Disallow multiple mounts of the same device. 39345652Smckusick * Disallow mounting of a device that is currently in use 39445652Smckusick * (except for root, which might share swap device for miniroot). 39540376Smckusick * Flush out any old buffers remaining from a previous use. 39640376Smckusick */ 39765672Shibler if (error = vfs_mountedon(devvp)) 39840376Smckusick return (error); 39945652Smckusick if (vcount(devvp) > 1 && devvp != rootvp) 40040376Smckusick return (EBUSY); 40168004Smckusick if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) 40254461Smckusick return (error); 40354461Smckusick 40454461Smckusick ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 40559472Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)) 40637737Smckusick return (error); 40768004Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) 40837737Smckusick size = DEV_BSIZE; 40968115Smckusick else 41030749Skarels size = dpart.disklab->d_secsize; 41154461Smckusick 41254461Smckusick bp = NULL; 41354461Smckusick ump = NULL; 41468554Smckusick if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, cred, &bp)) 41512795Ssam goto out; 41664511Sbostic fs = (struct fs *)bp->b_data; 41730749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 41830749Skarels fs->fs_bsize < sizeof(struct fs)) { 41941314Smckusick error = EINVAL; /* XXX needs translation */ 42016639Skarels goto out; 42116639Skarels } 42268116Smckusick /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ 42368116Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { 42468116Smckusick error = EROFS; /* needs translation */ 42568116Smckusick goto out; 42668116Smckusick } 42751473Sbostic ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 42852538Smckusick bzero((caddr_t)ump, sizeof *ump); 42951982Smckusick ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, 43034473Smckusick M_WAITOK); 43164511Sbostic bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); 43239675Smckusick if (fs->fs_sbsize < SBSIZE) 43339675Smckusick bp->b_flags |= B_INVAL; 43434421Skarels brelse(bp); 43534421Skarels bp = NULL; 43637737Smckusick fs = ump->um_fs; 43737737Smckusick fs->fs_ronly = ronly; 43812795Ssam if (ronly == 0) 43912795Ssam fs->fs_fmod = 1; 44067868Smckusick size = fs->fs_cssize; 44168116Smckusick blks = howmany(size, fs->fs_fsize); 44267868Smckusick if (fs->fs_contigsumsize > 0) 44367868Smckusick size += fs->fs_ncg * sizeof(int32_t); 44467868Smckusick base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK); 44512795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 44612795Ssam size = fs->fs_bsize; 44712795Ssam if (i + fs->fs_frag > blks) 44812795Ssam size = (blks - i) * fs->fs_fsize; 44968004Smckusick if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 45068004Smckusick cred, &bp)) { 45151982Smckusick free(base, M_UFSMNT); 45212795Ssam goto out; 45312795Ssam } 45464511Sbostic bcopy(bp->b_data, space, (u_int)size); 45517225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 45612795Ssam space += size; 45734421Skarels brelse(bp); 45834421Skarels bp = NULL; 45912795Ssam } 46067868Smckusick if (fs->fs_contigsumsize > 0) { 46167868Smckusick fs->fs_maxcluster = lp = (int32_t *)space; 46267868Smckusick for (i = 0; i < fs->fs_ncg; i++) 46367868Smckusick *lp++ = fs->fs_contigsumsize; 46467868Smckusick } 46541397Smckusick mp->mnt_data = (qaddr_t)ump; 46641397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 46768668Smckusick mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 46854305Smckusick mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 46937737Smckusick ump->um_mountp = mp; 47037737Smckusick ump->um_dev = dev; 47137737Smckusick ump->um_devvp = devvp; 47256446Smargo ump->um_nindir = fs->fs_nindir; 47356446Smargo ump->um_bptrtodb = fs->fs_fsbtodb; 47456446Smargo ump->um_seqinc = fs->fs_frag; 47541314Smckusick for (i = 0; i < MAXQUOTAS; i++) 47641314Smckusick ump->um_quotas[i] = NULLVP; 47740653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 47857051Smckusick ffs_oldfscompat(fs); 47967868Smckusick ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ 48068115Smckusick maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; /* XXX */ 48168115Smckusick if (fs->fs_maxfilesize > maxfilesize) /* XXX */ 48268115Smckusick fs->fs_maxfilesize = maxfilesize; /* XXX */ 48357051Smckusick return (0); 48457051Smckusick out: 48557051Smckusick if (bp) 48657051Smckusick brelse(bp); 48768004Smckusick (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); 48857051Smckusick if (ump) { 48957051Smckusick free(ump->um_fs, M_UFSMNT); 49057051Smckusick free(ump, M_UFSMNT); 49157051Smckusick mp->mnt_data = (qaddr_t)0; 49257051Smckusick } 49357051Smckusick return (error); 49457051Smckusick } 49537737Smckusick 49657051Smckusick /* 49757051Smckusick * Sanity checks for old file systems. 49857051Smckusick * 49957051Smckusick * XXX - goes away some day. 50057051Smckusick */ 50157051Smckusick ffs_oldfscompat(fs) 50257051Smckusick struct fs *fs; 50357051Smckusick { 50457051Smckusick int i; 50557051Smckusick 50655056Spendry fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 50755056Spendry fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 50834145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 50934145Smckusick fs->fs_nrpos = 8; /* XXX */ 51053913Smckusick if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 51168122Smckusick u_int64_t sizepb = fs->fs_bsize; /* XXX */ 51253913Smckusick /* XXX */ 51353913Smckusick fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 51453913Smckusick for (i = 0; i < NIADDR; i++) { /* XXX */ 51553913Smckusick sizepb *= NINDIR(fs); /* XXX */ 51653913Smckusick fs->fs_maxfilesize += sizepb; /* XXX */ 51753913Smckusick } /* XXX */ 51853913Smckusick fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 51953913Smckusick fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 52053913Smckusick } /* XXX */ 52137737Smckusick return (0); 52212795Ssam } 52312795Ssam 52439043Smckusick /* 52537737Smckusick * unmount system call 52637737Smckusick */ 52751473Sbostic int 52851473Sbostic ffs_unmount(mp, mntflags, p) 52937737Smckusick struct mount *mp; 53041314Smckusick int mntflags; 53148036Smckusick struct proc *p; 53212795Ssam { 53337737Smckusick register struct ufsmount *ump; 53437737Smckusick register struct fs *fs; 53567861Smckusick int error, flags; 53612795Ssam 53754461Smckusick flags = 0; 53848065Smckusick if (mntflags & MNT_FORCE) { 53965236Smckusick if (mp->mnt_flag & MNT_ROOTFS) 54048065Smckusick return (EINVAL); 54141314Smckusick flags |= FORCECLOSE; 54248065Smckusick } 54357051Smckusick if (error = ffs_flushfiles(mp, flags, p)) 54457051Smckusick return (error); 54537737Smckusick ump = VFSTOUFS(mp); 54657051Smckusick fs = ump->um_fs; 54757051Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 54867861Smckusick error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, 54957051Smckusick NOCRED, p); 55057051Smckusick vrele(ump->um_devvp); 55157051Smckusick free(fs->fs_csp[0], M_UFSMNT); 55257051Smckusick free(fs, M_UFSMNT); 55357051Smckusick free(ump, M_UFSMNT); 55457051Smckusick mp->mnt_data = (qaddr_t)0; 55557051Smckusick return (error); 55657051Smckusick } 55757051Smckusick 55857051Smckusick /* 55957051Smckusick * Flush out all the files in a filesystem. 56057051Smckusick */ 56157051Smckusick ffs_flushfiles(mp, flags, p) 56257051Smckusick register struct mount *mp; 56357051Smckusick int flags; 56457051Smckusick struct proc *p; 56557051Smckusick { 56657051Smckusick extern int doforce; 56757051Smckusick register struct ufsmount *ump; 56857051Smckusick int i, error; 56957051Smckusick 57057051Smckusick if (!doforce) 57157051Smckusick flags &= ~FORCECLOSE; 57257051Smckusick ump = VFSTOUFS(mp); 57312795Ssam #ifdef QUOTA 57441397Smckusick if (mp->mnt_flag & MNT_QUOTA) { 57541314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 57639898Smckusick return (error); 57741314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 57841314Smckusick if (ump->um_quotas[i] == NULLVP) 57941314Smckusick continue; 58050114Smckusick quotaoff(p, mp, i); 58141314Smckusick } 58239898Smckusick /* 58341314Smckusick * Here we fall through to vflush again to ensure 58441314Smckusick * that we have gotten rid of all the system vnodes. 58539898Smckusick */ 58641314Smckusick } 58712795Ssam #endif 58857051Smckusick error = vflush(mp, NULLVP, flags); 58930749Skarels return (error); 59012795Ssam } 59112795Ssam 59237737Smckusick /* 59337737Smckusick * Get file system statistics. 59437737Smckusick */ 59551473Sbostic int 59651473Sbostic ffs_statfs(mp, sbp, p) 59737737Smckusick struct mount *mp; 59837737Smckusick register struct statfs *sbp; 59948036Smckusick struct proc *p; 60037737Smckusick { 60137737Smckusick register struct ufsmount *ump; 60237737Smckusick register struct fs *fs; 60337737Smckusick 60437737Smckusick ump = VFSTOUFS(mp); 60537737Smckusick fs = ump->um_fs; 60637737Smckusick if (fs->fs_magic != FS_MAGIC) 60751473Sbostic panic("ffs_statfs"); 60851942Smckusick sbp->f_bsize = fs->fs_fsize; 60951942Smckusick sbp->f_iosize = fs->fs_bsize; 61037737Smckusick sbp->f_blocks = fs->fs_dsize; 61137737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 61237737Smckusick fs->fs_cstotal.cs_nffree; 61337737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 61437737Smckusick (fs->fs_dsize - sbp->f_bfree); 61539350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 61637737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 61741397Smckusick if (sbp != &mp->mnt_stat) { 61868668Smckusick sbp->f_type = mp->mnt_vfc->vfc_typenum; 61941397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 62040346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 62141397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 62240346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 62340346Smckusick } 62437737Smckusick return (0); 62537737Smckusick } 62637737Smckusick 62737737Smckusick /* 62837737Smckusick * Go through the disk queues to initiate sandbagged IO; 62937737Smckusick * go through the inodes to write those that have been modified; 63037737Smckusick * initiate the writing of the super block if it has been modified. 63141314Smckusick * 63241314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 63337737Smckusick */ 63451473Sbostic int 63554461Smckusick ffs_sync(mp, waitfor, cred, p) 63637737Smckusick struct mount *mp; 63737737Smckusick int waitfor; 63854461Smckusick struct ucred *cred; 63954461Smckusick struct proc *p; 64037737Smckusick { 64139390Smckusick register struct vnode *vp; 64237737Smckusick register struct inode *ip; 64337737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 64437737Smckusick register struct fs *fs; 64539596Smckusick int error, allerror = 0; 64637737Smckusick 64737737Smckusick fs = ump->um_fs; 64837737Smckusick /* 64937737Smckusick * Write back modified superblock. 65037737Smckusick * Consistency check that the superblock 65137737Smckusick * is still in the buffer cache. 65237737Smckusick */ 65337737Smckusick if (fs->fs_fmod != 0) { 65437737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 65537737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 65637737Smckusick panic("update: rofs mod"); 65737737Smckusick } 65837737Smckusick fs->fs_fmod = 0; 65937737Smckusick fs->fs_time = time.tv_sec; 66051473Sbostic allerror = ffs_sbupdate(ump, waitfor); 66137737Smckusick } 66237737Smckusick /* 66337737Smckusick * Write back each (modified) inode. 66437737Smckusick */ 66539877Smckusick loop: 66665236Smckusick for (vp = mp->mnt_vnodelist.lh_first; 66765236Smckusick vp != NULL; 66865236Smckusick vp = vp->v_mntvnodes.le_next) { 66941462Smckusick /* 67041462Smckusick * If the vnode that we are about to sync is no longer 67141462Smckusick * associated with this mount point, start over. 67241462Smckusick */ 67341462Smckusick if (vp->v_mount != mp) 67441462Smckusick goto loop; 67548359Smckusick if (VOP_ISLOCKED(vp)) 67648359Smckusick continue; 67739390Smckusick ip = VTOI(vp); 67864511Sbostic if ((ip->i_flag & 67964605Sbostic (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && 68065236Smckusick vp->v_dirtyblkhd.lh_first == NULL) 68137737Smckusick continue; 68265236Smckusick if (vget(vp, 1)) 68339877Smckusick goto loop; 68454461Smckusick if (error = VOP_FSYNC(vp, cred, waitfor, p)) 68539596Smckusick allerror = error; 68639596Smckusick vput(vp); 68737737Smckusick } 68837737Smckusick /* 68939675Smckusick * Force stale file system control information to be flushed. 69037737Smckusick */ 69154461Smckusick if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) 69254461Smckusick allerror = error; 69341314Smckusick #ifdef QUOTA 69441314Smckusick qsync(mp); 69541314Smckusick #endif 69639596Smckusick return (allerror); 69737737Smckusick } 69837737Smckusick 69937737Smckusick /* 70064605Sbostic * Look up a FFS dinode number to find its incore vnode, otherwise read it 70164605Sbostic * in from disk. If it is in core, wait for the lock bit to clear, then 70264605Sbostic * return the inode locked. Detection and handling of mount points must be 70364605Sbostic * done by the calling routine. 70454657Smckusick */ 70554657Smckusick int 70654657Smckusick ffs_vget(mp, ino, vpp) 70754657Smckusick struct mount *mp; 70854657Smckusick ino_t ino; 70954657Smckusick struct vnode **vpp; 71054657Smckusick { 71154657Smckusick register struct fs *fs; 71254657Smckusick register struct inode *ip; 71354657Smckusick struct ufsmount *ump; 71454657Smckusick struct buf *bp; 71554657Smckusick struct vnode *vp; 71654657Smckusick dev_t dev; 71754657Smckusick int i, type, error; 71854657Smckusick 71954657Smckusick ump = VFSTOUFS(mp); 72054657Smckusick dev = ump->um_dev; 72154657Smckusick if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 72254657Smckusick return (0); 72354657Smckusick 72454657Smckusick /* Allocate a new vnode/inode. */ 72554657Smckusick if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) { 72654657Smckusick *vpp = NULL; 72754657Smckusick return (error); 72854657Smckusick } 72954657Smckusick type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ 73054657Smckusick MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); 73159819Smckusick bzero((caddr_t)ip, sizeof(struct inode)); 73254657Smckusick vp->v_data = ip; 73354657Smckusick ip->i_vnode = vp; 73454657Smckusick ip->i_fs = fs = ump->um_fs; 73554657Smckusick ip->i_dev = dev; 73654657Smckusick ip->i_number = ino; 73754657Smckusick #ifdef QUOTA 73854657Smckusick for (i = 0; i < MAXQUOTAS; i++) 73954657Smckusick ip->i_dquot[i] = NODQUOT; 74054657Smckusick #endif 74154657Smckusick /* 74254657Smckusick * Put it onto its hash chain and lock it so that other requests for 74354657Smckusick * this inode will block if they arrive while we are sleeping waiting 74454657Smckusick * for old data structures to be purged or for the contents of the 74554657Smckusick * disk portion of this inode to be read. 74654657Smckusick */ 74754657Smckusick ufs_ihashins(ip); 74854657Smckusick 74954657Smckusick /* Read in the disk contents for the inode, copy into the inode. */ 75064605Sbostic if (error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 75154657Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 75254657Smckusick /* 75354657Smckusick * The inode does not contain anything useful, so it would 75459819Smckusick * be misleading to leave it on its hash chain. With mode 75559819Smckusick * still zero, it will be unlinked and returned to the free 75659819Smckusick * list by vput(). 75754657Smckusick */ 75856797Smckusick vput(vp); 75954657Smckusick brelse(bp); 76054657Smckusick *vpp = NULL; 76154657Smckusick return (error); 76254657Smckusick } 76364605Sbostic ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 76454657Smckusick brelse(bp); 76554657Smckusick 76654657Smckusick /* 76754657Smckusick * Initialize the vnode from the inode, check for aliases. 76854657Smckusick * Note that the underlying vnode may have changed. 76954657Smckusick */ 77054657Smckusick if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) { 77156797Smckusick vput(vp); 77254657Smckusick *vpp = NULL; 77354657Smckusick return (error); 77454657Smckusick } 77554657Smckusick /* 77654657Smckusick * Finish inode initialization now that aliasing has been resolved. 77754657Smckusick */ 77854657Smckusick ip->i_devvp = ump->um_devvp; 77954657Smckusick VREF(ip->i_devvp); 78054657Smckusick /* 78154657Smckusick * Set up a generation number for this inode if it does not 78254657Smckusick * already have one. This should only happen on old filesystems. 78354657Smckusick */ 78454657Smckusick if (ip->i_gen == 0) { 78554657Smckusick if (++nextgennumber < (u_long)time.tv_sec) 78654657Smckusick nextgennumber = time.tv_sec; 78754657Smckusick ip->i_gen = nextgennumber; 78854657Smckusick if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 78964605Sbostic ip->i_flag |= IN_MODIFIED; 79054657Smckusick } 79154657Smckusick /* 79254657Smckusick * Ensure that uid and gid are correct. This is a temporary 79354657Smckusick * fix until fsck has been changed to do the update. 79454657Smckusick */ 79554657Smckusick if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 79654657Smckusick ip->i_uid = ip->i_din.di_ouid; /* XXX */ 79754657Smckusick ip->i_gid = ip->i_din.di_ogid; /* XXX */ 79854657Smckusick } /* XXX */ 79954657Smckusick 80054657Smckusick *vpp = vp; 80154657Smckusick return (0); 80254657Smckusick } 80354657Smckusick 80454657Smckusick /* 80551545Smckusick * File handle to vnode 80651545Smckusick * 80751545Smckusick * Have to be really careful about stale file handles: 80851545Smckusick * - check that the inode number is valid 80951545Smckusick * - call ffs_vget() to get the locked inode 81051545Smckusick * - check for an unallocated inode (i_mode == 0) 81154733Smckusick * - check that the given client host has export rights and return 81254733Smckusick * those rights via. exflagsp and credanonp 81351545Smckusick */ 81451545Smckusick int 81554733Smckusick ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 81651545Smckusick register struct mount *mp; 81751545Smckusick struct fid *fhp; 81854733Smckusick struct mbuf *nam; 81951545Smckusick struct vnode **vpp; 82054733Smckusick int *exflagsp; 82154733Smckusick struct ucred **credanonp; 82251545Smckusick { 82351545Smckusick register struct ufid *ufhp; 82451545Smckusick struct fs *fs; 82551545Smckusick 82651545Smckusick ufhp = (struct ufid *)fhp; 82755890Smckusick fs = VFSTOUFS(mp)->um_fs; 82851545Smckusick if (ufhp->ufid_ino < ROOTINO || 82951545Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) 83054733Smckusick return (ESTALE); 83156245Smckusick return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); 83251545Smckusick } 83351545Smckusick 83451545Smckusick /* 83551545Smckusick * Vnode pointer to File handle 83651545Smckusick */ 83751545Smckusick /* ARGSUSED */ 83851545Smckusick ffs_vptofh(vp, fhp) 83951545Smckusick struct vnode *vp; 84051545Smckusick struct fid *fhp; 84151545Smckusick { 84251545Smckusick register struct inode *ip; 84351545Smckusick register struct ufid *ufhp; 84451545Smckusick 84551545Smckusick ip = VTOI(vp); 84651545Smckusick ufhp = (struct ufid *)fhp; 84751545Smckusick ufhp->ufid_len = sizeof(struct ufid); 84851545Smckusick ufhp->ufid_ino = ip->i_number; 84951545Smckusick ufhp->ufid_gen = ip->i_gen; 85051545Smckusick return (0); 85151545Smckusick } 85251545Smckusick 85351545Smckusick /* 85468668Smckusick * Initialize the filesystem; just use ufs_init. 85568668Smckusick */ 85668668Smckusick int 85768668Smckusick ffs_init(vfsp) 85868668Smckusick struct vfsconf *vfsp; 85968668Smckusick { 86068668Smckusick 86168668Smckusick return (ufs_init(vfsp)); 86268668Smckusick } 86368668Smckusick 86468668Smckusick /* 86568668Smckusick * fast filesystem related variables. 86668668Smckusick */ 86768668Smckusick ffs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 86868668Smckusick int *name; 86968668Smckusick u_int namelen; 87068668Smckusick void *oldp; 87168668Smckusick size_t *oldlenp; 87268668Smckusick void *newp; 87368668Smckusick size_t newlen; 87468668Smckusick struct proc *p; 87568668Smckusick { 87668668Smckusick extern int doclusterread, doclusterwrite, doreallocblks, doasyncfree; 87768668Smckusick 87868668Smckusick /* all sysctl names at this level are terminal */ 87968668Smckusick if (namelen != 1) 88068668Smckusick return (ENOTDIR); /* overloaded */ 88168668Smckusick 88268668Smckusick switch (name[0]) { 88368668Smckusick case FFS_CLUSTERREAD: 88468668Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, 88568668Smckusick &doclusterread)); 88668668Smckusick case FFS_CLUSTERWRITE: 88768668Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, 88868668Smckusick &doclusterwrite)); 88968668Smckusick case FFS_REALLOCBLKS: 89068668Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, 89168668Smckusick &doreallocblks)); 89268668Smckusick case FFS_ASYNCFREE: 89368668Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, &doasyncfree)); 89468668Smckusick default: 89568668Smckusick return (EOPNOTSUPP); 89668668Smckusick } 89768668Smckusick /* NOTREACHED */ 89868668Smckusick } 89968668Smckusick 90068668Smckusick /* 90137737Smckusick * Write a superblock and associated information back to disk. 90237737Smckusick */ 90351942Smckusick int 90451473Sbostic ffs_sbupdate(mp, waitfor) 90537737Smckusick struct ufsmount *mp; 90637737Smckusick int waitfor; 90737737Smckusick { 90867868Smckusick register struct fs *dfs, *fs = mp->um_fs; 90912795Ssam register struct buf *bp; 91012795Ssam int blks; 91112795Ssam caddr_t space; 91237737Smckusick int i, size, error = 0; 91312795Ssam 91457801Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); 91564511Sbostic bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); 91634145Smckusick /* Restore compatibility to old file systems. XXX */ 91767868Smckusick dfs = (struct fs *)bp->b_data; /* XXX */ 91834145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 91967868Smckusick dfs->fs_nrpos = -1; /* XXX */ 92067397Smkm if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 92168122Smckusick int32_t *lp, tmp; /* XXX */ 92267397Smkm /* XXX */ 92368122Smckusick lp = (int32_t *)&dfs->fs_qbmask; /* XXX */ 92467397Smkm tmp = lp[4]; /* XXX */ 92567397Smkm for (i = 4; i > 0; i--) /* XXX */ 92667397Smkm lp[i] = lp[i-1]; /* XXX */ 92767397Smkm lp[0] = tmp; /* XXX */ 92867397Smkm } /* XXX */ 92967868Smckusick dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ 93037737Smckusick if (waitfor == MNT_WAIT) 93137737Smckusick error = bwrite(bp); 93237737Smckusick else 93337737Smckusick bawrite(bp); 93412795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 93512795Ssam space = (caddr_t)fs->fs_csp[0]; 93612795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 93712795Ssam size = fs->fs_bsize; 93812795Ssam if (i + fs->fs_frag > blks) 93912795Ssam size = (blks - i) * fs->fs_fsize; 94057801Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), 94157801Smckusick size, 0, 0); 94264511Sbostic bcopy(space, bp->b_data, (u_int)size); 94312795Ssam space += size; 94437737Smckusick if (waitfor == MNT_WAIT) 94537737Smckusick error = bwrite(bp); 94637737Smckusick else 94737737Smckusick bawrite(bp); 94812795Ssam } 94937737Smckusick return (error); 95012795Ssam } 951