xfs_log.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,167 行 · 第 1/5 页
C
2,167 行
/* * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 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. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ *//* * High level interface routines for log manager */#include "xfs.h"#include "xfs_macros.h"#include "xfs_types.h"#include "xfs_inum.h"#include "xfs_ag.h"#include "xfs_sb.h"#include "xfs_log.h"#include "xfs_trans.h"#include "xfs_dir.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_alloc_btree.h"#include "xfs_log_recover.h"#include "xfs_bit.h"#include "xfs_rw.h"#include "xfs_trans_priv.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_unalloc_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);STATIC int xlog_state_sync_all(xlog_t *log, uint flags);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);/* local debug functions */#if defined(DEBUG) && !defined(XLOG_NOLOG)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)#endifint xlog_iclogs_empty(xlog_t *log);#ifdef DEBUGint xlog_do_error = 0;int xlog_req_num = 0;int xlog_error_mod = 33;#endif#define XLOG_FORCED_SHUTDOWN(log) (log->l_flags & XLOG_IO_ERROR)/* * 0 => disable log manager * 1 => enable log manager * 2 => enable log manager and log debugging */#if defined(XLOG_NOLOG) || defined(DEBUG)int xlog_debug = 1;xfs_buftarg_t *xlog_target;#endif#if defined(XFS_LOG_TRACE)voidxlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string){ if (! log->l_grant_trace) { log->l_grant_trace = ktrace_alloc(1024, KM_NOSLEEP); if (! log->l_grant_trace) return; } 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, ARCH_NOCONVERT)), (void *)((unsigned long)BLOCK_LSN(log->l_tail_lsn, ARCH_NOCONVERT)), (void *)string, (void *)((unsigned long)13), (void *)((unsigned long)14), (void *)((unsigned long)15), (void *)((unsigned long)16));}voidxlog_trace_iclog(xlog_in_core_t *iclog, uint state){ pid_t pid; pid = current_pid(); if (!iclog->ic_trace) iclog->ic_trace = ktrace_alloc(256, KM_SLEEP); ktrace_enter(iclog->ic_trace, (void *)((unsigned long)state), (void *)((unsigned long)pid), (void *)0, (void *)0, (void *)0, (void *)0, (void *)0, (void *)0, (void *)0, (void *)0, (void *)0, (void *)0, (void *)0, (void *)0, (void *)0, (void *)0);}#else#define xlog_trace_loggrant(log,tic,string)#define xlog_trace_iclog(iclog,state)#endif /* XFS_LOG_TRACE *//* * 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 defined(DEBUG) || defined(XLOG_NOLOG) if (!xlog_debug && xlog_target == log->l_targ) return 0;#endif 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 specifc * request has been made to release a permanent reservation. */ xlog_ungrant_log_space(log, ticket); xlog_state_put_ticket(log, ticket); } else { 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. */intxfs_log_force(xfs_mount_t *mp, xfs_lsn_t lsn, uint flags){ int rval; xlog_t *log = mp->m_log;#if defined(DEBUG) || defined(XLOG_NOLOG) if (!xlog_debug && xlog_target == log->l_targ) return 0;#endif ASSERT(flags & XFS_LOG_FORCE); XFS_STATS_INC(xs_log_force); if ((log->l_flags & XLOG_IO_ERROR) == 0) { if (lsn == 0) rval = xlog_state_sync_all(log, flags); else rval = xlog_state_sync(log, lsn, flags); } else { rval = XFS_ERROR(EIO); } return rval;} /* 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;#if defined(DEBUG) || defined(XLOG_NOLOG) if (!xlog_debug && xlog_target == log->l_targ) return 0;#endif 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, XFS_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. */intxfs_log_reserve(xfs_mount_t *mp, int unit_bytes, int cnt, xfs_log_ticket_t *ticket, __uint8_t client, uint flags){ xlog_t *log = mp->m_log; xlog_ticket_t *internal_ticket; int retval;#if defined(DEBUG) || defined(XLOG_NOLOG) if (!xlog_debug && xlog_target == log->l_targ) return 0;#endif 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_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); *ticket = internal_ticket; xlog_grant_push_ail(mp, (internal_ticket->t_unit_res * internal_ticket->t_cnt)); retval = xlog_grant_log_space(log, internal_ticket);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?