📄 xfs_log.c
字号:
/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_error.h"#include "xfs_log_priv.h"#include "xfs_buf_item.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_log_recover.h"#include "xfs_trans_priv.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_rw.h"#define xlog_write_adv_cnt(ptr, len, off, bytes) \ { (ptr) += (bytes); \ (len) -= (bytes); \ (off) += (bytes);}/* Local miscellaneous function prototypes */STATIC int xlog_bdstrat_cb(struct xfs_buf *);STATIC int xlog_commit_record(xfs_mount_t *mp, xlog_ticket_t *ticket, xlog_in_core_t **, xfs_lsn_t *);STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp, xfs_buftarg_t *log_target, xfs_daddr_t blk_offset, int num_bblks);STATIC int xlog_space_left(xlog_t *log, int cycle, int bytes);STATIC int xlog_sync(xlog_t *log, xlog_in_core_t *iclog);STATIC void xlog_dealloc_log(xlog_t *log);STATIC int xlog_write(xfs_mount_t *mp, xfs_log_iovec_t region[], int nentries, xfs_log_ticket_t tic, xfs_lsn_t *start_lsn, xlog_in_core_t **commit_iclog, uint flags);/* local state machine functions */STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int);STATIC void xlog_state_do_callback(xlog_t *log,int aborted, xlog_in_core_t *iclog);STATIC int xlog_state_get_iclog_space(xlog_t *log, int len, xlog_in_core_t **iclog, xlog_ticket_t *ticket, int *continued_write, int *logoffsetp);STATIC void xlog_state_put_ticket(xlog_t *log, xlog_ticket_t *tic);STATIC int xlog_state_release_iclog(xlog_t *log, xlog_in_core_t *iclog);STATIC void xlog_state_switch_iclogs(xlog_t *log, xlog_in_core_t *iclog, int eventual_size);STATIC int xlog_state_sync(xlog_t *log, xfs_lsn_t lsn, uint flags, int *log_flushed);STATIC int xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed);STATIC void xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog);/* local functions to manipulate grant head */STATIC int xlog_grant_log_space(xlog_t *log, xlog_ticket_t *xtic);STATIC void xlog_grant_push_ail(xfs_mount_t *mp, int need_bytes);STATIC void xlog_regrant_reserve_log_space(xlog_t *log, xlog_ticket_t *ticket);STATIC int xlog_regrant_write_log_space(xlog_t *log, xlog_ticket_t *ticket);STATIC void xlog_ungrant_log_space(xlog_t *log, xlog_ticket_t *ticket);/* local ticket functions */STATIC void xlog_state_ticket_alloc(xlog_t *log);STATIC xlog_ticket_t *xlog_ticket_get(xlog_t *log, int unit_bytes, int count, char clientid, uint flags);STATIC void xlog_ticket_put(xlog_t *log, xlog_ticket_t *ticket);#if defined(DEBUG)STATIC void xlog_verify_dest_ptr(xlog_t *log, __psint_t ptr);STATIC void xlog_verify_grant_head(xlog_t *log, int equals);STATIC void xlog_verify_iclog(xlog_t *log, xlog_in_core_t *iclog, int count, boolean_t syncing);STATIC void xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog, xfs_lsn_t tail_lsn);#else#define xlog_verify_dest_ptr(a,b)#define xlog_verify_grant_head(a,b)#define xlog_verify_iclog(a,b,c,d)#define xlog_verify_tail_lsn(a,b,c)#endifSTATIC int xlog_iclogs_empty(xlog_t *log);#if defined(XFS_LOG_TRACE)voidxlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string){ unsigned long cnts; if (!log->l_grant_trace) { log->l_grant_trace = ktrace_alloc(2048, KM_NOSLEEP); if (!log->l_grant_trace) return; } /* ticket counts are 1 byte each */ cnts = ((unsigned long)tic->t_ocnt) | ((unsigned long)tic->t_cnt) << 8; ktrace_enter(log->l_grant_trace, (void *)tic, (void *)log->l_reserve_headq, (void *)log->l_write_headq, (void *)((unsigned long)log->l_grant_reserve_cycle), (void *)((unsigned long)log->l_grant_reserve_bytes), (void *)((unsigned long)log->l_grant_write_cycle), (void *)((unsigned long)log->l_grant_write_bytes), (void *)((unsigned long)log->l_curr_cycle), (void *)((unsigned long)log->l_curr_block), (void *)((unsigned long)CYCLE_LSN(log->l_tail_lsn)), (void *)((unsigned long)BLOCK_LSN(log->l_tail_lsn)), (void *)string, (void *)((unsigned long)tic->t_trans_type), (void *)cnts, (void *)((unsigned long)tic->t_curr_res), (void *)((unsigned long)tic->t_unit_res));}voidxlog_trace_iclog(xlog_in_core_t *iclog, uint state){ if (!iclog->ic_trace) iclog->ic_trace = ktrace_alloc(256, KM_SLEEP); ktrace_enter(iclog->ic_trace, (void *)((unsigned long)state), (void *)((unsigned long)current_pid()), (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL, (void *)NULL);}#else#define xlog_trace_loggrant(log,tic,string)#define xlog_trace_iclog(iclog,state)#endif /* XFS_LOG_TRACE */static voidxlog_ins_ticketq(struct xlog_ticket **qp, struct xlog_ticket *tic){ if (*qp) { tic->t_next = (*qp); tic->t_prev = (*qp)->t_prev; (*qp)->t_prev->t_next = tic; (*qp)->t_prev = tic; } else { tic->t_prev = tic->t_next = tic; *qp = tic; } tic->t_flags |= XLOG_TIC_IN_Q;}static voidxlog_del_ticketq(struct xlog_ticket **qp, struct xlog_ticket *tic){ if (tic == tic->t_next) { *qp = NULL; } else { *qp = tic->t_next; tic->t_next->t_prev = tic->t_prev; tic->t_prev->t_next = tic->t_next; } tic->t_next = tic->t_prev = NULL; tic->t_flags &= ~XLOG_TIC_IN_Q;}static voidxlog_grant_sub_space(struct log *log, int bytes){ log->l_grant_write_bytes -= bytes; if (log->l_grant_write_bytes < 0) { log->l_grant_write_bytes += log->l_logsize; log->l_grant_write_cycle--; } log->l_grant_reserve_bytes -= bytes; if ((log)->l_grant_reserve_bytes < 0) { log->l_grant_reserve_bytes += log->l_logsize; log->l_grant_reserve_cycle--; }}static voidxlog_grant_add_space_write(struct log *log, int bytes){ log->l_grant_write_bytes += bytes; if (log->l_grant_write_bytes > log->l_logsize) { log->l_grant_write_bytes -= log->l_logsize; log->l_grant_write_cycle++; }}static voidxlog_grant_add_space_reserve(struct log *log, int bytes){ log->l_grant_reserve_bytes += bytes; if (log->l_grant_reserve_bytes > log->l_logsize) { log->l_grant_reserve_bytes -= log->l_logsize; log->l_grant_reserve_cycle++; }}static inline voidxlog_grant_add_space(struct log *log, int bytes){ xlog_grant_add_space_write(log, bytes); xlog_grant_add_space_reserve(log, bytes);}static voidxlog_tic_reset_res(xlog_ticket_t *tic){ tic->t_res_num = 0; tic->t_res_arr_sum = 0; tic->t_res_num_ophdrs = 0;}static voidxlog_tic_add_region(xlog_ticket_t *tic, uint len, uint type){ if (tic->t_res_num == XLOG_TIC_LEN_MAX) { /* add to overflow and start again */ tic->t_res_o_flow += tic->t_res_arr_sum; tic->t_res_num = 0; tic->t_res_arr_sum = 0; } tic->t_res_arr[tic->t_res_num].r_len = len; tic->t_res_arr[tic->t_res_num].r_type = type; tic->t_res_arr_sum += len; tic->t_res_num++;}/* * NOTES: * * 1. currblock field gets updated at startup and after in-core logs * marked as with WANT_SYNC. *//* * This routine is called when a user of a log manager ticket is done with * the reservation. If the ticket was ever used, then a commit record for * the associated transaction is written out as a log operation header with * no data. The flag XLOG_TIC_INITED is set when the first write occurs with * a given ticket. If the ticket was one with a permanent reservation, then * a few operations are done differently. Permanent reservation tickets by * default don't release the reservation. They just commit the current * transaction with the belief that the reservation is still needed. A flag * must be passed in before permanent reservations are actually released. * When these type of tickets are not released, they need to be set into * the inited state again. By doing this, a start record will be written * out when the next write occurs. */xfs_lsn_txfs_log_done(xfs_mount_t *mp, xfs_log_ticket_t xtic, void **iclog, uint flags){ xlog_t *log = mp->m_log; xlog_ticket_t *ticket = (xfs_log_ticket_t) xtic; xfs_lsn_t lsn = 0; if (XLOG_FORCED_SHUTDOWN(log) || /* * If nothing was ever written, don't write out commit record. * If we get an error, just continue and give back the log ticket. */ (((ticket->t_flags & XLOG_TIC_INITED) == 0) && (xlog_commit_record(mp, ticket, (xlog_in_core_t **)iclog, &lsn)))) { lsn = (xfs_lsn_t) -1; if (ticket->t_flags & XLOG_TIC_PERM_RESERV) { flags |= XFS_LOG_REL_PERM_RESERV; } } if ((ticket->t_flags & XLOG_TIC_PERM_RESERV) == 0 || (flags & XFS_LOG_REL_PERM_RESERV)) { /* * Release ticket if not permanent reservation or a specific * request has been made to release a permanent reservation. */ xlog_trace_loggrant(log, ticket, "xfs_log_done: (non-permanent)"); xlog_ungrant_log_space(log, ticket); xlog_state_put_ticket(log, ticket); } else { xlog_trace_loggrant(log, ticket, "xfs_log_done: (permanent)"); xlog_regrant_reserve_log_space(log, ticket); } /* If this ticket was a permanent reservation and we aren't * trying to release it, reset the inited flags; so next time * we write, a start record will be written out. */ if ((ticket->t_flags & XLOG_TIC_PERM_RESERV) && (flags & XFS_LOG_REL_PERM_RESERV) == 0) ticket->t_flags |= XLOG_TIC_INITED; return lsn;} /* xfs_log_done *//* * Force the in-core log to disk. If flags == XFS_LOG_SYNC, * the force is done synchronously. * * Asynchronous forces are implemented by setting the WANT_SYNC * bit in the appropriate in-core log and then returning. * * Synchronous forces are implemented with a semaphore. All callers * to force a given lsn to disk will wait on a semaphore attached to the * specific in-core log. When given in-core log finally completes its * write to disk, that thread will wake up all threads waiting on the * semaphore. */int_xfs_log_force( xfs_mount_t *mp, xfs_lsn_t lsn, uint flags, int *log_flushed){ xlog_t *log = mp->m_log; int dummy; if (!log_flushed) log_flushed = &dummy; ASSERT(flags & XFS_LOG_FORCE); XFS_STATS_INC(xs_log_force); if (log->l_flags & XLOG_IO_ERROR) return XFS_ERROR(EIO); if (lsn == 0) return xlog_state_sync_all(log, flags, log_flushed); else return xlog_state_sync(log, lsn, flags, log_flushed);} /* xfs_log_force *//* * Attaches a new iclog I/O completion callback routine during * transaction commit. If the log is in error state, a non-zero * return code is handed back and the caller is responsible for * executing the callback at an appropriate time. */intxfs_log_notify(xfs_mount_t *mp, /* mount of partition */ void *iclog_hndl, /* iclog to hang callback off */ xfs_log_callback_t *cb){ xlog_t *log = mp->m_log; xlog_in_core_t *iclog = (xlog_in_core_t *)iclog_hndl; int abortflg, spl; cb->cb_next = NULL; spl = LOG_LOCK(log); abortflg = (iclog->ic_state & XLOG_STATE_IOERROR); if (!abortflg) { ASSERT_ALWAYS((iclog->ic_state == XLOG_STATE_ACTIVE) || (iclog->ic_state == XLOG_STATE_WANT_SYNC)); cb->cb_next = NULL; *(iclog->ic_callback_tail) = cb; iclog->ic_callback_tail = &(cb->cb_next); } LOG_UNLOCK(log, spl); return abortflg;} /* xfs_log_notify */intxfs_log_release_iclog(xfs_mount_t *mp, void *iclog_hndl){ xlog_t *log = mp->m_log; xlog_in_core_t *iclog = (xlog_in_core_t *)iclog_hndl; if (xlog_state_release_iclog(log, iclog)) { xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); return EIO; } return 0;}/* * 1. Reserve an amount of on-disk log space and return a ticket corresponding * to the reservation. * 2. Potentially, push buffers at tail of log to disk. * * 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 * log record header from any reservation. By wasting space in each * reservation, we prevent over allocation problems. */int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -