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*68545Smckusick * @(#)ffs_vfsops.c 8.18 (Berkeley) 03/20/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, 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 } 9065236Smckusick TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 9165236Smckusick mp->mnt_flag |= MNT_ROOTFS; 9241397Smckusick mp->mnt_vnodecovered = NULLVP; 9337737Smckusick ump = VFSTOUFS(mp); 9437737Smckusick fs = ump->um_fs; 9540346Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 9637737Smckusick fs->fs_fsmnt[0] = '/'; 9741397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 9841397Smckusick MNAMELEN); 9941397Smckusick (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 10041397Smckusick &size); 10141397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 10251473Sbostic (void)ffs_statfs(mp, &mp->mnt_stat, p); 10337737Smckusick vfs_unlock(mp); 10437737Smckusick inittodr(fs->fs_time); 10537737Smckusick return (0); 10637737Smckusick } 10737737Smckusick 10837737Smckusick /* 10937737Smckusick * VFS Operations. 11037737Smckusick * 11137737Smckusick * mount system call 11237737Smckusick */ 11351942Smckusick int 11451473Sbostic ffs_mount(mp, path, data, ndp, p) 11540346Smckusick register struct mount *mp; 11637737Smckusick char *path; 11737737Smckusick caddr_t data; 11837737Smckusick struct nameidata *ndp; 11948036Smckusick struct proc *p; 12037737Smckusick { 12137737Smckusick struct vnode *devvp; 12237737Smckusick struct ufs_args args; 12337737Smckusick struct ufsmount *ump; 12437737Smckusick register struct fs *fs; 12537737Smckusick u_int size; 12657051Smckusick int error, flags; 12767534Smckusick mode_t accessmode; 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); 15267534Smckusick if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { 15367534Smckusick /* 15467534Smckusick * If upgrade to read-write by non-root, then verify 15567534Smckusick * that user has necessary permissions on the device. 15667534Smckusick */ 15767534Smckusick if (p->p_ucred->cr_uid != 0) { 15867534Smckusick devvp = ump->um_devvp; 15967534Smckusick VOP_LOCK(devvp); 16067534Smckusick if (error = VOP_ACCESS(devvp, VREAD | VWRITE, 16167534Smckusick p->p_ucred, p)) { 16267534Smckusick VOP_UNLOCK(devvp); 16367534Smckusick return (error); 16467534Smckusick } 16567534Smckusick VOP_UNLOCK(devvp); 16667534Smckusick } 16739336Smckusick fs->fs_ronly = 0; 16867534Smckusick } 16952177Smckusick if (args.fspec == 0) { 17052177Smckusick /* 17152177Smckusick * Process export requests. 17252177Smckusick */ 17365672Shibler return (vfs_export(mp, &ump->um_export, &args.export)); 17452177Smckusick } 17550264Skarels } 17650264Skarels /* 17750264Skarels * Not an update, or updating the name: look up the name 17850264Skarels * and verify that it refers to a sensible block device. 17950264Skarels */ 18052332Smckusick NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 18152332Smckusick if (error = namei(ndp)) 18250264Skarels return (error); 18350264Skarels devvp = ndp->ni_vp; 18451473Sbostic 18550264Skarels if (devvp->v_type != VBLK) { 18650264Skarels vrele(devvp); 18750264Skarels return (ENOTBLK); 18850264Skarels } 18950264Skarels if (major(devvp->v_rdev) >= nblkdev) { 19050264Skarels vrele(devvp); 19150264Skarels return (ENXIO); 19250264Skarels } 19367534Smckusick /* 19467534Smckusick * If mount by non-root, then verify that user has necessary 19567534Smckusick * permissions on the device. 19667534Smckusick */ 19767534Smckusick if (p->p_ucred->cr_uid != 0) { 19867534Smckusick accessmode = VREAD; 19967534Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0) 20067534Smckusick accessmode |= VWRITE; 20167534Smckusick VOP_LOCK(devvp); 20267534Smckusick if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) { 20367534Smckusick vput(devvp); 20467534Smckusick return (error); 20567534Smckusick } 20667534Smckusick VOP_UNLOCK(devvp); 20767534Smckusick } 20850264Skarels if ((mp->mnt_flag & MNT_UPDATE) == 0) 20951473Sbostic error = ffs_mountfs(devvp, mp, p); 21050264Skarels else { 21139336Smckusick if (devvp != ump->um_devvp) 21239336Smckusick error = EINVAL; /* needs translation */ 21342858Smckusick else 21442858Smckusick vrele(devvp); 21539336Smckusick } 21637737Smckusick if (error) { 21737737Smckusick vrele(devvp); 21837737Smckusick return (error); 21932721Smckusick } 22037737Smckusick ump = VFSTOUFS(mp); 22137737Smckusick fs = ump->um_fs; 22237737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 22337737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 22441397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 22541397Smckusick MNAMELEN); 22641397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 22741397Smckusick &size); 22841397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 22951473Sbostic (void)ffs_statfs(mp, &mp->mnt_stat, p); 23037737Smckusick return (0); 23112795Ssam } 23212795Ssam 23337737Smckusick /* 23457051Smckusick * Reload all incore data for a filesystem (used after running fsck on 23557051Smckusick * the root filesystem and finding things to fix). The filesystem must 23657051Smckusick * be mounted read-only. 23757051Smckusick * 23857051Smckusick * Things to do to update the mount: 23957051Smckusick * 1) invalidate all cached meta-data. 24057051Smckusick * 2) re-read superblock from disk. 24157051Smckusick * 3) re-read summary information from disk. 24257051Smckusick * 4) invalidate all inactive vnodes. 24357051Smckusick * 5) invalidate all cached file data. 24457051Smckusick * 6) re-read inode data for all active vnodes. 24557051Smckusick */ 24657051Smckusick ffs_reload(mountp, cred, p) 24757051Smckusick register struct mount *mountp; 24857051Smckusick struct ucred *cred; 24957051Smckusick struct proc *p; 25057051Smckusick { 25157051Smckusick register struct vnode *vp, *nvp, *devvp; 25257051Smckusick struct inode *ip; 25357051Smckusick struct csum *space; 25457051Smckusick struct buf *bp; 255*68545Smckusick struct fs *fs, *newfs; 25668115Smckusick struct partinfo dpart; 25757051Smckusick int i, blks, size, error; 25857051Smckusick 25957051Smckusick if ((mountp->mnt_flag & MNT_RDONLY) == 0) 26057051Smckusick return (EINVAL); 26157051Smckusick /* 26257051Smckusick * Step 1: invalidate all cached meta-data. 26357051Smckusick */ 26457051Smckusick devvp = VFSTOUFS(mountp)->um_devvp; 26557801Smckusick if (vinvalbuf(devvp, 0, cred, p, 0, 0)) 26657051Smckusick panic("ffs_reload: dirty1"); 26757051Smckusick /* 26857051Smckusick * Step 2: re-read superblock from disk. 26957051Smckusick */ 27068115Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 27168115Smckusick size = DEV_BSIZE; 27268115Smckusick else 27368115Smckusick size = dpart.disklab->d_secsize; 27468115Smckusick if (error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp)) 27557051Smckusick return (error); 276*68545Smckusick newfs = (struct fs *)bp->b_data; 277*68545Smckusick if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || 278*68545Smckusick newfs->fs_bsize < sizeof(struct fs)) { 27957051Smckusick brelse(bp); 28057051Smckusick return (EIO); /* XXX needs translation */ 28157051Smckusick } 28257051Smckusick fs = VFSTOUFS(mountp)->um_fs; 283*68545Smckusick bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp)); 284*68545Smckusick newfs->fs_maxcluster = fs->fs_maxcluster; 285*68545Smckusick bcopy(newfs, fs, (u_int)fs->fs_sbsize); 28657051Smckusick if (fs->fs_sbsize < SBSIZE) 28757051Smckusick bp->b_flags |= B_INVAL; 28857051Smckusick brelse(bp); 28967460Smckusick mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 29057051Smckusick ffs_oldfscompat(fs); 29157051Smckusick /* 29257051Smckusick * Step 3: re-read summary information from disk. 29357051Smckusick */ 29457051Smckusick blks = howmany(fs->fs_cssize, fs->fs_fsize); 29557051Smckusick space = fs->fs_csp[0]; 29657051Smckusick for (i = 0; i < blks; i += fs->fs_frag) { 29757051Smckusick size = fs->fs_bsize; 29857051Smckusick if (i + fs->fs_frag > blks) 29957051Smckusick size = (blks - i) * fs->fs_fsize; 30057051Smckusick if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 30157051Smckusick NOCRED, &bp)) 30257051Smckusick return (error); 30364511Sbostic bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); 30457051Smckusick brelse(bp); 30557051Smckusick } 30657051Smckusick loop: 30765236Smckusick for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 30865236Smckusick nvp = vp->v_mntvnodes.le_next; 30957051Smckusick /* 31057051Smckusick * Step 4: invalidate all inactive vnodes. 31157051Smckusick */ 31257051Smckusick if (vp->v_usecount == 0) { 31357051Smckusick vgone(vp); 31457051Smckusick continue; 31557051Smckusick } 31657051Smckusick /* 31757051Smckusick * Step 5: invalidate all cached file data. 31857051Smckusick */ 31965236Smckusick if (vget(vp, 1)) 32057051Smckusick goto loop; 32157801Smckusick if (vinvalbuf(vp, 0, cred, p, 0, 0)) 32257051Smckusick panic("ffs_reload: dirty2"); 32357051Smckusick /* 32457051Smckusick * Step 6: re-read inode data for all active vnodes. 32557051Smckusick */ 32657051Smckusick ip = VTOI(vp); 32764605Sbostic if (error = 32864605Sbostic bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 32957051Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 33057051Smckusick vput(vp); 33157051Smckusick return (error); 33257051Smckusick } 33364605Sbostic ip->i_din = *((struct dinode *)bp->b_data + 33464605Sbostic ino_to_fsbo(fs, ip->i_number)); 33557051Smckusick brelse(bp); 33657051Smckusick vput(vp); 33757051Smckusick if (vp->v_mount != mountp) 33857051Smckusick goto loop; 33957051Smckusick } 34057051Smckusick return (0); 34157051Smckusick } 34257051Smckusick 34357051Smckusick /* 34437737Smckusick * Common code for mount and mountroot 34537737Smckusick */ 34651473Sbostic int 34751473Sbostic ffs_mountfs(devvp, mp, p) 34840376Smckusick register struct vnode *devvp; 34937737Smckusick struct mount *mp; 35048036Smckusick struct proc *p; 35112795Ssam { 35254461Smckusick register struct ufsmount *ump; 35354461Smckusick struct buf *bp; 35412795Ssam register struct fs *fs; 35568004Smckusick dev_t dev; 35630749Skarels struct partinfo dpart; 35737737Smckusick caddr_t base, space; 35868115Smckusick int error, i, blks, size, ronly; 35967868Smckusick int32_t *lp; 36068004Smckusick struct ucred *cred; 36145652Smckusick extern struct vnode *rootvp; 36268115Smckusick u_int64_t maxfilesize; /* XXX */ 36312795Ssam 36468004Smckusick dev = devvp->v_rdev; 36568004Smckusick cred = p ? p->p_ucred : NOCRED; 36640376Smckusick /* 36740376Smckusick * Disallow multiple mounts of the same device. 36845652Smckusick * Disallow mounting of a device that is currently in use 36945652Smckusick * (except for root, which might share swap device for miniroot). 37040376Smckusick * Flush out any old buffers remaining from a previous use. 37140376Smckusick */ 37265672Shibler if (error = vfs_mountedon(devvp)) 37340376Smckusick return (error); 37445652Smckusick if (vcount(devvp) > 1 && devvp != rootvp) 37540376Smckusick return (EBUSY); 37668004Smckusick if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) 37754461Smckusick return (error); 37854461Smckusick 37954461Smckusick ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 38059472Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)) 38137737Smckusick return (error); 38268004Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) 38337737Smckusick size = DEV_BSIZE; 38468115Smckusick else 38530749Skarels size = dpart.disklab->d_secsize; 38654461Smckusick 38754461Smckusick bp = NULL; 38854461Smckusick ump = NULL; 38968115Smckusick if (error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, cred, &bp)) 39012795Ssam goto out; 39164511Sbostic fs = (struct fs *)bp->b_data; 39230749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 39330749Skarels fs->fs_bsize < sizeof(struct fs)) { 39441314Smckusick error = EINVAL; /* XXX needs translation */ 39516639Skarels goto out; 39616639Skarels } 39768116Smckusick /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ 39868116Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { 39968116Smckusick error = EROFS; /* needs translation */ 40068116Smckusick goto out; 40168116Smckusick } 40251473Sbostic ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 40352538Smckusick bzero((caddr_t)ump, sizeof *ump); 40451982Smckusick ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, 40534473Smckusick M_WAITOK); 40664511Sbostic bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); 40739675Smckusick if (fs->fs_sbsize < SBSIZE) 40839675Smckusick bp->b_flags |= B_INVAL; 40934421Skarels brelse(bp); 41034421Skarels bp = NULL; 41137737Smckusick fs = ump->um_fs; 41237737Smckusick fs->fs_ronly = ronly; 41312795Ssam if (ronly == 0) 41412795Ssam fs->fs_fmod = 1; 41567868Smckusick size = fs->fs_cssize; 41668116Smckusick blks = howmany(size, fs->fs_fsize); 41767868Smckusick if (fs->fs_contigsumsize > 0) 41867868Smckusick size += fs->fs_ncg * sizeof(int32_t); 41967868Smckusick base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK); 42012795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 42112795Ssam size = fs->fs_bsize; 42212795Ssam if (i + fs->fs_frag > blks) 42312795Ssam size = (blks - i) * fs->fs_fsize; 42468004Smckusick if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 42568004Smckusick cred, &bp)) { 42651982Smckusick free(base, M_UFSMNT); 42712795Ssam goto out; 42812795Ssam } 42964511Sbostic bcopy(bp->b_data, space, (u_int)size); 43017225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 43112795Ssam space += size; 43234421Skarels brelse(bp); 43334421Skarels bp = NULL; 43412795Ssam } 43567868Smckusick if (fs->fs_contigsumsize > 0) { 43667868Smckusick fs->fs_maxcluster = lp = (int32_t *)space; 43767868Smckusick for (i = 0; i < fs->fs_ncg; i++) 43867868Smckusick *lp++ = fs->fs_contigsumsize; 43967868Smckusick } 44041397Smckusick mp->mnt_data = (qaddr_t)ump; 44141397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 44241397Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 44354305Smckusick mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 44441397Smckusick mp->mnt_flag |= MNT_LOCAL; 44537737Smckusick ump->um_mountp = mp; 44637737Smckusick ump->um_dev = dev; 44737737Smckusick ump->um_devvp = devvp; 44856446Smargo ump->um_nindir = fs->fs_nindir; 44956446Smargo ump->um_bptrtodb = fs->fs_fsbtodb; 45056446Smargo ump->um_seqinc = fs->fs_frag; 45141314Smckusick for (i = 0; i < MAXQUOTAS; i++) 45241314Smckusick ump->um_quotas[i] = NULLVP; 45340653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 45457051Smckusick ffs_oldfscompat(fs); 45567868Smckusick ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ 45668115Smckusick maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; /* XXX */ 45768115Smckusick if (fs->fs_maxfilesize > maxfilesize) /* XXX */ 45868115Smckusick fs->fs_maxfilesize = maxfilesize; /* XXX */ 45957051Smckusick return (0); 46057051Smckusick out: 46157051Smckusick if (bp) 46257051Smckusick brelse(bp); 46368004Smckusick (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); 46457051Smckusick if (ump) { 46557051Smckusick free(ump->um_fs, M_UFSMNT); 46657051Smckusick free(ump, M_UFSMNT); 46757051Smckusick mp->mnt_data = (qaddr_t)0; 46857051Smckusick } 46957051Smckusick return (error); 47057051Smckusick } 47137737Smckusick 47257051Smckusick /* 47357051Smckusick * Sanity checks for old file systems. 47457051Smckusick * 47557051Smckusick * XXX - goes away some day. 47657051Smckusick */ 47757051Smckusick ffs_oldfscompat(fs) 47857051Smckusick struct fs *fs; 47957051Smckusick { 48057051Smckusick int i; 48157051Smckusick 48255056Spendry fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 48355056Spendry fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 48434145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 48534145Smckusick fs->fs_nrpos = 8; /* XXX */ 48653913Smckusick if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 48768122Smckusick u_int64_t sizepb = fs->fs_bsize; /* XXX */ 48853913Smckusick /* XXX */ 48953913Smckusick fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 49053913Smckusick for (i = 0; i < NIADDR; i++) { /* XXX */ 49153913Smckusick sizepb *= NINDIR(fs); /* XXX */ 49253913Smckusick fs->fs_maxfilesize += sizepb; /* XXX */ 49353913Smckusick } /* XXX */ 49453913Smckusick fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 49553913Smckusick fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 49653913Smckusick } /* XXX */ 49737737Smckusick return (0); 49812795Ssam } 49912795Ssam 50039043Smckusick /* 50137737Smckusick * unmount system call 50237737Smckusick */ 50351473Sbostic int 50451473Sbostic ffs_unmount(mp, mntflags, p) 50537737Smckusick struct mount *mp; 50641314Smckusick int mntflags; 50748036Smckusick struct proc *p; 50812795Ssam { 50937737Smckusick register struct ufsmount *ump; 51037737Smckusick register struct fs *fs; 51167861Smckusick int error, flags; 51212795Ssam 51354461Smckusick flags = 0; 51448065Smckusick if (mntflags & MNT_FORCE) { 51565236Smckusick if (mp->mnt_flag & MNT_ROOTFS) 51648065Smckusick return (EINVAL); 51741314Smckusick flags |= FORCECLOSE; 51848065Smckusick } 51957051Smckusick if (error = ffs_flushfiles(mp, flags, p)) 52057051Smckusick return (error); 52137737Smckusick ump = VFSTOUFS(mp); 52257051Smckusick fs = ump->um_fs; 52357051Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 52467861Smckusick error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, 52557051Smckusick NOCRED, p); 52657051Smckusick vrele(ump->um_devvp); 52757051Smckusick free(fs->fs_csp[0], M_UFSMNT); 52857051Smckusick free(fs, M_UFSMNT); 52957051Smckusick free(ump, M_UFSMNT); 53057051Smckusick mp->mnt_data = (qaddr_t)0; 53157051Smckusick mp->mnt_flag &= ~MNT_LOCAL; 53257051Smckusick return (error); 53357051Smckusick } 53457051Smckusick 53557051Smckusick /* 53657051Smckusick * Flush out all the files in a filesystem. 53757051Smckusick */ 53857051Smckusick ffs_flushfiles(mp, flags, p) 53957051Smckusick register struct mount *mp; 54057051Smckusick int flags; 54157051Smckusick struct proc *p; 54257051Smckusick { 54357051Smckusick extern int doforce; 54457051Smckusick register struct ufsmount *ump; 54557051Smckusick int i, error; 54657051Smckusick 54757051Smckusick if (!doforce) 54857051Smckusick flags &= ~FORCECLOSE; 54957051Smckusick ump = VFSTOUFS(mp); 55012795Ssam #ifdef QUOTA 55141397Smckusick if (mp->mnt_flag & MNT_QUOTA) { 55241314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 55339898Smckusick return (error); 55441314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 55541314Smckusick if (ump->um_quotas[i] == NULLVP) 55641314Smckusick continue; 55750114Smckusick quotaoff(p, mp, i); 55841314Smckusick } 55939898Smckusick /* 56041314Smckusick * Here we fall through to vflush again to ensure 56141314Smckusick * that we have gotten rid of all the system vnodes. 56239898Smckusick */ 56341314Smckusick } 56412795Ssam #endif 56557051Smckusick error = vflush(mp, NULLVP, flags); 56630749Skarels return (error); 56712795Ssam } 56812795Ssam 56937737Smckusick /* 57037737Smckusick * Get file system statistics. 57137737Smckusick */ 57251473Sbostic int 57351473Sbostic ffs_statfs(mp, sbp, p) 57437737Smckusick struct mount *mp; 57537737Smckusick register struct statfs *sbp; 57648036Smckusick struct proc *p; 57737737Smckusick { 57837737Smckusick register struct ufsmount *ump; 57937737Smckusick register struct fs *fs; 58037737Smckusick 58137737Smckusick ump = VFSTOUFS(mp); 58237737Smckusick fs = ump->um_fs; 58337737Smckusick if (fs->fs_magic != FS_MAGIC) 58451473Sbostic panic("ffs_statfs"); 58537737Smckusick sbp->f_type = MOUNT_UFS; 58651942Smckusick sbp->f_bsize = fs->fs_fsize; 58751942Smckusick sbp->f_iosize = fs->fs_bsize; 58837737Smckusick sbp->f_blocks = fs->fs_dsize; 58937737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 59037737Smckusick fs->fs_cstotal.cs_nffree; 59137737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 59237737Smckusick (fs->fs_dsize - sbp->f_bfree); 59339350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 59437737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 59541397Smckusick if (sbp != &mp->mnt_stat) { 59641397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 59740346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 59841397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 59940346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 60040346Smckusick } 60137737Smckusick return (0); 60237737Smckusick } 60337737Smckusick 60437737Smckusick /* 60537737Smckusick * Go through the disk queues to initiate sandbagged IO; 60637737Smckusick * go through the inodes to write those that have been modified; 60737737Smckusick * initiate the writing of the super block if it has been modified. 60841314Smckusick * 60941314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 61037737Smckusick */ 61151473Sbostic int 61254461Smckusick ffs_sync(mp, waitfor, cred, p) 61337737Smckusick struct mount *mp; 61437737Smckusick int waitfor; 61554461Smckusick struct ucred *cred; 61654461Smckusick struct proc *p; 61737737Smckusick { 61839390Smckusick register struct vnode *vp; 61937737Smckusick register struct inode *ip; 62037737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 62137737Smckusick register struct fs *fs; 62239596Smckusick int error, allerror = 0; 62337737Smckusick 62437737Smckusick fs = ump->um_fs; 62537737Smckusick /* 62637737Smckusick * Write back modified superblock. 62737737Smckusick * Consistency check that the superblock 62837737Smckusick * is still in the buffer cache. 62937737Smckusick */ 63037737Smckusick if (fs->fs_fmod != 0) { 63137737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 63237737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 63337737Smckusick panic("update: rofs mod"); 63437737Smckusick } 63537737Smckusick fs->fs_fmod = 0; 63637737Smckusick fs->fs_time = time.tv_sec; 63751473Sbostic allerror = ffs_sbupdate(ump, waitfor); 63837737Smckusick } 63937737Smckusick /* 64037737Smckusick * Write back each (modified) inode. 64137737Smckusick */ 64239877Smckusick loop: 64365236Smckusick for (vp = mp->mnt_vnodelist.lh_first; 64465236Smckusick vp != NULL; 64565236Smckusick vp = vp->v_mntvnodes.le_next) { 64641462Smckusick /* 64741462Smckusick * If the vnode that we are about to sync is no longer 64841462Smckusick * associated with this mount point, start over. 64941462Smckusick */ 65041462Smckusick if (vp->v_mount != mp) 65141462Smckusick goto loop; 65248359Smckusick if (VOP_ISLOCKED(vp)) 65348359Smckusick continue; 65439390Smckusick ip = VTOI(vp); 65564511Sbostic if ((ip->i_flag & 65664605Sbostic (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && 65765236Smckusick vp->v_dirtyblkhd.lh_first == NULL) 65837737Smckusick continue; 65965236Smckusick if (vget(vp, 1)) 66039877Smckusick goto loop; 66154461Smckusick if (error = VOP_FSYNC(vp, cred, waitfor, p)) 66239596Smckusick allerror = error; 66339596Smckusick vput(vp); 66437737Smckusick } 66537737Smckusick /* 66639675Smckusick * Force stale file system control information to be flushed. 66737737Smckusick */ 66854461Smckusick if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) 66954461Smckusick allerror = error; 67041314Smckusick #ifdef QUOTA 67141314Smckusick qsync(mp); 67241314Smckusick #endif 67339596Smckusick return (allerror); 67437737Smckusick } 67537737Smckusick 67637737Smckusick /* 67764605Sbostic * Look up a FFS dinode number to find its incore vnode, otherwise read it 67864605Sbostic * in from disk. If it is in core, wait for the lock bit to clear, then 67964605Sbostic * return the inode locked. Detection and handling of mount points must be 68064605Sbostic * done by the calling routine. 68154657Smckusick */ 68254657Smckusick int 68354657Smckusick ffs_vget(mp, ino, vpp) 68454657Smckusick struct mount *mp; 68554657Smckusick ino_t ino; 68654657Smckusick struct vnode **vpp; 68754657Smckusick { 68854657Smckusick register struct fs *fs; 68954657Smckusick register struct inode *ip; 69054657Smckusick struct ufsmount *ump; 69154657Smckusick struct buf *bp; 69254657Smckusick struct vnode *vp; 69354657Smckusick dev_t dev; 69454657Smckusick int i, type, error; 69554657Smckusick 69654657Smckusick ump = VFSTOUFS(mp); 69754657Smckusick dev = ump->um_dev; 69854657Smckusick if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 69954657Smckusick return (0); 70054657Smckusick 70154657Smckusick /* Allocate a new vnode/inode. */ 70254657Smckusick if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) { 70354657Smckusick *vpp = NULL; 70454657Smckusick return (error); 70554657Smckusick } 70654657Smckusick type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ 70754657Smckusick MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); 70859819Smckusick bzero((caddr_t)ip, sizeof(struct inode)); 70954657Smckusick vp->v_data = ip; 71054657Smckusick ip->i_vnode = vp; 71154657Smckusick ip->i_fs = fs = ump->um_fs; 71254657Smckusick ip->i_dev = dev; 71354657Smckusick ip->i_number = ino; 71454657Smckusick #ifdef QUOTA 71554657Smckusick for (i = 0; i < MAXQUOTAS; i++) 71654657Smckusick ip->i_dquot[i] = NODQUOT; 71754657Smckusick #endif 71854657Smckusick /* 71954657Smckusick * Put it onto its hash chain and lock it so that other requests for 72054657Smckusick * this inode will block if they arrive while we are sleeping waiting 72154657Smckusick * for old data structures to be purged or for the contents of the 72254657Smckusick * disk portion of this inode to be read. 72354657Smckusick */ 72454657Smckusick ufs_ihashins(ip); 72554657Smckusick 72654657Smckusick /* Read in the disk contents for the inode, copy into the inode. */ 72764605Sbostic if (error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 72854657Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 72954657Smckusick /* 73054657Smckusick * The inode does not contain anything useful, so it would 73159819Smckusick * be misleading to leave it on its hash chain. With mode 73259819Smckusick * still zero, it will be unlinked and returned to the free 73359819Smckusick * list by vput(). 73454657Smckusick */ 73556797Smckusick vput(vp); 73654657Smckusick brelse(bp); 73754657Smckusick *vpp = NULL; 73854657Smckusick return (error); 73954657Smckusick } 74064605Sbostic ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 74154657Smckusick brelse(bp); 74254657Smckusick 74354657Smckusick /* 74454657Smckusick * Initialize the vnode from the inode, check for aliases. 74554657Smckusick * Note that the underlying vnode may have changed. 74654657Smckusick */ 74754657Smckusick if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) { 74856797Smckusick vput(vp); 74954657Smckusick *vpp = NULL; 75054657Smckusick return (error); 75154657Smckusick } 75254657Smckusick /* 75354657Smckusick * Finish inode initialization now that aliasing has been resolved. 75454657Smckusick */ 75554657Smckusick ip->i_devvp = ump->um_devvp; 75654657Smckusick VREF(ip->i_devvp); 75754657Smckusick /* 75854657Smckusick * Set up a generation number for this inode if it does not 75954657Smckusick * already have one. This should only happen on old filesystems. 76054657Smckusick */ 76154657Smckusick if (ip->i_gen == 0) { 76254657Smckusick if (++nextgennumber < (u_long)time.tv_sec) 76354657Smckusick nextgennumber = time.tv_sec; 76454657Smckusick ip->i_gen = nextgennumber; 76554657Smckusick if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 76664605Sbostic ip->i_flag |= IN_MODIFIED; 76754657Smckusick } 76854657Smckusick /* 76954657Smckusick * Ensure that uid and gid are correct. This is a temporary 77054657Smckusick * fix until fsck has been changed to do the update. 77154657Smckusick */ 77254657Smckusick if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 77354657Smckusick ip->i_uid = ip->i_din.di_ouid; /* XXX */ 77454657Smckusick ip->i_gid = ip->i_din.di_ogid; /* XXX */ 77554657Smckusick } /* XXX */ 77654657Smckusick 77754657Smckusick *vpp = vp; 77854657Smckusick return (0); 77954657Smckusick } 78054657Smckusick 78154657Smckusick /* 78251545Smckusick * File handle to vnode 78351545Smckusick * 78451545Smckusick * Have to be really careful about stale file handles: 78551545Smckusick * - check that the inode number is valid 78651545Smckusick * - call ffs_vget() to get the locked inode 78751545Smckusick * - check for an unallocated inode (i_mode == 0) 78854733Smckusick * - check that the given client host has export rights and return 78954733Smckusick * those rights via. exflagsp and credanonp 79051545Smckusick */ 79151545Smckusick int 79254733Smckusick ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 79351545Smckusick register struct mount *mp; 79451545Smckusick struct fid *fhp; 79554733Smckusick struct mbuf *nam; 79651545Smckusick struct vnode **vpp; 79754733Smckusick int *exflagsp; 79854733Smckusick struct ucred **credanonp; 79951545Smckusick { 80051545Smckusick register struct ufid *ufhp; 80151545Smckusick struct fs *fs; 80251545Smckusick 80351545Smckusick ufhp = (struct ufid *)fhp; 80455890Smckusick fs = VFSTOUFS(mp)->um_fs; 80551545Smckusick if (ufhp->ufid_ino < ROOTINO || 80651545Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) 80754733Smckusick return (ESTALE); 80856245Smckusick return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); 80951545Smckusick } 81051545Smckusick 81151545Smckusick /* 81251545Smckusick * Vnode pointer to File handle 81351545Smckusick */ 81451545Smckusick /* ARGSUSED */ 81551545Smckusick ffs_vptofh(vp, fhp) 81651545Smckusick struct vnode *vp; 81751545Smckusick struct fid *fhp; 81851545Smckusick { 81951545Smckusick register struct inode *ip; 82051545Smckusick register struct ufid *ufhp; 82151545Smckusick 82251545Smckusick ip = VTOI(vp); 82351545Smckusick ufhp = (struct ufid *)fhp; 82451545Smckusick ufhp->ufid_len = sizeof(struct ufid); 82551545Smckusick ufhp->ufid_ino = ip->i_number; 82651545Smckusick ufhp->ufid_gen = ip->i_gen; 82751545Smckusick return (0); 82851545Smckusick } 82951545Smckusick 83051545Smckusick /* 83137737Smckusick * Write a superblock and associated information back to disk. 83237737Smckusick */ 83351942Smckusick int 83451473Sbostic ffs_sbupdate(mp, waitfor) 83537737Smckusick struct ufsmount *mp; 83637737Smckusick int waitfor; 83737737Smckusick { 83867868Smckusick register struct fs *dfs, *fs = mp->um_fs; 83912795Ssam register struct buf *bp; 84012795Ssam int blks; 84112795Ssam caddr_t space; 84237737Smckusick int i, size, error = 0; 84312795Ssam 84457801Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); 84564511Sbostic bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); 84634145Smckusick /* Restore compatibility to old file systems. XXX */ 84767868Smckusick dfs = (struct fs *)bp->b_data; /* XXX */ 84834145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 84967868Smckusick dfs->fs_nrpos = -1; /* XXX */ 85067397Smkm if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 85168122Smckusick int32_t *lp, tmp; /* XXX */ 85267397Smkm /* XXX */ 85368122Smckusick lp = (int32_t *)&dfs->fs_qbmask; /* XXX */ 85467397Smkm tmp = lp[4]; /* XXX */ 85567397Smkm for (i = 4; i > 0; i--) /* XXX */ 85667397Smkm lp[i] = lp[i-1]; /* XXX */ 85767397Smkm lp[0] = tmp; /* XXX */ 85867397Smkm } /* XXX */ 85967868Smckusick dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ 86037737Smckusick if (waitfor == MNT_WAIT) 86137737Smckusick error = bwrite(bp); 86237737Smckusick else 86337737Smckusick bawrite(bp); 86412795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 86512795Ssam space = (caddr_t)fs->fs_csp[0]; 86612795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 86712795Ssam size = fs->fs_bsize; 86812795Ssam if (i + fs->fs_frag > blks) 86912795Ssam size = (blks - i) * fs->fs_fsize; 87057801Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), 87157801Smckusick size, 0, 0); 87264511Sbostic bcopy(space, bp->b_data, (u_int)size); 87312795Ssam space += size; 87437737Smckusick if (waitfor == MNT_WAIT) 87537737Smckusick error = bwrite(bp); 87637737Smckusick else 87737737Smckusick bawrite(bp); 87812795Ssam } 87937737Smckusick return (error); 88012795Ssam } 881