Exemplo n.º 1
0
int
ffs_wapbl_stop(struct mount *mp, int force)
{
	struct ufsmount *ump = VFSTOUFS(mp);
	struct fs *fs = ump->um_fs;
	int error;

	if (mp->mnt_wapbl) {
		KDASSERT(fs->fs_ronly == 0);

		/*
		 * Make sure turning off FS_DOWAPBL is only removed
		 * as the only change in the final flush since otherwise
		 * a transaction may reorder writes.
		 */
		error = wapbl_flush(mp->mnt_wapbl, 1);
		if (error && !force)
			return error;
		if (error && force)
			goto forceout;
		error = UFS_WAPBL_BEGIN(mp);
		if (error && !force)
			return error;
		if (error && force)
			goto forceout;
		KASSERT(fs->fs_flags & FS_DOWAPBL);

		fs->fs_flags &= ~FS_DOWAPBL;
		error = ffs_sbupdate(ump, MNT_WAIT);
		KASSERT(error == 0);	/* XXX a bit drastic! */
		UFS_WAPBL_END(mp);
	forceout:
		error = wapbl_stop(mp->mnt_wapbl, force);
		if (error) {
			KASSERT(!force);
			fs->fs_flags |= FS_DOWAPBL;
			return error;
		}
		fs->fs_flags &= ~FS_DOWAPBL; /* Repeat in case of forced error */
		mp->mnt_wapbl = NULL;

#ifdef WAPBL_DEBUG
		printf("%s: disabled logging\n", fs->fs_fsmnt);
#endif
	}

	return 0;
}
static int
g_journal_ufs_clean(struct mount *mp)
{
	struct ufsmount *ump;
	struct fs *fs;
	int flags;

	ump = VFSTOUFS(mp);
	fs = ump->um_fs;

	flags = fs->fs_flags;
	fs->fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK);
	ffs_sbupdate(ump, MNT_WAIT, 1);
	fs->fs_flags = flags;

	return (0);
}
Exemplo n.º 3
0
/*
 * unmount system call
 */
int
ffs_unmount(struct mount *mp, int mntflags, struct proc *p)
{
	struct ufsmount *ump;
	struct fs *fs;
	int error, flags;

	flags = 0;
	if (mntflags & MNT_FORCE)
		flags |= FORCECLOSE;

	ump = VFSTOUFS(mp);
	fs = ump->um_fs;
	if (mp->mnt_flag & MNT_SOFTDEP)
		error = softdep_flushfiles(mp, flags, p);
	else
		error = ffs_flushfiles(mp, flags, p);
	if (error != 0)
		return (error);

	if (fs->fs_ronly == 0) {
		fs->fs_clean = (fs->fs_flags & FS_UNCLEAN) ? 0 : 1;
		error = ffs_sbupdate(ump, MNT_WAIT);
		/* ignore write errors if mounted RW on read-only device */
		if (error && error != EROFS) {
			fs->fs_clean = 0;
			return (error);
		}
		free(fs->fs_contigdirs, M_UFSMNT);
	}
	ump->um_devvp->v_specmountpoint = NULL;

	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0);
	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
		NOCRED, p);
	VOP_UNLOCK(ump->um_devvp, 0, p);
	vrele(ump->um_devvp);
	free(fs->fs_csp, M_UFSMNT);
	free(fs, M_UFSMNT);
	free(ump, M_UFSMNT);
	mp->mnt_data = (qaddr_t)0;
	mp->mnt_flag &= ~MNT_LOCAL;
	return (error);
}
Exemplo n.º 4
0
/*
 * Common code for mount and mountroot
 */
int
ffs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p)
{
	struct ufsmount *ump;
	struct buf *bp;
	struct fs *fs;
	dev_t dev;
	struct partinfo dpart;
	caddr_t space;
	ufs2_daddr_t sbloc;
	int error, i, blks, size, ronly;
	int32_t *lp;
	size_t strsize;
	struct ucred *cred;
	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);
	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
	error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
	VOP_UNLOCK(devvp, 0, p);
	if (error)
		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;

	/*
	 * Try reading the super-block in each of its possible locations.
	 */
	for (i = 0; sbtry[i] != -1; i++) {
		if (bp != NULL) {
			bp->b_flags |= B_NOCACHE;
			brelse(bp);
			bp = NULL;
		}

		error = bread(devvp, sbtry[i] / size, SBSIZE, cred, &bp);
		if (error)
			goto out;

		fs = (struct fs *) bp->b_data;
		sbloc = sbtry[i];

#if 0
		if (fs->fs_magic == FS_UFS2_MAGIC) {
			printf("ffs_mountfs(): Sorry, no UFS2 support (yet)\n");
			error = EFTYPE;
			goto out;
		}
#endif

		/*
		 * Do not look for an FFS1 file system at SBLOCK_UFS2. Doing so
		 * will find the wrong super-block for file systems with 64k
		 * block size.
		 */
		if (fs->fs_magic == FS_UFS1_MAGIC && sbloc == SBLOCK_UFS2)
			continue;

		if (ffs_validate(fs))
			break; /* Super block validated */
	}

	if (sbtry[i] == -1) {
		error = EINVAL;
		goto out;
	}

	fs->fs_fmod = 0;
	fs->fs_flags &= ~FS_UNCLEAN;
	if (fs->fs_clean == 0) {
		fs->fs_flags |= FS_UNCLEAN;
#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 (ronly || (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 = EROFS;
			goto out;
		}
	}

	if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
#ifndef SMALL_KERNEL
		printf("ffs_mountfs(): obsolete rotational table format, "
		    "please use fsck_ffs(8) -c 1\n");
#endif
		error = EFTYPE;
		goto out;
	}

	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
	bzero(ump, sizeof *ump);
	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
	    M_WAITOK);

	if (fs->fs_magic == FS_UFS1_MAGIC)
		ump->um_fstype = UM_UFS1;
#ifdef FFS2
	else
		ump->um_fstype = UM_UFS2;
#endif

	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;
	fs = ump->um_fs;

	ffs1_compat_read(fs, ump, sbloc);

	fs->fs_ronly = ronly;
	size = fs->fs_cssize;
	blks = howmany(size, fs->fs_fsize);
	if (fs->fs_contigsumsize > 0)
		size += fs->fs_ncg * sizeof(int32_t);
	space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
	fs->fs_csp = (struct csum *)space;
	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,
			      cred, &bp);
		if (error) {
			free(fs->fs_csp, M_UFSMNT);
			goto out;
		}
		bcopy(bp->b_data, space, (u_int)size);
		space += size;
		brelse(bp);
		bp = NULL;
	}
	if (fs->fs_contigsumsize > 0) {
		fs->fs_maxcluster = lp = (int32_t *)space;
		for (i = 0; i < fs->fs_ncg; i++)
			*lp++ = fs->fs_contigsumsize;
	}
	mp->mnt_data = (qaddr_t)ump;
	mp->mnt_stat.f_fsid.val[0] = (long)dev;
	/* Use on-disk fsid if it exists, else fake it */
	if (fs->fs_id[0] != 0 && fs->fs_id[1] != 0)
		mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
	else
		mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
	mp->mnt_flag |= MNT_LOCAL;
	ump->um_mountp = mp;
	ump->um_dev = dev;
	ump->um_devvp = devvp;
	ump->um_nindir = fs->fs_nindir;
	ump->um_bptrtodb = fs->fs_fsbtodb;
	ump->um_seqinc = fs->fs_frag;
	for (i = 0; i < MAXQUOTAS; i++)
		ump->um_quotas[i] = NULLVP;

	devvp->v_specmountpoint = mp;
	ffs_oldfscompat(fs);

	if (ronly)
		fs->fs_contigdirs = NULL;
	else {
		fs->fs_contigdirs = (u_int8_t*)malloc((u_long)fs->fs_ncg,
						      M_UFSMNT, M_WAITOK);
		bzero(fs->fs_contigdirs, fs->fs_ncg);
	}

	/*
	 * Set FS local "last mounted on" information (NULL pad)
	 */
	copystr(mp->mnt_stat.f_mntonname,	/* mount point*/
		fs->fs_fsmnt,			/* copy area*/
		sizeof(fs->fs_fsmnt) - 1,	/* max size*/
		&strsize);			/* real size*/
	bzero(fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize);

#if 0
	if( mp->mnt_flag & MNT_ROOTFS) {
		/*
		 * Root mount; update timestamp in mount structure.
		 * this will be used by the common root mount code
		 * to update the system clock.
		 */
		mp->mnt_time = fs->fs_time;
	}
#endif

	/*
	 * XXX
	 * Limit max file size.  Even though ffs can handle files up to 16TB,
	 * we do limit the max file to 2^31 pages to prevent overflow of
	 * a 32-bit unsigned int.  The buffer cache has its own checks but
	 * a little added paranoia never hurts.
	 */
	ump->um_savedmaxfilesize = fs->fs_maxfilesize;		/* XXX */
	maxfilesize = (u_int64_t)0x80000000 * MIN(PAGE_SIZE, fs->fs_bsize) - 1;
	if (fs->fs_maxfilesize > maxfilesize)			/* XXX */
		fs->fs_maxfilesize = maxfilesize;		/* XXX */
	if (ronly == 0) {
		if ((fs->fs_flags & FS_DOSOFTDEP) &&
		    (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
			free(fs->fs_csp, M_UFSMNT);
			free(fs->fs_contigdirs, M_UFSMNT);
			goto out;
		}
		fs->fs_fmod = 1;
		fs->fs_clean = 0;
		if (mp->mnt_flag & MNT_SOFTDEP)
			fs->fs_flags |= FS_DOSOFTDEP;
		else
			fs->fs_flags &= ~FS_DOSOFTDEP;
		(void) ffs_sbupdate(ump, MNT_WAIT);
	}
	return (0);
out:
	devvp->v_specmountpoint = NULL;
	if (bp)
		brelse(bp);
	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
	VOP_UNLOCK(devvp, 0, p);
	if (ump) {
		free(ump->um_fs, M_UFSMNT);
		free(ump, M_UFSMNT);
		mp->mnt_data = (qaddr_t)0;
	}
	return (error);
}
Exemplo n.º 5
0
/*
 * VFS Operations.
 *
 * mount system call
 */
int
ffs_mount(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;
	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)) {
			/* Flush any dirty data */
			mp->mnt_flag &= ~MNT_RDONLY;
			VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p);
			mp->mnt_flag |= MNT_RDONLY;

			/*
			 * Get rid of files open for writing.
			 */
			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);
			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 (suser(p, 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 = EROFS;
					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_info);
			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 (suser(p, 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)
				free(fs->fs_contigdirs, M_UFSMNT);
		}
		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);
}
Exemplo n.º 6
0
/*
 * Go through the disk queues to initiate sandbagged IO;
 * go through the inodes to write those that have been modified;
 * initiate the writing of the super block if it has been modified.
 *
 * Should always be called with the mount point locked.
 */
int
ffs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p)
{
	struct ufsmount *ump = VFSTOUFS(mp);
	struct fs *fs;
	int error, allerror = 0, count;
	struct ffs_sync_args fsa;

	fs = ump->um_fs;
	/*
	 * Write back modified superblock.
	 * Consistency check that the superblock
	 * is still in the buffer cache.
	 */
	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {
		printf("fs = %s\n", fs->fs_fsmnt);
		panic("update: rofs mod");
	}
 loop:
	/*
	 * Write back each (modified) inode.
	 */
	fsa.allerror = 0;
	fsa.p = p;
	fsa.cred = cred;
	fsa.waitfor = waitfor;

	/*
	 * Don't traverse the vnode list if we want to skip all of them.
	 */
	if (waitfor != MNT_LAZY) {
		vfs_mount_foreach_vnode(mp, ffs_sync_vnode, &fsa);
		allerror = fsa.allerror;
	}

	/*
	 * Force stale file system control information to be flushed.
	 */
	if ((ump->um_mountp->mnt_flag & MNT_SOFTDEP) && waitfor == MNT_WAIT) {
		if ((error = softdep_flushworklist(ump->um_mountp, &count, p)))
			allerror = error;
		/* Flushed work items may create new vnodes to clean */
		if (count) 
			goto loop;
	}
	if (waitfor != MNT_LAZY) {
		if (ump->um_mountp->mnt_flag & MNT_SOFTDEP)
			waitfor = MNT_NOWAIT;
		vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
		if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
			allerror = error;
		VOP_UNLOCK(ump->um_devvp, 0, p);
	}
	qsync(mp);
	/*
	 * Write back modified superblock.
	 */

	if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
		allerror = error;

	return (allerror);
}
Exemplo n.º 7
0
/*
 * If the superblock doesn't already have a recorded journal location
 * then we allocate the journal in one of two positions:
 *
 *  - At the end of the partition after the filesystem if there's
 *    enough space.  "Enough space" is defined as >= 1MB of journal
 *    per 1GB of filesystem or 64MB, whichever is smaller.
 *
 *  - Inside the filesystem.  We try to allocate a contiguous journal
 *    based on the total filesystem size - the target is 1MB of journal
 *    per 1GB of filesystem, up to a maximum journal size of 64MB.  As
 *    a worst case allowing for fragmentation, we'll allocate a journal
 *    1/4 of the desired size but never smaller than 1MB.
 *
 *    XXX In the future if we allow for non-contiguous journal files we
 *    can tighten the above restrictions.
 *
 * XXX
 * These seems like a lot of duplication both here and in some of
 * the userland tools (fsck_ffs, dumpfs, tunefs) with similar 
 * "switch (fs_journal_location)" constructs.  Can we centralise
 * this sort of code somehow/somewhere?
 */
int
wapbl_log_position(struct mount *mp, struct fs *fs, struct vnode *devvp,
    daddr_t *startp, size_t *countp, size_t *blksizep, uint64_t *extradatap)
{
	struct ufsmount *ump = VFSTOUFS(mp);
	daddr_t logstart, logend, desired_logsize;
	uint64_t numsecs;
	unsigned secsize;
	int error, location;

	if (fs->fs_journal_version == UFS_WAPBL_VERSION) {
		switch (fs->fs_journal_location) {
		case UFS_WAPBL_JOURNALLOC_END_PARTITION:
			DPRINTF("found existing end-of-partition log\n");
			*startp = fs->fs_journallocs[UFS_WAPBL_EPART_ADDR];
			*countp = fs->fs_journallocs[UFS_WAPBL_EPART_COUNT];
			*blksizep = fs->fs_journallocs[UFS_WAPBL_EPART_BLKSZ];
			DPRINTF(" start = %lld, size = %zu, "
			    "blksize = %zu\n", *startp, *countp, *blksizep);
			return 0;

		case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
			DPRINTF("found existing in-filesystem log\n");
			*startp = fs->fs_journallocs[UFS_WAPBL_INFS_ADDR];
			*countp = fs->fs_journallocs[UFS_WAPBL_INFS_COUNT];
			*blksizep = fs->fs_journallocs[UFS_WAPBL_INFS_BLKSZ];
			DPRINTF(" start = %lld, size = %zu, "
			    "blksize = %zu\n", *startp, *countp, *blksizep);
			return 0;

		default:
			printf("ffs_wapbl: unknown journal type %d\n",
			    fs->fs_journal_location);
			return EINVAL;
		}
	}

	desired_logsize =
	    lfragtosize(fs, fs->fs_size) / UFS_WAPBL_JOURNAL_SCALE;
	DPRINTF("desired log size = %lld kB\n", desired_logsize / 1024);
	desired_logsize = max(desired_logsize, UFS_WAPBL_MIN_JOURNAL_SIZE);
	desired_logsize = min(desired_logsize, UFS_WAPBL_MAX_JOURNAL_SIZE);
	DPRINTF("adjusted desired log size = %lld kB\n",
	    desired_logsize / 1024);

	/* Is there space after after filesystem on partition for log? */
	logstart = fsbtodb(fs, fs->fs_size);
	error = wapbl_getdisksize(devvp, &numsecs, &secsize);
	if (error)
		return error;
	KDASSERT(secsize != 0);
	logend = btodb(numsecs * secsize);

	if (dbtob(logend - logstart) >= desired_logsize) {
		DPRINTF("enough space, use end-of-partition log\n");

		location = UFS_WAPBL_JOURNALLOC_END_PARTITION;
		*blksizep = secsize;

		*startp = logstart;
		*countp = (logend - logstart);
		*extradatap = 0;

		/* convert to physical block numbers */
		*startp = dbtob(*startp) / secsize;
		*countp = dbtob(*countp) / secsize;

		fs->fs_journallocs[UFS_WAPBL_EPART_ADDR] = *startp;
		fs->fs_journallocs[UFS_WAPBL_EPART_COUNT] = *countp;
		fs->fs_journallocs[UFS_WAPBL_EPART_BLKSZ] = *blksizep;
		fs->fs_journallocs[UFS_WAPBL_EPART_UNUSED] = *extradatap;
	} else {
		DPRINTF("end-of-partition has only %lld free\n",
		    logend - logstart);

		location = UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM;
		*blksizep = secsize;

		error = wapbl_create_infs_log(mp, fs, devvp,
		                  startp, countp, extradatap);
		ffs_sync(mp, MNT_WAIT, FSCRED, curproc);

		/* convert to physical block numbers */
		*startp = dbtob(*startp) / secsize;
		*countp = dbtob(*countp) / secsize;

		fs->fs_journallocs[UFS_WAPBL_INFS_ADDR] = *startp;
		fs->fs_journallocs[UFS_WAPBL_INFS_COUNT] = *countp;
		fs->fs_journallocs[UFS_WAPBL_INFS_BLKSZ] = *blksizep;
		fs->fs_journallocs[UFS_WAPBL_INFS_INO] = *extradatap;
	}

	if (error == 0) {
		/* update superblock with log location */
		fs->fs_journal_version = UFS_WAPBL_VERSION;
		fs->fs_journal_location = location;
		fs->fs_journal_flags = 0;

		error = ffs_sbupdate(ump, MNT_WAIT);
	}

	return error;
}
Exemplo n.º 8
0
int
ffs_wapbl_start(struct mount *mp)
{
	struct ufsmount *ump = VFSTOUFS(mp);
	struct fs *fs = ump->um_fs;
	struct vnode *devvp = ump->um_devvp;
	daddr_t off;
	size_t count;
	size_t blksize;
	uint64_t extradata;
	int error;

	if (mp->mnt_wapbl == NULL) {
		if (fs->fs_journal_flags & UFS_WAPBL_FLAGS_CLEAR_LOG) {
			/* Clear out any existing journal file */
			error = wapbl_remove_log(mp);
			if (error != 0)
				return error;
		}

		if (mp->mnt_flag & MNT_LOG) {
			KDASSERT(fs->fs_ronly == 0);

			/* WAPBL needs UFS2 format super block */
			if (ffs_superblock_layout(fs) < 2) {
				printf("%s fs superblock in old format, "
				   "not journaling\n",
				   VFSTOUFS(mp)->um_fs->fs_fsmnt);
				mp->mnt_flag &= ~MNT_LOG;
				return EINVAL;
			}

			error = wapbl_log_position(mp, fs, devvp, &off,
			    &count, &blksize, &extradata);
			if (error)
				return error;

			error = wapbl_start(&mp->mnt_wapbl, mp, devvp, off,
			    count, blksize, mp->mnt_wapbl_replay,
			    ffs_wapbl_sync_metadata,
			    ffs_wapbl_abort_sync_metadata);
			if (error)
				return error;

			mp->mnt_wapbl_op = &wapbl_ops;

#ifdef WAPBL_DEBUG
			printf("%s: enabling logging\n", fs->fs_fsmnt);
#endif

			if ((fs->fs_flags & FS_DOWAPBL) == 0) {
				UFS_WAPBL_BEGIN(mp);
				fs->fs_flags |= FS_DOWAPBL;
				error = ffs_sbupdate(ump, MNT_WAIT);
				if (error) {
					UFS_WAPBL_END(mp);
					ffs_wapbl_stop(mp, MNT_FORCE);
					return error;
				}
				UFS_WAPBL_END(mp);
				error = wapbl_flush(mp->mnt_wapbl, 1);
				if (error) {
					ffs_wapbl_stop(mp, MNT_FORCE);
					return error;
				}
			}
		} else if (fs->fs_flags & FS_DOWAPBL) {
			fs->fs_fmod = 1;
			fs->fs_flags &= ~FS_DOWAPBL;
		}
	}

	/*
	 * It is recommended that you finish replay with logging enabled.
	 * However, even if logging is not enabled, the remaining log
	 * replay should be safely recoverable with an fsck, so perform
	 * it anyway.
	 */
	if ((fs->fs_ronly == 0) && mp->mnt_wapbl_replay) {
		int saveflag = mp->mnt_flag & MNT_RDONLY;
		/*
		 * Make sure MNT_RDONLY is not set so that the inode
		 * cleanup in ufs_inactive will actually do its work.
		 */
		mp->mnt_flag &= ~MNT_RDONLY;
		ffs_wapbl_replay_finish(mp);
		mp->mnt_flag |= saveflag;
		KASSERT(fs->fs_ronly == 0);
	}

	return 0;
}
Exemplo n.º 9
0
int
wapbl_remove_log(struct mount *mp)
{
	struct ufsmount *ump = VFSTOUFS(mp);
	struct fs *fs = ump->um_fs;
	struct vnode *vp;
	struct inode *ip;
	ino_t log_ino;
	int error;

	/* If super block layout is too old to support WAPBL, return */
	if (ffs_superblock_layout(fs) < 2)
		return 0;

	/* If all the log locators are 0, just clean up */
	if (fs->fs_journallocs[0] == 0 &&
	    fs->fs_journallocs[1] == 0 &&
	    fs->fs_journallocs[2] == 0 &&
	    fs->fs_journallocs[3] == 0) {
		DPRINTF("empty locators, just clear\n");
		goto done;
	}

	switch (fs->fs_journal_location) {
	case UFS_WAPBL_JOURNALLOC_NONE:
		/* nothing! */
		DPRINTF("no log\n");
		break;

	case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
		log_ino = fs->fs_journallocs[UFS_WAPBL_INFS_INO];
		DPRINTF("in-fs log, ino = %lld\n",log_ino);

		/* if no existing log inode, just clear all fields and bail */
		if (log_ino == 0)
			goto done;
		error = VFS_VGET(mp, log_ino, &vp);
		if (error != 0) {
			printf("ffs_wapbl: vget failed %d\n",
			    error);
			/* clear out log info on error */
			goto done;
		}
		ip = VTOI(vp);
		KASSERT(log_ino == ip->i_number);
		if ((DIP(ip, flags) & SF_LOG) == 0) {
			printf("ffs_wapbl: try to clear non-log inode "
			    "%lld\n", log_ino);
			vput(vp);
			/* clear out log info on error */
			goto done;
		}

		/*
		 * remove the log inode by setting its link count back
		 * to zero and bail.
		 */
		ip->i_effnlink = 0;
		DIP_ASSIGN(ip, nlink, 0);
		vput(vp);

	case UFS_WAPBL_JOURNALLOC_END_PARTITION:
		DPRINTF("end-of-partition log\n");
		/* no extra work required */
		break;

	default:
		printf("ffs_wapbl: unknown journal type %d\n",
		    fs->fs_journal_location);
		break;
	}


done:
	/* Clear out all previous knowledge of journal */
	fs->fs_journal_version = 0;
	fs->fs_journal_location = 0;
	fs->fs_journal_flags = 0;
	fs->fs_journallocs[0] = 0;
	fs->fs_journallocs[1] = 0;
	fs->fs_journallocs[2] = 0;
	fs->fs_journallocs[3] = 0;
	(void) ffs_sbupdate(ump, MNT_WAIT);

	return 0;
}
Exemplo n.º 10
0
static int
ntfs_mount ( 
	struct mount *mp,
	char *path,
	caddr_t data,
	struct nameidata *ndp,
	struct proc *p )
{
	u_int		size;
	int		err = 0;
	struct vnode	*devvp;
	struct ntfs_args args;

	/*
	 * Use NULL path to flag a root mount
	 */
	if( path == NULL) {
		/*
		 ***
		 * Mounting root file system
		 ***
		 */
	
		/* Get vnode for root device*/
		if( bdevvp( rootdev, &rootvp))
			panic("ffs_mountroot: can't setup bdevvp for root");

		/*
		 * FS specific handling
		 */
		mp->mnt_flag |= MNT_RDONLY;	/* XXX globally applicable?*/

		/*
		 * Attempt mount
		 */
		if( ( err = ntfs_mountfs(rootvp, mp, &args, p)) != 0) {
			/* fs specific cleanup (if any)*/
			goto error_1;
		}

		goto dostatfs;		/* success*/

	}

	/*
	 ***
	 * Mounting non-root file system or updating a file system
	 ***
	 */

	/* copy in user arguments*/
	err = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args));
	if (err)
		goto error_1;		/* can't get arguments*/

	/*
	 * 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) {
		printf("ntfs_mount(): MNT_UPDATE not supported\n");
		err = EINVAL;
		goto error_1;

#if 0
		ump = VFSTOUFS(mp);
		fs = ump->um_fs;
		err = 0;
		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
			flags = WRITECLOSE;
			if (mp->mnt_flag & MNT_FORCE)
				flags |= FORCECLOSE;
			if (vfs_busy(mp)) {
				err = EBUSY;
				goto error_1;
			}
			err = ffs_flushfiles(mp, flags, p);
			vfs_unbusy(mp);
		}
		if (!err && (mp->mnt_flag & MNT_RELOAD))
			err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
		if (err) {
			goto error_1;
		}
		if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
			if (!fs->fs_clean) {
				if (mp->mnt_flag & MNT_FORCE) {
					printf("WARNING: %s was not properly dismounted.\n",fs->fs_fsmnt);
				} else {
					printf("WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck.\n",
					    fs->fs_fsmnt);
					err = EPERM;
					goto error_1;
				}
			}
			fs->fs_ronly = 0;
		}
		if (fs->fs_ronly == 0) {
			fs->fs_clean = 0;
			ffs_sbupdate(ump, MNT_WAIT);
		}
		/* if not updating name...*/
		if (args.fspec == 0) {
			/*
			 * Process export requests.  Jumping to "success"
			 * will return the vfs_export() error code.
			 */
			err = vfs_export(mp, &ump->um_export, &args.export);
			goto success;
		}