⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfs_log.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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 + -