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

📄 journal.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 4 页
字号:
 * writes are done to the journal (unless there are any already in * progress). *//* Quick version for internal journal use (doesn't lock the journal). * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, * and don't attempt to make any other journal updates. */void __journal_abort_hard (journal_t *journal){	transaction_t *transaction;	if (journal->j_flags & JFS_ABORT)		return;	printk (KERN_ERR "Aborting journal on device %s.\n",		journal_dev_name(journal));	journal->j_flags |= JFS_ABORT;	transaction = journal->j_running_transaction;	if (transaction)		log_start_commit(journal, transaction);}/* Soft abort: record the abort error status in the journal superblock, * but don't do any other IO. */void __journal_abort_soft (journal_t *journal, int errno){	if (journal->j_flags & JFS_ABORT)		return;	if (!journal->j_errno)		journal->j_errno = errno;	__journal_abort_hard(journal);	if (errno)		journal_update_superblock(journal, 1);}/* Full version for external use */void journal_abort (journal_t *journal, int errno){	lock_journal(journal);	__journal_abort_soft(journal, errno);	unlock_journal(journal);}int journal_errno (journal_t *journal){	int err;	lock_journal(journal);	if (journal->j_flags & JFS_ABORT)		err = -EROFS;	else		err = journal->j_errno;	unlock_journal(journal);	return err;}int journal_clear_err (journal_t *journal){	int err = 0;	lock_journal(journal);	if (journal->j_flags & JFS_ABORT)		err = -EROFS;	else		journal->j_errno = 0;	unlock_journal(journal);	return err;}void journal_ack_err (journal_t *journal){	lock_journal(journal);	if (journal->j_errno)		journal->j_flags |= JFS_ACK_ERR;	unlock_journal(journal);}int journal_blocks_per_page(struct inode *inode){	return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);}/* * shrink_journal_memory(). * Called when we're under memory pressure.  Free up all the written-back * checkpointed metadata buffers. */void shrink_journal_memory(void){	struct list_head *list;	lock_kernel();	list_for_each(list, &all_journals) {		journal_t *journal =			list_entry(list, journal_t, j_all_journals);		spin_lock(&journal_datalist_lock);		__journal_clean_checkpoint_list(journal);		spin_unlock(&journal_datalist_lock);	}	unlock_kernel();}/* * Simple support for retying memory allocations.  Introduced to help to * debug different VM deadlock avoidance strategies.  *//* * Simple support for retying memory allocations.  Introduced to help to * debug different VM deadlock avoidance strategies.  */void * __jbd_kmalloc (char *where, size_t size, int flags, int retry){	void *p;	static unsigned long last_warning;		while (1) {		p = kmalloc(size, flags);		if (p)			return p;		if (!retry)			return NULL;		/* Log every retry for debugging.  Also log them to the		 * syslog, but do rate-limiting on the non-debugging		 * messages. */		jbd_debug(1, "ENOMEM in %s, retrying.\n", where);		if (time_after(jiffies, last_warning + 5*HZ)) {			printk(KERN_NOTICE			       "ENOMEM in %s, retrying.\n", where);			last_warning = jiffies;		}				current->policy |= SCHED_YIELD;		schedule();	}}/* * Journal_head storage management */static kmem_cache_t *journal_head_cache;#ifdef CONFIG_JBD_DEBUGstatic atomic_t nr_journal_heads = ATOMIC_INIT(0);#endifstatic int journal_init_journal_head_cache(void){	int retval;	J_ASSERT(journal_head_cache == 0);	journal_head_cache = kmem_cache_create("journal_head",				sizeof(struct journal_head),				0,		/* offset */				0,		/* flags */				NULL,		/* ctor */				NULL);		/* dtor */	retval = 0;	if (journal_head_cache == 0) {		retval = -ENOMEM;		printk(KERN_EMERG "JBD: no memory for journal_head cache\n");	}	return retval;}static void journal_destroy_journal_head_cache(void){	J_ASSERT(journal_head_cache != NULL);	kmem_cache_destroy(journal_head_cache);	journal_head_cache = 0;}/* * journal_head splicing and dicing */static struct journal_head *journal_alloc_journal_head(void){	struct journal_head *ret;	static unsigned long last_warning;#ifdef CONFIG_JBD_DEBUG	atomic_inc(&nr_journal_heads);#endif	ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS);	if (ret == 0) {		jbd_debug(1, "out of memory for journal_head\n");		if (time_after(jiffies, last_warning + 5*HZ)) {			printk(KERN_NOTICE "ENOMEM in " __FUNCTION__			       ", retrying.\n");			last_warning = jiffies;		}		while (ret == 0) {			current->policy |= SCHED_YIELD;			schedule();			ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS);		}	}	return ret;}static void journal_free_journal_head(struct journal_head *jh){#ifdef CONFIG_JBD_DEBUG	atomic_dec(&nr_journal_heads);	memset(jh, 0x5b, sizeof(*jh));#endif	kmem_cache_free(journal_head_cache, jh);}/* * A journal_head is attached to a buffer_head whenever JBD has an * interest in the buffer. * * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit * is set.  This bit is tested in core kernel code where we need to take * JBD-specific actions.  Testing the zeroness of ->b_private is not reliable * there. * * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one. * * When a buffer has its BH_JBD bit set it is immune from being released by * core kernel code, mainly via ->b_count. * * A journal_head may be detached from its buffer_head when the journal_head's * b_transaction, b_cp_transaction and b_next_transaction pointers are NULL. * Various places in JBD call journal_remove_journal_head() to indicate that the * journal_head can be dropped if needed. * * Various places in the kernel want to attach a journal_head to a buffer_head * _before_ attaching the journal_head to a transaction.  To protect the * journal_head in this situation, journal_add_journal_head elevates the * journal_head's b_jcount refcount by one.  The caller must call * journal_unlock_journal_head() to undo this. * * So the typical usage would be: * *	(Attach a journal_head if needed.  Increments b_jcount) *	struct journal_head *jh = journal_add_journal_head(bh); *	... *	jh->b_transaction = xxx; *	journal_unlock_journal_head(jh); * * Now, the journal_head's b_jcount is zero, but it is safe from being released * because it has a non-zero b_transaction. *//* * Give a buffer_head a journal_head. * * Doesn't need the journal lock. * May sleep. * Cannot be called with journal_datalist_lock held. */struct journal_head *journal_add_journal_head(struct buffer_head *bh){	struct journal_head *jh;	spin_lock(&journal_datalist_lock);	if (buffer_jbd(bh)) {		jh = bh2jh(bh);	} else {		J_ASSERT_BH(bh,			(atomic_read(&bh->b_count) > 0) ||			(bh->b_page && bh->b_page->mapping));		spin_unlock(&journal_datalist_lock);		jh = journal_alloc_journal_head();		memset(jh, 0, sizeof(*jh));		spin_lock(&journal_datalist_lock);		if (buffer_jbd(bh)) {			/* Someone did it for us! */			J_ASSERT_BH(bh, bh->b_private != NULL);			journal_free_journal_head(jh);			jh = bh->b_private;		} else {			/*			 * We actually don't need jh_splice_lock when			 * adding a journal_head - only on removal.			 */			spin_lock(&jh_splice_lock);			set_bit(BH_JBD, &bh->b_state);			bh->b_private = jh;			jh->b_bh = bh;			atomic_inc(&bh->b_count);			spin_unlock(&jh_splice_lock);			BUFFER_TRACE(bh, "added journal_head");		}	}	jh->b_jcount++;	spin_unlock(&journal_datalist_lock);	return bh->b_private;}/* * journal_remove_journal_head(): if the buffer isn't attached to a transaction * and has a zero b_jcount then remove and release its journal_head.   If we did * see that the buffer is not used by any transaction we also "logically" * decrement ->b_count. * * We in fact take an additional increment on ->b_count as a convenience, * because the caller usually wants to do additional things with the bh * after calling here. * The caller of journal_remove_journal_head() *must* run __brelse(bh) at some * time.  Once the caller has run __brelse(), the buffer is eligible for * reaping by try_to_free_buffers(). * * Requires journal_datalist_lock. */void __journal_remove_journal_head(struct buffer_head *bh){	struct journal_head *jh = bh2jh(bh);	assert_spin_locked(&journal_datalist_lock);	J_ASSERT_JH(jh, jh->b_jcount >= 0);	atomic_inc(&bh->b_count);	if (jh->b_jcount == 0) {		if (jh->b_transaction == NULL &&				jh->b_next_transaction == NULL &&				jh->b_cp_transaction == NULL) {			J_ASSERT_BH(bh, buffer_jbd(bh));			J_ASSERT_BH(bh, jh2bh(jh) == bh);			BUFFER_TRACE(bh, "remove journal_head");			spin_lock(&jh_splice_lock);			bh->b_private = NULL;			jh->b_bh = NULL;	/* debug, really */			clear_bit(BH_JBD, &bh->b_state);			__brelse(bh);			spin_unlock(&jh_splice_lock);			journal_free_journal_head(jh);		} else {			BUFFER_TRACE(bh, "journal_head was locked");		}	}}void journal_unlock_journal_head(struct journal_head *jh){	spin_lock(&journal_datalist_lock);	J_ASSERT_JH(jh, jh->b_jcount > 0);	--jh->b_jcount;	if (!jh->b_jcount && !jh->b_transaction) {		struct buffer_head *bh;		bh = jh2bh(jh);		__journal_remove_journal_head(bh);		__brelse(bh);	}		spin_unlock(&journal_datalist_lock);}void journal_remove_journal_head(struct buffer_head *bh){	spin_lock(&journal_datalist_lock);	__journal_remove_journal_head(bh);	spin_unlock(&journal_datalist_lock);}/* * /proc tunables */#if defined(CONFIG_JBD_DEBUG)int journal_enable_debug;EXPORT_SYMBOL(journal_enable_debug);#endif#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS)static struct proc_dir_entry *proc_jbd_debug;int read_jbd_debug(char *page, char **start, off_t off,			  int count, int *eof, void *data){	int ret;	ret = sprintf(page + off, "%d\n", journal_enable_debug);	*eof = 1;	return ret;}int write_jbd_debug(struct file *file, const char *buffer,			   unsigned long count, void *data){	char buf[32];	if (count > ARRAY_SIZE(buf) - 1)		count = ARRAY_SIZE(buf) - 1;	if (copy_from_user(buf, buffer, count))		return -EFAULT;	buf[ARRAY_SIZE(buf) - 1] = '\0';	journal_enable_debug = simple_strtoul(buf, NULL, 10);	return count;}#define JBD_PROC_NAME "sys/fs/jbd-debug"static void __init create_jbd_proc_entry(void){	proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL);	if (proc_jbd_debug) {		/* Why is this so hard? */		proc_jbd_debug->read_proc = read_jbd_debug;		proc_jbd_debug->write_proc = write_jbd_debug;	}}static void __exit remove_jbd_proc_entry(void){	if (proc_jbd_debug)		remove_proc_entry(JBD_PROC_NAME, NULL);}#else#define create_jbd_proc_entry() do {} while (0)#define remove_jbd_proc_entry() do {} while (0)#endif/* * Module startup and shutdown */static int __init journal_init_caches(void){	int ret;	ret = journal_init_revoke_caches();	if (ret == 0)		ret = journal_init_journal_head_cache();	return ret;}static void journal_destroy_caches(void){	journal_destroy_revoke_caches();	journal_destroy_journal_head_cache();}static int __init journal_init(void){	int ret;	printk(KERN_INFO "Journalled Block Device driver loaded\n");	ret = journal_init_caches();	if (ret != 0)		journal_destroy_caches();	create_jbd_proc_entry();	return ret;}static void __exit journal_exit(void){#ifdef CONFIG_JBD_DEBUG	int n = atomic_read(&nr_journal_heads);	if (n)		printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);#endif	remove_jbd_proc_entry();	journal_destroy_caches();}MODULE_LICENSE("GPL");module_init(journal_init);module_exit(journal_exit);

⌨️ 快捷键说明

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