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

📄 log.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved. * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License version 2. */#include <linux/sched.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/completion.h>#include <linux/buffer_head.h>#include <linux/gfs2_ondisk.h>#include <linux/crc32.h>#include <linux/lm_interface.h>#include <linux/delay.h>#include "gfs2.h"#include "incore.h"#include "bmap.h"#include "glock.h"#include "log.h"#include "lops.h"#include "meta_io.h"#include "util.h"#include "dir.h"#define PULL 1/** * gfs2_struct2blk - compute stuff * @sdp: the filesystem * @nstruct: the number of structures * @ssize: the size of the structures * * Compute the number of log descriptor blocks needed to hold a certain number * of structures of a certain size. * * Returns: the number of blocks needed (minimum is always 1) */unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,			     unsigned int ssize){	unsigned int blks;	unsigned int first, second;	blks = 1;	first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / ssize;	if (nstruct > first) {		second = (sdp->sd_sb.sb_bsize -			  sizeof(struct gfs2_meta_header)) / ssize;		blks += DIV_ROUND_UP(nstruct - first, second);	}	return blks;}/** * gfs2_remove_from_ail - Remove an entry from the ail lists, updating counters * @mapping: The associated mapping (maybe NULL) * @bd: The gfs2_bufdata to remove * * The log lock _must_ be held when calling this function * */void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd){	bd->bd_ail = NULL;	list_del_init(&bd->bd_ail_st_list);	list_del_init(&bd->bd_ail_gl_list);	atomic_dec(&bd->bd_gl->gl_ail_count);	if (mapping)		gfs2_meta_cache_flush(GFS2_I(mapping->host));	brelse(bd->bd_bh);}/** * gfs2_ail1_start_one - Start I/O on a part of the AIL * @sdp: the filesystem * @tr: the part of the AIL * */static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai){	struct gfs2_bufdata *bd, *s;	struct buffer_head *bh;	int retry;	BUG_ON(!spin_is_locked(&sdp->sd_log_lock));	do {		retry = 0;		list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list,						 bd_ail_st_list) {			bh = bd->bd_bh;			gfs2_assert(sdp, bd->bd_ail == ai);			if (!buffer_busy(bh)) {				if (!buffer_uptodate(bh))					gfs2_io_error_bh(sdp, bh);				list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);				continue;			}			if (!buffer_dirty(bh))				continue;			list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list);			get_bh(bh);			gfs2_log_unlock(sdp);			lock_buffer(bh);			if (test_clear_buffer_dirty(bh)) {				bh->b_end_io = end_buffer_write_sync;				submit_bh(WRITE, bh);			} else {				unlock_buffer(bh);				brelse(bh);			}			gfs2_log_lock(sdp);			retry = 1;			break;		}	} while (retry);}/** * gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced * @sdp: the filesystem * @ai: the AIL entry * */static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags){	struct gfs2_bufdata *bd, *s;	struct buffer_head *bh;	list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list,					 bd_ail_st_list) {		bh = bd->bd_bh;		gfs2_assert(sdp, bd->bd_ail == ai);		if (buffer_busy(bh)) {			if (flags & DIO_ALL)				continue;			else				break;		}		if (!buffer_uptodate(bh))			gfs2_io_error_bh(sdp, bh);		list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);	}	return list_empty(&ai->ai_ail1_list);}static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags){	struct list_head *head;	u64 sync_gen;	struct list_head *first;	struct gfs2_ail *first_ai, *ai, *tmp;	int done = 0;	gfs2_log_lock(sdp);	head = &sdp->sd_ail1_list;	if (list_empty(head)) {		gfs2_log_unlock(sdp);		return;	}	sync_gen = sdp->sd_ail_sync_gen++;	first = head->prev;	first_ai = list_entry(first, struct gfs2_ail, ai_list);	first_ai->ai_sync_gen = sync_gen;	gfs2_ail1_start_one(sdp, first_ai); /* This may drop log lock */	if (flags & DIO_ALL)		first = NULL;	while(!done) {		if (first && (head->prev != first ||			      gfs2_ail1_empty_one(sdp, first_ai, 0)))			break;		done = 1;		list_for_each_entry_safe_reverse(ai, tmp, head, ai_list) {			if (ai->ai_sync_gen >= sync_gen)				continue;			ai->ai_sync_gen = sync_gen;			gfs2_ail1_start_one(sdp, ai); /* This may drop log lock */			done = 0;			break;		}	}	gfs2_log_unlock(sdp);}int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags){	struct gfs2_ail *ai, *s;	int ret;	gfs2_log_lock(sdp);	list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) {		if (gfs2_ail1_empty_one(sdp, ai, flags))			list_move(&ai->ai_list, &sdp->sd_ail2_list);		else if (!(flags & DIO_ALL))			break;	}	ret = list_empty(&sdp->sd_ail1_list);	gfs2_log_unlock(sdp);	return ret;}/** * gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced * @sdp: the filesystem * @ai: the AIL entry * */static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai){	struct list_head *head = &ai->ai_ail2_list;	struct gfs2_bufdata *bd;	while (!list_empty(head)) {		bd = list_entry(head->prev, struct gfs2_bufdata,				bd_ail_st_list);		gfs2_assert(sdp, bd->bd_ail == ai);		gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd);	}}static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail){	struct gfs2_ail *ai, *safe;	unsigned int old_tail = sdp->sd_log_tail;	int wrap = (new_tail < old_tail);	int a, b, rm;	gfs2_log_lock(sdp);	list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) {		a = (old_tail <= ai->ai_first);		b = (ai->ai_first < new_tail);		rm = (wrap) ? (a || b) : (a && b);		if (!rm)			continue;		gfs2_ail2_empty_one(sdp, ai);		list_del(&ai->ai_list);		gfs2_assert_warn(sdp, list_empty(&ai->ai_ail1_list));		gfs2_assert_warn(sdp, list_empty(&ai->ai_ail2_list));		kfree(ai);	}	gfs2_log_unlock(sdp);}/** * gfs2_log_reserve - Make a log reservation * @sdp: The GFS2 superblock * @blks: The number of blocks to reserve * * Note that we never give out the last few blocks of the journal. Thats * due to the fact that there is a small number of header blocks * associated with each log flush. The exact number can't be known until * flush time, so we ensure that we have just enough free blocks at all * times to avoid running out during a log flush. * * Returns: errno */int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks){	unsigned int try = 0;	unsigned reserved_blks = 6 * (4096 / sdp->sd_vfs->s_blocksize);	if (gfs2_assert_warn(sdp, blks) ||	    gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks))		return -EINVAL;	mutex_lock(&sdp->sd_log_reserve_mutex);	gfs2_log_lock(sdp);	while(sdp->sd_log_blks_free <= (blks + reserved_blks)) {		gfs2_log_unlock(sdp);		gfs2_ail1_empty(sdp, 0);		gfs2_log_flush(sdp, NULL);		if (try++)			gfs2_ail1_start(sdp, 0);		gfs2_log_lock(sdp);	}	sdp->sd_log_blks_free -= blks;	gfs2_log_unlock(sdp);	mutex_unlock(&sdp->sd_log_reserve_mutex);	down_read(&sdp->sd_log_flush_lock);	return 0;}/** * gfs2_log_release - Release a given number of log blocks * @sdp: The GFS2 superblock * @blks: The number of blocks * */void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks){	gfs2_log_lock(sdp);	sdp->sd_log_blks_free += blks;	gfs2_assert_withdraw(sdp,			     sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);	gfs2_log_unlock(sdp);	up_read(&sdp->sd_log_flush_lock);}static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn){	struct inode *inode = sdp->sd_jdesc->jd_inode;	int error;	struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };	bh_map.b_size = 1 << inode->i_blkbits;	error = gfs2_block_map(inode, lbn, 0, &bh_map);	if (error || !bh_map.b_blocknr)		printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error,		       (unsigned long long)bh_map.b_blocknr, lbn);	gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);	return bh_map.b_blocknr;}/** * log_distance - Compute distance between two journal blocks * @sdp: The GFS2 superblock * @newer: The most recent journal block of the pair * @older: The older journal block of the pair * *   Compute the distance (in the journal direction) between two *   blocks in the journal * * Returns: the distance in blocks */static inline unsigned int log_distance(struct gfs2_sbd *sdp, unsigned int newer,					unsigned int older){	int dist;	dist = newer - older;	if (dist < 0)		dist += sdp->sd_jdesc->jd_blocks;	return dist;}/** * calc_reserved - Calculate the number of blocks to reserve when *                 refunding a transaction's unused buffers. * @sdp: The GFS2 superblock * * This is complex.  We need to reserve room for all our currently used * metadata buffers (e.g. normal file I/O rewriting file time stamps) and  * all our journaled data buffers for journaled files (e.g. files in the  * meta_fs like rindex, or files for which chattr +j was done.) * If we don't reserve enough space, gfs2_log_refund and gfs2_log_flush * will count it as free space (sd_log_blks_free) and corruption will follow. * * We can have metadata bufs and jdata bufs in the same journal.  So each * type gets its own log header, for which we need to reserve a block. * In fact, each type has the potential for needing more than one header  * in cases where we have more buffers than will fit on a journal page. * Metadata journal entries take up half the space of journaled buffer entries. * Thus, metadata entries have buf_limit (502) and journaled buffers have * databuf_limit (251) before they cause a wrap around. * * Also, we need to reserve blocks for revoke journal entries and one for an * overall header for the lot. * * Returns: the number of blocks reserved */static unsigned int calc_reserved(struct gfs2_sbd *sdp){	unsigned int reserved = 0;	unsigned int mbuf_limit, metabufhdrs_needed;	unsigned int dbuf_limit, databufhdrs_needed;	unsigned int revokes = 0;	mbuf_limit = buf_limit(sdp);	metabufhdrs_needed = (sdp->sd_log_commited_buf +			      (mbuf_limit - 1)) / mbuf_limit;	dbuf_limit = databuf_limit(sdp);	databufhdrs_needed = (sdp->sd_log_commited_databuf +			      (dbuf_limit - 1)) / dbuf_limit;	if (sdp->sd_log_commited_revoke)		revokes = gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke,					  sizeof(u64));	reserved = sdp->sd_log_commited_buf + metabufhdrs_needed +		sdp->sd_log_commited_databuf + databufhdrs_needed +		revokes;	/* One for the overall header */	if (reserved)		reserved++;	return reserved;}static unsigned int current_tail(struct gfs2_sbd *sdp){

⌨️ 快捷键说明

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