123400Smckusick /* 250264Skarels * Copyright (c) 1989, 1991 The Regents of the University of California. 337737Smckusick * All rights reserved. 423400Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*59819Smckusick * @(#)ffs_vfsops.c 7.86 (Berkeley) 05/09/93 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, 4251545Smckusick ffs_root, 4341314Smckusick ufs_quotactl, 4451473Sbostic ffs_statfs, 4551473Sbostic ffs_sync, 4654657Smckusick ffs_vget, 4751545Smckusick ffs_fhtovp, 4851545Smckusick ffs_vptofh, 4951473Sbostic ffs_init, 5037737Smckusick }; 5137737Smckusick 5254657Smckusick extern u_long nextgennumber; 5354657Smckusick 5437737Smckusick /* 5553045Sralph * Called by main() when ufs is going to be mounted as root. 5637737Smckusick * 5739336Smckusick * Name is updated by mount(8) after booting. 5837737Smckusick */ 5939297Smckusick #define ROOTNAME "root_device" 6037737Smckusick 6151473Sbostic ffs_mountroot() 6212795Ssam { 6351473Sbostic extern struct vnode *rootvp; 6451473Sbostic register struct fs *fs; 6537737Smckusick register struct mount *mp; 6648036Smckusick struct proc *p = curproc; /* XXX */ 6737737Smckusick struct ufsmount *ump; 6837737Smckusick u_int size; 6937737Smckusick int error; 7056332Smckusick 7156332Smckusick /* 7256332Smckusick * Get vnodes for swapdev and rootdev. 7356332Smckusick */ 7456332Smckusick if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) 7556332Smckusick panic("ffs_mountroot: can't setup bdevvp's"); 7612795Ssam 7753045Sralph mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); 7854305Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 7941397Smckusick mp->mnt_op = &ufs_vfsops; 8041397Smckusick mp->mnt_flag = MNT_RDONLY; 8151473Sbostic if (error = ffs_mountfs(rootvp, mp, p)) { 8251473Sbostic free(mp, M_MOUNT); 8337737Smckusick return (error); 8412795Ssam } 8539336Smckusick if (error = vfs_lock(mp)) { 8651473Sbostic (void)ffs_unmount(mp, 0, p); 8751473Sbostic free(mp, M_MOUNT); 8837737Smckusick return (error); 8921013Smckusick } 9039336Smckusick rootfs = mp; 9141397Smckusick mp->mnt_next = mp; 9241397Smckusick mp->mnt_prev = mp; 9341397Smckusick mp->mnt_vnodecovered = NULLVP; 9437737Smckusick ump = VFSTOUFS(mp); 9537737Smckusick fs = ump->um_fs; 9640346Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 9737737Smckusick fs->fs_fsmnt[0] = '/'; 9841397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 9941397Smckusick MNAMELEN); 10041397Smckusick (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 10141397Smckusick &size); 10241397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 10351473Sbostic (void)ffs_statfs(mp, &mp->mnt_stat, p); 10437737Smckusick vfs_unlock(mp); 10537737Smckusick inittodr(fs->fs_time); 10637737Smckusick return (0); 10737737Smckusick } 10837737Smckusick 10937737Smckusick /* 11037737Smckusick * VFS Operations. 11137737Smckusick * 11237737Smckusick * mount system call 11337737Smckusick */ 11451942Smckusick int 11551473Sbostic ffs_mount(mp, path, data, ndp, p) 11640346Smckusick register struct mount *mp; 11737737Smckusick char *path; 11837737Smckusick caddr_t data; 11937737Smckusick struct nameidata *ndp; 12048036Smckusick struct proc *p; 12137737Smckusick { 12237737Smckusick struct vnode *devvp; 12337737Smckusick struct ufs_args args; 12437737Smckusick struct ufsmount *ump; 12537737Smckusick register struct fs *fs; 12637737Smckusick u_int size; 12757051Smckusick int error, flags; 12837737Smckusick 12937737Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 13037737Smckusick return (error); 13140371Smckusick /* 13250264Skarels * If updating, check whether changing from read-only to 13350264Skarels * read/write; if there is no device name, that's all we do. 13450264Skarels */ 13550264Skarels if (mp->mnt_flag & MNT_UPDATE) { 13639336Smckusick ump = VFSTOUFS(mp); 13739336Smckusick fs = ump->um_fs; 13857051Smckusick error = 0; 13957051Smckusick if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 14057051Smckusick flags = WRITECLOSE; 14157051Smckusick if (mp->mnt_flag & MNT_FORCE) 14257051Smckusick flags |= FORCECLOSE; 14357051Smckusick if (vfs_busy(mp)) 14457051Smckusick return (EBUSY); 14557051Smckusick error = ffs_flushfiles(mp, flags, p); 14657051Smckusick vfs_unbusy(mp); 14757051Smckusick } 14857051Smckusick if (!error && (mp->mnt_flag & MNT_RELOAD)) 14957051Smckusick error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); 15057051Smckusick if (error) 15157051Smckusick return (error); 15257051Smckusick if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) 15339336Smckusick fs->fs_ronly = 0; 15452177Smckusick if (args.fspec == 0) { 15552177Smckusick /* 15652177Smckusick * Process export requests. 15752177Smckusick */ 15852177Smckusick if (args.exflags & MNT_EXPORTED) { 15954618Smckusick if (error = ufs_hang_addrlist(mp, &args)) 16052177Smckusick return (error); 16152177Smckusick mp->mnt_flag |= MNT_EXPORTED; 16252177Smckusick } 16352177Smckusick if (args.exflags & MNT_DELEXPORT) { 16454618Smckusick ufs_free_addrlist(ump); 16552177Smckusick mp->mnt_flag &= 16652177Smckusick ~(MNT_EXPORTED | MNT_DEFEXPORTED); 16752177Smckusick } 16840371Smckusick return (0); 16952177Smckusick } 17050264Skarels } 17150264Skarels /* 17250264Skarels * Not an update, or updating the name: look up the name 17350264Skarels * and verify that it refers to a sensible block device. 17450264Skarels */ 17552332Smckusick NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 17652332Smckusick if (error = namei(ndp)) 17750264Skarels return (error); 17850264Skarels devvp = ndp->ni_vp; 17951473Sbostic 18050264Skarels if (devvp->v_type != VBLK) { 18150264Skarels vrele(devvp); 18250264Skarels return (ENOTBLK); 18350264Skarels } 18450264Skarels if (major(devvp->v_rdev) >= nblkdev) { 18550264Skarels vrele(devvp); 18650264Skarels return (ENXIO); 18750264Skarels } 18850264Skarels if ((mp->mnt_flag & MNT_UPDATE) == 0) 18951473Sbostic error = ffs_mountfs(devvp, mp, p); 19050264Skarels else { 19139336Smckusick if (devvp != ump->um_devvp) 19239336Smckusick error = EINVAL; /* needs translation */ 19342858Smckusick else 19442858Smckusick vrele(devvp); 19539336Smckusick } 19637737Smckusick if (error) { 19737737Smckusick vrele(devvp); 19837737Smckusick return (error); 19932721Smckusick } 20037737Smckusick ump = VFSTOUFS(mp); 20137737Smckusick fs = ump->um_fs; 20237737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 20337737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 20441397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 20541397Smckusick MNAMELEN); 20641397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 20741397Smckusick &size); 20841397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 20951473Sbostic (void)ffs_statfs(mp, &mp->mnt_stat, p); 21037737Smckusick return (0); 21112795Ssam } 21212795Ssam 21337737Smckusick /* 21457051Smckusick * Reload all incore data for a filesystem (used after running fsck on 21557051Smckusick * the root filesystem and finding things to fix). The filesystem must 21657051Smckusick * be mounted read-only. 21757051Smckusick * 21857051Smckusick * Things to do to update the mount: 21957051Smckusick * 1) invalidate all cached meta-data. 22057051Smckusick * 2) re-read superblock from disk. 22157051Smckusick * 3) re-read summary information from disk. 22257051Smckusick * 4) invalidate all inactive vnodes. 22357051Smckusick * 5) invalidate all cached file data. 22457051Smckusick * 6) re-read inode data for all active vnodes. 22557051Smckusick */ 22657051Smckusick ffs_reload(mountp, cred, p) 22757051Smckusick register struct mount *mountp; 22857051Smckusick struct ucred *cred; 22957051Smckusick struct proc *p; 23057051Smckusick { 23157051Smckusick register struct vnode *vp, *nvp, *devvp; 23257051Smckusick struct inode *ip; 23357051Smckusick struct dinode *dp; 23457051Smckusick struct csum *space; 23557051Smckusick struct buf *bp; 23657051Smckusick struct fs *fs; 23757051Smckusick int i, blks, size, error; 23857051Smckusick 23957051Smckusick if ((mountp->mnt_flag & MNT_RDONLY) == 0) 24057051Smckusick return (EINVAL); 24157051Smckusick /* 24257051Smckusick * Step 1: invalidate all cached meta-data. 24357051Smckusick */ 24457051Smckusick devvp = VFSTOUFS(mountp)->um_devvp; 24557801Smckusick if (vinvalbuf(devvp, 0, cred, p, 0, 0)) 24657051Smckusick panic("ffs_reload: dirty1"); 24757051Smckusick /* 24857051Smckusick * Step 2: re-read superblock from disk. 24957051Smckusick */ 25057051Smckusick if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 25157051Smckusick return (error); 25257051Smckusick fs = bp->b_un.b_fs; 25357051Smckusick if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 25457051Smckusick fs->fs_bsize < sizeof(struct fs)) { 25557051Smckusick brelse(bp); 25657051Smckusick return (EIO); /* XXX needs translation */ 25757051Smckusick } 25857051Smckusick fs = VFSTOUFS(mountp)->um_fs; 25957051Smckusick bcopy((caddr_t)&fs->fs_csp[0], (caddr_t)&bp->b_un.b_fs->fs_csp[0], 26057051Smckusick sizeof(fs->fs_csp)); 26157051Smckusick bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)fs, (u_int)fs->fs_sbsize); 26257051Smckusick if (fs->fs_sbsize < SBSIZE) 26357051Smckusick bp->b_flags |= B_INVAL; 26457051Smckusick brelse(bp); 26557051Smckusick ffs_oldfscompat(fs); 26657051Smckusick /* 26757051Smckusick * Step 3: re-read summary information from disk. 26857051Smckusick */ 26957051Smckusick blks = howmany(fs->fs_cssize, fs->fs_fsize); 27057051Smckusick space = fs->fs_csp[0]; 27157051Smckusick for (i = 0; i < blks; i += fs->fs_frag) { 27257051Smckusick size = fs->fs_bsize; 27357051Smckusick if (i + fs->fs_frag > blks) 27457051Smckusick size = (blks - i) * fs->fs_fsize; 27557051Smckusick if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 27657051Smckusick NOCRED, &bp)) 27757051Smckusick return (error); 27857051Smckusick bcopy((caddr_t)bp->b_un.b_addr, fs->fs_csp[fragstoblks(fs, i)], 27957051Smckusick (u_int)size); 28057051Smckusick brelse(bp); 28157051Smckusick } 28257051Smckusick loop: 28357051Smckusick for (vp = mountp->mnt_mounth; vp; vp = nvp) { 28457051Smckusick nvp = vp->v_mountf; 28557051Smckusick /* 28657051Smckusick * Step 4: invalidate all inactive vnodes. 28757051Smckusick */ 28857051Smckusick if (vp->v_usecount == 0) { 28957051Smckusick vgone(vp); 29057051Smckusick continue; 29157051Smckusick } 29257051Smckusick /* 29357051Smckusick * Step 5: invalidate all cached file data. 29457051Smckusick */ 29557051Smckusick if (vget(vp)) 29657051Smckusick goto loop; 29757801Smckusick if (vinvalbuf(vp, 0, cred, p, 0, 0)) 29857051Smckusick panic("ffs_reload: dirty2"); 29957051Smckusick /* 30057051Smckusick * Step 6: re-read inode data for all active vnodes. 30157051Smckusick */ 30257051Smckusick ip = VTOI(vp); 30357051Smckusick if (error = bread(devvp, fsbtodb(fs, itod(fs, ip->i_number)), 30457051Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 30557051Smckusick vput(vp); 30657051Smckusick return (error); 30757051Smckusick } 30857051Smckusick dp = bp->b_un.b_dino; 30957051Smckusick dp += itoo(fs, ip->i_number); 31057051Smckusick ip->i_din = *dp; 31157051Smckusick brelse(bp); 31257051Smckusick vput(vp); 31357051Smckusick if (vp->v_mount != mountp) 31457051Smckusick goto loop; 31557051Smckusick } 31657051Smckusick return (0); 31757051Smckusick } 31857051Smckusick 31957051Smckusick /* 32037737Smckusick * Common code for mount and mountroot 32137737Smckusick */ 32251473Sbostic int 32351473Sbostic ffs_mountfs(devvp, mp, p) 32440376Smckusick register struct vnode *devvp; 32537737Smckusick struct mount *mp; 32648036Smckusick struct proc *p; 32712795Ssam { 32854461Smckusick register struct ufsmount *ump; 32954461Smckusick struct buf *bp; 33012795Ssam register struct fs *fs; 33137737Smckusick dev_t dev = devvp->v_rdev; 33230749Skarels struct partinfo dpart; 33337737Smckusick caddr_t base, space; 33430749Skarels int havepart = 0, blks; 33537737Smckusick int error, i, size; 33654461Smckusick int ronly; 33745652Smckusick extern struct vnode *rootvp; 33812795Ssam 33940376Smckusick /* 34040376Smckusick * Disallow multiple mounts of the same device. 34145652Smckusick * Disallow mounting of a device that is currently in use 34245652Smckusick * (except for root, which might share swap device for miniroot). 34340376Smckusick * Flush out any old buffers remaining from a previous use. 34440376Smckusick */ 34551473Sbostic if (error = ufs_mountedon(devvp)) 34640376Smckusick return (error); 34745652Smckusick if (vcount(devvp) > 1 && devvp != rootvp) 34840376Smckusick return (EBUSY); 34957801Smckusick if (error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)) 35054461Smckusick return (error); 35154461Smckusick 35254461Smckusick ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 35359472Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)) 35437737Smckusick return (error); 35548036Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 35637737Smckusick size = DEV_BSIZE; 35748036Smckusick else { 35830749Skarels havepart = 1; 35930749Skarels size = dpart.disklab->d_secsize; 36037737Smckusick } 36154461Smckusick 36254461Smckusick bp = NULL; 36354461Smckusick ump = NULL; 36441314Smckusick if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 36512795Ssam goto out; 36634421Skarels fs = bp->b_un.b_fs; 36730749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 36830749Skarels fs->fs_bsize < sizeof(struct fs)) { 36941314Smckusick error = EINVAL; /* XXX needs translation */ 37016639Skarels goto out; 37116639Skarels } 37251473Sbostic ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 37352538Smckusick bzero((caddr_t)ump, sizeof *ump); 37451982Smckusick ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, 37534473Smckusick M_WAITOK); 37637737Smckusick bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 37712795Ssam (u_int)fs->fs_sbsize); 37839675Smckusick if (fs->fs_sbsize < SBSIZE) 37939675Smckusick bp->b_flags |= B_INVAL; 38034421Skarels brelse(bp); 38134421Skarels bp = NULL; 38237737Smckusick fs = ump->um_fs; 38337737Smckusick fs->fs_ronly = ronly; 38412795Ssam if (ronly == 0) 38512795Ssam fs->fs_fmod = 1; 38630749Skarels if (havepart) { 38730749Skarels dpart.part->p_fstype = FS_BSDFFS; 38830749Skarels dpart.part->p_fsize = fs->fs_fsize; 38930749Skarels dpart.part->p_frag = fs->fs_frag; 39031385Skarels dpart.part->p_cpg = fs->fs_cpg; 39130749Skarels } 39212795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 39351982Smckusick base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT, 39434473Smckusick M_WAITOK); 39512795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 39612795Ssam size = fs->fs_bsize; 39712795Ssam if (i + fs->fs_frag > blks) 39812795Ssam size = (blks - i) * fs->fs_fsize; 39938776Smckusick error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 40038776Smckusick NOCRED, &bp); 40137737Smckusick if (error) { 40251982Smckusick free(base, M_UFSMNT); 40312795Ssam goto out; 40412795Ssam } 40534421Skarels bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 40617225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 40712795Ssam space += size; 40834421Skarels brelse(bp); 40934421Skarels bp = NULL; 41012795Ssam } 41141397Smckusick mp->mnt_data = (qaddr_t)ump; 41241397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 41341397Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 41454305Smckusick mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 41541397Smckusick mp->mnt_flag |= MNT_LOCAL; 41637737Smckusick ump->um_mountp = mp; 41737737Smckusick ump->um_dev = dev; 41837737Smckusick ump->um_devvp = devvp; 41956446Smargo ump->um_nindir = fs->fs_nindir; 42056446Smargo ump->um_bptrtodb = fs->fs_fsbtodb; 42156446Smargo ump->um_seqinc = fs->fs_frag; 42241314Smckusick for (i = 0; i < MAXQUOTAS; i++) 42341314Smckusick ump->um_quotas[i] = NULLVP; 42440653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 42557051Smckusick ffs_oldfscompat(fs); 42657051Smckusick return (0); 42757051Smckusick out: 42857051Smckusick if (bp) 42957051Smckusick brelse(bp); 43057051Smckusick (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 43157051Smckusick if (ump) { 43257051Smckusick free(ump->um_fs, M_UFSMNT); 43357051Smckusick free(ump, M_UFSMNT); 43457051Smckusick mp->mnt_data = (qaddr_t)0; 43557051Smckusick } 43657051Smckusick return (error); 43757051Smckusick } 43837737Smckusick 43957051Smckusick /* 44057051Smckusick * Sanity checks for old file systems. 44157051Smckusick * 44257051Smckusick * XXX - goes away some day. 44357051Smckusick */ 44457051Smckusick ffs_oldfscompat(fs) 44557051Smckusick struct fs *fs; 44657051Smckusick { 44757051Smckusick int i; 44857051Smckusick 44955056Spendry fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 45055056Spendry fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 45134145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 45234145Smckusick fs->fs_nrpos = 8; /* XXX */ 45353913Smckusick if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 45453913Smckusick quad_t sizepb = fs->fs_bsize; /* XXX */ 45553913Smckusick /* XXX */ 45653913Smckusick fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 45753913Smckusick for (i = 0; i < NIADDR; i++) { /* XXX */ 45853913Smckusick sizepb *= NINDIR(fs); /* XXX */ 45953913Smckusick fs->fs_maxfilesize += sizepb; /* XXX */ 46053913Smckusick } /* XXX */ 46153913Smckusick fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 46253913Smckusick fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 46353913Smckusick } /* XXX */ 46437737Smckusick return (0); 46512795Ssam } 46612795Ssam 46739043Smckusick /* 46837737Smckusick * unmount system call 46937737Smckusick */ 47051473Sbostic int 47151473Sbostic ffs_unmount(mp, mntflags, p) 47237737Smckusick struct mount *mp; 47341314Smckusick int mntflags; 47448036Smckusick struct proc *p; 47512795Ssam { 47637737Smckusick register struct ufsmount *ump; 47737737Smckusick register struct fs *fs; 47857051Smckusick int error, flags, ronly; 47912795Ssam 48054461Smckusick flags = 0; 48148065Smckusick if (mntflags & MNT_FORCE) { 48257051Smckusick if (mp == rootfs) 48348065Smckusick return (EINVAL); 48441314Smckusick flags |= FORCECLOSE; 48548065Smckusick } 48657051Smckusick if (error = ffs_flushfiles(mp, flags, p)) 48757051Smckusick return (error); 48837737Smckusick ump = VFSTOUFS(mp); 48957051Smckusick fs = ump->um_fs; 49057051Smckusick ronly = !fs->fs_ronly; 49157051Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 49257051Smckusick error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 49357051Smckusick NOCRED, p); 49457051Smckusick vrele(ump->um_devvp); 49557051Smckusick free(fs->fs_csp[0], M_UFSMNT); 49657051Smckusick free(fs, M_UFSMNT); 49757051Smckusick free(ump, M_UFSMNT); 49857051Smckusick mp->mnt_data = (qaddr_t)0; 49957051Smckusick mp->mnt_flag &= ~MNT_LOCAL; 50057051Smckusick return (error); 50157051Smckusick } 50257051Smckusick 50357051Smckusick /* 50457051Smckusick * Flush out all the files in a filesystem. 50557051Smckusick */ 50657051Smckusick ffs_flushfiles(mp, flags, p) 50757051Smckusick register struct mount *mp; 50857051Smckusick int flags; 50957051Smckusick struct proc *p; 51057051Smckusick { 51157051Smckusick extern int doforce; 51257051Smckusick register struct ufsmount *ump; 51357051Smckusick int i, error; 51457051Smckusick 51557051Smckusick if (!doforce) 51657051Smckusick flags &= ~FORCECLOSE; 51757051Smckusick ump = VFSTOUFS(mp); 51812795Ssam #ifdef QUOTA 51941397Smckusick if (mp->mnt_flag & MNT_QUOTA) { 52041314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 52139898Smckusick return (error); 52241314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 52341314Smckusick if (ump->um_quotas[i] == NULLVP) 52441314Smckusick continue; 52550114Smckusick quotaoff(p, mp, i); 52641314Smckusick } 52739898Smckusick /* 52841314Smckusick * Here we fall through to vflush again to ensure 52941314Smckusick * that we have gotten rid of all the system vnodes. 53039898Smckusick */ 53141314Smckusick } 53212795Ssam #endif 53357051Smckusick error = vflush(mp, NULLVP, flags); 53430749Skarels return (error); 53512795Ssam } 53612795Ssam 53737737Smckusick /* 53851545Smckusick * Return root of a filesystem 53951545Smckusick */ 54051545Smckusick int 54151545Smckusick ffs_root(mp, vpp) 54251545Smckusick struct mount *mp; 54351545Smckusick struct vnode **vpp; 54451545Smckusick { 54551545Smckusick struct vnode *nvp; 54651545Smckusick int error; 54751545Smckusick 54854657Smckusick if (error = VFS_VGET(mp, (ino_t)ROOTINO, &nvp)) 54951545Smckusick return (error); 55051545Smckusick *vpp = nvp; 55151545Smckusick return (0); 55251545Smckusick } 55351545Smckusick 55451545Smckusick /* 55537737Smckusick * Get file system statistics. 55637737Smckusick */ 55751473Sbostic int 55851473Sbostic ffs_statfs(mp, sbp, p) 55937737Smckusick struct mount *mp; 56037737Smckusick register struct statfs *sbp; 56148036Smckusick struct proc *p; 56237737Smckusick { 56337737Smckusick register struct ufsmount *ump; 56437737Smckusick register struct fs *fs; 56537737Smckusick 56637737Smckusick ump = VFSTOUFS(mp); 56737737Smckusick fs = ump->um_fs; 56837737Smckusick if (fs->fs_magic != FS_MAGIC) 56951473Sbostic panic("ffs_statfs"); 57037737Smckusick sbp->f_type = MOUNT_UFS; 57151942Smckusick sbp->f_bsize = fs->fs_fsize; 57251942Smckusick sbp->f_iosize = fs->fs_bsize; 57337737Smckusick sbp->f_blocks = fs->fs_dsize; 57437737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 57537737Smckusick fs->fs_cstotal.cs_nffree; 57637737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 57737737Smckusick (fs->fs_dsize - sbp->f_bfree); 57839350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 57937737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 58041397Smckusick if (sbp != &mp->mnt_stat) { 58141397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 58240346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 58341397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 58440346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 58540346Smckusick } 58637737Smckusick return (0); 58737737Smckusick } 58837737Smckusick 58937737Smckusick /* 59037737Smckusick * Go through the disk queues to initiate sandbagged IO; 59137737Smckusick * go through the inodes to write those that have been modified; 59237737Smckusick * initiate the writing of the super block if it has been modified. 59341314Smckusick * 59441314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 59537737Smckusick */ 59651473Sbostic int 59754461Smckusick ffs_sync(mp, waitfor, cred, p) 59837737Smckusick struct mount *mp; 59937737Smckusick int waitfor; 60054461Smckusick struct ucred *cred; 60154461Smckusick struct proc *p; 60237737Smckusick { 60339390Smckusick register struct vnode *vp; 60437737Smckusick register struct inode *ip; 60537737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 60637737Smckusick register struct fs *fs; 60739596Smckusick int error, allerror = 0; 60837737Smckusick 60937737Smckusick fs = ump->um_fs; 61037737Smckusick /* 61137737Smckusick * Write back modified superblock. 61237737Smckusick * Consistency check that the superblock 61337737Smckusick * is still in the buffer cache. 61437737Smckusick */ 61537737Smckusick if (fs->fs_fmod != 0) { 61637737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 61737737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 61837737Smckusick panic("update: rofs mod"); 61937737Smckusick } 62037737Smckusick fs->fs_fmod = 0; 62137737Smckusick fs->fs_time = time.tv_sec; 62251473Sbostic allerror = ffs_sbupdate(ump, waitfor); 62337737Smckusick } 62437737Smckusick /* 62537737Smckusick * Write back each (modified) inode. 62637737Smckusick */ 62739877Smckusick loop: 62841462Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 62941462Smckusick /* 63041462Smckusick * If the vnode that we are about to sync is no longer 63141462Smckusick * associated with this mount point, start over. 63241462Smckusick */ 63341462Smckusick if (vp->v_mount != mp) 63441462Smckusick goto loop; 63548359Smckusick if (VOP_ISLOCKED(vp)) 63648359Smckusick continue; 63739390Smckusick ip = VTOI(vp); 63839877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 63956465Smckusick vp->v_dirtyblkhd.le_next == NULL) 64037737Smckusick continue; 64139877Smckusick if (vget(vp)) 64239877Smckusick goto loop; 64354461Smckusick if (error = VOP_FSYNC(vp, cred, waitfor, p)) 64439596Smckusick allerror = error; 64539596Smckusick vput(vp); 64637737Smckusick } 64737737Smckusick /* 64839675Smckusick * Force stale file system control information to be flushed. 64937737Smckusick */ 65054461Smckusick if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) 65154461Smckusick allerror = error; 65241314Smckusick #ifdef QUOTA 65341314Smckusick qsync(mp); 65441314Smckusick #endif 65539596Smckusick return (allerror); 65637737Smckusick } 65737737Smckusick 65837737Smckusick /* 65954657Smckusick * Look up a FFS dinode number to find its incore vnode. 66054657Smckusick * If it is not in core, read it in from the specified device. 66154657Smckusick * If it is in core, wait for the lock bit to clear, then 66254657Smckusick * return the inode locked. Detection and handling of mount 66354657Smckusick * points must be done by the calling routine. 66454657Smckusick */ 66554657Smckusick int 66654657Smckusick ffs_vget(mp, ino, vpp) 66754657Smckusick struct mount *mp; 66854657Smckusick ino_t ino; 66954657Smckusick struct vnode **vpp; 67054657Smckusick { 67154657Smckusick register struct fs *fs; 67254657Smckusick register struct inode *ip; 67354657Smckusick struct ufsmount *ump; 67454657Smckusick struct buf *bp; 67554657Smckusick struct dinode *dp; 67654657Smckusick struct vnode *vp; 67754657Smckusick union ihead *ih; 67854657Smckusick dev_t dev; 67954657Smckusick int i, type, error; 68054657Smckusick 68154657Smckusick ump = VFSTOUFS(mp); 68254657Smckusick dev = ump->um_dev; 68354657Smckusick if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 68454657Smckusick return (0); 68554657Smckusick 68654657Smckusick /* Allocate a new vnode/inode. */ 68754657Smckusick if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) { 68854657Smckusick *vpp = NULL; 68954657Smckusick return (error); 69054657Smckusick } 69154657Smckusick type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ 69254657Smckusick MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); 693*59819Smckusick bzero((caddr_t)ip, sizeof(struct inode)); 69454657Smckusick vp->v_data = ip; 69554657Smckusick ip->i_vnode = vp; 69654657Smckusick ip->i_fs = fs = ump->um_fs; 69754657Smckusick ip->i_dev = dev; 69854657Smckusick ip->i_number = ino; 69954657Smckusick #ifdef QUOTA 70054657Smckusick for (i = 0; i < MAXQUOTAS; i++) 70154657Smckusick ip->i_dquot[i] = NODQUOT; 70254657Smckusick #endif 70354657Smckusick /* 70454657Smckusick * Put it onto its hash chain and lock it so that other requests for 70554657Smckusick * this inode will block if they arrive while we are sleeping waiting 70654657Smckusick * for old data structures to be purged or for the contents of the 70754657Smckusick * disk portion of this inode to be read. 70854657Smckusick */ 70954657Smckusick ufs_ihashins(ip); 71054657Smckusick 71154657Smckusick /* Read in the disk contents for the inode, copy into the inode. */ 71254657Smckusick if (error = bread(ump->um_devvp, fsbtodb(fs, itod(fs, ino)), 71354657Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 71454657Smckusick /* 71554657Smckusick * The inode does not contain anything useful, so it would 716*59819Smckusick * be misleading to leave it on its hash chain. With mode 717*59819Smckusick * still zero, it will be unlinked and returned to the free 718*59819Smckusick * list by vput(). 71954657Smckusick */ 72056797Smckusick vput(vp); 72154657Smckusick brelse(bp); 72254657Smckusick *vpp = NULL; 72354657Smckusick return (error); 72454657Smckusick } 72554657Smckusick dp = bp->b_un.b_dino; 72654657Smckusick dp += itoo(fs, ino); 72754657Smckusick ip->i_din = *dp; 72854657Smckusick brelse(bp); 72954657Smckusick 73054657Smckusick /* 73154657Smckusick * Initialize the vnode from the inode, check for aliases. 73254657Smckusick * Note that the underlying vnode may have changed. 73354657Smckusick */ 73454657Smckusick if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) { 73556797Smckusick vput(vp); 73654657Smckusick *vpp = NULL; 73754657Smckusick return (error); 73854657Smckusick } 73954657Smckusick /* 74054657Smckusick * Finish inode initialization now that aliasing has been resolved. 74154657Smckusick */ 74254657Smckusick ip->i_devvp = ump->um_devvp; 74354657Smckusick VREF(ip->i_devvp); 74454657Smckusick /* 74554657Smckusick * Set up a generation number for this inode if it does not 74654657Smckusick * already have one. This should only happen on old filesystems. 74754657Smckusick */ 74854657Smckusick if (ip->i_gen == 0) { 74954657Smckusick if (++nextgennumber < (u_long)time.tv_sec) 75054657Smckusick nextgennumber = time.tv_sec; 75154657Smckusick ip->i_gen = nextgennumber; 75254657Smckusick if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 75354657Smckusick ip->i_flag |= IMOD; 75454657Smckusick } 75554657Smckusick /* 75654657Smckusick * Ensure that uid and gid are correct. This is a temporary 75754657Smckusick * fix until fsck has been changed to do the update. 75854657Smckusick */ 75954657Smckusick if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 76054657Smckusick ip->i_uid = ip->i_din.di_ouid; /* XXX */ 76154657Smckusick ip->i_gid = ip->i_din.di_ogid; /* XXX */ 76254657Smckusick } /* XXX */ 76354657Smckusick 76454657Smckusick *vpp = vp; 76554657Smckusick return (0); 76654657Smckusick } 76754657Smckusick 76854657Smckusick /* 76951545Smckusick * File handle to vnode 77051545Smckusick * 77151545Smckusick * Have to be really careful about stale file handles: 77251545Smckusick * - check that the inode number is valid 77351545Smckusick * - call ffs_vget() to get the locked inode 77451545Smckusick * - check for an unallocated inode (i_mode == 0) 77554733Smckusick * - check that the given client host has export rights and return 77654733Smckusick * those rights via. exflagsp and credanonp 77751545Smckusick */ 77851545Smckusick int 77954733Smckusick ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 78051545Smckusick register struct mount *mp; 78151545Smckusick struct fid *fhp; 78254733Smckusick struct mbuf *nam; 78351545Smckusick struct vnode **vpp; 78454733Smckusick int *exflagsp; 78554733Smckusick struct ucred **credanonp; 78651545Smckusick { 78751545Smckusick register struct ufid *ufhp; 78851545Smckusick struct fs *fs; 78951545Smckusick 79051545Smckusick ufhp = (struct ufid *)fhp; 79155890Smckusick fs = VFSTOUFS(mp)->um_fs; 79251545Smckusick if (ufhp->ufid_ino < ROOTINO || 79351545Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) 79454733Smckusick return (ESTALE); 79556245Smckusick return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); 79651545Smckusick } 79751545Smckusick 79851545Smckusick /* 79951545Smckusick * Vnode pointer to File handle 80051545Smckusick */ 80151545Smckusick /* ARGSUSED */ 80251545Smckusick ffs_vptofh(vp, fhp) 80351545Smckusick struct vnode *vp; 80451545Smckusick struct fid *fhp; 80551545Smckusick { 80651545Smckusick register struct inode *ip; 80751545Smckusick register struct ufid *ufhp; 80851545Smckusick 80951545Smckusick ip = VTOI(vp); 81051545Smckusick ufhp = (struct ufid *)fhp; 81151545Smckusick ufhp->ufid_len = sizeof(struct ufid); 81251545Smckusick ufhp->ufid_ino = ip->i_number; 81351545Smckusick ufhp->ufid_gen = ip->i_gen; 81451545Smckusick return (0); 81551545Smckusick } 81651545Smckusick 81751545Smckusick /* 81837737Smckusick * Write a superblock and associated information back to disk. 81937737Smckusick */ 82051942Smckusick int 82151473Sbostic ffs_sbupdate(mp, waitfor) 82237737Smckusick struct ufsmount *mp; 82337737Smckusick int waitfor; 82437737Smckusick { 82537737Smckusick register struct fs *fs = mp->um_fs; 82612795Ssam register struct buf *bp; 82712795Ssam int blks; 82812795Ssam caddr_t space; 82937737Smckusick int i, size, error = 0; 83012795Ssam 83157801Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); 83212795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 83334145Smckusick /* Restore compatibility to old file systems. XXX */ 83434145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 83534145Smckusick bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 83637737Smckusick if (waitfor == MNT_WAIT) 83737737Smckusick error = bwrite(bp); 83837737Smckusick else 83937737Smckusick bawrite(bp); 84012795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 84112795Ssam space = (caddr_t)fs->fs_csp[0]; 84212795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 84312795Ssam size = fs->fs_bsize; 84412795Ssam if (i + fs->fs_frag > blks) 84512795Ssam size = (blks - i) * fs->fs_fsize; 84657801Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), 84757801Smckusick size, 0, 0); 84812795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 84912795Ssam space += size; 85037737Smckusick if (waitfor == MNT_WAIT) 85137737Smckusick error = bwrite(bp); 85237737Smckusick else 85337737Smckusick bawrite(bp); 85412795Ssam } 85537737Smckusick return (error); 85612795Ssam } 857