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; +} |