static CacheData *getCacheData(int device, int block) { CacheData *cacheData = findCacheData(device, block); if (cacheData==NULL) { CacheData *temp = startFreeEntry; while (temp!=NULL && temp->nextFree!=startFreeEntry) { if (temp->count==0) { if (cacheData==NULL || BADNESS(temp)<BADNESS(cacheData)) { cacheData = temp; if (BADNESS(temp)==0) { break; } } } temp = temp->nextFree; } cacheData->count = 1; cacheData->isDirty = false; cacheData->isUptoDate = false; removeFromQueue(cacheData); cacheData->device = device; cacheData->block = block; insertIntoQueue(cacheData); } return cacheData; }
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; }
struct buffer_head * getblk(int dev,int block) { // printk("getblk -------------------------------- 1\n"); struct buffer_head *tmp,*bh; repeat: if((bh = get_hash_buffer(dev,block))) return bh; tmp = buffer_free_list; do{ if(tmp->b_count) continue; if(!bh || (BADNESS(bh) > BADNESS(tmp))) { bh = tmp; if(!BADNESS(tmp)) break; } }while((tmp = tmp->b_next_free) != buffer_free_list); 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; } */ ///已经被其他的进程取走 if(find_buffer(dev,block)) goto repeat; 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; }
struct buffer_head * getblk(int dev, int block, int size) { struct buffer_head * bh, * tmp; int buffers; repeat: if (bh = get_hash_table(dev, block, size)) return bh; if (nr_free_pages > 30) grow_buffers(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 (!bh || BADNESS(tmp)<BADNESS(bh)) { bh = tmp; if (!BADNESS(tmp)) break; } #if 0 if (tmp->b_dirt) ll_rw_block(WRITEA,tmp); #endif } if (!bh && nr_free_pages > 5) { grow_buffers(size); goto repeat; } /* and repeat until we find something good */ if (!bh) { 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(bh->b_dev); 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 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; }
//// 取高速缓冲中指定的缓冲区。 // 检查所指定的缓冲区是否已经在高速缓冲中,如果不在,就需要在高速缓冲中建立一个对应的新项。 // 返回相应缓冲区头指针。 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; }
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); bh->b_dev=dev; bh->b_blocknr=block; insert_into_queues(bh); return bh; }
//// 取高速缓冲中指定的缓冲区。 // 检查所指定的缓冲区是否已经在高速缓冲中,如果不在,就需要在高速缓冲中建立一个对应的新项。 // 返回相应缓冲区头指针。 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; }