static void flash_release(struct inode *inode, struct file *filp) { #ifdef CONFIG_BLK_DEV_FLASH sync_dev(inode->i_rdev); #endif return; }
static void mcd_release(struct inode * inode, struct file * file) { MOD_DEC_USE_COUNT; if (!--mcd_open_count) { mcd_invalidate_buffers(); sync_dev(inode->i_rdev); invalidate_buffers(inode -> i_rdev); } }
/* * 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. */ struct buffer_head * getblk(int dev,int block) { struct buffer_head * tmp; repeat: if ((tmp=get_hash_table(dev,block))) return tmp; tmp = free_list; do { if (!tmp->b_count) { wait_on_buffer(tmp); /* we still have to wait */ if (!tmp->b_count) /* on it, it might be dirty */ break; } tmp = tmp->b_next_free; } while (tmp != free_list || (tmp=NULL)); /* Kids, don't try THIS at home ^^^^^. Magic */ if (!tmp) { printk("Sleeping on free buffer .."); sleep_on(&buffer_wait); printk("ok\n"); goto repeat; } tmp->b_count++; remove_from_queues(tmp); /* * Now, when we know nobody can get to this node (as it's removed from the * free list), we write it out. We can sleep here without fear of race- * conditions. */ if (tmp->b_dirt) sync_dev(tmp->b_dev); /* update buffer contents */ tmp->b_dev=dev; tmp->b_blocknr=block; tmp->b_dirt=0; tmp->b_uptodate=0; /* NOTE!! While we possibly slept in sync_dev(), somebody else might have * added "this" block already, so check for that. Thank God for goto's. */ if (find_buffer(dev,block)) { tmp->b_dev=0; /* ok, someone else has beaten us */ tmp->b_blocknr=0; /* to it - free this block and */ tmp->b_count=0; /* try again */ insert_into_queues(tmp); goto repeat; } /* and then insert into correct position */ insert_into_queues(tmp); return tmp; }
struct buffer_head * getblk(int dev,int block) { struct buffer_head * bh, * tmp; int buffers; repeat: if (bh = get_hash_table(dev,block)) return bh; buffers = NR_BUFFERS; tmp = free_list; do { tmp = tmp->b_next_free; if (tmp->b_count) continue; if (!bh || BADNESS(tmp)<BADNESS(bh)) { bh = tmp; if (!BADNESS(tmp)) break; } if (tmp->b_dirt) ll_rw_block(WRITEA,tmp); /* and repeat until we find something good */ } while (buffers--); if (!bh) { sleep_on(&buffer_wait); goto repeat; } wait_on_buffer(bh); if (bh->b_count) goto repeat; while (bh->b_dirt) { sync_dev(bh->b_dev); wait_on_buffer(bh); if (bh->b_count) 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)) goto repeat; /* OK, FINALLY we know that this buffer is the only one of it's 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; remove_from_queues(bh); bh->b_dev=dev; bh->b_blocknr=block; insert_into_queues(bh); return bh; }
static void sd_release(struct inode * inode, struct file * file) { int target; sync_dev(inode->i_rdev); target = DEVICE_NR(MINOR(inode->i_rdev)); rscsi_disks[target].device->access_count--; if(rscsi_disks[target].device->removable) { if(!rscsi_disks[target].device->access_count) sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); }; }
//// 取高速缓冲中指定的缓冲区。 // 检查所指定的缓冲区是否已经在高速缓冲中,如果不在,就需要在高速缓冲中建立一个对应的新项。 // 返回相应缓冲区头指针。 struct buffer_head * getblk( int dev, int block ) { struct buffer_head *tmp, *bh; repeat: // 搜索hash 表,如果指定块已经在高速缓冲中,则返回对应缓冲区头指针,退出。 if( bh = get_hash_table( dev, block ) ) { return bh; } // 扫描空闲数据块链表,寻找空闲缓冲区。 // 首先让tmp 指向空闲链表的第一个空闲缓冲区头。 tmp = free_list; do { // 如果该缓冲区正被使用(引用计数不等于0),则继续扫描下一项。 if( tmp->b_count ) { continue; } // 如果缓冲头指针bh 为空,或者tmp 所指缓冲头的标志(修改、锁定)权重小于bh 头标志的权重, // 则让bh 指向该tmp 缓冲区头。如果该tmp 缓冲区头表明缓冲区既没有修改也没有锁定标志置位, // 则说明已为指定设备上的块取得对应的高速缓冲区,则退出循环。 if( !bh || BADNESS( tmp ) < BADNESS( bh ) ) { bh = tmp; if( !BADNESS( tmp ) ) { break; } } /* and repeat until we find something good *//* 重复操作直到找到适合的缓冲区 */ } while( ( tmp = tmp->b_next_free ) != free_list ); // 如果所有缓冲区都正被使用(所有缓冲区的头部引用计数都>0),则睡眠,等待有空闲的缓冲区可用。 if( !bh ) { sleep_on( &buffer_wait ); goto repeat; } // 等待该缓冲区解锁(如果已被上锁的话)。 wait_on_buffer( bh ); // 如果该缓冲区又被其它任务使用的话,只好重复上述过程。 if( bh->b_count ) { goto repeat; } // 如果该缓冲区已被修改,则将数据写盘,并再次等待缓冲区解锁。如果该缓冲区又被其它任务使用 // 的话,只好再重复上述过程。 while( bh->b_dirt ) { sync_dev( bh->b_dev ); wait_on_buffer( bh ); if( bh->b_count ) { goto repeat; } } /* NOTE!! While we slept waiting for this block, somebody else might */ /* already have added "this" block to the cache. check it */ /* 注意!!当进程为了等待该缓冲块而睡眠时,其它进程可能已经将该缓冲块 */ ** / // 在高速缓冲hash 表中检查指定设备和块的缓冲区是否已经被加入进去。如果是的话,就再次重复 // 上述过程。 if( find_buffer( dev, block ) ) { goto repeat; } /* OK, FINALLY we know that this buffer is the only one of it's kind, */ /* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ /* OK,最终我们知道该缓冲区是指定参数的唯一一块,*/ /* 而且还没有被使用(b_count=0),未被上锁(b_lock=0),并且是干净的(未被修改的)*/ // 于是让我们占用此缓冲区。置引用计数为1,复位修改标志和有效(更新)标志。 bh->b_count = 1; bh->b_dirt = 0; bh->b_uptodate = 0; // 从hash 队列和空闲块链表中移出该缓冲区头,让该缓冲区用于指定设备和其上的指定块。 remove_from_queues( bh ); bh->b_dev = dev; bh->b_blocknr = block; // 然后根据此新的设备号和块号重新插入空闲链表和hash 队列新位置处。并最终返回缓冲头指针。 insert_into_queues( bh ); return bh; }
//检查指定(设备号和块号)的缓冲区是否已经在高速缓冲中。如果指定块已经在高速缓冲中,则返回 //对应缓冲区头指针退出;如果不在,就需要在高速缓冲中设置一个对应设备号和块号的新项。返回相应 //缓冲区头指针 struct buffer_head * getblk(int dev,int block) { struct buffer_head * tmp, * bh; repeat: if ( (bh = get_hash_table(dev,block)) ) return bh; tmp = free_list; do { if (tmp->b_count) continue; if (!bh || BADNESS(tmp)<BADNESS(bh)) { bh = tmp; if (!BADNESS(tmp)) break; } /* and repeat until we find something good */ } while ((tmp = tmp->b_next_free) != free_list); //如果循环检查所有缓冲块都正在被使用(所有缓冲块的头部引用计数都>0)中,则睡眠等待有空闲 //缓冲块可用。当有空闲块可用时本进程会被明确地唤醒。然后我们就跳转到函数开始处重新查找空闲 //缓冲块 if (!bh) { sleep_on(&buffer_wait); goto repeat; } //如果跑到这里,说明已经找到一个空闲的缓冲区块。于是先等待该缓冲区解锁(如果已经被上锁的话)。 wait_on_buffer(bh); if (bh->b_count) goto repeat; //如果该缓冲区已被修改,则将数据写盘,并再次等待缓冲区解锁。 while (bh->b_dirt) { sync_dev(bh->b_dev); wait_on_buffer(bh); if (bh->b_count) 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)) goto repeat; /* OK, FINALLY we know that this buffer is the only one of it's kind, */ /* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ //到了这里,最终我们知道该缓冲块是指定参数的唯一一块,而且目前还没有被占用(b_count=0) //也没有被上锁(b_lock=0),而且是干净的(b_dirt=0) //于是我们占用此缓冲块。置引用计数为1,复位修改标志和有效标志 bh->b_count=1; bh->b_dirt=0; bh->b_uptodate=0; //从hash队列和空闲块链表中移出该缓冲区头,让该缓冲区用于指定设备和其上的指定块。然后根据 //此新的设备号和块号重新插入空闲链表和hash队列新位置处。并最终返回缓冲头指针。 remove_from_queues(bh); bh->b_dev=dev; bh->b_blocknr=block; insert_into_queues(bh); return bh; }
asmlinkage int sys_sync(void) { sync_dev(0); return 0; }
//// 取高速缓冲中指定的缓冲区。 // 检查所指定的缓冲区是否已经在高速缓冲中,如果不在,就需要在高速缓冲中建立一个对应的新项。 // 返回相应缓冲区头指针。 struct buffer_head * getblk(int dev,int block) { struct buffer_head * tmp, * bh; repeat: // 搜索hash 表,如果指定块已经在高速缓冲中,则返回对应缓冲区头指针,退出。 if (bh = get_hash_table(dev,block)) return bh; // 扫描空闲数据块链表,寻找空闲缓冲区。 // 首先让tmp 指向空闲链表的第一个空闲缓冲区头。 tmp = free_list; do { // 如果该缓冲区正被使用(引用计数不等于0),则继续扫描下一项。 if (tmp->b_count) continue; // 如果缓冲头指针bh 为空,或者tmp 所指缓冲头的标志(修改、锁定)权重小于bh 头标志的权重, // 则让bh 指向该tmp 缓冲区头。如果该tmp 缓冲区头表明缓冲区既没有修改也没有锁定标志置位, // 则说明已为指定设备上的块取得对应的高速缓冲区,则退出循环。 if (!bh || BADNESS(tmp)<BADNESS(bh)) { bh = tmp; if (!BADNESS(tmp)) break; } /* 重复操作直到找到适合的缓冲区 */ } while ((tmp = tmp->b_next_free) != free_list); // 如果所有缓冲区都正被使用(所有缓冲区的头部引用计数都>0), // 则睡眠,等待有空闲的缓冲区可用。 if (!bh) { sleep_on(&buffer_wait); goto repeat; } // 等待该缓冲区解锁(如果已被上锁的话)。 wait_on_buffer(bh); // 如果该缓冲区又被其它任务使用的话,只好重复上述过程。 if (bh->b_count) goto repeat; // 如果该缓冲区已被修改,则将数据写盘,并再次等待缓冲区解锁。如果该缓冲区又被其它任务使用 // 的话,只好再重复上述过程。 while (bh->b_dirt) { sync_dev(bh->b_dev); wait_on_buffer(bh); if (bh->b_count) goto repeat; } /* 注意!!当进程为了等待该缓冲块而睡眠时,其它进程可能已经将该缓冲块 */ /* 加入进高速缓冲中,所以要对此进行检查。 */ // 在高速缓冲hash 表中检查指定设备和块的缓冲区是否已经被加入进去。如果是的话,就再次重复 // 上述过程。 if (find_buffer(dev,block)) goto repeat; /* OK,最终我们知道该缓冲区是指定参数的唯一一块, */ /* 而且还没有被使用(b_count=0),未被上锁(b_lock=0),并且是干净的(未被修改的) */ // 于是让我们占用此缓冲区。置引用计数为1,复位修改标志和有效(更新)标志。 bh->b_count=1; bh->b_dirt=0; bh->b_uptodate=0; // 从hash 队列和空闲块链表中移出该缓冲区头,让该缓冲区用于指定设备和其上的指定块。 remove_from_queues(bh); bh->b_dev=dev; bh->b_blocknr=block; // 然后根据此新的设备号和块号重新插入空闲链表和hash 队列新位置处。并最终返回缓冲头指针。 insert_into_queues(bh); return bh; }