FreeBSD/sys/fs/ext2fs/ext2_vfsops.c
/*
 * VFS Operations.
 *
 * mount system call
 */
VFS Operations.
mount system call
VFS Operations . mount system call
static int
ext2_mount(struct mount *mp)
{
	struct vfsoptlist *opts;
	struct vnode *devvp;
	struct thread *td;
	struct ext2mount *ump = NULL;
	struct m_ext2fs *fs;
	struct nameidata nd, *ndp = &nd;
	accmode_t accmode;
	char *path, *fspec;
	int error, flags, len;
	td = curthread;
	opts = mp->mnt_optnew;
	if (vfs_filteropt(opts, ext2_opts))
		return (EINVAL);
	vfs_getopt(opts, "fspath", (void **)&path, NULL);
	if (strlen(path) >= MAXMNTLEN)
		return (ENAMETOOLONG);
	fspec = NULL;
	error = vfs_getopt(opts, "from", (void **)&fspec, &len);
	if (!error && fspec[len - 1] != '\0')
		return (EINVAL);
	if (mp->mnt_flag & MNT_UPDATE) {
		ump = VFSTOEXT2(mp);
		fs = ump->um_e2fs; 
		error = 0;
		if (fs->e2fs_ronly == 0 &&
		    vfs_flagopt(opts, "ro", NULL, 0)) {
			error = VFS_SYNC(mp, MNT_WAIT);
			if (error)
				return (error);
			flags = WRITECLOSE;
			if (mp->mnt_flag & MNT_FORCE)
				flags |= FORCECLOSE;
			error = ext2_flushfiles(mp, flags, td);
			if ( error == 0 && fs->e2fs_wasvalid && ext2_cgupdate(ump, MNT_WAIT) == 0) {
				fs->e2fs->e2fs_state |= E2FS_ISCLEAN;
				ext2_sbupdate(ump, MNT_WAIT);
			}
			fs->e2fs_ronly = 1;
			vfs_flagopt(opts, "ro", &mp->mnt_flag, MNT_RDONLY);
			g_topology_lock();
			g_access(ump->um_cp, 0, -1, 0);
			g_topology_unlock();
		}
		if (!error && (mp->mnt_flag & MNT_RELOAD))
			error = ext2_reload(mp, td);
		if (error)
			return (error);
		devvp = ump->um_devvp;
		if (fs->e2fs_ronly && !vfs_flagopt(opts, "ro", NULL, 0)) {
			if (ext2_check_sb_compat(fs->e2fs, devvp->v_rdev, 0))
				return (EPERM);
			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
			error = VOP_ACCESS(devvp, VREAD | VWRITE,
			    td->td_ucred, td);
			if (error)
				error = priv_check(td, PRIV_VFS_MOUNT_PERM);
			if (error) {
				VOP_UNLOCK(devvp, 0);
				return (error);
			}
			VOP_UNLOCK(devvp, 0);
			g_topology_lock();
			error = g_access(ump->um_cp, 0, 1, 0);
			g_topology_unlock();
			if (error)
				return (error);
			if ((fs->e2fs->e2fs_state & E2FS_ISCLEAN) == 0 ||
			    (fs->e2fs->e2fs_state & E2FS_ERRORS)) {
				if (mp->mnt_flag & MNT_FORCE) {
					printf(
"WARNING: %s was not properly dismounted\n", fs->e2fs_fsmnt);
				} else {
					printf(
"WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",
					    fs->e2fs_fsmnt);
					return (EPERM);
				}
			}
			fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN;
			(void)ext2_cgupdate(ump, MNT_WAIT);
			fs->e2fs_ronly = 0;
			MNT_ILOCK(mp);
			mp->mnt_flag &= ~MNT_RDONLY;
			MNT_IUNLOCK(mp);
		}
		if (vfs_flagopt(opts, "export", NULL, 0)) {
			return (error);
		}
	}
	if (fspec == NULL)
		return (EINVAL);
	NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td);
	if ((error = namei(ndp)) != 0)
		return (error);
	NDFREE(ndp, NDF_ONLY_PNBUF);
	devvp = ndp->ni_vp;
	if (!vn_isdisk(devvp, &error)) {
		vput(devvp);
		return (error);
	}
	accmode = VREAD;
	if ((mp->mnt_flag & MNT_RDONLY) == 0)
		accmode |= VWRITE;
	error = VOP_ACCESS(devvp, accmode, td->td_ucred, td);
	if (error)
		error = priv_check(td, PRIV_VFS_MOUNT_PERM);
	if (error) {
		vput(devvp);
		return (error);
	}
	if ((mp->mnt_flag & MNT_UPDATE) == 0) {
		error = ext2_mountfs(devvp, mp);
	} else {
		if (devvp != ump->um_devvp) {
			vput(devvp);
			return (EINVAL);	
		} else
			vput(devvp);
	}
	if (error) {
		vrele(devvp);
		return (error);
	}
	ump = VFSTOEXT2(mp);
	fs = ump->um_e2fs;
	strncpy(fs->e2fs_fsmnt, path, MAXMNTLEN);
	fs->e2fs_fsmnt[MAXMNTLEN - 1] = '\0';
	vfs_mountedfrom(mp, fspec);
	return (0);
}
static int ext2_mount ( struct mount * mp ) { struct vfsoptlist * opts ; struct vnode * devvp ; struct thread * td ; struct ext2mount * ump = NULL ; struct m_ext2fs * fs ; struct nameidata nd , * ndp = & nd ; accmode_t accmode ; char * path , * fspec ; int error , flags , len ; td = curthread ; opts = mp -> mnt_optnew ; if ( vfs_filteropt ( opts , ext2_opts ) ) return ( EINVAL ) ; vfs_getopt ( opts , " " , ( void * * ) & path , NULL ) ; if ( strlen ( path ) >= MAXMNTLEN ) return ( ENAMETOOLONG ) ; fspec = NULL ; error = vfs_getopt ( opts , " " , ( void * * ) & fspec , & len ) ; if ( ! error && fspec [ len - 1 ] != ' \0 ' ) return ( EINVAL ) ; if ( mp -> mnt_flag & MNT_UPDATE ) { ump = VFSTOEXT2 ( mp ) ; fs = ump -> um_e2fs ; error = 0 ; if ( fs -> e2fs_ronly == 0 && vfs_flagopt ( opts , " " , NULL , 0 ) ) { error = VFS_SYNC ( mp , MNT_WAIT ) ; if ( error ) return ( error ) ; flags = WRITECLOSE ; if ( mp -> mnt_flag & MNT_FORCE ) flags |= FORCECLOSE ; error = ext2_flushfiles ( mp , flags , td ) ; if ( error == 0 && fs -> e2fs_wasvalid && ext2_cgupdate ( ump , MNT_WAIT ) == 0 ) { fs -> e2fs -> e2fs_state |= E2FS_ISCLEAN ; ext2_sbupdate ( ump , MNT_WAIT ) ; } fs -> e2fs_ronly = 1 ; vfs_flagopt ( opts , " " , & mp -> mnt_flag , MNT_RDONLY ) ; g_topology_lock ( ) ; g_access ( ump -> um_cp , 0 , -1 , 0 ) ; g_topology_unlock ( ) ; } if ( ! error && ( mp -> mnt_flag & MNT_RELOAD ) ) error = ext2_reload ( mp , td ) ; if ( error ) return ( error ) ; devvp = ump -> um_devvp ; if ( fs -> e2fs_ronly && ! vfs_flagopt ( opts , " " , NULL , 0 ) ) { if ( ext2_check_sb_compat ( fs -> e2fs , devvp -> v_rdev , 0 ) ) return ( EPERM ) ; vn_lock ( devvp , LK_EXCLUSIVE | LK_RETRY ) ; error = VOP_ACCESS ( devvp , VREAD | VWRITE , td -> td_ucred , td ) ; if ( error ) error = priv_check ( td , PRIV_VFS_MOUNT_PERM ) ; if ( error ) { VOP_UNLOCK ( devvp , 0 ) ; return ( error ) ; } VOP_UNLOCK ( devvp , 0 ) ; g_topology_lock ( ) ; error = g_access ( ump -> um_cp , 0 , 1 , 0 ) ; g_topology_unlock ( ) ; if ( error ) return ( error ) ; if ( ( fs -> e2fs -> e2fs_state & E2FS_ISCLEAN ) == 0 || ( fs -> e2fs -> e2fs_state & E2FS_ERRORS ) ) { if ( mp -> mnt_flag & MNT_FORCE ) { printf ( " \n " , fs -> e2fs_fsmnt ) ; } else { printf ( " \n " , fs -> e2fs_fsmnt ) ; return ( EPERM ) ; } } fs -> e2fs -> e2fs_state &= ~ E2FS_ISCLEAN ; ( void ) ext2_cgupdate ( ump , MNT_WAIT ) ; fs -> e2fs_ronly = 0 ; MNT_ILOCK ( mp ) ; mp -> mnt_flag &= ~ MNT_RDONLY ; MNT_IUNLOCK ( mp ) ; } if ( vfs_flagopt ( opts , " " , NULL , 0 ) ) { return ( error ) ; } } if ( fspec == NULL ) return ( EINVAL ) ; NDINIT ( ndp , LOOKUP , FOLLOW | LOCKLEAF , UIO_SYSSPACE , fspec , td ) ; if ( ( error = namei ( ndp ) ) != 0 ) return ( error ) ; NDFREE ( ndp , NDF_ONLY_PNBUF ) ; devvp = ndp -> ni_vp ; if ( ! vn_isdisk ( devvp , & error ) ) { vput ( devvp ) ; return ( error ) ; } accmode = VREAD ; if ( ( mp -> mnt_flag & MNT_RDONLY ) == 0 ) accmode |= VWRITE ; error = VOP_ACCESS ( devvp , accmode , td -> td_ucred , td ) ; if ( error ) error = priv_check ( td , PRIV_VFS_MOUNT_PERM ) ; if ( error ) { vput ( devvp ) ; return ( error ) ; } if ( ( mp -> mnt_flag & MNT_UPDATE ) == 0 ) { error = ext2_mountfs ( devvp , mp ) ; } else { if ( devvp != ump -> um_devvp ) { vput ( devvp ) ; return ( EINVAL ) ; } else vput ( devvp ) ; } if ( error ) { vrele ( devvp ) ; return ( error ) ; } ump = VFSTOEXT2 ( mp ) ; fs = ump -> um_e2fs ; strncpy ( fs -> e2fs_fsmnt , path , MAXMNTLEN ) ; fs -> e2fs_fsmnt [ MAXMNTLEN - 1 ] = ' \0 ' ; vfs_mountedfrom ( mp , fspec ) ; return ( 0 ) ; }
VFS Operations.
VFS Operations .
/* Double-check the length of path.. */ /*
	 * If updating, check whether changing from read-only to
	 * read/write; if there is no device name, that's all we do.
	 */ /*
			 * If upgrade to read-write by non-root, then verify
			 * that user has necessary permissions on the device.
			 */ /* Process export requests in vfs_mount.c. */ /*
	 * Not an update, or updating the name: look up the name
	 * and verify that it refers to a sensible disk device.
	 */ /*
	 * If mount by non-root, then verify that user has necessary
	 * permissions on the device.
	 *
	 * XXXRW: VOP_ACCESS() enough?
	 */ /* needs translation */ /*
	 * Note that this strncpy() is ok because of a check at the start
	 * of ext2_mount().
	 */