diff options
Diffstat (limited to 'fs/xfs/xfs_log.c')
| -rw-r--r-- | fs/xfs/xfs_log.c | 156 | 
1 files changed, 93 insertions, 63 deletions
| diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 5e56f3b93d4b..c3b610b687d1 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -410,7 +410,7 @@ out_error:  }  /* - * Reserve log space and return a ticket corresponding the reservation. + * Reserve log space and return a ticket corresponding to the reservation.   *   * Each reservation is going to reserve extra space for a log record header.   * When writes happen to the on-disk log, we don't subtract the length of the @@ -826,6 +826,88 @@ xfs_log_mount_cancel(   * deallocation must not be done until source-end.   */ +/* Actually write the unmount record to disk. */ +static void +xfs_log_write_unmount_record( +	struct xfs_mount	*mp) +{ +	/* the data section must be 32 bit size aligned */ +	struct xfs_unmount_log_format magic = { +		.magic = XLOG_UNMOUNT_TYPE, +	}; +	struct xfs_log_iovec reg = { +		.i_addr = &magic, +		.i_len = sizeof(magic), +		.i_type = XLOG_REG_TYPE_UNMOUNT, +	}; +	struct xfs_log_vec vec = { +		.lv_niovecs = 1, +		.lv_iovecp = ®, +	}; +	struct xlog		*log = mp->m_log; +	struct xlog_in_core	*iclog; +	struct xlog_ticket	*tic = NULL; +	xfs_lsn_t		lsn; +	uint			flags = XLOG_UNMOUNT_TRANS; +	int			error; + +	error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0); +	if (error) +		goto out_err; + +	/* +	 * If we think the summary counters are bad, clear the unmount header +	 * flag in the unmount record so that the summary counters will be +	 * recalculated during log recovery at next mount.  Refer to +	 * xlog_check_unmount_rec for more details. +	 */ +	if (XFS_TEST_ERROR((mp->m_flags & XFS_MOUNT_BAD_SUMMARY), mp, +			XFS_ERRTAG_FORCE_SUMMARY_RECALC)) { +		xfs_alert(mp, "%s: will fix summary counters at next mount", +				__func__); +		flags &= ~XLOG_UNMOUNT_TRANS; +	} + +	/* remove inited flag, and account for space used */ +	tic->t_flags = 0; +	tic->t_curr_res -= sizeof(magic); +	error = xlog_write(log, &vec, tic, &lsn, NULL, flags); +	/* +	 * At this point, we're umounting anyway, so there's no point in +	 * transitioning log state to IOERROR. Just continue... +	 */ +out_err: +	if (error) +		xfs_alert(mp, "%s: unmount record failed", __func__); + +	spin_lock(&log->l_icloglock); +	iclog = log->l_iclog; +	atomic_inc(&iclog->ic_refcnt); +	xlog_state_want_sync(log, iclog); +	spin_unlock(&log->l_icloglock); +	error = xlog_state_release_iclog(log, iclog); + +	spin_lock(&log->l_icloglock); +	switch (iclog->ic_state) { +	default: +		if (!XLOG_FORCED_SHUTDOWN(log)) { +			xlog_wait(&iclog->ic_force_wait, &log->l_icloglock); +			break; +		} +		/* fall through */ +	case XLOG_STATE_ACTIVE: +	case XLOG_STATE_DIRTY: +		spin_unlock(&log->l_icloglock); +		break; +	} + +	if (tic) { +		trace_xfs_log_umount_write(log, tic); +		xlog_ungrant_log_space(log, tic); +		xfs_log_ticket_put(tic); +	} +} +  /*   * Unmount record used to have a string "Unmount filesystem--" in the   * data section where the "Un" was really a magic number (XLOG_UNMOUNT_TYPE). @@ -842,8 +924,6 @@ xfs_log_unmount_write(xfs_mount_t *mp)  #ifdef DEBUG  	xlog_in_core_t	 *first_iclog;  #endif -	xlog_ticket_t	*tic = NULL; -	xfs_lsn_t	 lsn;  	int		 error;  	/* @@ -870,66 +950,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)  	} while (iclog != first_iclog);  #endif  	if (! (XLOG_FORCED_SHUTDOWN(log))) { -		error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0); -		if (!error) { -			/* the data section must be 32 bit size aligned */ -			struct { -			    uint16_t magic; -			    uint16_t pad1; -			    uint32_t pad2; /* may as well make it 64 bits */ -			} magic = { -				.magic = XLOG_UNMOUNT_TYPE, -			}; -			struct xfs_log_iovec reg = { -				.i_addr = &magic, -				.i_len = sizeof(magic), -				.i_type = XLOG_REG_TYPE_UNMOUNT, -			}; -			struct xfs_log_vec vec = { -				.lv_niovecs = 1, -				.lv_iovecp = ®, -			}; - -			/* remove inited flag, and account for space used */ -			tic->t_flags = 0; -			tic->t_curr_res -= sizeof(magic); -			error = xlog_write(log, &vec, tic, &lsn, -					   NULL, XLOG_UNMOUNT_TRANS); -			/* -			 * At this point, we're umounting anyway, -			 * so there's no point in transitioning log state -			 * to IOERROR. Just continue... -			 */ -		} - -		if (error) -			xfs_alert(mp, "%s: unmount record failed", __func__); - - -		spin_lock(&log->l_icloglock); -		iclog = log->l_iclog; -		atomic_inc(&iclog->ic_refcnt); -		xlog_state_want_sync(log, iclog); -		spin_unlock(&log->l_icloglock); -		error = xlog_state_release_iclog(log, iclog); - -		spin_lock(&log->l_icloglock); -		if (!(iclog->ic_state == XLOG_STATE_ACTIVE || -		      iclog->ic_state == XLOG_STATE_DIRTY)) { -			if (!XLOG_FORCED_SHUTDOWN(log)) { -				xlog_wait(&iclog->ic_force_wait, -							&log->l_icloglock); -			} else { -				spin_unlock(&log->l_icloglock); -			} -		} else { -			spin_unlock(&log->l_icloglock); -		} -		if (tic) { -			trace_xfs_log_umount_write(log, tic); -			xlog_ungrant_log_space(log, tic); -			xfs_log_ticket_put(tic); -		} +		xfs_log_write_unmount_record(mp);  	} else {  		/*  		 * We're already in forced_shutdown mode, couldn't @@ -4083,3 +4104,12 @@ xfs_log_check_lsn(  	return valid;  } + +bool +xfs_log_in_recovery( +	struct xfs_mount	*mp) +{ +	struct xlog		*log = mp->m_log; + +	return log->l_flags & XLOG_ACTIVE_RECOVERY; +} |