📄 xfs_log.c
字号:
xfs_log_reserve(xfs_mount_t *mp, int unit_bytes, int cnt, xfs_log_ticket_t *ticket, __uint8_t client, uint flags, uint t_type){ xlog_t *log = mp->m_log; xlog_ticket_t *internal_ticket; int retval = 0; ASSERT(client == XFS_TRANSACTION || client == XFS_LOG); ASSERT((flags & XFS_LOG_NOSLEEP) == 0); if (XLOG_FORCED_SHUTDOWN(log)) return XFS_ERROR(EIO); XFS_STATS_INC(xs_try_logspace); if (*ticket != NULL) { ASSERT(flags & XFS_LOG_PERM_RESERV); internal_ticket = (xlog_ticket_t *)*ticket; xlog_trace_loggrant(log, internal_ticket, "xfs_log_reserve: existing ticket (permanent trans)"); xlog_grant_push_ail(mp, internal_ticket->t_unit_res); retval = xlog_regrant_write_log_space(log, internal_ticket); } else { /* may sleep if need to allocate more tickets */ internal_ticket = xlog_ticket_get(log, unit_bytes, cnt, client, flags); internal_ticket->t_trans_type = t_type; *ticket = internal_ticket; xlog_trace_loggrant(log, internal_ticket, (internal_ticket->t_flags & XLOG_TIC_PERM_RESERV) ? "xfs_log_reserve: create new ticket (permanent trans)" : "xfs_log_reserve: create new ticket"); xlog_grant_push_ail(mp, (internal_ticket->t_unit_res * internal_ticket->t_cnt)); retval = xlog_grant_log_space(log, internal_ticket); } return retval;} /* xfs_log_reserve *//* * Mount a log filesystem * * mp - ubiquitous xfs mount point structure * log_target - buftarg of on-disk log device * blk_offset - Start block # where block size is 512 bytes (BBSIZE) * num_bblocks - Number of BBSIZE blocks in on-disk log * * Return error or zero. */intxfs_log_mount(xfs_mount_t *mp, xfs_buftarg_t *log_target, xfs_daddr_t blk_offset, int num_bblks){ if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) cmn_err(CE_NOTE, "XFS mounting filesystem %s", mp->m_fsname); else { cmn_err(CE_NOTE, "!Mounting filesystem \"%s\" in no-recovery mode. Filesystem will be inconsistent.", mp->m_fsname); ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); } mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks); /* * skip log recovery on a norecovery mount. pretend it all * just worked. */ if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { int error, readonly = (mp->m_flags & XFS_MOUNT_RDONLY); if (readonly) mp->m_flags &= ~XFS_MOUNT_RDONLY; error = xlog_recover(mp->m_log); if (readonly) mp->m_flags |= XFS_MOUNT_RDONLY; if (error) { cmn_err(CE_WARN, "XFS: log mount/recovery failed: error %d", error); xlog_dealloc_log(mp->m_log); return error; } } /* Normal transactions can now occur */ mp->m_log->l_flags &= ~XLOG_ACTIVE_RECOVERY; /* End mounting message in xfs_log_mount_finish */ return 0;} /* xfs_log_mount *//* * Finish the recovery of the file system. This is separate from * the xfs_log_mount() call, because it depends on the code in * xfs_mountfs() to read in the root and real-time bitmap inodes * between calling xfs_log_mount() and here. * * mp - ubiquitous xfs mount point structure */intxfs_log_mount_finish(xfs_mount_t *mp, int mfsi_flags){ int error; if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) error = xlog_recover_finish(mp->m_log, mfsi_flags); else { error = 0; ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); } return error;}/* * Unmount processing for the log. */intxfs_log_unmount(xfs_mount_t *mp){ int error; error = xfs_log_unmount_write(mp); xfs_log_unmount_dealloc(mp); return error;}/* * Final log writes as part of unmount. * * Mark the filesystem clean as unmount happens. Note that during relocation * this routine needs to be executed as part of source-bag while the * deallocation must not be done until source-end. *//* * Unmount record used to have a string "Unmount filesystem--" in the * data section where the "Un" was really a magic number (XLOG_UNMOUNT_TYPE). * We just write the magic number now since that particular field isn't * currently architecture converted and "nUmount" is a bit foo. * As far as I know, there weren't any dependencies on the old behaviour. */intxfs_log_unmount_write(xfs_mount_t *mp){ xlog_t *log = mp->m_log; xlog_in_core_t *iclog;#ifdef DEBUG xlog_in_core_t *first_iclog;#endif xfs_log_iovec_t reg[1]; xfs_log_ticket_t tic = NULL; xfs_lsn_t lsn; int error; SPLDECL(s); /* 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 = { XLOG_UNMOUNT_TYPE, 0, 0 }; /* * Don't write out unmount record on read-only mounts. * Or, if we are doing a forced umount (typically because of IO errors). */ if (mp->m_flags & XFS_MOUNT_RDONLY) return 0; xfs_log_force(mp, 0, XFS_LOG_FORCE|XFS_LOG_SYNC);#ifdef DEBUG first_iclog = iclog = log->l_iclog; do { if (!(iclog->ic_state & XLOG_STATE_IOERROR)) { ASSERT(iclog->ic_state & XLOG_STATE_ACTIVE); ASSERT(iclog->ic_offset == 0); } iclog = iclog->ic_next; } while (iclog != first_iclog);#endif if (! (XLOG_FORCED_SHUTDOWN(log))) { reg[0].i_addr = (void*)&magic; reg[0].i_len = sizeof(magic); XLOG_VEC_SET_TYPE(®[0], XLOG_REG_TYPE_UNMOUNT); error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0, XLOG_UNMOUNT_REC_TYPE); if (!error) { /* remove inited flag */ ((xlog_ticket_t *)tic)->t_flags = 0; error = xlog_write(mp, reg, 1, 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_fs_cmn_err(CE_ALERT, mp, "xfs_log_unmount: unmount record failed"); } s = LOG_LOCK(log); iclog = log->l_iclog; iclog->ic_refcnt++; LOG_UNLOCK(log, s); xlog_state_want_sync(log, iclog); (void) xlog_state_release_iclog(log, iclog); s = LOG_LOCK(log); if (!(iclog->ic_state == XLOG_STATE_ACTIVE || iclog->ic_state == XLOG_STATE_DIRTY)) { if (!XLOG_FORCED_SHUTDOWN(log)) { sv_wait(&iclog->ic_forcesema, PMEM, &log->l_icloglock, s); } else { LOG_UNLOCK(log, s); } } else { LOG_UNLOCK(log, s); } if (tic) { xlog_trace_loggrant(log, tic, "unmount rec"); xlog_ungrant_log_space(log, tic); xlog_state_put_ticket(log, tic); } } else { /* * We're already in forced_shutdown mode, couldn't * even attempt to write out the unmount transaction. * * Go through the motions of sync'ing and releasing * the iclog, even though no I/O will actually happen, * we need to wait for other log I/Os that may already * be in progress. Do this as a separate section of * code so we'll know if we ever get stuck here that * we're in this odd situation of trying to unmount * a file system that went into forced_shutdown as * the result of an unmount.. */ s = LOG_LOCK(log); iclog = log->l_iclog; iclog->ic_refcnt++; LOG_UNLOCK(log, s); xlog_state_want_sync(log, iclog); (void) xlog_state_release_iclog(log, iclog); s = LOG_LOCK(log); if ( ! ( iclog->ic_state == XLOG_STATE_ACTIVE || iclog->ic_state == XLOG_STATE_DIRTY || iclog->ic_state == XLOG_STATE_IOERROR) ) { sv_wait(&iclog->ic_forcesema, PMEM, &log->l_icloglock, s); } else { LOG_UNLOCK(log, s); } } return 0;} /* xfs_log_unmount_write *//* * Deallocate log structures for unmount/relocation. */voidxfs_log_unmount_dealloc(xfs_mount_t *mp){ xlog_dealloc_log(mp->m_log);}/* * Write region vectors to log. The write happens using the space reservation * of the ticket (tic). It is not a requirement that all writes for a given * transaction occur with one call to xfs_log_write(). */intxfs_log_write(xfs_mount_t * mp, xfs_log_iovec_t reg[], int nentries, xfs_log_ticket_t tic, xfs_lsn_t *start_lsn){ int error; xlog_t *log = mp->m_log; if (XLOG_FORCED_SHUTDOWN(log)) return XFS_ERROR(EIO); if ((error = xlog_write(mp, reg, nentries, tic, start_lsn, NULL, 0))) { xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); } return error;} /* xfs_log_write */voidxfs_log_move_tail(xfs_mount_t *mp, xfs_lsn_t tail_lsn){ xlog_ticket_t *tic; xlog_t *log = mp->m_log; int need_bytes, free_bytes, cycle, bytes; SPLDECL(s); if (XLOG_FORCED_SHUTDOWN(log)) return; ASSERT(!XFS_FORCED_SHUTDOWN(mp)); if (tail_lsn == 0) { /* needed since sync_lsn is 64 bits */ s = LOG_LOCK(log); tail_lsn = log->l_last_sync_lsn; LOG_UNLOCK(log, s); } s = GRANT_LOCK(log); /* Also an invalid lsn. 1 implies that we aren't passing in a valid * tail_lsn. */ if (tail_lsn != 1) { log->l_tail_lsn = tail_lsn; } if ((tic = log->l_write_headq)) {#ifdef DEBUG if (log->l_flags & XLOG_ACTIVE_RECOVERY) panic("Recovery problem");#endif cycle = log->l_grant_write_cycle; bytes = log->l_grant_write_bytes; free_bytes = xlog_space_left(log, cycle, bytes); do { ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV); if (free_bytes < tic->t_unit_res && tail_lsn != 1) break; tail_lsn = 0; free_bytes -= tic->t_unit_res; sv_signal(&tic->t_sema); tic = tic->t_next; } while (tic != log->l_write_headq); } if ((tic = log->l_reserve_headq)) {#ifdef DEBUG if (log->l_flags & XLOG_ACTIVE_RECOVERY) panic("Recovery problem");#endif cycle = log->l_grant_reserve_cycle; bytes = log->l_grant_reserve_bytes; free_bytes = xlog_space_left(log, cycle, bytes); do { if (tic->t_flags & XLOG_TIC_PERM_RESERV) need_bytes = tic->t_unit_res*tic->t_cnt; else need_bytes = tic->t_unit_res; if (free_bytes < need_bytes && tail_lsn != 1) break; tail_lsn = 0; free_bytes -= need_bytes; sv_signal(&tic->t_sema); tic = tic->t_next; } while (tic != log->l_reserve_headq); } GRANT_UNLOCK(log, s);} /* xfs_log_move_tail *//* * Determine if we have a transaction that has gone to disk * that needs to be covered. Log activity needs to be idle (no AIL and * nothing in the iclogs). And, we need to be in the right state indicating * something has gone out. */intxfs_log_need_covered(xfs_mount_t *mp){ SPLDECL(s); int needed = 0, gen; xlog_t *log = mp->m_log; if (!xfs_fs_writable(mp)) return 0; s = LOG_LOCK(log); if (((log->l_covered_state == XLOG_STATE_COVER_NEED) || (log->l_covered_state == XLOG_STATE_COVER_NEED2)) && !xfs_trans_first_ail(mp, &gen) && xlog_iclogs_empty(log)) { if (log->l_covered_state == XLOG_STATE_COVER_NEED) log->l_covered_state = XLOG_STATE_COVER_DONE; else { ASSERT(log->l_covered_state == XLOG_STATE_COVER_NEED2); log->l_covered_state = XLOG_STATE_COVER_DONE2; } needed = 1; } LOG_UNLOCK(log, s); return needed;}/****************************************************************************** * * local routines * ****************************************************************************** *//* xfs_trans_tail_ail returns 0 when there is nothing in the list. * The log manager must keep track of the last LR which was committed * to disk. The lsn of this LR will become the new tail_lsn whenever * xfs_trans_tail_ail returns 0. If we don't do this, we run into * the situation where stuff could be written into the log but nothing * was ever in the AIL when asked. Eventually, we panic since the * tail hits the head. * * We may be holding the log iclog lock upon entering this routine. */xfs_lsn_txlog_assign_tail_lsn(xfs_mount_t *mp){ xfs_lsn_t tail_lsn; SPLDECL(s); xlog_t *log = mp->m_log;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -