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

📄 buffer.c

📁 elinux jffs初始版本 具体了解JFFS的文件系统!
💻 C
📖 第 1 页 / 共 4 页
字号:
	unsigned long page;	struct buffer_head *bh, *tmp;	struct buffer_head * insert_point;	int isize;	if ((size & 511) || (size > PAGE_SIZE)) {		printk("VFS: grow_buffers: size = %d\n",size);		return 0;	}	isize = BUFSIZE_INDEX(size);	if (!(page = __get_free_page(pri)))		return 0;	bh = create_buffers(page, size);	if (!bh) {		free_page(page);		return 0;	}	insert_point = free_list[isize];	tmp = bh;	while (1) {		if (insert_point) {			tmp->b_next_free = insert_point->b_next_free;			tmp->b_prev_free = insert_point;			insert_point->b_next_free->b_prev_free = tmp;			insert_point->b_next_free = tmp;		} else {			tmp->b_prev_free = tmp;			tmp->b_next_free = tmp;		}		insert_point = tmp;		++nr_buffers;		if (tmp->b_this_page)			tmp = tmp->b_this_page;		else			break;	}	tmp->b_this_page = bh;	free_list[isize] = bh;	mem_map[MAP_NR(page)].buffers = bh;	buffermem += PAGE_SIZE;	return 1;}/* =========== Reduce the buffer memory ============= */static inline int buffer_waiting(struct buffer_head * bh){	return waitqueue_active(&bh->b_wait);}/* * try_to_free_buffer() checks if all the buffers on this particular page * are unused, and free's the page if so. */int try_to_free_buffer(struct buffer_head * bh, struct buffer_head ** bhp,		       int priority){	unsigned long page;	struct buffer_head * tmp, * p;	*bhp = bh;	page = (unsigned long) bh->b_data;	page &= PAGE_MASK;	tmp = bh;	do {		if (!tmp)			return 0;		if (tmp->b_count || buffer_protected(tmp) ||		    buffer_dirty(tmp) || buffer_locked(tmp) ||		    buffer_waiting(tmp))			return 0;		if (priority && buffer_touched(tmp))			return 0;		tmp = tmp->b_this_page;	} while (tmp != bh);	tmp = bh;	do {		p = tmp;		tmp = tmp->b_this_page;		nr_buffers--;		if (p == *bhp)		  {		    *bhp = p->b_prev_free;		    if (p == *bhp) /* Was this the last in the list? */		      *bhp = NULL;		  }		remove_from_queues(p);		put_unused_buffer_head(p);	} while (tmp != bh);	buffermem -= PAGE_SIZE;	mem_map[MAP_NR(page)].buffers = NULL;	free_page(page);	return !mem_map[MAP_NR(page)].count;}/* ================== Debugging =================== */void show_buffers(void){	struct buffer_head * bh;	int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;	int protected = 0;	int nlist;	static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","LOCKED1","DIRTY"};	printk("Buffer memory:   %6dkB\n",buffermem>>10);	printk("Buffer heads:    %6d\n",nr_buffer_heads);	printk("Buffer blocks:   %6d\n",nr_buffers);	for(nlist = 0; nlist < NR_LIST; nlist++) {	  found = locked = dirty = used = lastused = protected = 0;	  bh = lru_list[nlist];	  if(!bh) continue;	  do {		found++;		if (buffer_locked(bh))			locked++;		if (buffer_protected(bh))			protected++;		if (buffer_dirty(bh))			dirty++;		if (bh->b_count)			used++, lastused = found;		bh = bh->b_next_free;	  } while (bh != lru_list[nlist]);	  printk("%8s: %d buffers, %d used (last=%d), "		 "%d locked, %d protected, %d dirty\n",		 buf_types[nlist], found, used, lastused,		 locked, protected, dirty);	};}/* ===================== Init ======================= *//* * allocate the hash table and init the free list */void buffer_init(void){	hash_table = (struct buffer_head **)vmalloc(NR_HASH*sizeof(struct buffer_head *));	if (!hash_table)		panic("Failed to allocate buffer hash table\n");	memset(hash_table,0,NR_HASH*sizeof(struct buffer_head *));	lru_list[BUF_CLEAN] = 0;	grow_buffers(GFP_KERNEL, BLOCK_SIZE);}/* ====================== bdflush support =================== *//* This is a simple kernel daemon, whose job it is to provide a dynamic * response to dirty buffers.  Once this process is activated, we write back * a limited number of buffers to the disks and then go back to sleep again. */struct wait_queue * bdflush_wait = NULL;struct wait_queue * bdflush_done = NULL;struct task_struct *bdflush_tsk = 0;static void wakeup_bdflush(int wait){	if (current == bdflush_tsk)		return;	wake_up(&bdflush_wait);	if (wait) {		run_task_queue(&tq_disk);		sleep_on(&bdflush_done);		recover_reusable_buffer_heads();	}}/*  * Here we attempt to write back old buffers.  We also try to flush inodes  * and supers as well, since this function is essentially "update", and  * otherwise there would be no way of ensuring that these quantities ever  * get written back.  Ideally, we would have a timestamp on the inodes * and superblocks so that we could write back only the old ones as well */asmlinkage int sync_old_buffers(void){	int i;	int ndirty, nwritten;	int nlist;	int ncount;	struct buffer_head * bh, *next;	sync_supers(0);	sync_inodes(0);	ncount = 0;#ifdef DEBUG	for(nlist = 0; nlist < NR_LIST; nlist++)#else	for(nlist = BUF_DIRTY; nlist <= BUF_DIRTY; nlist++)#endif	{		ndirty = 0;		nwritten = 0;	repeat:		allow_interrupts();		bh = lru_list[nlist];		if(bh) 			 for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {				 /* We may have stalled while waiting for I/O to complete. */				 if(bh->b_list != nlist) goto repeat;				 next = bh->b_next_free;				 if(!lru_list[nlist]) {					 printk("Dirty list empty %d\n", i);					 break;				 }				 				 /* Clean buffer on dirty list?  Refile it */				 if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh))				  {					  refile_buffer(bh);					  continue;				  }				 				 if (buffer_locked(bh) || !buffer_dirty(bh))					  continue;				 ndirty++;				 if(bh->b_flushtime > jiffies) continue;				 nwritten++;				 next->b_count++;				 bh->b_count++;				 bh->b_flushtime = 0;#ifdef DEBUG				 if(nlist != BUF_DIRTY) ncount++;#endif				 ll_rw_block(WRITE, 1, &bh);				 bh->b_count--;				 next->b_count--;			 }	}	run_task_queue(&tq_disk);#ifdef DEBUG	if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);	printk("Wrote %d/%d buffers\n", nwritten, ndirty);#endif		return 0;}/* This is the interface to bdflush.  As we get more sophisticated, we can * pass tuning parameters to this "process", to adjust how it behaves.  * We would want to verify each parameter, however, to make sure that it  * is reasonable. */asmlinkage int sys_bdflush(int func, long data){	if (!suser())		return -EPERM;	if (func == 1)		 return sync_old_buffers();	/* Basically func 1 means read param 1, 2 means write param 1, etc */	if (func >= 2) {		int i = (func-2) >> 1;		if (i < 0 || i >= N_PARAM)			return -EINVAL;		if((func & 1) == 0) {			int error = verify_area(VERIFY_WRITE, (int*)data, 4);			if (!error)				put_user(bdf_prm.data[i], (int*)data);			return error;		}		if (data < bdflush_min[i] || data > bdflush_max[i])			return -EINVAL;		bdf_prm.data[i] = data;	}	/* Having func 0 used to launch the actual bdflush and then never	 * return (unless explicitly killed). We return zero here to 	 * remain semi-compatible with present update(8) programs.	 */	return 0;}/* This is the actual bdflush daemon itself. It used to be started from * the syscall above, but now we launch it ourselves internally with * kernel_thread(...)  directly after the first thread in init/main.c *//* To prevent deadlocks for a loop device: * 1) Do non-blocking writes to loop (avoids deadlock with running *	out of request blocks). * 2) But do a blocking write if the only dirty buffers are loop buffers *	(otherwise we go into an infinite busy-loop). * 3) Quit writing loop blocks if a freelist went low (avoids deadlock *	with running out of free buffers for loop's "real" device).*/int bdflush(void * unused) {	int i;	int ndirty;	int nlist;	int ncount;	struct buffer_head * bh, *next;	int major;	int wrta_cmd = WRITEA;	/* non-blocking write for LOOP */	/*	 *	We have a bare-bones task_struct, and really should fill	 *	in a few more things so "top" and /proc/2/{exe,root,cwd}	 *	display semi-sane things. Not real crucial though...  	 */	current->session = 1;	current->pgrp = 1;	sprintf(current->comm, "kflushd");	bdflush_tsk = current;	/*	 *	As a kernel thread we want to tamper with system buffers	 *	and other internals and thus be subject to the SMP locking	 *	rules. (On a uniprocessor box this does nothing).	 */#ifdef __SMP__	lock_kernel();	syscall_count++;#endif	for (;;) {#ifdef DEBUG		printk("bdflush() activated...");#endif				ncount = 0;#ifdef DEBUG		for(nlist = 0; nlist < NR_LIST; nlist++)#else		for(nlist = BUF_DIRTY; nlist <= BUF_DIRTY; nlist++)#endif		 {			 ndirty = 0;			 refilled = 0;		 repeat:			 allow_interrupts();			 bh = lru_list[nlist];			 if(bh) 				  for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 				       bh = next) {					  /* We may have stalled while waiting for I/O to complete. */					  if(bh->b_list != nlist) goto repeat;					  next = bh->b_next_free;					  if(!lru_list[nlist]) {						  printk("Dirty list empty %d\n", i);						  break;					  }					  					  /* Clean buffer on dirty list?  Refile it */					  if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh))					   {						   refile_buffer(bh);						   continue;					   }					  					  if (buffer_locked(bh) || !buffer_dirty(bh))						   continue;					  major = MAJOR(bh->b_dev);					  /* Should we write back buffers that are shared or not??					     currently dirty buffers are not shared, so it does not matter */					  if (refilled && major == LOOP_MAJOR)						   continue;					  next->b_count++;					  bh->b_count++;					  ndirty++;					  bh->b_flushtime = 0;					  if (major == LOOP_MAJOR) {						  ll_rw_block(wrta_cmd,1, &bh);						  wrta_cmd = WRITEA;						  if (buffer_dirty(bh))							  --ndirty;					  }					  else					  ll_rw_block(WRITE, 1, &bh);#ifdef DEBUG					  if(nlist != BUF_DIRTY) ncount++;#endif					  bh->b_count--;					  next->b_count--;				  }		 }#ifdef DEBUG		if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount);		printk("sleeping again.\n");#endif		/* If we didn't write anything, but there are still		 * dirty buffers, then make the next write to a		 * loop device to be a blocking write.		 * This lets us block--which we _must_ do! */		if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {			wrta_cmd = WRITE;			continue;		}		run_task_queue(&tq_disk);				/* If there are still a lot of dirty buffers around, skip the sleep		   and flush some more */		if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {			wake_up(&bdflush_done);			current->signal = 0;			interruptible_sleep_on(&bdflush_wait);		}	}}#ifdef MAGIC_ROM_PTRint bromptr(kdev_t dev, struct vm_area_struct * vma){        struct inode inode_fake;        extern struct file_operations * get_blkfops(unsigned int);        if (get_blkfops(MAJOR(dev))->romptr!=NULL)        {                inode_fake.i_rdev=dev;                return get_blkfops(MAJOR(dev))->romptr(&inode_fake, NULL, vma);        }        return -ENOSYS;}#endif/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only.  This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 8 * c-brace-imaginary-offset: 0 * c-brace-offset: -8 * c-argdecl-indent: 8 * c-label-offset: -8 * c-continued-statement-offset: 8 * c-continued-brace-offset: 0 * End: */

⌨️ 快捷键说明

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