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

📄 buffer.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  linux/fs/buffer.c * *  Copyright (C) 1991, 1992  Linus Torvalds * *  OSKit support added by the University of Utah, 1997 *//* *  'buffer.c' implements the buffer-cache functions. Race-conditions have * been avoided by NEVER letting an interrupt change a buffer (except for the * data, of course), but instead letting the caller do it. *//* Start bdflush() with kernel_thread not syscall - Paul Gortmaker, 12/95 *//* Removed a lot of unnecessary code and simplified things now that * the buffer cache isn't our primary cache - Andrew Tridgell 12/96 *//* Speed up hash, lru, and free list operations.  Use gfp() for allocating * hash table, use SLAB cache for buffer heads. -DaveM *//* Added 32k buffer block sizes - these are required older ARM systems. * - RMK */#include <linux/malloc.h>#include <linux/locks.h>#include <linux/errno.h>#include <linux/swap.h>#include <linux/swapctl.h>#include <linux/smp_lock.h>#include <linux/vmalloc.h>#include <linux/blkdev.h>#include <linux/sysrq.h>#include <linux/file.h>#include <linux/init.h>#include <linux/quotaops.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/bitops.h>#define NR_SIZES 7static char buffersize_index[65] ={-1,  0,  1, -1,  2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,  4, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,  5, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,  6};#define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)#define NR_RESERVED (2*MAX_BUF_PER_PAGE)#define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this 					     number of unused buffer heads *//* * Hash table mask.. */static unsigned long bh_hash_mask = 0;static int grow_buffers(int size);static struct buffer_head ** hash_table;static struct buffer_head * lru_list[NR_LIST] = {NULL, };static struct buffer_head * free_list[NR_SIZES] = {NULL, };static kmem_cache_t *bh_cachep;static struct buffer_head * unused_list = NULL;static struct buffer_head * reuse_list = NULL;static struct wait_queue * buffer_wait = NULL;static int nr_buffers = 0;static int nr_buffers_type[NR_LIST] = {0,};static int nr_buffer_heads = 0;static int nr_unused_buffer_heads = 0;static int nr_hashed_buffers = 0;/* This is used by some architectures to estimate available memory. */int buffermem = 0;/* Here is the parameter block for the bdflush process. If you add or * remove any of the parameters, make sure to update kernel/sysctl.c. */#define N_PARAM 9/* The dummy values in this structure are left in there for compatibility * with old programs that play with the /proc entries. */union bdflush_param{	struct {		int nfract;  /* Percentage of buffer cache dirty to 				activate bdflush */		int ndirty;  /* Maximum number of dirty blocks to write out per				wake-cycle */		int nrefill; /* Number of clean buffers to try to obtain				each time we call refill */		int nref_dirt; /* Dirty buffer threshold for activating bdflush				  when trying to refill buffers. */		int interval; /* jiffies delay between kupdate flushes */		int age_buffer;  /* Time for normal buffer to age before 				    we flush it */		int age_super;  /* Time for superblock to age before we 				   flush it */		int dummy2;    /* unused */		int dummy3;    /* unused */	} b_un;	unsigned int data[N_PARAM];} bdf_prm = {{40, 500, 64, 256, 5*HZ, 30*HZ, 5*HZ, 1884, 2}};/* These are the min and max parameter values that we will allow to be assigned */int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   1*HZ, 1, 1};int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,60*HZ, 600*HZ, 600*HZ, 2047, 5};void wakeup_bdflush(int);#ifndef OSKIT/* * Rewrote the wait-routines to use the "new" wait-queue functionality, * and getting rid of the cli-sti pairs. The wait-queue routines still * need cli-sti, but now it's just a couple of 386 instructions or so. * * Note that the real wait_on_buffer() is an inline function that checks * if 'b_wait' is set before calling this, so that the queues aren't set * up unnecessarily. */void __wait_on_buffer(struct buffer_head * bh){	struct task_struct *tsk = current;	struct wait_queue wait;	bh->b_count++;	wait.task = tsk;	add_wait_queue(&bh->b_wait, &wait);repeat:	tsk->state = TASK_UNINTERRUPTIBLE;	run_task_queue(&tq_disk);	if (buffer_locked(bh)) {		schedule();		goto repeat;	}	tsk->state = TASK_RUNNING;	remove_wait_queue(&bh->b_wait, &wait);	bh->b_count--;}#endif /* OSKIT *//* Call sync_buffers with wait!=0 to ensure that the call does not * return until all buffer writes have completed.  Sync() may return * before the writes have finished; fsync() may not. *//* Godamity-damn.  Some buffers (bitmaps for filesystems) * spontaneously dirty themselves without ever brelse being called. * We will ultimately want to put these in a separate list, but for * now we search all of the lists for dirty buffers. */static int sync_buffers(kdev_t dev, int wait){	int i, retry, pass = 0, err = 0;	struct buffer_head * bh, *next;	/* One pass for no-wait, three for wait:	 * 0) write out all dirty, unlocked buffers;	 * 1) write out all dirty buffers, waiting if locked;	 * 2) wait for completion by waiting for all buffers to unlock.	 */	do {		retry = 0;repeat:		/* We search all lists as a failsafe mechanism, not because we expect		 * there to be dirty buffers on any of the other lists.		 */		bh = lru_list[BUF_DIRTY];		if (!bh)			goto repeat2;		for (i = nr_buffers_type[BUF_DIRTY]*2 ; i-- > 0 ; bh = next) {			if (bh->b_list != BUF_DIRTY)				goto repeat;			next = bh->b_next_free;			if (!lru_list[BUF_DIRTY])				break;			if (dev && bh->b_dev != dev)				continue;			if (buffer_locked(bh)) {				/* Buffer is locked; skip it unless wait is				 * requested AND pass > 0.				 */				if (!wait || !pass) {					retry = 1;					continue;				}				wait_on_buffer (bh);				goto repeat;			}			/* If an unlocked buffer is not uptodate, there has			 * been an IO error. Skip it.			 */			if (wait && buffer_req(bh) && !buffer_locked(bh) &&			    !buffer_dirty(bh) && !buffer_uptodate(bh)) {				err = -EIO;				continue;			}			/* Don't write clean buffers.  Don't write ANY buffers			 * on the third pass.			 */			if (!buffer_dirty(bh) || pass >= 2)				continue;			/* Don't bother about locked buffers.			 *			 * XXX We checked if it was locked above and there is no			 * XXX way we could have slept in between. -DaveM			 */			if (buffer_locked(bh))				continue;			bh->b_count++;			next->b_count++;			bh->b_flushtime = 0;			ll_rw_block(WRITE, 1, &bh);			bh->b_count--;			next->b_count--;			retry = 1;		}    repeat2:		bh = lru_list[BUF_LOCKED];		if (!bh)			break;		for (i = nr_buffers_type[BUF_LOCKED]*2 ; i-- > 0 ; bh = next) {			if (bh->b_list != BUF_LOCKED)				goto repeat2;			next = bh->b_next_free;			if (!lru_list[BUF_LOCKED])				break;			if (dev && bh->b_dev != dev)				continue;			if (buffer_locked(bh)) {				/* Buffer is locked; skip it unless wait is				 * requested AND pass > 0.				 */				if (!wait || !pass) {					retry = 1;					continue;				}				wait_on_buffer (bh);				goto repeat2;			}		}		/* If we are waiting for the sync to succeed, and if any dirty		 * blocks were written, then repeat; on the second pass, only		 * wait for buffers being written (do not pass to write any		 * more buffers on the second pass).		 */	} while (wait && retry && ++pass<=2);	return err;}void sync_dev(kdev_t dev){	sync_buffers(dev, 0);	sync_supers(dev);	sync_inodes(dev);	sync_buffers(dev, 0);	DQUOT_SYNC(dev);	/*	 * FIXME(eric) we need to sync the physical devices here.	 * This is because some (scsi) controllers have huge amounts of	 * cache onboard (hundreds of Mb), and we need to instruct	 * them to commit all of the dirty memory to disk, and we should	 * not return until this has happened.	 *	 * This would need to get implemented by going through the assorted	 * layers so that each block major number can be synced, and this	 * would call down into the upper and mid-layer scsi.	 */}int fsync_dev(kdev_t dev){	sync_buffers(dev, 0);	sync_supers(dev);	sync_inodes(dev);	DQUOT_SYNC(dev);	return sync_buffers(dev, 1);}asmlinkage int sys_sync(void){	lock_kernel();	fsync_dev(0);	unlock_kernel();	return 0;}/* *	filp may be NULL if called via the msync of a vma. */ int file_fsync(struct file *filp, struct dentry *dentry){	struct inode * inode = dentry->d_inode;	struct super_block * sb;	kdev_t dev;	/* sync the inode to buffers */	write_inode_now(inode);	/* sync the superblock to buffers */	sb = inode->i_sb;	wait_on_super(sb);	if (sb->s_op && sb->s_op->write_super)		sb->s_op->write_super(sb);	/* .. finally sync the buffers to disk */	dev = inode->i_dev;	return sync_buffers(dev, 1);}#ifndef OSKITasmlinkage int sys_fsync(unsigned int fd){	struct file * file;	struct dentry * dentry;	struct inode * inode;	int err;	lock_kernel();	err = -EBADF;	file = fget(fd);	if (!file)		goto out;	dentry = file->f_dentry;	if (!dentry)		goto out_putf;	inode = dentry->d_inode;	if (!inode)		goto out_putf;	err = -EINVAL;	if (!file->f_op || !file->f_op->fsync)		goto out_putf;	/* We need to protect against concurrent writers.. */	down(&inode->i_sem);	err = file->f_op->fsync(file, dentry);	up(&inode->i_sem);out_putf:	fput(file);out:	unlock_kernel();	return err;}asmlinkage int sys_fdatasync(unsigned int fd){	struct file * file;	struct dentry * dentry;	struct inode * inode;	int err;	lock_kernel();	err = -EBADF;	file = fget(fd);	if (!file)		goto out;	dentry = file->f_dentry;	if (!dentry)		goto out_putf;	inode = dentry->d_inode;	if (!inode)		goto out_putf;	err = -EINVAL;	if (!file->f_op || !file->f_op->fsync)		goto out_putf;	/* this needs further work, at the moment it is identical to fsync() */	down(&inode->i_sem);	err = file->f_op->fsync(file, dentry);	up(&inode->i_sem);out_putf:	fput(file);out:	unlock_kernel();	return err;}#endif /* OSKIT */void invalidate_buffers(kdev_t dev){	int i;	int nlist;	struct buffer_head * bh;	for(nlist = 0; nlist < NR_LIST; nlist++) {		bh = lru_list[nlist];		for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bh->b_next_free) {			if (bh->b_dev != dev)				continue;			wait_on_buffer(bh);			if (bh->b_dev != dev)				continue;			if (bh->b_count)				continue;			bh->b_flushtime = 0;			clear_bit(BH_Protected, &bh->b_state);			clear_bit(BH_Uptodate, &bh->b_state);			clear_bit(BH_Dirty, &bh->b_state);			clear_bit(BH_Req, &bh->b_state);		}	}}#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block)) & bh_hash_mask)#define hash(dev,block) hash_table[_hashfn(dev,block)]static inline void remove_from_hash_queue(struct buffer_head * bh){	struct buffer_head **pprev = bh->b_pprev;	if (pprev) {		struct buffer_head * next = bh->b_next;		if (next) {			next->b_pprev = pprev;			bh->b_next = NULL;		}		*pprev = next;		bh->b_pprev = NULL;	}	nr_hashed_buffers--;}static inline void remove_from_lru_list(struct buffer_head * bh){	if (!(bh->b_prev_free) || !(bh->b_next_free))		panic("VFS: LRU block list corrupted");	if (bh->b_dev == B_FREE)		panic("LRU list corrupted");	bh->b_prev_free->b_next_free = bh->b_next_free;	bh->b_next_free->b_prev_free = bh->b_prev_free;	if (lru_list[bh->b_list] == bh)		 lru_list[bh->b_list] = bh->b_next_free;	if (lru_list[bh->b_list] == bh)		 lru_list[bh->b_list] = NULL;	bh->b_next_free = bh->b_prev_free = NULL;}static inline void remove_from_free_list(struct buffer_head * bh){	int isize = BUFSIZE_INDEX(bh->b_size);	if (!(bh->b_prev_free) || !(bh->b_next_free))		panic("VFS: Free block list corrupted");	if(bh->b_dev != B_FREE)		panic("Free list corrupted");	if(!free_list[isize])		panic("Free list empty");	if(bh->b_next_free == bh)		 free_list[isize] = NULL;	else {

⌨️ 快捷键说明

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