ffs_vfsops.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,012 行 · 第 1/2 页
C
1,012 行
/* $NetBSD: ffs_vfsops.c,v 1.19 1996/02/09 22:22:26 christos Exp $ *//* * Copyright (c) 1989, 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ffs_vfsops.c 8.14 (Berkeley) 11/28/94 */#include <sys/param.h>#include <sys/systm.h>#include <sys/namei.h>#include <sys/proc.h>#include <sys/kernel.h>#include <sys/vnode.h>#include <sys/socket.h>#include <sys/mount.h>#include <sys/buf.h>#include <sys/mbuf.h>#include <sys/file.h>#include <sys/disklabel.h>#include <sys/ioctl.h>#include <sys/errno.h>#include <sys/malloc.h>#include <miscfs/specfs/specdev.h>#include <ufs/ufs/quota.h>#include <ufs/ufs/ufsmount.h>#include <ufs/ufs/inode.h>#include <ufs/ufs/ufs_extern.h>#include <ufs/ffs/fs.h>#include <ufs/ffs/ffs_extern.h>int ffs_sbupdate __P((struct ufsmount *, int));struct vfsops ffs_vfsops = { MOUNT_FFS, ffs_mount, ufs_start, ffs_unmount, ufs_root, ufs_quotactl, ffs_statfs, ffs_sync, ffs_vget, ffs_fhtovp, ffs_vptofh, ffs_init,};extern u_long nextgennumber;/* * Called by main() when ufs is going to be mounted as root. * * Name is updated by mount(8) after booting. */#define ROOTNAME "root_device"int#ifdef OSKITffs_mountroot(dev_t dev, int flags, struct mount **out_mp)#elseffs_mountroot()#endif{#ifdef OSKIT struct vnode *devvp;#else extern struct vnode *rootvp;#endif /* OSKIT */ register struct fs *fs; register struct mount *mp; struct proc *p = curproc; /* XXX */ struct ufsmount *ump; size_t size; int error; /* * Get vnodes for swapdev and rootdev. */#ifdef OSKIT if (bdevvp(dev, &devvp)) panic("ffs_mountroot: can't setup bdevvp's");#else if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) panic("ffs_mountroot: can't setup bdevvp's");#endif /* OSKIT */ mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); bzero((char *)mp, (u_long)sizeof(struct mount)); mp->mnt_op = &ffs_vfsops;#ifdef OSKIT mp->mnt_flag = flags; if ((error = ffs_mountfs(devvp, mp, p)) != 0) {#else mp->mnt_flag = MNT_RDONLY; if ((error = ffs_mountfs(rootvp, mp, p)) != 0) {#endif /* OSKIT */ free(mp, M_MOUNT); return (error); } if ((error = vfs_lock(mp)) != 0) { (void)ffs_unmount(mp, 0, p); free(mp, M_MOUNT); return (error); } CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); mp->mnt_vnodecovered = NULLVP; ump = VFSTOUFS(mp); fs = ump->um_fs; bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); fs->fs_fsmnt[0] = '/'; bcopy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN); (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); (void)ffs_statfs(mp, &mp->mnt_stat, p); vfs_unlock(mp); inittodr(fs->fs_time);#ifdef OSKIT *out_mp = mp;#endif /* OSKIT */ return (0);}/* * VFS Operations. * * mount system call */intffs_mount(mp, path, data, ndp, p) register struct mount *mp; char *path; caddr_t data; struct nameidata *ndp; struct proc *p;{ struct vnode *devvp; struct ufs_args args; struct ufsmount *ump = NULL; register struct fs *fs; size_t size; int error, flags; mode_t accessmode;#ifndef OSKIT error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); if (error) return (error);#endif /* OSKIT */ /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { ump = VFSTOUFS(mp); fs = ump->um_fs; if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; if (vfs_busy(mp)) return (EBUSY); error = ffs_flushfiles(mp, flags, p); if (error == 0 && ffs_cgupdate(ump, MNT_WAIT) == 0 && fs->fs_clean & FS_WASCLEAN) { fs->fs_clean = FS_ISCLEAN; (void) ffs_sbupdate(ump, MNT_WAIT); } vfs_unbusy(mp); if (error) return (error); fs->fs_ronly = 1; } if (mp->mnt_flag & MNT_RELOAD) { error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); if (error) return (error); } if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ if (p->p_ucred->cr_uid != 0) { devvp = ump->um_devvp; VOP_LOCK(devvp); error = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p); if (error) { VOP_UNLOCK(devvp); return (error); } VOP_UNLOCK(devvp); } fs->fs_ronly = 0; fs->fs_clean <<= 1; fs->fs_fmod = 1; }#ifdef OSKIT return 0;#endif /* OSKIT */ if (args.fspec == 0) { /* * Process export requests. */ return (vfs_export(mp, &ump->um_export, &args.export)); } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); if ((error = namei(ndp)) != 0) return (error); devvp = ndp->ni_vp; if (devvp->v_type != VBLK) { vrele(devvp); return (ENOTBLK); } if (major(devvp->v_rdev) >= nblkdev) { vrele(devvp); return (ENXIO); } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ if (p->p_ucred->cr_uid != 0) { accessmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accessmode |= VWRITE; VOP_LOCK(devvp); error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); if (error) { vput(devvp); return (error); } VOP_UNLOCK(devvp); } if ((mp->mnt_flag & MNT_UPDATE) == 0) error = ffs_mountfs(devvp, mp, p); else { if (devvp != ump->um_devvp) error = EINVAL; /* needs translation */ else vrele(devvp); } if (error) { vrele(devvp); return (error); } ump = VFSTOUFS(mp); fs = ump->um_fs; (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); bcopy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN); (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); if (fs->fs_fmod != 0) { /* XXX */ fs->fs_fmod = 0; if (fs->fs_clean & FS_WASCLEAN) fs->fs_time = time.tv_sec; else printf("%s: file system not clean; please fsck(8)\n", mp->mnt_stat.f_mntfromname); (void) ffs_cgupdate(ump, MNT_WAIT); } return (0);}/* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must * be mounted read-only. * * Things to do to update the mount: * 1) invalidate all cached meta-data. * 2) re-read superblock from disk. * 3) re-read summary information from disk. * 4) invalidate all inactive vnodes. * 5) invalidate all cached file data. * 6) re-read inode data for all active vnodes. */intffs_reload(mountp, cred, p) register struct mount *mountp; struct ucred *cred; struct proc *p;{ register struct vnode *vp, *nvp, *devvp; struct inode *ip; struct csum *space; struct buf *bp; struct fs *fs, *newfs; struct partinfo dpart; int i, blks, size, error; int32_t *lp; if ((mountp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); /* * Step 1: invalidate all cached meta-data. */ devvp = VFSTOUFS(mountp)->um_devvp; if (vinvalbuf(devvp, 0, cred, p, 0, 0)) panic("ffs_reload: dirty1"); /* * Step 2: re-read superblock from disk. */ if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) size = DEV_BSIZE; else size = dpart.disklab->d_secsize; error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp); if (error) return (error); newfs = (struct fs *)bp->b_data; if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || newfs->fs_bsize < sizeof(struct fs)) { brelse(bp); return (EIO); /* XXX needs translation */ } fs = VFSTOUFS(mountp)->um_fs; /* * Copy pointer fields back into superblock before copying in XXX * new superblock. These should really be in the ufsmount. XXX * Note that important parameters (eg fs_ncg) are unchanged. */ bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp)); newfs->fs_maxcluster = fs->fs_maxcluster; bcopy(newfs, fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; brelse(bp); mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; ffs_oldfscompat(fs); /* * Step 3: re-read summary information from disk. */ blks = howmany(fs->fs_cssize, fs->fs_fsize); space = fs->fs_csp[0]; for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, NOCRED, &bp); if (error) return (error); bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); brelse(bp); } /* * We no longer know anything about clusters per cylinder group. */ if (fs->fs_contigsumsize > 0) { lp = fs->fs_maxcluster; for (i = 0; i < fs->fs_ncg; i++) *lp++ = fs->fs_contigsumsize; }loop: for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { nvp = vp->v_mntvnodes.le_next; /* * Step 4: invalidate all inactive vnodes. */ if (vp->v_usecount == 0) { vgone(vp); continue; } /* * Step 5: invalidate all cached file data. */ if (vget(vp, 1)) goto loop; if (vinvalbuf(vp, 0, cred, p, 0, 0)) panic("ffs_reload: dirty2"); /* * Step 6: re-read inode data for all active vnodes. */ ip = VTOI(vp); error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->fs_bsize, NOCRED, &bp); if (error) { vput(vp); return (error); } ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)); brelse(bp); vput(vp); if (vp->v_mount != mountp) goto loop; } return (0);}/* * Common code for mount and mountroot */intffs_mountfs(devvp, mp, p) register struct vnode *devvp; struct mount *mp; struct proc *p;{ register struct ufsmount *ump; struct buf *bp; register struct fs *fs; dev_t dev; struct partinfo dpart; caddr_t base, space; int blks; int error, i, size, ronly; int32_t *lp; struct ucred *cred; extern struct vnode *rootvp; u_int64_t maxfilesize; /* XXX */ dev = devvp->v_rdev; cred = p ? p->p_ucred : NOCRED; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use * (except for root, which might share swap device for miniroot). * Flush out any old buffers remaining from a previous use. */ if ((error = vfs_mountedon(devvp)) != 0) return (error); if (vcount(devvp) > 1 && devvp != rootvp) return (EBUSY); if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); if (error) return (error); if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) size = DEV_BSIZE; else size = dpart.disklab->d_secsize; bp = NULL; ump = NULL; error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, cred, &bp); if (error) goto out; fs = (struct fs *)bp->b_data; if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { error = EINVAL; /* XXX needs translation */ goto out; } /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { error = EROFS; /* XXX what should be returned? */ goto out; } ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); bzero((caddr_t)ump, sizeof *ump); ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, M_WAITOK); bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; brelse(bp); bp = NULL;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?