FreeBSD/sys/fs/ext2fs/ext2_vfsops.c
/*
 * Common code for mount and mountroot.
 */
Common code for mount and mountroot.
Common code for mount and mountroot .
static int
ext2_mountfs(struct vnode *devvp, struct mount *mp)
{
	struct ext2mount *ump;
	struct buf *bp;
	struct m_ext2fs *fs;
	struct ext2fs *es;
	struct cdev *dev = devvp->v_rdev;
	struct g_consumer *cp;
	struct bufobj *bo;
	struct csum *sump;
	int error;
	int ronly;
	int i, size;
	int32_t *lp;
	int32_t e2fs_maxcontig;
	ronly = vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0);
	g_topology_lock();
	error = g_vfs_open(devvp, &cp, "ext2fs", ronly ? 0 : 1);
	g_topology_unlock();
	VOP_UNLOCK(devvp, 0);
	if (error)
		return (error);
	if (((SBSIZE % cp->provider->sectorsize) != 0) ||
	    (SBSIZE < cp->provider->sectorsize)) {
		g_topology_lock();
		g_vfs_close(cp);
		g_topology_unlock();
		return (EINVAL);
	}
	bo = &devvp->v_bufobj;
	bo->bo_private = cp;
	bo->bo_ops = g_vfs_bufops;
	if (devvp->v_rdev->si_iosize_max != 0)
		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
	if (mp->mnt_iosize_max > MAXPHYS)
		mp->mnt_iosize_max = MAXPHYS;
	bp = NULL;
	ump = NULL;
	if ((error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) != 0)
		goto out;
	es = (struct ext2fs *)bp->b_data;
	if (ext2_check_sb_compat(es, dev, ronly) != 0) {
		error = EINVAL;		
		goto out;
	}
	if ((es->e2fs_state & E2FS_ISCLEAN) == 0 ||
	    (es->e2fs_state & E2FS_ERRORS)) {
		if (ronly || (mp->mnt_flag & MNT_FORCE)) {
			printf(
"WARNING: Filesystem was not properly dismounted\n");
		} else {
			printf(
"WARNING: R/W mount denied.  Filesystem is not clean - run fsck\n");
			error = EPERM;
			goto out;
		}
	}
	ump = malloc(sizeof(*ump), M_EXT2MNT, M_WAITOK | M_ZERO);
	ump->um_e2fs = malloc(sizeof(struct m_ext2fs),
		M_EXT2MNT, M_WAITOK | M_ZERO);
	ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs),
		M_EXT2MNT, M_WAITOK);
	mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF);
	bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs));
	if ((error = compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs)))
		goto out;
	e2fs_maxcontig = MAX(1, MAXPHYS / ump->um_e2fs->e2fs_bsize);
	ump->um_e2fs->e2fs_contigsumsize = MIN(e2fs_maxcontig, EXT2_MAXCONTIG);
	if (ump->um_e2fs->e2fs_contigsumsize > 0) {
		size = ump->um_e2fs->e2fs_gcount * sizeof(int32_t);
		ump->um_e2fs->e2fs_maxcluster = malloc(size, M_EXT2MNT, M_WAITOK);
		size = ump->um_e2fs->e2fs_gcount * sizeof(struct csum);
		ump->um_e2fs->e2fs_clustersum = malloc(size, M_EXT2MNT, M_WAITOK);
		lp = ump->um_e2fs->e2fs_maxcluster;
		sump = ump->um_e2fs->e2fs_clustersum;
		for (i = 0; i < ump->um_e2fs->e2fs_gcount; i++, sump++) {
			*lp++ = ump->um_e2fs->e2fs_contigsumsize;
			sump->cs_init = 0;
			sump->cs_sum = malloc((ump->um_e2fs->e2fs_contigsumsize + 1) *
			    sizeof(int32_t), M_EXT2MNT, M_WAITOK | M_ZERO);
		}
	}
	brelse(bp);
	bp = NULL;
	fs = ump->um_e2fs;
	fs->e2fs_ronly = ronly;	
	fs->e2fs_wasvalid = fs->e2fs->e2fs_state & E2FS_ISCLEAN ? 1 : 0;
	if (ronly == 0) {
		fs->e2fs_fmod = 1;		
		fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN;	
	}
	mp->mnt_data = ump;
	mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
	mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN;
	MNT_ILOCK(mp);
	mp->mnt_flag |= MNT_LOCAL;
	MNT_IUNLOCK(mp);
	ump->um_mountp = mp;
	ump->um_dev = dev;
	ump->um_devvp = devvp;
	ump->um_bo = &devvp->v_bufobj;
	ump->um_cp = cp;
	ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs);
	ump->um_bptrtodb = fs->e2fs->e2fs_log_bsize + 1;
	ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs);
	if (ronly == 0)
		ext2_sbupdate(ump, MNT_WAIT);
	MNT_ILOCK(mp);
	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED |
	    MNTK_USES_BCACHE;
	MNT_IUNLOCK(mp);
	return (0);
out:
	if (bp)
		brelse(bp);
	if (cp != NULL) {
		g_topology_lock();
		g_vfs_close(cp);
		g_topology_unlock();
	}
	if (ump) {
		mtx_destroy(EXT2_MTX(ump));
		free(ump->um_e2fs->e2fs_gd, M_EXT2MNT);
		free(ump->um_e2fs->e2fs_contigdirs, M_EXT2MNT);
		free(ump->um_e2fs->e2fs, M_EXT2MNT);
		free(ump->um_e2fs, M_EXT2MNT);
		free(ump, M_EXT2MNT);
		mp->mnt_data = NULL;
	}
	return (error);
}
static int ext2_mountfs ( struct vnode * devvp , struct mount * mp ) { struct ext2mount * ump ; struct buf * bp ; struct m_ext2fs * fs ; struct ext2fs * es ; struct cdev * dev = devvp -> v_rdev ; struct g_consumer * cp ; struct bufobj * bo ; struct csum * sump ; int error ; int ronly ; int i , size ; int32_t * lp ; int32_t e2fs_maxcontig ; ronly = vfs_flagopt ( mp -> mnt_optnew , " " , NULL , 0 ) ; g_topology_lock ( ) ; error = g_vfs_open ( devvp , & cp , " " , ronly ? 0 : 1 ) ; g_topology_unlock ( ) ; VOP_UNLOCK ( devvp , 0 ) ; if ( error ) return ( error ) ; if ( ( ( SBSIZE % cp -> provider -> sectorsize ) != 0 ) || ( SBSIZE < cp -> provider -> sectorsize ) ) { g_topology_lock ( ) ; g_vfs_close ( cp ) ; g_topology_unlock ( ) ; return ( EINVAL ) ; } bo = & devvp -> v_bufobj ; bo -> bo_private = cp ; bo -> bo_ops = g_vfs_bufops ; if ( devvp -> v_rdev -> si_iosize_max != 0 ) mp -> mnt_iosize_max = devvp -> v_rdev -> si_iosize_max ; if ( mp -> mnt_iosize_max > MAXPHYS ) mp -> mnt_iosize_max = MAXPHYS ; bp = NULL ; ump = NULL ; if ( ( error = bread ( devvp , SBLOCK , SBSIZE , NOCRED , & bp ) ) != 0 ) goto out ; es = ( struct ext2fs * ) bp -> b_data ; if ( ext2_check_sb_compat ( es , dev , ronly ) != 0 ) { error = EINVAL ; goto out ; } if ( ( es -> e2fs_state & E2FS_ISCLEAN ) == 0 || ( es -> e2fs_state & E2FS_ERRORS ) ) { if ( ronly || ( mp -> mnt_flag & MNT_FORCE ) ) { printf ( " \n " ) ; } else { printf ( " \n " ) ; error = EPERM ; goto out ; } } ump = malloc ( sizeof ( * ump ) , M_EXT2MNT , M_WAITOK | M_ZERO ) ; ump -> um_e2fs = malloc ( sizeof ( struct m_ext2fs ) , M_EXT2MNT , M_WAITOK | M_ZERO ) ; ump -> um_e2fs -> e2fs = malloc ( sizeof ( struct ext2fs ) , M_EXT2MNT , M_WAITOK ) ; mtx_init ( EXT2_MTX ( ump ) , " " , " " , MTX_DEF ) ; bcopy ( es , ump -> um_e2fs -> e2fs , ( u_int ) sizeof ( struct ext2fs ) ) ; if ( ( error = compute_sb_data ( devvp , ump -> um_e2fs -> e2fs , ump -> um_e2fs ) ) ) goto out ; e2fs_maxcontig = MAX ( 1 , MAXPHYS / ump -> um_e2fs -> e2fs_bsize ) ; ump -> um_e2fs -> e2fs_contigsumsize = MIN ( e2fs_maxcontig , EXT2_MAXCONTIG ) ; if ( ump -> um_e2fs -> e2fs_contigsumsize > 0 ) { size = ump -> um_e2fs -> e2fs_gcount * sizeof ( int32_t ) ; ump -> um_e2fs -> e2fs_maxcluster = malloc ( size , M_EXT2MNT , M_WAITOK ) ; size = ump -> um_e2fs -> e2fs_gcount * sizeof ( struct csum ) ; ump -> um_e2fs -> e2fs_clustersum = malloc ( size , M_EXT2MNT , M_WAITOK ) ; lp = ump -> um_e2fs -> e2fs_maxcluster ; sump = ump -> um_e2fs -> e2fs_clustersum ; for ( i = 0 ; i < ump -> um_e2fs -> e2fs_gcount ; i ++ , sump ++ ) { * lp ++ = ump -> um_e2fs -> e2fs_contigsumsize ; sump -> cs_init = 0 ; sump -> cs_sum = malloc ( ( ump -> um_e2fs -> e2fs_contigsumsize + 1 ) * sizeof ( int32_t ) , M_EXT2MNT , M_WAITOK | M_ZERO ) ; } } brelse ( bp ) ; bp = NULL ; fs = ump -> um_e2fs ; fs -> e2fs_ronly = ronly ; fs -> e2fs_wasvalid = fs -> e2fs -> e2fs_state & E2FS_ISCLEAN ? 1 : 0 ; if ( ronly == 0 ) { fs -> e2fs_fmod = 1 ; fs -> e2fs -> e2fs_state &= ~ E2FS_ISCLEAN ; } mp -> mnt_data = ump ; mp -> mnt_stat . f_fsid . val [ 0 ] = dev2udev ( dev ) ; mp -> mnt_stat . f_fsid . val [ 1 ] = mp -> mnt_vfc -> vfc_typenum ; mp -> mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN ; MNT_ILOCK ( mp ) ; mp -> mnt_flag |= MNT_LOCAL ; MNT_IUNLOCK ( mp ) ; ump -> um_mountp = mp ; ump -> um_dev = dev ; ump -> um_devvp = devvp ; ump -> um_bo = & devvp -> v_bufobj ; ump -> um_cp = cp ; ump -> um_nindir = EXT2_ADDR_PER_BLOCK ( fs ) ; ump -> um_bptrtodb = fs -> e2fs -> e2fs_log_bsize + 1 ; ump -> um_seqinc = EXT2_FRAGS_PER_BLOCK ( fs ) ; if ( ronly == 0 ) ext2_sbupdate ( ump , MNT_WAIT ) ; MNT_ILOCK ( mp ) ; mp -> mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED | MNTK_USES_BCACHE ; MNT_IUNLOCK ( mp ) ; return ( 0 ) ; out : if ( bp ) brelse ( bp ) ; if ( cp != NULL ) { g_topology_lock ( ) ; g_vfs_close ( cp ) ; g_topology_unlock ( ) ; } if ( ump ) { mtx_destroy ( EXT2_MTX ( ump ) ) ; free ( ump -> um_e2fs -> e2fs_gd , M_EXT2MNT ) ; free ( ump -> um_e2fs -> e2fs_contigdirs , M_EXT2MNT ) ; free ( ump -> um_e2fs -> e2fs , M_EXT2MNT ) ; free ( ump -> um_e2fs , M_EXT2MNT ) ; free ( ump , M_EXT2MNT ) ; mp -> mnt_data = NULL ; } return ( error ) ; }
Common code for mount and mountroot.
Common code for mount and mountroot .
/* XXX: use VOP_ACESS to check FS perms */ /* XXX: should we check for some sectorsize or 512 instead? */ /* XXX needs translation */ /*
	 * I don't know whether this is the right strategy. Note that
	 * we dynamically allocate both an m_ext2fs and an ext2fs
	 * while Linux keeps the super block in a locked buffer.
	 */ /*
	 * Calculate the maximum contiguous blocks and size of cluster summary
	 * array.  In FFS this is done by newfs; however, the superblock 
	 * in ext2fs doesn't have these variables, so we can calculate 
	 * them here.
	 */ /* ronly is set according to mnt_flags */ /*
	 * If the fs is not mounted read-only, make sure the super block is
	 * always written back on a sync().
	 */ /* mark it modified */ /* set fs invalid */ /*
	 * Setting those two parameters allowed us to use
	 * ufs_bmap w/o changse!
	 */ /*
	 * Initialize filesystem stat information in mount struct.
	 */