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 + -
显示快捷键?