//调用路径:ip_defrag->ip_evictor // 分片重组时,可使用内存上下限: // 1.sysctl_ipfrag_high_thresh 可用内存上限 // 2.sysctl_ipfrag_low_thresh 内存超过上限后,需要释放内存到此限 1.1 static void ip_evictor(void) { struct ipq *qp; struct list_head *tmp; int work; //计算需要释放的内存 work = atomic_read(&ip_frag_mem) - sysctl_ipfrag_low_thresh; if (work <= 0) return; while (work > 0) { read_lock(&ipfrag_lock); if (list_empty(&ipq_lru_list)) {//最近最久没有没有被使用的链表,链表头的ipq最久没有被使用 read_unlock(&ipfrag_lock); return; } //在获取锁的情况下,释放ipq tmp = ipq_lru_list.next; qp = list_entry(tmp, struct ipq, lru_list); atomic_inc(&qp->refcnt);//增加ipq的引用计数,防止其突然消失 read_unlock(&ipfrag_lock); spin_lock(&qp->lock); if (!(qp->last_in&COMPLETE))//ipq没有接收完全 ipq_kill(qp);// spin_unlock(&qp->lock); ipq_put(qp, &work); IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); } } //调用路径:ip_evictor->ipq_kill 1.2 static void ipq_kill(struct ipq *ipq) { if (del_timer(&ipq->timer))//删除ipq的定时器 atomic_dec(&ipq->refcnt);//递减定时器持有的引用计数 if (!(ipq->last_in & COMPLETE)) {//ipq没有接收完全 ipq_unlink(ipq);//将ipq从ipq hash表bucket的链表上摘下来 atomic_dec(&ipq->refcnt);//递减ipq hash表bucket对其持有的引用计数 ipq->last_in |= COMPLETE;//标记ipq接收完全,防止其被更新 } } 1.3 static __inline__ void ipq_put(struct ipq *ipq, int *work) { if (atomic_dec_and_test(&ipq->refcnt))//递减在ip_evictor中对ipq的引用 ip_frag_destroy(ipq, work);//释放关联到此ipq的skb } 1.4 static void ip_frag_destroy(struct ipq *qp, int *work) { struct sk_buff *fp; //此ipq接收到的所有分片 fp = qp->fragments; while (fp) { struct sk_buff *xp = fp->next; frag_kfree_skb(fp, work);//释放skb,从work中减去此skb的大小 fp = xp; } frag_free_queue(qp, work);//释放ipq结构 }