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

📄 xfs_log.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    int		     partial_copy;   /* did we split a region? */    int		     partial_copy_len;/* # bytes copied if split region */    int		     need_copy;	     /* # bytes need to memcpy this region */    int		     copy_len;	     /* # bytes actually memcpy'ing */    int		     copy_off;	     /* # bytes from entry start */    int		     contwr;	     /* continued write of in-core log? */    int		     error;    int		     record_cnt = 0, data_cnt = 0;    partial_copy_len = partial_copy = 0;    /* Calculate potential maximum space.  Each region gets its own     * xlog_op_header_t and may need to be double word aligned.     */    len = 0;    if (ticket->t_flags & XLOG_TIC_INITED) {    /* acct for start rec of xact */	len += sizeof(xlog_op_header_t);	ticket->t_res_num_ophdrs++;    }    for (index = 0; index < nentries; index++) {	len += sizeof(xlog_op_header_t);	    /* each region gets >= 1 */	ticket->t_res_num_ophdrs++;	len += reg[index].i_len;	xlog_tic_add_region(ticket, reg[index].i_len, reg[index].i_type);    }    contwr = *start_lsn = 0;    if (ticket->t_curr_res < len) {	xlog_print_tic_res(mp, ticket);#ifdef DEBUG	xlog_panic(		"xfs_log_write: reservation ran out. Need to up reservation");#else	/* Customer configurable panic */	xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp,		"xfs_log_write: reservation ran out. Need to up reservation");	/* If we did not panic, shutdown the filesystem */	xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);#endif    } else	ticket->t_curr_res -= len;    for (index = 0; index < nentries; ) {	if ((error = xlog_state_get_iclog_space(log, len, &iclog, ticket,					       &contwr, &log_offset)))		return error;	ASSERT(log_offset <= iclog->ic_size - 1);	ptr = (__psint_t) ((char *)iclog->ic_datap+log_offset);	/* start_lsn is the first lsn written to. That's all we need. */	if (! *start_lsn)	    *start_lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT);	/* This loop writes out as many regions as can fit in the amount	 * of space which was allocated by xlog_state_get_iclog_space().	 */	while (index < nentries) {	    ASSERT(reg[index].i_len % sizeof(__int32_t) == 0);	    ASSERT((__psint_t)ptr % sizeof(__int32_t) == 0);	    start_rec_copy = 0;	    /* If first write for transaction, insert start record.	     * We can't be trying to commit if we are inited.  We can't	     * have any "partial_copy" if we are inited.	     */	    if (ticket->t_flags & XLOG_TIC_INITED) {		logop_head		= (xlog_op_header_t *)ptr;		INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid);		logop_head->oh_clientid = ticket->t_clientid;		logop_head->oh_len	= 0;		logop_head->oh_flags    = XLOG_START_TRANS;		logop_head->oh_res2	= 0;		ticket->t_flags		&= ~XLOG_TIC_INITED;	/* clear bit */		record_cnt++;		start_rec_copy = sizeof(xlog_op_header_t);		xlog_write_adv_cnt(ptr, len, log_offset, start_rec_copy);	    }	    /* Copy log operation header directly into data section */	    logop_head			= (xlog_op_header_t *)ptr;	    INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid);	    logop_head->oh_clientid	= ticket->t_clientid;	    logop_head->oh_res2		= 0;	    /* header copied directly */	    xlog_write_adv_cnt(ptr, len, log_offset, sizeof(xlog_op_header_t));	    /* are we copying a commit or unmount record? */	    logop_head->oh_flags = flags;	    /*	     * We've seen logs corrupted with bad transaction client	     * ids.  This makes sure that XFS doesn't generate them on.	     * Turn this into an EIO and shut down the filesystem.	     */	    switch (logop_head->oh_clientid)  {	    case XFS_TRANSACTION:	    case XFS_VOLUME:	    case XFS_LOG:		break;	    default:		xfs_fs_cmn_err(CE_WARN, mp,		    "Bad XFS transaction clientid 0x%x in ticket 0x%p",		    logop_head->oh_clientid, tic);		return XFS_ERROR(EIO);	    }	    /* Partial write last time? => (partial_copy != 0)	     * need_copy is the amount we'd like to copy if everything could	     * fit in the current memcpy.	     */	    need_copy =	reg[index].i_len - partial_copy_len;	    copy_off = partial_copy_len;	    if (need_copy <= iclog->ic_size - log_offset) { /*complete write */		INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len = need_copy);		if (partial_copy)		    logop_head->oh_flags|= (XLOG_END_TRANS|XLOG_WAS_CONT_TRANS);		partial_copy_len = partial_copy = 0;	    } else {					    /* partial write */		copy_len = iclog->ic_size - log_offset;		INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len);		logop_head->oh_flags |= XLOG_CONTINUE_TRANS;		if (partial_copy)			logop_head->oh_flags |= XLOG_WAS_CONT_TRANS;		partial_copy_len += copy_len;		partial_copy++;		len += sizeof(xlog_op_header_t); /* from splitting of region */		/* account for new log op header */		ticket->t_curr_res -= sizeof(xlog_op_header_t);		ticket->t_res_num_ophdrs++;	    }	    xlog_verify_dest_ptr(log, ptr);	    /* copy region */	    ASSERT(copy_len >= 0);	    memcpy((xfs_caddr_t)ptr, reg[index].i_addr + copy_off, copy_len);	    xlog_write_adv_cnt(ptr, len, log_offset, copy_len);	    /* make copy_len total bytes copied, including headers */	    copy_len += start_rec_copy + sizeof(xlog_op_header_t);	    record_cnt++;	    data_cnt += contwr ? copy_len : 0;	    if (partial_copy) {			/* copied partial region */		    /* already marked WANT_SYNC by xlog_state_get_iclog_space */		    xlog_state_finish_copy(log, iclog, record_cnt, data_cnt);		    record_cnt = data_cnt = 0;		    if ((error = xlog_state_release_iclog(log, iclog)))			    return error;		    break;			/* don't increment index */	    } else {				/* copied entire region */		index++;		partial_copy_len = partial_copy = 0;		if (iclog->ic_size - log_offset <= sizeof(xlog_op_header_t)) {		    xlog_state_finish_copy(log, iclog, record_cnt, data_cnt);		    record_cnt = data_cnt = 0;		    xlog_state_want_sync(log, iclog);		    if (commit_iclog) {			ASSERT(flags & XLOG_COMMIT_TRANS);			*commit_iclog = iclog;		    } else if ((error = xlog_state_release_iclog(log, iclog)))			   return error;		    if (index == nentries)			    return 0;		/* we are done */		    else			    break;		}	    } /* if (partial_copy) */	} /* while (index < nentries) */    } /* for (index = 0; index < nentries; ) */    ASSERT(len == 0);    xlog_state_finish_copy(log, iclog, record_cnt, data_cnt);    if (commit_iclog) {	ASSERT(flags & XLOG_COMMIT_TRANS);	*commit_iclog = iclog;	return 0;    }    return xlog_state_release_iclog(log, iclog);}	/* xlog_write *//***************************************************************************** * *		State Machine functions * ***************************************************************************** *//* Clean iclogs starting from the head.  This ordering must be * maintained, so an iclog doesn't become ACTIVE beyond one that * is SYNCING.  This is also required to maintain the notion that we use * a counting semaphore to hold off would be writers to the log when every * iclog is trying to sync to disk. * * State Change: DIRTY -> ACTIVE */STATIC voidxlog_state_clean_log(xlog_t *log){	xlog_in_core_t	*iclog;	int changed = 0;	iclog = log->l_iclog;	do {		if (iclog->ic_state == XLOG_STATE_DIRTY) {			iclog->ic_state	= XLOG_STATE_ACTIVE;			iclog->ic_offset       = 0;			iclog->ic_callback	= NULL;   /* don't need to free */			/*			 * If the number of ops in this iclog indicate it just			 * contains the dummy transaction, we can			 * change state into IDLE (the second time around).			 * Otherwise we should change the state into			 * NEED a dummy.			 * We don't need to cover the dummy.			 */			if (!changed &&			   (INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT) == XLOG_COVER_OPS)) {				changed = 1;			} else {				/*				 * We have two dirty iclogs so start over				 * This could also be num of ops indicates				 * this is not the dummy going out.				 */				changed = 2;			}			iclog->ic_header.h_num_logops = 0;			memset(iclog->ic_header.h_cycle_data, 0,			      sizeof(iclog->ic_header.h_cycle_data));			iclog->ic_header.h_lsn = 0;		} else if (iclog->ic_state == XLOG_STATE_ACTIVE)			/* do nothing */;		else			break;	/* stop cleaning */		iclog = iclog->ic_next;	} while (iclog != log->l_iclog);	/* log is locked when we are called */	/*	 * Change state for the dummy log recording.	 * We usually go to NEED. But we go to NEED2 if the changed indicates	 * we are done writing the dummy record.	 * If we are done with the second dummy recored (DONE2), then	 * we go to IDLE.	 */	if (changed) {		switch (log->l_covered_state) {		case XLOG_STATE_COVER_IDLE:		case XLOG_STATE_COVER_NEED:		case XLOG_STATE_COVER_NEED2:			log->l_covered_state = XLOG_STATE_COVER_NEED;			break;		case XLOG_STATE_COVER_DONE:			if (changed == 1)				log->l_covered_state = XLOG_STATE_COVER_NEED2;			else				log->l_covered_state = XLOG_STATE_COVER_NEED;			break;		case XLOG_STATE_COVER_DONE2:			if (changed == 1)				log->l_covered_state = XLOG_STATE_COVER_IDLE;			else				log->l_covered_state = XLOG_STATE_COVER_NEED;			break;		default:			ASSERT(0);		}	}}	/* xlog_state_clean_log */STATIC xfs_lsn_txlog_get_lowest_lsn(	xlog_t		*log){	xlog_in_core_t  *lsn_log;	xfs_lsn_t	lowest_lsn, lsn;	lsn_log = log->l_iclog;	lowest_lsn = 0;	do {	    if (!(lsn_log->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY))) {		lsn = INT_GET(lsn_log->ic_header.h_lsn, ARCH_CONVERT);		if ((lsn && !lowest_lsn) ||		    (XFS_LSN_CMP(lsn, lowest_lsn) < 0)) {			lowest_lsn = lsn;		}	    }	    lsn_log = lsn_log->ic_next;	} while (lsn_log != log->l_iclog);	return lowest_lsn;}STATIC voidxlog_state_do_callback(	xlog_t		*log,	int		aborted,	xlog_in_core_t	*ciclog){	xlog_in_core_t	   *iclog;	xlog_in_core_t	   *first_iclog;	/* used to know when we've						 * processed all iclogs once */	xfs_log_callback_t *cb, *cb_next;	int		   flushcnt = 0;	xfs_lsn_t	   lowest_lsn;	int		   ioerrors;	/* counter: iclogs with errors */	int		   loopdidcallbacks; /* flag: inner loop did callbacks*/	int		   funcdidcallbacks; /* flag: function did callbacks */	int		   repeats;	/* for issuing console warnings if					 * looping too many times */	SPLDECL(s);	s = LOG_LOCK(log);	first_iclog = iclog = log->l_iclog;	ioerrors = 0;	funcdidcallbacks = 0;	repeats = 0;	do {		/*		 * Scan all iclogs starting with the one pointed to by the		 * log.  Reset this starting point each time the log is		 * unlocked (during callbacks).		 *		 * Keep looping through iclogs until one full pass is made		 * without running any callbacks.		 */		first_iclog = log->l_iclog;		iclog = log->l_iclog;		loopdidcallbacks = 0;		repeats++;		do {			/* skip all iclogs in the ACTIVE & DIRTY states */			if (iclog->ic_state &			    (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY)) {				iclog = iclog->ic_next;				continue;			}			/*			 * Between marking a filesystem SHUTDOWN and stopping			 * the log, we do flush all iclogs to disk (if there			 * wasn't a log I/O error). So, we do want things to			 * go smoothly in case of just a SHUTDOWN  w/o a			 * LOG_IO_ERROR.			 */			if (!(iclog->ic_state & XLOG_STATE_IOERROR)) {				/*				 * Can only perform callbacks in order.  Since				 * this iclog is not in the DONE_SYNC/				 * DO_CALLBACK state, we skip the rest and				 * just try to clean up.  If we set our iclog				 * to DO_CALLBACK, we will not process it when				 * we retry since a previous iclog is in the				 * CALLBACK and the state cannot change since				 * we are holding the LOG_LOCK.				 */				if (!(iclog->ic_state &					(XLOG_STATE_DONE_SYNC |						 XLOG_STATE_DO_CALLBACK))) {					if (ciclog && (ciclog->ic_state ==							XLOG_STATE_DONE_SYNC)) {						ciclog->ic_state = XLOG_STATE_DO_CALLBACK;					}					break;				}				/*				 * We now have an iclog that is in either the				 * DO_CALLBACK or DONE_SYNC states. The other				 * states (WANT_SYNC, SYNCING, or CALLBACK were				 * caught by the above if and are going to				 * clean (i.e. we aren't doing their callbacks)				 * see the above if.				 */				/*				 * We will do one more check here to see if we				 * have chased our tail around.				 */				lowest_lsn = xlog_get_lowest_lsn(log);				if (lowest_lsn && (					XFS_LSN_CMP(						lowest_lsn,						INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT)					)<0)) {					iclog = iclog->ic_next;					continue; /* Leave this iclog for						   * another thread */				}				iclog->ic_state = XLOG_STATE_CALLBACK;				LOG_UNLOCK(log, s);				/* l_last_sync_lsn field protected by				 * GRANT_LOCK. Don't worry about iclog's lsn.				 * No one else can be here except us.				 */				s = GRANT_LOCK(log);				ASSERT(XFS_LSN_CMP(						log->l_last_sync_lsn,						INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT)					)<=0);				log->l_last_sync_lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT);				GRANT_UNLOCK(log, s);				/*				 * Keep processing entries in the callback list				 * until we come around and it is empty.  We				 * need to atomically see that the list is				 * empty and change the state to DIRTY so that				 * we don't miss any more callbacks being added.				 */				s = LOG_LOCK(log);			} else {				ioerrors++;			}			cb = iclog->ic_callback;			while (cb) {				iclog->ic_callback_tail = &(iclog->ic_callback);				iclog->ic_callback = NULL;				LOG_UNLOCK(log, s);				/* perform callbacks in the order given */				for (; cb; cb = cb_next) {					cb_next = cb->cb_next;					cb->cb_func(cb->cb_arg, aborte

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -