xfs_mount.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,582 行 · 第 1/3 页

C
1,582
字号
			  sizeof(xfs_perag_busy_t) * XFS_PAGB_NUM_SLOTS);	kmem_free(mp->m_perag, sbp->sb_agcount * sizeof(xfs_perag_t));	mp->m_perag = NULL;	/* FALLTHROUGH */ error1:	if (uuid_mounted)		xfs_uuid_unmount(mp);	xfs_freesb(mp);	return error;}/* * xfs_unmountfs * * This flushes out the inodes,dquots and the superblock, unmounts the * log and makes sure that incore structures are freed. */intxfs_unmountfs(xfs_mount_t *mp, struct cred *cr){	struct vfs	*vfsp = XFS_MTOVFS(mp);#if defined(DEBUG) || defined(INDUCE_IO_ERROR)	int64_t		fsid;#endif	xfs_iflush_all(mp, XFS_FLUSH_ALL);	XFS_QM_DQPURGEALL(mp,		XFS_QMOPT_UQUOTA | XFS_QMOPT_GQUOTA | XFS_QMOPT_UMOUNTING);	/*	 * Flush out the log synchronously so that we know for sure	 * that nothing is pinned.  This is important because bflush()	 * will skip pinned buffers.	 */	xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);	xfs_binval(mp->m_ddev_targp);	if (mp->m_rtdev_targp) {		xfs_binval(mp->m_rtdev_targp);	}	xfs_unmountfs_writesb(mp);	xfs_log_unmount(mp);			/* Done! No more fs ops. */	xfs_freesb(mp);	/*	 * All inodes from this mount point should be freed.	 */	ASSERT(mp->m_inodes == NULL);	/*	 * We may have bufs that are in the process of getting written still.	 * We must wait for the I/O completion of those. The sync flag here	 * does a two pass iteration thru the bufcache.	 */	if (XFS_FORCED_SHUTDOWN(mp)) {		xfs_incore_relse(mp->m_ddev_targp, 0, 1); /* synchronous */	}	xfs_unmountfs_close(mp, cr);	if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0)		xfs_uuid_unmount(mp);#if defined(DEBUG) || defined(INDUCE_IO_ERROR)	/*	 * clear all error tags on this filesystem	 */	memcpy(&fsid, &vfsp->vfs_fsid, sizeof(int64_t));	xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0);#endif	XFS_IODONE(vfsp);	xfs_mount_free(mp, 1);	return 0;}voidxfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr){	if (mp->m_logdev_targp != mp->m_ddev_targp)		xfs_free_buftarg(mp->m_logdev_targp, 1);	if (mp->m_rtdev_targp)		xfs_free_buftarg(mp->m_rtdev_targp, 1);	xfs_free_buftarg(mp->m_ddev_targp, 0);}intxfs_unmountfs_writesb(xfs_mount_t *mp){	xfs_buf_t	*sbp;	xfs_sb_t	*sb;	int		error = 0;	/*	 * skip superblock write if fs is read-only, or	 * if we are doing a forced umount.	 */	sbp = xfs_getsb(mp, 0);	if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY ||		XFS_FORCED_SHUTDOWN(mp))) {		/*		 * mark shared-readonly if desired		 */		sb = XFS_BUF_TO_SBP(sbp);		if (mp->m_mk_sharedro) {			if (!(sb->sb_flags & XFS_SBF_READONLY))				sb->sb_flags |= XFS_SBF_READONLY;			if (!XFS_SB_VERSION_HASSHARED(sb))				XFS_SB_VERSION_ADDSHARED(sb);			xfs_fs_cmn_err(CE_NOTE, mp,				"Unmounting, marking shared read-only");		}		XFS_BUF_UNDONE(sbp);		XFS_BUF_UNREAD(sbp);		XFS_BUF_UNDELAYWRITE(sbp);		XFS_BUF_WRITE(sbp);		XFS_BUF_UNASYNC(sbp);		ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp);		xfsbdstrat(mp, sbp);		/* Nevermind errors we might get here. */		error = xfs_iowait(sbp);		if (error)			xfs_ioerror_alert("xfs_unmountfs_writesb",					  mp, sbp, XFS_BUF_ADDR(sbp));		if (error && mp->m_mk_sharedro)			xfs_fs_cmn_err(CE_ALERT, mp, "Superblock write error detected while unmounting.  Filesystem may not be marked shared readonly");	}	xfs_buf_relse(sbp);	return (error);}/* * xfs_mod_sb() can be used to copy arbitrary changes to the * in-core superblock into the superblock buffer to be logged. * It does not provide the higher level of locking that is * needed to protect the in-core superblock from concurrent * access. */voidxfs_mod_sb(xfs_trans_t *tp, __int64_t fields){	xfs_buf_t	*bp;	int		first;	int		last;	xfs_mount_t	*mp;	xfs_sb_t	*sbp;	xfs_sb_field_t	f;	ASSERT(fields);	if (!fields)		return;	mp = tp->t_mountp;	bp = xfs_trans_getsb(tp, mp, 0);	sbp = XFS_BUF_TO_SBP(bp);	first = sizeof(xfs_sb_t);	last = 0;	/* translate/copy */	xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), -1, ARCH_CONVERT, fields);	/* find modified range */	f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);	ASSERT((1LL << f) & XFS_SB_MOD_BITS);	first = xfs_sb_info[f].offset;	f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields);	ASSERT((1LL << f) & XFS_SB_MOD_BITS);	last = xfs_sb_info[f + 1].offset - 1;	xfs_trans_log_buf(tp, bp, first, last);}/* * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply * a delta to a specified field in the in-core superblock.  Simply * switch on the field indicated and apply the delta to that field. * Fields are not allowed to dip below zero, so if the delta would * do this do not apply it and return EINVAL. * * The SB_LOCK must be held when this routine is called. */STATIC intxfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field,			int delta, int rsvd){	int		scounter;	/* short counter for 32 bit fields */	long long	lcounter;	/* long counter for 64 bit fields */	long long	res_used, rem;	/*	 * With the in-core superblock spin lock held, switch	 * on the indicated field.  Apply the delta to the	 * proper field.  If the fields value would dip below	 * 0, then do not apply the delta and return EINVAL.	 */	switch (field) {	case XFS_SBS_ICOUNT:		lcounter = (long long)mp->m_sb.sb_icount;		lcounter += delta;		if (lcounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_icount = lcounter;		return (0);	case XFS_SBS_IFREE:		lcounter = (long long)mp->m_sb.sb_ifree;		lcounter += delta;		if (lcounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_ifree = lcounter;		return (0);	case XFS_SBS_FDBLOCKS:		lcounter = (long long)mp->m_sb.sb_fdblocks;		res_used = (long long)(mp->m_resblks - mp->m_resblks_avail);		if (delta > 0) {		/* Putting blocks back */			if (res_used > delta) {				mp->m_resblks_avail += delta;			} else {				rem = delta - res_used;				mp->m_resblks_avail = mp->m_resblks;				lcounter += rem;			}		} else {				/* Taking blocks away */			lcounter += delta;		/*		 * If were out of blocks, use any available reserved blocks if		 * were allowed to.		 */			if (lcounter < 0) {				if (rsvd) {					lcounter = (long long)mp->m_resblks_avail + delta;					if (lcounter < 0) {						return (XFS_ERROR(ENOSPC));					}					mp->m_resblks_avail = lcounter;					return (0);				} else {	/* not reserved */					return (XFS_ERROR(ENOSPC));				}			}		}		mp->m_sb.sb_fdblocks = lcounter;		return (0);	case XFS_SBS_FREXTENTS:		lcounter = (long long)mp->m_sb.sb_frextents;		lcounter += delta;		if (lcounter < 0) {			return (XFS_ERROR(ENOSPC));		}		mp->m_sb.sb_frextents = lcounter;		return (0);	case XFS_SBS_DBLOCKS:		lcounter = (long long)mp->m_sb.sb_dblocks;		lcounter += delta;		if (lcounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_dblocks = lcounter;		return (0);	case XFS_SBS_AGCOUNT:		scounter = mp->m_sb.sb_agcount;		scounter += delta;		if (scounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_agcount = scounter;		return (0);	case XFS_SBS_IMAX_PCT:		scounter = mp->m_sb.sb_imax_pct;		scounter += delta;		if (scounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_imax_pct = scounter;		return (0);	case XFS_SBS_REXTSIZE:		scounter = mp->m_sb.sb_rextsize;		scounter += delta;		if (scounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_rextsize = scounter;		return (0);	case XFS_SBS_RBMBLOCKS:		scounter = mp->m_sb.sb_rbmblocks;		scounter += delta;		if (scounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_rbmblocks = scounter;		return (0);	case XFS_SBS_RBLOCKS:		lcounter = (long long)mp->m_sb.sb_rblocks;		lcounter += delta;		if (lcounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_rblocks = lcounter;		return (0);	case XFS_SBS_REXTENTS:		lcounter = (long long)mp->m_sb.sb_rextents;		lcounter += delta;		if (lcounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_rextents = lcounter;		return (0);	case XFS_SBS_REXTSLOG:		scounter = mp->m_sb.sb_rextslog;		scounter += delta;		if (scounter < 0) {			ASSERT(0);			return (XFS_ERROR(EINVAL));		}		mp->m_sb.sb_rextslog = scounter;		return (0);	default:		ASSERT(0);		return (XFS_ERROR(EINVAL));	}}/* * xfs_mod_incore_sb() is used to change a field in the in-core * superblock structure by the specified delta.  This modification * is protected by the SB_LOCK.  Just use the xfs_mod_incore_sb_unlocked() * routine to do the work. */intxfs_mod_incore_sb(xfs_mount_t *mp, xfs_sb_field_t field, int delta, int rsvd){	unsigned long	s;	int	status;	s = XFS_SB_LOCK(mp);	status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);	XFS_SB_UNLOCK(mp, s);	return (status);}/* * xfs_mod_incore_sb_batch() is used to change more than one field * in the in-core superblock structure at a time.  This modification * is protected by a lock internal to this module.  The fields and * changes to those fields are specified in the array of xfs_mod_sb * structures passed in. * * Either all of the specified deltas will be applied or none of * them will.  If any modified field dips below 0, then all modifications * will be backed out and EINVAL will be returned. */intxfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd){	unsigned long	s;	int		status=0;	xfs_mod_sb_t	*msbp;	/*	 * Loop through the array of mod structures and apply each	 * individually.  If any fail, then back out all those	 * which have already been applied.  Do all of this within	 * the scope of the SB_LOCK so that all of the changes will	 * be atomic.	 */	s = XFS_SB_LOCK(mp);	msbp = &msb[0];	for (msbp = &msbp[0]; msbp < (msb + nmsb); msbp++) {		/*		 * Apply the delta at index n.  If it fails, break		 * from the loop so we'll fall into the undo loop		 * below.		 */		status = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field,						    msbp->msb_delta, rsvd);		if (status != 0) {			break;		}	}	/*	 * If we didn't complete the loop above, then back out	 * any changes made to the superblock.  If you add code	 * between the loop above and here, make sure that you	 * preserve the value of status. Loop back until	 * we step below the beginning of the array.  Make sure	 * we don't touch anything back there.	 */	if (status != 0) {		msbp--;		while (msbp >= msb) {			status = xfs_mod_incore_sb_unlocked(mp,				    msbp->msb_field, -(msbp->msb_delta), rsvd);			ASSERT(status == 0);			msbp--;		}	}	XFS_SB_UNLOCK(mp, s);	return (status);}/* * xfs_getsb() is called to obtain the buffer for the superblock. * The buffer is returned locked and read in from disk. * The buffer should be released with a call to xfs_brelse(). * * If the flags parameter is BUF_TRYLOCK, then we'll only return * the superblock buffer if it can be locked without sleeping. * If it can't then we'll return NULL. */xfs_buf_t *xfs_getsb(	xfs_mount_t	*mp,	int		flags){	xfs_buf_t	*bp;	ASSERT(mp->m_sb_bp != NULL);	bp = mp->m_sb_bp;	if (flags & XFS_BUF_TRYLOCK) {		if (!XFS_BUF_CPSEMA(bp)) {			return NULL;		}	} else {		XFS_BUF_PSEMA(bp, PRIBIO);	}	XFS_BUF_HOLD(bp);	ASSERT(XFS_BUF_ISDONE(bp));	return (bp);}/* * Used to free the superblock along various error paths. */voidxfs_freesb(	xfs_mount_t	*mp){	xfs_buf_t	*bp;	/*	 * Use xfs_getsb() so that the buffer will be locked	 * when we call xfs_buf_relse().	 */	bp = xfs_getsb(mp, 0);	XFS_BUF_UNMANAGE(bp);	xfs_buf_relse(bp);	mp->m_sb_bp = NULL;}/* * See if the UUID is unique among mounted XFS filesystems. * Mount fails if UUID is nil or a FS with the same UUID is already mounted. */STATIC intxfs_uuid_mount(	xfs_mount_t	*mp){	if (uuid_is_nil(&mp->m_sb.sb_uuid)) {		cmn_err(CE_WARN,			"XFS: Filesystem %s has nil UUID - can't mount",			mp->m_fsname);		return -1;	}	if (!uuid_table_insert(&mp->m_sb.sb_uuid)) {		cmn_err(CE_WARN,			"XFS: Filesystem %s has duplicate UUID - can't mount",			mp->m_fsname);		return -1;	}	return 0;}/* * Remove filesystem from the UUID table. */STATIC voidxfs_uuid_unmount(	xfs_mount_t	*mp){	uuid_table_remove(&mp->m_sb.sb_uuid);}/* * Used to log changes to the superblock unit and width fields which could * be altered by the mount options. Only the first superblock is updated. */STATIC voidxfs_mount_log_sbunit(	xfs_mount_t	*mp,	__int64_t	fields){	xfs_trans_t	*tp;	ASSERT(fields & (XFS_SB_UNIT|XFS_SB_WIDTH|XFS_SB_UUID));	tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT);	if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,				XFS_DEFAULT_LOG_COUNT)) {		xfs_trans_cancel(tp, 0);		return;	}	xfs_mod_sb(tp, fields);	xfs_trans_commit(tp, 0, NULL);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?