free(fs->fs_contigdirs, M_WAITOK);
ffs_mount(mp, path, data, ndp, p)	register struct mount *mp;	const char *path;	void *data;	struct nameidata *ndp;	struct proc *p;{	struct vnode *devvp;	struct ufs_args args;	struct ufsmount *ump = NULL;	register struct fs *fs;	int error = 0, flags;	int ronly;	mode_t accessmode;	size_t size;	error = copyin(data, &args, sizeof (struct ufs_args));	if (error)		return (error);#ifndef FFS_SOFTUPDATES	if (mp->mnt_flag & MNT_SOFTDEP) {		printf("WARNING: soft updates isn't compiled in\n");		mp->mnt_flag &= ~MNT_SOFTDEP;	}#endif	/*	 * Soft updates is incompatible with "async",	 * so if we are doing softupdates stop the user	 * from setting the async flag.	 */	if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) ==	    (MNT_SOFTDEP | MNT_ASYNC)) {		return (EINVAL);	}	/*	 * 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;		devvp = ump->um_devvp;		error = 0;		ronly = fs->fs_ronly;		if (ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {			flags = WRITECLOSE;			if (mp->mnt_flag & MNT_FORCE)				flags |= FORCECLOSE;			if (fs->fs_flags & FS_DOSOFTDEP) {				error = softdep_flushfiles(mp, flags, p);				mp->mnt_flag &= ~MNT_SOFTDEP;			} else				error = ffs_flushfiles(mp, flags, p);			free(fs->fs_contigdirs, M_WAITOK);			ronly = 1;		}		/*		 * Flush soft dependencies if disabling it via an update		 * mount. This may leave some items to be processed,		 * so don't do this yet XXX.		 */		if ((fs->fs_flags & FS_DOSOFTDEP) &&		    !(mp->mnt_flag & MNT_SOFTDEP) &&		    !(mp->mnt_flag & MNT_RDONLY) && fs->fs_ronly == 0) {#if 0			flags = WRITECLOSE;			if (mp->mnt_flag & MNT_FORCE)				flags |= FORCECLOSE;			error = softdep_flushfiles(mp, flags, p);#elif FFS_SOFTUPDATES			mp->mnt_flag |= MNT_SOFTDEP;#endif		}		/*		 * When upgrading to a softdep mount, we must first flush		 * all vnodes. (not done yet -- see above)		 */		if (!(fs->fs_flags & FS_DOSOFTDEP) &&		    (mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) {#if 0			flags = WRITECLOSE;			if (mp->mnt_flag & MNT_FORCE)				flags |= FORCECLOSE;			error = ffs_flushfiles(mp, flags, p);#else			mp->mnt_flag &= ~MNT_SOFTDEP;#endif		}		if (!error && (mp->mnt_flag & MNT_RELOAD))			error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);		if (error)			goto error_1;		if (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) {				vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);				error = VOP_ACCESS(devvp, VREAD | VWRITE,						   p->p_ucred, p);				VOP_UNLOCK(devvp, 0, p);				if (error)					goto error_1;			}			if (fs->fs_clean == 0) {#if 0				/*				 * It is safe mount unclean file system				 * if it was previously mounted with softdep				 * but we may loss space and must				 * sometimes run fsck manually.				 */				if (fs->fs_flags & FS_DOSOFTDEP)					printf("WARNING: %s was not properly unmounted\n",					    fs->fs_fsmnt);				else#endif				if (mp->mnt_flag & MNT_FORCE) {					printf("WARNING: %s was not properly unmounted\n",					    fs->fs_fsmnt);				} else {					printf("WARNING: R/W mount of %s denied.  Filesystem is not clean - run fsck\n",					    fs->fs_fsmnt);					error = EPERM;					goto error_1;				}			}			if ((fs->fs_flags & FS_DOSOFTDEP)) {				error = softdep_mount(devvp, mp, fs,						      p->p_ucred);				if (error)					goto error_1;			}			fs->fs_contigdirs=(u_int8_t*)malloc((u_long)fs->fs_ncg,							    M_UFSMNT, M_WAITOK);			bzero(fs->fs_contigdirs, fs->fs_ncg);			ronly = 0;		}		if (args.fspec == 0) {			/*			 * Process export requests.			 */			error = vfs_export(mp, &ump->um_export, &args.export);			if (error)				goto error_1;			else				goto success;		}	}	/*	 * 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)		goto error_1;	devvp = ndp->ni_vp;	if (devvp->v_type != VBLK) {		error = ENOTBLK;		goto error_2;	}	if (major(devvp->v_rdev) >= nblkdev) {		error = ENXIO;		goto error_2;	}	/*	 * 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;		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);		error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);		VOP_UNLOCK(devvp, 0, p);		if (error)			goto error_2;	}	if (mp->mnt_flag & MNT_UPDATE) {		/*		 * UPDATE		 * If it's not the same vnode, or at least the same device		 * then it's not correct.		 */		if (devvp != ump->um_devvp) {			if (devvp->v_rdev == ump->um_devvp->v_rdev) {				vrele(devvp);			} else {				error = EINVAL;	/* needs translation */			}		} else			vrele(devvp);		/*		 * Update device name only on success		 */		if (!error) {			/*			 * Save "mounted from" info for mount point (NULL pad)			 */			copyinstr(args.fspec,				  mp->mnt_stat.f_mntfromname,				  MNAMELEN - 1,				  &size);			bzero(mp->mnt_stat.f_mntfromname + size,			      MNAMELEN - size);		}	} else {		/*		 * Since this is a new mount, we want the names for		 * the device and the mount point copied in.  If an		 * error occurs,  the mountpoint is discarded by the		 * upper level code.		 */		/* Save "last mounted on" info for mount point (NULL pad)*/		copyinstr(path,				/* mount point*/			  mp->mnt_stat.f_mntonname,	/* save area*/			  MNAMELEN - 1,			/* max size*/			  &size);			/* real size*/		bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);		/* Save "mounted from" info for mount point (NULL pad)*/		copyinstr(args.fspec,			/* device name*/			  mp->mnt_stat.f_mntfromname,	/* save area*/			  MNAMELEN - 1,			/* max size*/			  &size);			/* real size*/		bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);		error = ffs_mountfs(devvp, mp, p);	}	if (error)		goto error_2;	/*	 * Initialize FS stat information in mount struct; uses both	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname	 *	 * This code is common to root and non-root mounts	 */	bcopy(&args, &mp->mnt_stat.mount_info.ufs_args, sizeof(args));	(void)VFS_STATFS(mp, &mp->mnt_stat, p);success:	if (path && (mp->mnt_flag & MNT_UPDATE)) {		/* Update clean flag after changing read-onlyness. */		fs = ump->um_fs;		if (ronly != fs->fs_ronly) {			fs->fs_ronly = ronly;			fs->fs_clean = ronly &&			    (fs->fs_flags & FS_UNCLEAN) == 0 ? 1 : 0;		}		if (!ronly) {			if (mp->mnt_flag & MNT_SOFTDEP)				fs->fs_flags |= FS_DOSOFTDEP;			else				fs->fs_flags &= ~FS_DOSOFTDEP;		}		ffs_sbupdate(ump, MNT_WAIT);	}	return (0);error_2:	/* error with devvp held */	vrele (devvp);error_1:	/* no state to back out */	return (error);}