547
技術社區[雲棲]
網絡子係統39_inet_peer緩存通用接口
// 查找inet_peer
// 參數:
// daddr,ip地址
// create,指示daddr不存在時,是否新建
// 注:inet_peer在內存中組織為平衡樹的形式
1.1 struct inet_peer *inet_getpeer(__be32 daddr, int create)
{
struct inet_peer *p, *n;
struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
//獲取讀鎖
read_lock_bh(&peer_pool_lock);
p = lookup(daddr, NULL);//執行查找
if (p != peer_avl_empty)//有效節點
atomic_inc(&p->refcnt);
read_unlock_bh(&peer_pool_lock);
if (p != peer_avl_empty) {
unlink_from_unused(p);//如果節點在unused_list鏈表上,從其上取下
return p;//返回
}
if (!create)//沒有找到,並且不創建
return NULL;//返回空
//通過SLAB 分配一個inet_peer
n = kmem_cache_alloc(peer_cachep, GFP_ATOMIC);
if (n == NULL)
return NULL;
n->v4daddr = daddr;//ip地址
atomic_set(&n->refcnt, 1);//引用技術
atomic_set(&n->rid, 0);
n->ip_id_count = secure_ip_id(daddr);//隨機生成一個ip id的起始值
n->tcp_ts_stamp = 0;
write_lock_bh(&peer_pool_lock);//獲取寫鎖,
p = lookup(daddr, stack);//再一次查找,防止在之前的處理過程中,另一個並行路徑,已經添加此inet_peer
if (p != peer_avl_empty)
goto out_free;//此地址被添加
link_to_pool(n);//將此節點連接到avl數中
INIT_LIST_HEAD(&n->unused);
peer_total++;//係統中inet_peer總數
write_unlock_bh(&peer_pool_lock);
if (peer_total >= inet_peer_threshold)
cleanup_once(0);//超過閥值,釋放unused中第一個inet_peer
return n;
out_free:
atomic_inc(&p->refcnt);
write_unlock_bh(&peer_pool_lock);
unlink_from_unused(p);
kmem_cache_free(peer_cachep, n);
return p;
}
// 釋放inet_peer引用計數
// 函數主要內容:
// 1.遞減引用計數
// 2.如果引用計數=0,加入到unused_peers鏈表
// 3.更新inet_peer加入到unused_peers的時間戳
// 注:引用計數為0的inet_peer並不立即刪除,而是掛載到unused_peers中, 由垃圾回收機製釋放。
1.2 void inet_putpeer(struct inet_peer *p)
{
//在遞減引用計數前,獲取unused_list鎖,防止先遞減後被並發路徑遞增,使引用計數非0的inet_peer被加入到鏈表中
spin_lock_bh(&inet_peer_unused_lock);
if (atomic_dec_and_test(&p->refcnt)) {//如果引用計數為0,則將其加入到鏈表中
list_add_tail(&p->unused, &unused_peers);
p->dtime = (__u32)jiffies;//加入到鏈表的時間戳
}
spin_unlock_bh(&inet_peer_unused_lock);//開鎖,開軟中斷
}
// 異步垃圾回收
// 函數主要任務:
// 1.根據係統中inet_peer數量,確定清理對象的範圍
// 2.同步清理符合範圍的inet_peer
// 3.根據清理的情況,調整下次異步垃圾回收的時間
// 3.1 如果係統中剩餘inet_peer仍然超過閾值,則定時器下一次盡快到期
// 3.2 否則在一定範圍內隨機化下一次的到期時間
2.1 static void peer_check_expire(unsigned long dummy)
{
unsigned long now = jiffies;
int ttl;
//係統中inet_peer數量超過了閥值
if (peer_total >= inet_peer_threshold)
ttl = inet_peer_minttl;//確定未用時長的inet_peer作為清除對象
else
ttl = inet_peer_maxttl
- (inet_peer_maxttl - inet_peer_minttl) / HZ *
peer_total / inet_peer_threshold * HZ;
while (!cleanup_once(ttl)) {//清除老化的inter_peer
if (jiffies != now)//清除操作耗時超過了1個jiffies
break;
}
if (peer_total >= inet_peer_threshold)//數量仍然超過閥值
peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime;//使gc盡快到期
else
peer_periodic_timer.expires = jiffies
+ inet_peer_gc_maxtime
- (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *
peer_total / inet_peer_threshold * HZ;
add_timer(&peer_periodic_timer);
}
// 同步垃圾回收
// 參數:
// ttl, 回收inet_peer的標準,如果inet_peer->dtime > jiffies+ttl,則回收此inet_peer
// 調用路徑:peer_check_expire->cleanup_once
// 注:
// 1.unused_list上的inet_peer仍然保存在avl樹中,當inet_peer再次被使用時(inet_getpeer),會從unused_list
// 上取下,因此一個inet_peer會進出unused_list數次
// 2.進入unused_list的inet_peer,refcnt=0
// 函數主要任務:
// 1.遍曆unused_list,取下滿足條件的inet_peer
// 2.從avl樹中刪除此inet_peer
2.2 static int cleanup_once(unsigned long ttl)
{
struct inet_peer *p = NULL;
spin_lock_bh(&inet_peer_unused_lock);//關軟中斷,獲取鎖
if (!list_empty(&unused_peers)) {//存在未使用的inet_peer
__u32 delta;
p = list_first_entry(&unused_peers, struct inet_peer, unused);
delta = (__u32)jiffies - p->dtime;
if (delta < ttl) {//在unused_peers上度過的時間短於被清除的要求
spin_unlock_bh(&inet_peer_unused_lock);
return -1;//直接返回
}
list_del_init(&p->unused);//從unused鏈表上刪除下來
atomic_inc(&p->refcnt);//增加引用技術,防止被其他係統釋放
}
spin_unlock_bh(&inet_peer_unused_lock);
if (p == NULL)//沒有空閑的inet_peer
return -1;
unlink_from_pool(p);//從avl樹中刪除inet_peer,調整avl樹
return 0;
}
最後更新:2017-04-03 15:22:13
上一篇:
如何用10隻實驗鼠檢驗出1000個藥瓶中哪個有毒藥?
下一篇:
機房收費係統之主窗體
素描個人展-徐昕
了解ASP.NET MVC幾種ActionResult的本質:JavaScriptResult & JsonResult
數據挖掘之數據準備——原始數據的特性
AMD戰略逐漸明晰
雲服務器 ECS 搭建WordPress網站:備案
Swift學習之四:類型別名(Type Aliases)
【Python學習】Python解決漢諾塔問題
開發者論壇一周精粹(第五期):安全組規則讓你的win主機更安全
hibernate中many-to-many基本操作
PostgreSQL 按需切片的實現(TimescaleDB插件自動切片功能的plpgsql schemaless實現)