亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來(lái)到蟲(chóng)蟲(chóng)下載站! | ?? 資源下載 ?? 資源專輯 ?? 關(guān)于我們
? 蟲(chóng)蟲(chóng)下載站

?? buffer.c

?? LINUX1.0源代碼,代碼條理清晰
?? C
?? 第 1 頁(yè) / 共 2 頁(yè)
字號(hào):
/*
 *  linux/fs/buffer.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

/*
 *  '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.
 */

/*
 * NOTE! There is one discordant note here: checking floppies for
 * disk change. This is where it fits best, I think, as it should
 * invalidate changed floppy-disk-caches.
 */

#include <stdarg.h>
 
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/errno.h>

#include <asm/system.h>
#include <asm/io.h>

#ifdef CONFIG_SCSI
#ifdef CONFIG_BLK_DEV_SR
extern int check_cdrom_media_change(int, int);
#endif
#ifdef CONFIG_BLK_DEV_SD
extern int check_scsidisk_media_change(int, int);
extern int revalidate_scsidisk(int, int);
#endif
#endif
#ifdef CONFIG_CDU31A
extern int check_cdu31a_media_change(int, int);
#endif
#ifdef CONFIG_MCD
extern int check_mcd_media_change(int, int);
#endif

static int grow_buffers(int pri, int size);

static struct buffer_head * hash_table[NR_HASH];
static struct buffer_head * free_list = NULL;
static struct buffer_head * unused_list = NULL;
static struct wait_queue * buffer_wait = NULL;

int nr_buffers = 0;
int buffermem = 0;
int nr_buffer_heads = 0;
static int min_free_pages = 20;	/* nr free pages needed before buffer grows */
extern int *blksize_size[];

/*
 * 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 wait_queue wait = { current, NULL };

	bh->b_count++;
	add_wait_queue(&bh->b_wait, &wait);
repeat:
	current->state = TASK_UNINTERRUPTIBLE;
	if (bh->b_lock) {
		schedule();
		goto repeat;
	}
	remove_wait_queue(&bh->b_wait, &wait);
	bh->b_count--;
	current->state = TASK_RUNNING;
}

/* 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. */

static int sync_buffers(dev_t dev, int wait)
{
	int i, retry, pass = 0, err = 0;
	struct buffer_head * bh;

	/* 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.
	 */
repeat:
	retry = 0;
	bh = free_list;
	for (i = nr_buffers*2 ; i-- > 0 ; bh = bh->b_next_free) {
		if (dev && bh->b_dev != dev)
			continue;
#ifdef 0 /* Disable bad-block debugging code */
		if (bh->b_req && !bh->b_lock &&
		    !bh->b_dirt && !bh->b_uptodate)
			printk ("Warning (IO error) - orphaned block %08x on %04x\n",
				bh->b_blocknr, bh->b_dev);
#endif
		if (bh->b_lock)
		{
			/* Buffer is locked; skip it unless wait is
			   requested AND pass > 0. */
			if (!wait || !pass) {
				retry = 1;
				continue;
			}
			wait_on_buffer (bh);
		}
		/* If an unlocked buffer is not uptodate, there has been 
		   an IO error. Skip it. */
		if (wait && bh->b_req && !bh->b_lock &&
		    !bh->b_dirt && !bh->b_uptodate)
		{
			err = 1;
			continue;
		}
		/* Don't write clean buffers.  Don't write ANY buffers
		   on the third pass. */
		if (!bh->b_dirt || pass>=2)
			continue;
		bh->b_count++;
		ll_rw_block(WRITE, 1, &bh);
		bh->b_count--;
		retry = 1;
	}
	/* 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). */
	if (wait && retry && ++pass<=2)
		goto repeat;
	return err;
}

void sync_dev(dev_t dev)
{
	sync_buffers(dev, 0);
	sync_supers(dev);
	sync_inodes(dev);
	sync_buffers(dev, 0);
}

int fsync_dev(dev_t dev)
{
	sync_buffers(dev, 0);
	sync_supers(dev);
	sync_inodes(dev);
	return sync_buffers(dev, 1);
}

asmlinkage int sys_sync(void)
{
	sync_dev(0);
	return 0;
}

int file_fsync (struct inode *inode, struct file *filp)
{
	return fsync_dev(inode->i_dev);
}

asmlinkage int sys_fsync(unsigned int fd)
{
	struct file * file;
	struct inode * inode;

	if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode))
		return -EBADF;
	if (!file->f_op || !file->f_op->fsync)
		return -EINVAL;
	if (file->f_op->fsync(inode,file))
		return -EIO;
	return 0;
}

void invalidate_buffers(dev_t dev)
{
	int i;
	struct buffer_head * bh;

	bh = free_list;
	for (i = nr_buffers*2 ; --i > 0 ; bh = bh->b_next_free) {
		if (bh->b_dev != dev)
			continue;
		wait_on_buffer(bh);
		if (bh->b_dev == dev)
			bh->b_uptodate = bh->b_dirt = bh->b_req = 0;
	}
}

/*
 * This routine checks whether a floppy has been changed, and
 * invalidates all buffer-cache-entries in that case. This
 * is a relatively slow routine, so we have to try to minimize using
 * it. Thus it is called only upon a 'mount' or 'open'. This
 * is the best way of combining speed and utility, I think.
 * People changing diskettes in the middle of an operation deserve
 * to loose :-)
 *
 * NOTE! Although currently this is only for floppies, the idea is
 * that any additional removable block-device will use this routine,
 * and that mount/open needn't know that floppies/whatever are
 * special.
 */
void check_disk_change(dev_t dev)
{
	int i;
	struct buffer_head * bh;

	switch(MAJOR(dev)){
	case FLOPPY_MAJOR:
		if (!(bh = getblk(dev,0,1024)))
			return;
		i = floppy_change(bh);
		brelse(bh);
		break;

#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
         case SCSI_DISK_MAJOR:
		i = check_scsidisk_media_change(dev, 0);
		break;
#endif

#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
	 case SCSI_CDROM_MAJOR:
		i = check_cdrom_media_change(dev, 0);
		break;
#endif

#if defined(CONFIG_CDU31A)
         case CDU31A_CDROM_MAJOR:
		i = check_cdu31a_media_change(dev, 0);
		break;
#endif

#if defined(CONFIG_MCD)
         case MITSUMI_CDROM_MAJOR:
		i = check_mcd_media_change(dev, 0);
		break;
#endif

         default:
		return;
	};

	if (!i)	return;

	printk("VFS: Disk change detected on device %d/%d\n",
					MAJOR(dev), MINOR(dev));
	for (i=0 ; i<NR_SUPER ; i++)
		if (super_blocks[i].s_dev == dev)
			put_super(super_blocks[i].s_dev);
	invalidate_inodes(dev);
	invalidate_buffers(dev);

#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
/* This is trickier for a removable hardisk, because we have to invalidate
   all of the partitions that lie on the disk. */
	if (MAJOR(dev) == SCSI_DISK_MAJOR)
		revalidate_scsidisk(dev, 0);
#endif
}

#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
#define hash(dev,block) hash_table[_hashfn(dev,block)]

static inline void remove_from_hash_queue(struct buffer_head * bh)
{
	if (bh->b_next)
		bh->b_next->b_prev = bh->b_prev;
	if (bh->b_prev)
		bh->b_prev->b_next = bh->b_next;
	if (hash(bh->b_dev,bh->b_blocknr) == bh)
		hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
	bh->b_next = bh->b_prev = NULL;
}

static inline void remove_from_free_list(struct buffer_head * bh)
{
	if (!(bh->b_prev_free) || !(bh->b_next_free))
		panic("VFS: Free block 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 (free_list == bh)
		free_list = bh->b_next_free;
	bh->b_next_free = bh->b_prev_free = NULL;
}

static inline void remove_from_queues(struct buffer_head * bh)
{
	remove_from_hash_queue(bh);
	remove_from_free_list(bh);
}

static inline void put_first_free(struct buffer_head * bh)
{
	if (!bh || (bh == free_list))
		return;
	remove_from_free_list(bh);
/* add to front of free list */
	bh->b_next_free = free_list;
	bh->b_prev_free = free_list->b_prev_free;
	free_list->b_prev_free->b_next_free = bh;
	free_list->b_prev_free = bh;
	free_list = bh;
}

static inline void put_last_free(struct buffer_head * bh)
{
	if (!bh)
		return;
	if (bh == free_list) {
		free_list = bh->b_next_free;
		return;
	}
	remove_from_free_list(bh);
/* add to back of free list */
	bh->b_next_free = free_list;
	bh->b_prev_free = free_list->b_prev_free;
	free_list->b_prev_free->b_next_free = bh;
	free_list->b_prev_free = bh;
}

static inline void insert_into_queues(struct buffer_head * bh)
{
/* put at end of free list */
	bh->b_next_free = free_list;
	bh->b_prev_free = free_list->b_prev_free;
	free_list->b_prev_free->b_next_free = bh;
	free_list->b_prev_free = bh;
/* put the buffer in new hash-queue if it has a device */
	bh->b_prev = NULL;
	bh->b_next = NULL;
	if (!bh->b_dev)
		return;
	bh->b_next = hash(bh->b_dev,bh->b_blocknr);
	hash(bh->b_dev,bh->b_blocknr) = bh;
	if (bh->b_next)
		bh->b_next->b_prev = bh;
}

static struct buffer_head * find_buffer(dev_t dev, int block, int size)
{		
	struct buffer_head * tmp;

	for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
		if (tmp->b_dev==dev && tmp->b_blocknr==block)
			if (tmp->b_size == size)
				return tmp;
			else {
				printk("VFS: Wrong blocksize on device %d/%d\n",
							MAJOR(dev), MINOR(dev));
				return NULL;
			}
	return NULL;
}

/*
 * Why like this, I hear you say... The reason is race-conditions.
 * As we don't lock buffers (unless we are readint them, that is),
 * something might happen to it while we sleep (ie a read-error
 * will force it bad). This shouldn't really happen currently, but
 * the code is ready.
 */
struct buffer_head * get_hash_table(dev_t dev, int block, int size)
{
	struct buffer_head * bh;

	for (;;) {
		if (!(bh=find_buffer(dev,block,size)))
			return NULL;
		bh->b_count++;
		wait_on_buffer(bh);
		if (bh->b_dev == dev && bh->b_blocknr == block && bh->b_size == size)
			return bh;
		bh->b_count--;
	}
}

void set_blocksize(dev_t dev, int size)
{
	int i;
	struct buffer_head * bh, *bhnext;

	if (!blksize_size[MAJOR(dev)])
		return;

	switch(size) {
		default: panic("Invalid blocksize passed to set_blocksize");
		case 512: case 1024: case 2048: case 4096:;
	}

	if (blksize_size[MAJOR(dev)][MINOR(dev)] == 0 && size == BLOCK_SIZE) {
		blksize_size[MAJOR(dev)][MINOR(dev)] = size;
		return;
	}
	if (blksize_size[MAJOR(dev)][MINOR(dev)] == size)
		return;
	sync_buffers(dev, 2);
	blksize_size[MAJOR(dev)][MINOR(dev)] = size;

  /* We need to be quite careful how we do this - we are moving entries
     around on the free list, and we can get in a loop if we are not careful.*/

	bh = free_list;
	for (i = nr_buffers*2 ; --i > 0 ; bh = bhnext) {
		bhnext = bh->b_next_free; 
		if (bh->b_dev != dev)
			continue;
		if (bh->b_size == size)
			continue;

		wait_on_buffer(bh);
		if (bh->b_dev == dev && bh->b_size != size)
			bh->b_uptodate = bh->b_dirt = 0;
		remove_from_hash_queue(bh);
/*    put_first_free(bh); */
	}
}

/*
 * Ok, this is getblk, and it isn't very clear, again to hinder
 * race-conditions. Most of the code is seldom used, (ie repeating),
 * so it should be much more efficient than it looks.
 *
 * The algoritm is changed: hopefully better, and an elusive bug removed.
 *
 * 14.02.92: changed it to sync dirty buffers a bit: better performance
 * when the filesystem starts to get full of dirty blocks (I hope).
 */
#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
struct buffer_head * getblk(dev_t dev, int block, int size)
{
	struct buffer_head * bh, * tmp;
	int buffers;
	static int grow_size = 0;

repeat:
	bh = get_hash_table(dev, block, size);
	if (bh) {
		if (bh->b_uptodate && !bh->b_dirt)
			put_last_free(bh);
		return bh;
	}
	grow_size -= size;
	if (nr_free_pages > min_free_pages && grow_size <= 0) {
		if (grow_buffers(GFP_BUFFER, size))
			grow_size = PAGE_SIZE;
	}
	buffers = nr_buffers;
	bh = NULL;

	for (tmp = free_list; buffers-- > 0 ; tmp = tmp->b_next_free) {
		if (tmp->b_count || tmp->b_size != size)
			continue;
		if (mem_map[MAP_NR((unsigned long) tmp->b_data)] != 1)
			continue;
		if (!bh || BADNESS(tmp)<BADNESS(bh)) {
			bh = tmp;
			if (!BADNESS(tmp))
				break;
		}
#if 0
		if (tmp->b_dirt) {
			tmp->b_count++;
			ll_rw_block(WRITEA, 1, &tmp);
			tmp->b_count--;
		}
#endif
	}

	if (!bh) {
		if (nr_free_pages > 5)
			if (grow_buffers(GFP_BUFFER, size))
				goto repeat;
		if (!grow_buffers(GFP_ATOMIC, size))
			sleep_on(&buffer_wait);
		goto repeat;
	}

	wait_on_buffer(bh);
	if (bh->b_count || bh->b_size != size)
		goto repeat;
	if (bh->b_dirt) {
		sync_buffers(0,0);
		goto repeat;
	}
/* NOTE!! While we slept waiting for this block, somebody else might */
/* already have added "this" block to the cache. check it */
	if (find_buffer(dev,block,size))
		goto repeat;
/* OK, FINALLY we know that this buffer is the only one of its kind, */
/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
	bh->b_count=1;
	bh->b_dirt=0;
	bh->b_uptodate=0;
	bh->b_req=0;
	remove_from_queues(bh);

?? 快捷鍵說(shuō)明

復(fù)制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號(hào) Ctrl + =
減小字號(hào) Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
在线观看91视频| 日韩精品一区二| 亚洲国产aⅴ天堂久久| 在线播放中文字幕一区| 韩国欧美一区二区| 亚洲欧洲精品一区二区精品久久久 | 国产精品国产馆在线真实露脸| 午夜国产精品影院在线观看| 91精品欧美久久久久久动漫 | 亚洲欧美日韩人成在线播放| 欧美伊人久久久久久午夜久久久久| 成人免费一区二区三区在线观看| 国产一区二区精品久久| 亚洲精品乱码久久久久久黑人| 大白屁股一区二区视频| 三级精品在线观看| 欧美极品xxx| 7777精品伊人久久久大香线蕉超级流畅| 中文字幕制服丝袜一区二区三区| 国产美女一区二区| 亚洲一区欧美一区| 国产欧美日韩久久| 91精品国产综合久久久蜜臀粉嫩| 日韩专区欧美专区| 国产精品久久久久久久久久久免费看| 国产馆精品极品| 夜夜揉揉日日人人青青一国产精品| 91麻豆6部合集magnet| 美女mm1313爽爽久久久蜜臀| 亚洲欧洲日本在线| 久久嫩草精品久久久精品一| 欧美午夜在线观看| 成人av免费在线播放| 另类小说视频一区二区| 亚洲一区二区欧美日韩| 国产精品嫩草99a| 日韩欧美成人午夜| 欧美日韩色一区| 91亚洲精华国产精华精华液| 国产一区二区视频在线播放| 亚洲不卡一区二区三区| 中文字幕一区二区三区蜜月 | 国产精品人成在线观看免费| 欧美一级高清片在线观看| 在线视频国产一区| 99久久久久久99| 国产一区二区三区香蕉| 日韩激情中文字幕| 一区二区三区加勒比av| 国产欧美综合在线| 精品国产1区2区3区| 欧美一区二区三区视频免费| 欧美三级资源在线| 在线观看免费一区| 在线视频观看一区| 欧美亚洲一区二区三区四区| 95精品视频在线| 成人国产亚洲欧美成人综合网| 午夜视黄欧洲亚洲| 亚洲香蕉伊在人在线观| 一区二区免费在线播放| 亚洲色图丝袜美腿| 亚洲精品一二三区| 一区二区三区免费观看| 亚洲一区二区四区蜜桃| 亚洲综合区在线| 一区二区三区蜜桃| 亚洲风情在线资源站| 亚洲一区在线免费观看| 亚洲制服丝袜av| 亚洲国产一二三| 日韩影视精彩在线| 狠狠色综合日日| 国产一区二区伦理| 成人性生交大片免费看视频在线| 日韩一区精品视频| 蜜桃视频在线观看一区二区| 久久99精品久久久久| 国产一区二区在线影院| 床上的激情91.| 91亚洲精品乱码久久久久久蜜桃| 精品一区二区三区日韩| 国产剧情在线观看一区二区| 国产91精品精华液一区二区三区| 亚洲电影你懂得| 美女视频黄免费的久久| 黑人巨大精品欧美一区| 成人手机在线视频| 一本大道久久精品懂色aⅴ| 在线观看不卡视频| 7777精品伊人久久久大香线蕉完整版 | 一二三四社区欧美黄| 亚洲国产日韩在线一区模特 | 激情五月婷婷综合| 国产成人在线色| 91网站在线观看视频| 欧美日韩午夜在线| 欧美大白屁股肥臀xxxxxx| 欧美激情在线一区二区| 夜夜嗨av一区二区三区| 日本一区中文字幕| 国产成人精品影视| 欧美色视频在线| 日韩欧美不卡在线观看视频| 中文字幕在线观看一区| 日韩精品一级二级| 丁香六月久久综合狠狠色| 91久久精品国产91性色tv| 欧美电影免费观看高清完整版在线| 欧美精品粉嫩高潮一区二区| 精品欧美一区二区三区精品久久| 精品欧美一区二区久久| 综合久久一区二区三区| 美女网站色91| 色拍拍在线精品视频8848| 日韩视频一区二区三区在线播放| 在线不卡免费欧美| 国产精品国产三级国产aⅴ入口| 欧美激情中文不卡| 三级不卡在线观看| 播五月开心婷婷综合| 欧美一区二区视频在线观看2020 | 香蕉久久一区二区不卡无毒影院| 亚洲精品日产精品乱码不卡| 麻豆91精品91久久久的内涵| 成人免费电影视频| 欧美一区二区性放荡片| 亚洲三级在线观看| 国产精品夜夜嗨| 911国产精品| 亚洲欧美综合另类在线卡通| 免费观看成人av| 欧洲av一区二区嗯嗯嗯啊| 国产欧美日韩另类一区| 热久久久久久久| 色天使色偷偷av一区二区| 国产网红主播福利一区二区| 午夜视黄欧洲亚洲| 色呦呦网站一区| 欧美激情在线观看视频免费| 日本vs亚洲vs韩国一区三区二区| 极品少妇xxxx偷拍精品少妇| 欧美蜜桃一区二区三区| 中文字幕中文字幕在线一区| 蜜桃视频免费观看一区| 欧美性高清videossexo| 亚洲少妇最新在线视频| 国产91对白在线观看九色| 日韩一级免费一区| 天天射综合影视| 欧美三级电影网| 自拍视频在线观看一区二区| 国产电影一区在线| 久久久综合网站| 久草中文综合在线| 欧美一区二区美女| 午夜不卡av免费| 欧洲亚洲国产日韩| 夜夜夜精品看看| 色狠狠一区二区三区香蕉| 中文字幕一区二区三区视频| 丁香啪啪综合成人亚洲小说 | 欧美va在线播放| 另类小说图片综合网| 在线播放亚洲一区| 五月天中文字幕一区二区| 欧美视频一区二区三区在线观看| 26uuu另类欧美| 国产精品一区二区男女羞羞无遮挡| 91浏览器入口在线观看| 亚洲视频在线观看一区| 94色蜜桃网一区二区三区| 日韩美女精品在线| 99久久综合色| 亚洲美女免费视频| 欧美色图一区二区三区| 石原莉奈在线亚洲二区| 日韩一区二区三区免费看 | 日韩写真欧美这视频| 日本免费在线视频不卡一不卡二| 不卡的av网站| 亚洲精品老司机| 欧美三级电影精品| 日韩vs国产vs欧美| 欧美成人艳星乳罩| 高清在线成人网| 亚洲精品视频在线观看网站| 欧美四级电影网| 久久精品国产免费| 久久久精品黄色| 99re热视频这里只精品| 亚洲午夜久久久久久久久久久| 成熟亚洲日本毛茸茸凸凹| 亚洲欧洲成人精品av97| 日本高清免费不卡视频| 日本网站在线观看一区二区三区| 欧美性xxxxxx少妇| 久久精品国产成人一区二区三区 | 欧美成人一级视频| 成人午夜视频在线观看|